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