]>
Commit | Line | Data |
---|---|---|
261f4d6d AB |
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 | ||
7 | import gdb | |
8 | ||
9 | failcount = 0 | |
10 | ||
11 | ||
12 | def report(cond, msg): | |
13 | "Report success/fail of test" | |
14 | if cond: | |
15 | print ("PASS: %s" % (msg)) | |
16 | else: | |
17 | print ("FAIL: %s" % (msg)) | |
f251cb23 | 18 | global failcount |
261f4d6d AB |
19 | failcount += 1 |
20 | ||
21 | ||
22 | def 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 | ||
31 | def 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 | |
48 | def 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 | ||
65 | class 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 | ||
86 | def 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 | ||
99 | def 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 | ||
112 | class 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 | ||
124 | def run_test(): | |
e50a6121 | 125 | "Run through the tests one by one" |
261f4d6d AB |
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 | ||
157 | try: | |
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 | ||
168 | except: | |
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 | |
176 | gdb.execute("kill") | |
177 | exit(failcount) |