1 | #!/usr/bin/env python |
---|
2 | |
---|
3 | # An oops analyser for Xen |
---|
4 | # Usage: xensymoops path-to-xen.s < oops-message |
---|
5 | |
---|
6 | # There's probably some more features that could go in here but this |
---|
7 | # is sufficient to analyse most errors in my code ;-) |
---|
8 | |
---|
9 | # by Mark Williamson (C) 2004 Intel Research Cambridge |
---|
10 | |
---|
11 | import re, sys |
---|
12 | |
---|
13 | def read_oops(): |
---|
14 | """Process an oops message on stdin and return (eip_addr, stack_addrs) |
---|
15 | |
---|
16 | eip_addr is the location of EIP at the point of the crash. |
---|
17 | stack_addrs is a dictionary mapping potential code addresses in the stack |
---|
18 | to their order in the stack trace. |
---|
19 | """ |
---|
20 | stackaddr_ptn = "\[([a-z,0-9]*)\]" |
---|
21 | stackaddr_re = re.compile(stackaddr_ptn) |
---|
22 | |
---|
23 | eip_ptn = ".*EIP:.*<([a-z,0-9]*)>.*" |
---|
24 | eip_re = re.compile(eip_ptn) |
---|
25 | |
---|
26 | matches = 0 |
---|
27 | stack_addresses = {} |
---|
28 | eip_addr = "Not known" |
---|
29 | |
---|
30 | while True: |
---|
31 | line = sys.stdin.readline() |
---|
32 | if not line: break |
---|
33 | |
---|
34 | m = eip_re.match(line) |
---|
35 | if m: eip_addr = m.group(1) |
---|
36 | |
---|
37 | m = stackaddr_re.findall(line) |
---|
38 | |
---|
39 | for i in m: |
---|
40 | stack_addresses[i] = matches |
---|
41 | matches += 1 |
---|
42 | |
---|
43 | return (eip_addr, stack_addresses) |
---|
44 | |
---|
45 | def usage(): |
---|
46 | print >> sys.stderr, """Usage: %s path-to-asm < oops-msg |
---|
47 | The oops message should be fed to the standard input. The |
---|
48 | command-line argument specifies the path to the Xen assembly dump |
---|
49 | produced by \"make debug\". The location of EIP and the backtrace |
---|
50 | will be output to standard output. |
---|
51 | """ % sys.argv[0] |
---|
52 | sys.exit() |
---|
53 | |
---|
54 | ##### main |
---|
55 | |
---|
56 | if len(sys.argv) != 2: |
---|
57 | usage() |
---|
58 | |
---|
59 | # get address of EIP and the potential code addresses from the stack |
---|
60 | (eip_addr, stk_addrs) = read_oops() |
---|
61 | |
---|
62 | # open Xen disassembly |
---|
63 | asm_file = open(sys.argv[1]) |
---|
64 | |
---|
65 | # regexp to match addresses of code lines in the objdump |
---|
66 | addr_ptn = "([a-z,0-9]*):" |
---|
67 | addr_re = re.compile(addr_ptn) |
---|
68 | |
---|
69 | # regexp to match the start of functions in the objdump |
---|
70 | func_ptn = "(.*<[\S]*>):" |
---|
71 | func_re = re.compile(func_ptn) |
---|
72 | |
---|
73 | func = "<No function>" # holds the name of the current function being scanned |
---|
74 | |
---|
75 | eip_func = "<No function>" # name of the function EIP was in |
---|
76 | |
---|
77 | # list of (position in original backtrace, code address, function) tuples |
---|
78 | # describing all the potential code addresses we identified in the backtrace |
---|
79 | # whose addresses we also located in the objdump output |
---|
80 | backtrace = [] |
---|
81 | |
---|
82 | while True: |
---|
83 | line = asm_file.readline() |
---|
84 | if not line: break |
---|
85 | |
---|
86 | # if we've read the start of the function, record the name and address |
---|
87 | fm = func_re.match(line) |
---|
88 | if fm: |
---|
89 | func = fm.group(1) |
---|
90 | continue |
---|
91 | |
---|
92 | # try match the address at the start of the line |
---|
93 | m = addr_re.match(line) |
---|
94 | if not m: continue |
---|
95 | |
---|
96 | # we're on a code line... |
---|
97 | |
---|
98 | address = m.group(1) |
---|
99 | |
---|
100 | # if this address was seen as a potential code address in the backtrace then |
---|
101 | # record it in the backtrace list |
---|
102 | if stk_addrs.has_key(address): |
---|
103 | backtrace.append((stk_addrs[address], address, func)) |
---|
104 | |
---|
105 | # if this was the address that EIP... |
---|
106 | if address == eip_addr: |
---|
107 | eip_func = func |
---|
108 | |
---|
109 | |
---|
110 | print "EIP %s in function %s" % (eip_addr, eip_func) |
---|
111 | print "Backtrace:" |
---|
112 | |
---|
113 | # sorting will order primarily by the first element of each tuple, |
---|
114 | # i.e. the order in the original oops |
---|
115 | backtrace.sort() |
---|
116 | |
---|
117 | for (i, a, f) in backtrace: |
---|
118 | print "%s in function %s" % ( a, f ) |
---|