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