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 puts(line) 71 72 if not line.strip().startswith('STACK:'): 73 continue 74 75 try: 76 pretty_print_stack(binary, line) 77 except Exception: 78 puts('Error pretty printing stack:\n') 79 puts(traceback.format_exc()) 80 puts('Continuing without pretty printing...\n') 81 while True: 82 puts(line) 83 line = sys.stdin.readline() 84 if line == '': 85 break 86 except: 87 sys.exit(1) 88 89if __name__ == '__main__': 90 main() 91