xref: /kvm-unit-tests/scripts/pretty_print_stacks.py (revision 762f9cd8d2c15c8f6ab82e757b51660ed6ca027d)
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