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