mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 18:21:39 +01:00
119 lines
3.2 KiB
Python
Executable File
119 lines
3.2 KiB
Python
Executable File
#!/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 )
|