cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

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)