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