debug.c 4.0 KB

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