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 11import re, sys 12 13def 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 45def 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 56if 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 63asm_file = open(sys.argv[1]) 64 65# regexp to match addresses of code lines in the objdump 66addr_ptn = "([a-z,0-9]*):" 67addr_re = re.compile(addr_ptn) 68 69# regexp to match the start of functions in the objdump 70func_ptn = "(.*<[\S]*>):" 71func_re = re.compile(func_ptn) 72 73func = "<No function>" # holds the name of the current function being scanned 74 75eip_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 80backtrace = [] 81 82while 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 110print "EIP %s in function %s" % (eip_addr, eip_func) 111print "Backtrace:" 112 113# sorting will order primarily by the first element of each tuple, 114# i.e. the order in the original oops 115backtrace.sort() 116 117for (i, a, f) in backtrace: 118 print "%s in function %s" % ( a, f ) 119