test-gdbstub.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. from __future__ import print_function
  2. #
  3. # This script needs to be run on startup
  4. # qemu -kernel ${KERNEL} -s -S
  5. # and then:
  6. # gdb ${KERNEL}.vmlinux -x ${QEMU_SRC}/tests/guest-debug/test-gdbstub.py
  7. import gdb
  8. failcount = 0
  9. def report(cond, msg):
  10. "Report success/fail of test"
  11. if cond:
  12. print ("PASS: %s" % (msg))
  13. else:
  14. print ("FAIL: %s" % (msg))
  15. failcount += 1
  16. def check_step():
  17. "Step an instruction, check it moved."
  18. start_pc = gdb.parse_and_eval('$pc')
  19. gdb.execute("si")
  20. end_pc = gdb.parse_and_eval('$pc')
  21. return not (start_pc == end_pc)
  22. def check_break(sym_name):
  23. "Setup breakpoint, continue and check we stopped."
  24. sym, ok = gdb.lookup_symbol(sym_name)
  25. bp = gdb.Breakpoint(sym_name)
  26. gdb.execute("c")
  27. # hopefully we came back
  28. end_pc = gdb.parse_and_eval('$pc')
  29. print ("%s == %s %d" % (end_pc, sym.value(), bp.hit_count))
  30. bp.delete()
  31. # can we test we hit bp?
  32. return end_pc == sym.value()
  33. # We need to do hbreak manually as the python interface doesn't export it
  34. def check_hbreak(sym_name):
  35. "Setup hardware breakpoint, continue and check we stopped."
  36. sym, ok = gdb.lookup_symbol(sym_name)
  37. gdb.execute("hbreak %s" % (sym_name))
  38. gdb.execute("c")
  39. # hopefully we came back
  40. end_pc = gdb.parse_and_eval('$pc')
  41. print ("%s == %s" % (end_pc, sym.value()))
  42. if end_pc == sym.value():
  43. gdb.execute("d 1")
  44. return True
  45. else:
  46. return False
  47. class WatchPoint(gdb.Breakpoint):
  48. def get_wpstr(self, sym_name):
  49. "Setup sym and wp_str for given symbol."
  50. self.sym, ok = gdb.lookup_symbol(sym_name)
  51. wp_addr = gdb.parse_and_eval(sym_name).address
  52. self.wp_str = '*(%(type)s)(&%(address)s)' % dict(
  53. type = wp_addr.type, address = sym_name)
  54. return(self.wp_str)
  55. def __init__(self, sym_name, type):
  56. wp_str = self.get_wpstr(sym_name)
  57. super(WatchPoint, self).__init__(wp_str, gdb.BP_WATCHPOINT, type)
  58. def stop(self):
  59. end_pc = gdb.parse_and_eval('$pc')
  60. print ("HIT WP @ %s" % (end_pc))
  61. return True
  62. def do_one_watch(sym, wtype, text):
  63. wp = WatchPoint(sym, wtype)
  64. gdb.execute("c")
  65. report_str = "%s for %s (%s)" % (text, sym, wp.sym.value())
  66. if wp.hit_count > 0:
  67. report(True, report_str)
  68. wp.delete()
  69. else:
  70. report(False, report_str)
  71. def check_watches(sym_name):
  72. "Watch a symbol for any access."
  73. # Should hit for any read
  74. do_one_watch(sym_name, gdb.WP_ACCESS, "awatch")
  75. # Again should hit for reads
  76. do_one_watch(sym_name, gdb.WP_READ, "rwatch")
  77. # Finally when it is written
  78. do_one_watch(sym_name, gdb.WP_WRITE, "watch")
  79. class CatchBreakpoint(gdb.Breakpoint):
  80. def __init__(self, sym_name):
  81. super(CatchBreakpoint, self).__init__(sym_name)
  82. self.sym, ok = gdb.lookup_symbol(sym_name)
  83. def stop(self):
  84. end_pc = gdb.parse_and_eval('$pc')
  85. print ("CB: %s == %s" % (end_pc, self.sym.value()))
  86. if end_pc == self.sym.value():
  87. report(False, "Hit final catchpoint")
  88. def run_test():
  89. "Run through the tests one by one"
  90. print ("Checking we can step the first few instructions")
  91. step_ok = 0
  92. for i in range(3):
  93. if check_step():
  94. step_ok += 1
  95. report(step_ok == 3, "single step in boot code")
  96. print ("Checking HW breakpoint works")
  97. break_ok = check_hbreak("kernel_init")
  98. report(break_ok, "hbreak @ kernel_init")
  99. # Can't set this up until we are in the kernel proper
  100. # if we make it to run_init_process we've over-run and
  101. # one of the tests failed
  102. print ("Setup catch-all for run_init_process")
  103. cbp = CatchBreakpoint("run_init_process")
  104. cpb2 = CatchBreakpoint("try_to_run_init_process")
  105. print ("Checking Normal breakpoint works")
  106. break_ok = check_break("wait_for_completion")
  107. report(break_ok, "break @ wait_for_completion")
  108. print ("Checking watchpoint works")
  109. check_watches("system_state")
  110. #
  111. # This runs as the script it sourced (via -x)
  112. #
  113. try:
  114. print ("Connecting to remote")
  115. gdb.execute("target remote localhost:1234")
  116. # These are not very useful in scripts
  117. gdb.execute("set pagination off")
  118. gdb.execute("set confirm off")
  119. # Run the actual tests
  120. run_test()
  121. except:
  122. print ("GDB Exception: %s" % (sys.exc_info()[0]))
  123. failcount += 1
  124. import code
  125. code.InteractiveConsole(locals=globals()).interact()
  126. raise
  127. # Finally kill the inferior and exit gdb with a count of failures
  128. gdb.execute("kill")
  129. exit(failcount)