1#!/usr/bin/env python 2 3import re 4import subprocess 5import sys 6import traceback 7 8# Subvert output buffering. 9def puts(string): 10 sys.stdout.write(string) 11 sys.stdout.flush() 12 13def pretty_print_stack(binary, line): 14 addrs = line.split()[1:] 15 # Addresses are return addresses unless preceded by a '@'. We want the 16 # caller address so line numbers are more intuitive. Thus we subtract 1 17 # from the address to get the call code. 18 for i in range(len(addrs)): 19 addr = addrs[i] 20 if addr.startswith('@'): 21 addrs[i] = addr[1:] 22 else: 23 addrs[i] = '%lx' % (int(addrs[i], 16) - 1) 24 25 # Output like this: 26 # 0x004002be: start64 at path/to/kvm-unit-tests/x86/cstart64.S:208 27 # (inlined by) test_ept_violation at path/to/kvm-unit-tests/x86/vmx_tests.c:1719 (discriminator 1) 28 cmd = ['addr2line', '-e', binary, '-i', '-f', '--pretty', '--address'] 29 cmd.extend(addrs) 30 31 p = subprocess.Popen(cmd, stdout=subprocess.PIPE) 32 out, err = p.communicate() 33 if p.returncode != 0: 34 puts(line) 35 return 36 37 for line in out.splitlines(): 38 m = re.match('(.*) at [^ ]*/kvm-unit-tests/([^ ]*):([0-9]+)(.*)', line) 39 if m is None: 40 puts('%s\n' % line) 41 return 42 43 head, path, line, tail = m.groups() 44 line = int(line) 45 puts('%s at %s:%d%s\n' % (head, path, line, tail)) 46 try: 47 lines = open(path).readlines() 48 except IOError: 49 continue 50 if line > 1: 51 puts(' %s\n' % lines[line - 2].rstrip()) 52 puts(' > %s\n' % lines[line - 1].rstrip()) 53 if line < len(lines): 54 puts(' %s\n' % lines[line].rstrip()) 55 56def main(): 57 if len(sys.argv) != 2: 58 sys.stderr.write('usage: %s <kernel>\n' % sys.argv[0]) 59 sys.exit(1) 60 61 binary = sys.argv[1] 62 63 try: 64 while True: 65 # Subvert input buffering. 66 line = sys.stdin.readline() 67 if line == '': 68 break 69 70 if not line.strip().startswith('STACK:'): 71 puts(line) 72 continue 73 74 try: 75 pretty_print_stack(binary, line) 76 except Exception: 77 puts('Error pretty printing stack:\n') 78 puts(traceback.format_exc()) 79 puts('Continuing without pretty printing...\n') 80 while True: 81 puts(line) 82 line = sys.stdin.readline() 83 if line == '': 84 break 85 except: 86 sys.exit(1) 87 88if __name__ == '__main__': 89 main() 90