summaryrefslogtreecommitdiff
path: root/tools/misc/xensymoops
blob: 835d187e9013bfaad8db350c5ac43a4238afc474 (plain)
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 )