1 /* 2 * Test for x86 debugging facilities 3 * 4 * Copyright (c) Siemens AG, 2014 5 * 6 * Authors: 7 * Jan Kiszka <jan.kiszka@siemens.com> 8 * 9 * This work is licensed under the terms of the GNU GPL, version 2. 10 */ 11 12 #include "libcflat.h" 13 #include "desc.h" 14 15 static volatile unsigned long bp_addr[10], dr6[10]; 16 static volatile unsigned int n; 17 static volatile unsigned long value; 18 19 static unsigned long get_dr6(void) 20 { 21 unsigned long value; 22 23 asm volatile("mov %%dr6,%0" : "=r" (value)); 24 return value; 25 } 26 27 static void set_dr0(void *value) 28 { 29 asm volatile("mov %0,%%dr0" : : "r" (value)); 30 } 31 32 static void set_dr1(void *value) 33 { 34 asm volatile("mov %0,%%dr1" : : "r" (value)); 35 } 36 37 static void set_dr6(unsigned long value) 38 { 39 asm volatile("mov %0,%%dr6" : : "r" (value)); 40 } 41 42 static void set_dr7(unsigned long value) 43 { 44 asm volatile("mov %0,%%dr7" : : "r" (value)); 45 } 46 47 static void handle_db(struct ex_regs *regs) 48 { 49 bp_addr[n] = regs->rip; 50 dr6[n] = get_dr6(); 51 52 if (dr6[n] & 0x1) 53 regs->rflags |= (1 << 16); 54 55 if (++n >= 10) { 56 regs->rflags &= ~(1 << 8); 57 set_dr7(0x00000400); 58 } 59 } 60 61 static void handle_bp(struct ex_regs *regs) 62 { 63 bp_addr[0] = regs->rip; 64 } 65 66 int main(int ac, char **av) 67 { 68 unsigned long start; 69 70 setup_idt(); 71 handle_exception(DB_VECTOR, handle_db); 72 handle_exception(BP_VECTOR, handle_bp); 73 74 sw_bp: 75 asm volatile("int3"); 76 report("#BP", bp_addr[0] == (unsigned long)&&sw_bp + 1); 77 78 n = 0; 79 set_dr0(&&hw_bp1); 80 set_dr7(0x00000402); 81 hw_bp1: 82 asm volatile("nop"); 83 report("hw breakpoint (test that dr6.BS is not set)", 84 n == 1 && 85 bp_addr[0] == ((unsigned long)&&hw_bp1) && dr6[0] == 0xffff0ff1); 86 87 n = 0; 88 set_dr0(&&hw_bp2); 89 set_dr6(0x00004002); 90 hw_bp2: 91 asm volatile("nop"); 92 report("hw breakpoint (test that dr6.BS is not cleared)", 93 n == 1 && 94 bp_addr[0] == ((unsigned long)&&hw_bp2) && dr6[0] == 0xffff4ff1); 95 96 n = 0; 97 set_dr6(0); 98 asm volatile( 99 "pushf\n\t" 100 "pop %%rax\n\t" 101 "or $(1<<8),%%rax\n\t" 102 "push %%rax\n\t" 103 "lea (%%rip),%0\n\t" 104 "popf\n\t" 105 "and $~(1<<8),%%rax\n\t" 106 "push %%rax\n\t" 107 "popf\n\t" 108 : "=g" (start) : : "rax"); 109 report("single step", 110 n == 3 && 111 bp_addr[0] == start+1+6 && dr6[0] == 0xffff4ff0 && 112 bp_addr[1] == start+1+6+1 && dr6[1] == 0xffff4ff0 && 113 bp_addr[2] == start+1+6+1+1 && dr6[2] == 0xffff4ff0); 114 115 /* 116 * cpuid and rdmsr (among others) trigger VM exits and are then 117 * emulated. Test that single stepping works on emulated instructions. 118 */ 119 n = 0; 120 set_dr6(0); 121 asm volatile( 122 "pushf\n\t" 123 "pop %%rax\n\t" 124 "or $(1<<8),%%rax\n\t" 125 "push %%rax\n\t" 126 "lea (%%rip),%0\n\t" 127 "popf\n\t" 128 "and $~(1<<8),%%rax\n\t" 129 "push %%rax\n\t" 130 "xor %%rax,%%rax\n\t" 131 "cpuid\n\t" 132 "movl $0x1a0,%%ecx\n\t" 133 "rdmsr\n\t" 134 "popf\n\t" 135 : "=g" (start) : : "rax", "ebx", "ecx", "edx"); 136 report("single step emulated instructions", 137 n == 7 && 138 bp_addr[0] == start+1+6 && dr6[0] == 0xffff4ff0 && 139 bp_addr[1] == start+1+6+1 && dr6[1] == 0xffff4ff0 && 140 bp_addr[2] == start+1+6+1+3 && dr6[2] == 0xffff4ff0 && 141 bp_addr[3] == start+1+6+1+3+2 && dr6[3] == 0xffff4ff0 && 142 bp_addr[4] == start+1+6+1+3+2+5 && dr6[4] == 0xffff4ff0 && 143 bp_addr[5] == start+1+6+1+3+2+5+2 && dr6[5] == 0xffff4ff0 && 144 bp_addr[6] == start+1+6+1+3+2+5+2+1 && dr6[6] == 0xffff4ff0); 145 146 n = 0; 147 set_dr1((void *)&value); 148 set_dr7(0x00d0040a); 149 150 asm volatile( 151 "mov $42,%%rax\n\t" 152 "mov %%rax,%0\n\t" 153 : "=m" (value) : : "rax"); 154 hw_wp1: 155 report("hw watchpoint (test that dr6.BS is not cleared)", 156 n == 1 && 157 bp_addr[0] == ((unsigned long)&&hw_wp1) && dr6[0] == 0xffff4ff2); 158 159 n = 0; 160 set_dr6(0); 161 162 asm volatile( 163 "mov $42,%%rax\n\t" 164 "mov %%rax,%0\n\t" 165 : "=m" (value) : : "rax"); 166 hw_wp2: 167 report("hw watchpoint (test that dr6.BS is not set)", 168 n == 1 && 169 bp_addr[0] == ((unsigned long)&&hw_wp2) && dr6[0] == 0xffff0ff2); 170 171 n = 0; 172 set_dr6(0); 173 sw_icebp: 174 asm volatile(".byte 0xf1"); 175 report("icebp", 176 n == 1 && 177 bp_addr[0] == (unsigned long)&&sw_icebp + 1 && 178 dr6[0] == 0xffff0ff0); 179 180 return report_summary(); 181 } 182