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