123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- /*
- * Test for x86 debugging facilities
- *
- * Copyright (c) Siemens AG, 2014
- *
- * Authors:
- * Jan Kiszka <jan.kiszka@siemens.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.
- */
- #include "libcflat.h"
- #include "desc.h"
- static volatile unsigned long bp_addr[10], dr6[10];
- static volatile unsigned int n;
- static volatile unsigned long value;
- static unsigned long get_dr6(void)
- {
- unsigned long value;
- asm volatile("mov %%dr6,%0" : "=r" (value));
- return value;
- }
- static void set_dr0(void *value)
- {
- asm volatile("mov %0,%%dr0" : : "r" (value));
- }
- static void set_dr1(void *value)
- {
- asm volatile("mov %0,%%dr1" : : "r" (value));
- }
- static void set_dr6(unsigned long value)
- {
- asm volatile("mov %0,%%dr6" : : "r" (value));
- }
- static void set_dr7(unsigned long value)
- {
- asm volatile("mov %0,%%dr7" : : "r" (value));
- }
- static void handle_db(struct ex_regs *regs)
- {
- bp_addr[n] = regs->rip;
- dr6[n] = get_dr6();
- if (dr6[n] & 0x1)
- regs->rflags |= (1 << 16);
- if (++n >= 10) {
- regs->rflags &= ~(1 << 8);
- set_dr7(0x00000400);
- }
- }
- static void handle_bp(struct ex_regs *regs)
- {
- bp_addr[0] = regs->rip;
- }
- int main(int ac, char **av)
- {
- unsigned long start;
- setup_idt();
- handle_exception(DB_VECTOR, handle_db);
- handle_exception(BP_VECTOR, handle_bp);
- sw_bp:
- asm volatile("int3");
- report("#BP", bp_addr[0] == (unsigned long)&&sw_bp + 1);
- n = 0;
- set_dr0(&&hw_bp1);
- set_dr7(0x00000402);
- hw_bp1:
- asm volatile("nop");
- report("hw breakpoint (test that dr6.BS is not set)",
- n == 1 &&
- bp_addr[0] == ((unsigned long)&&hw_bp1) && dr6[0] == 0xffff0ff1);
- n = 0;
- set_dr0(&&hw_bp2);
- set_dr6(0x00004002);
- hw_bp2:
- asm volatile("nop");
- report("hw breakpoint (test that dr6.BS is not cleared)",
- n == 1 &&
- bp_addr[0] == ((unsigned long)&&hw_bp2) && dr6[0] == 0xffff4ff1);
- n = 0;
- set_dr6(0);
- asm volatile(
- "pushf\n\t"
- "pop %%rax\n\t"
- "or $(1<<8),%%rax\n\t"
- "push %%rax\n\t"
- "lea (%%rip),%0\n\t"
- "popf\n\t"
- "and $~(1<<8),%%rax\n\t"
- "push %%rax\n\t"
- "popf\n\t"
- : "=g" (start) : : "rax");
- report("single step",
- n == 3 &&
- bp_addr[0] == start+1+6 && dr6[0] == 0xffff4ff0 &&
- bp_addr[1] == start+1+6+1 && dr6[1] == 0xffff4ff0 &&
- bp_addr[2] == start+1+6+1+1 && dr6[2] == 0xffff4ff0);
- /*
- * cpuid and rdmsr (among others) trigger VM exits and are then
- * emulated. Test that single stepping works on emulated instructions.
- */
- n = 0;
- set_dr6(0);
- asm volatile(
- "pushf\n\t"
- "pop %%rax\n\t"
- "or $(1<<8),%%rax\n\t"
- "push %%rax\n\t"
- "lea (%%rip),%0\n\t"
- "popf\n\t"
- "and $~(1<<8),%%rax\n\t"
- "push %%rax\n\t"
- "xor %%rax,%%rax\n\t"
- "cpuid\n\t"
- "movl $0x1a0,%%ecx\n\t"
- "rdmsr\n\t"
- "popf\n\t"
- : "=g" (start) : : "rax", "ebx", "ecx", "edx");
- report("single step emulated instructions",
- n == 7 &&
- bp_addr[0] == start+1+6 && dr6[0] == 0xffff4ff0 &&
- bp_addr[1] == start+1+6+1 && dr6[1] == 0xffff4ff0 &&
- bp_addr[2] == start+1+6+1+3 && dr6[2] == 0xffff4ff0 &&
- bp_addr[3] == start+1+6+1+3+2 && dr6[3] == 0xffff4ff0 &&
- bp_addr[4] == start+1+6+1+3+2+5 && dr6[4] == 0xffff4ff0 &&
- bp_addr[5] == start+1+6+1+3+2+5+2 && dr6[5] == 0xffff4ff0 &&
- bp_addr[6] == start+1+6+1+3+2+5+2+1 && dr6[6] == 0xffff4ff0);
- n = 0;
- set_dr1((void *)&value);
- set_dr7(0x00d0040a);
- asm volatile(
- "mov $42,%%rax\n\t"
- "mov %%rax,%0\n\t"
- : "=m" (value) : : "rax");
- hw_wp1:
- report("hw watchpoint (test that dr6.BS is not cleared)",
- n == 1 &&
- bp_addr[0] == ((unsigned long)&&hw_wp1) && dr6[0] == 0xffff4ff2);
- n = 0;
- set_dr6(0);
- asm volatile(
- "mov $42,%%rax\n\t"
- "mov %%rax,%0\n\t"
- : "=m" (value) : : "rax");
- hw_wp2:
- report("hw watchpoint (test that dr6.BS is not set)",
- n == 1 &&
- bp_addr[0] == ((unsigned long)&&hw_wp2) && dr6[0] == 0xffff0ff2);
- n = 0;
- set_dr6(0);
- sw_icebp:
- asm volatile(".byte 0xf1");
- report("icebp",
- n == 1 &&
- bp_addr[0] == (unsigned long)&&sw_icebp + 1 &&
- dr6[0] == 0xffff0ff0);
- return report_summary();
- }
|