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