xref: /kvm-unit-tests/scripts/pretty_print_stacks.py (revision 3ad01e61ebee6125d8d7e5e45386cfe70a3a163c)
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:
2532e7ba06SNina 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():
40*3ad01e61SNina Schoetterl-Glausch        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
45*3ad01e61SNina Schoetterl-Glausch        head, path, maybeline, line, tail = m.groups()
46*3ad01e61SNina Schoetterl-Glausch        puts('%s at %s:%s%s\n' % (head.decode(), path.decode(), maybeline.decode(), tail.decode()))
47*3ad01e61SNina Schoetterl-Glausch        if line:
48a9143a24SPeter Feiner            line = int(line)
49a9143a24SPeter Feiner            try:
50a9143a24SPeter Feiner                lines = open(path).readlines()
51a9143a24SPeter Feiner            except IOError:
52a9143a24SPeter Feiner                continue
53a9143a24SPeter Feiner            if line > 1:
54a9143a24SPeter Feiner                puts('        %s\n' % lines[line - 2].rstrip())
55a9143a24SPeter Feiner            puts('      > %s\n' % lines[line - 1].rstrip())
56a9143a24SPeter Feiner            if line < len(lines):
57a9143a24SPeter Feiner                puts('        %s\n' % lines[line].rstrip())
58a9143a24SPeter Feiner
59a9143a24SPeter Feinerdef main():
60a9143a24SPeter Feiner    if len(sys.argv) != 2:
61a9143a24SPeter Feiner        sys.stderr.write('usage: %s <kernel>\n' % sys.argv[0])
62a9143a24SPeter Feiner        sys.exit(1)
63a9143a24SPeter Feiner
64e1f45419SAndrew Jones    binary = sys.argv[1].replace(".flat", ".elf")
65a9143a24SPeter Feiner
66e593c4fdSAndrew Jones    with open("config.mak") as config_file:
67e593c4fdSAndrew Jones        for line in config_file:
68e593c4fdSAndrew Jones            name, val = line.partition("=")[::2]
69e593c4fdSAndrew Jones            config[name.strip()] = val.strip()
70e593c4fdSAndrew Jones
71a9143a24SPeter Feiner    try:
72a9143a24SPeter Feiner        while True:
73a9143a24SPeter Feiner            # Subvert input buffering.
74a9143a24SPeter Feiner            line = sys.stdin.readline()
75a9143a24SPeter Feiner            if line == '':
76a9143a24SPeter Feiner                break
77a9143a24SPeter Feiner
78a9143a24SPeter Feiner            puts(line)
79762f9cd8SAndrew Jones
80762f9cd8SAndrew Jones            if not line.strip().startswith('STACK:'):
81a9143a24SPeter Feiner                continue
82a9143a24SPeter Feiner
83a9143a24SPeter Feiner            try:
84a9143a24SPeter Feiner                pretty_print_stack(binary, line)
85a9143a24SPeter Feiner            except Exception:
86a9143a24SPeter Feiner                puts('Error pretty printing stack:\n')
87a9143a24SPeter Feiner                puts(traceback.format_exc())
88a9143a24SPeter Feiner                puts('Continuing without pretty printing...\n')
89a9143a24SPeter Feiner                while True:
90a9143a24SPeter Feiner                    puts(line)
91a9143a24SPeter Feiner                    line = sys.stdin.readline()
92a9143a24SPeter Feiner                    if line == '':
93a9143a24SPeter Feiner                        break
94a9143a24SPeter Feiner    except:
95a9143a24SPeter Feiner        sys.exit(1)
96a9143a24SPeter Feiner
97a9143a24SPeter Feinerif __name__ == '__main__':
98a9143a24SPeter Feiner    main()
99