qemu/tests/guest-debug/test-gdbstub.py
<<
>>
Prefs
   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)
 178