Flutter Engine
The Flutter Engine
symbolize_stack_trace.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2# Copyright 2022 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6import collections
7import os
8import re
9import subprocess
10import sys
11
12
13# Run a command and symbolize anything that looks like a stacktrace in the
14# stdout/stderr. This will return with the same error code as the command.
15def main(basedir, cmd):
16 logs = collections.deque(maxlen=500)
17
18 proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
19 stderr=subprocess.STDOUT,
20 encoding='ISO-8859-1')
21 for line in iter(proc.stdout.readline, ''):
22 sys.stdout.write(line)
23 logs.append(line)
24 proc.wait()
25 print('Command exited with code %s' % proc.returncode)
26
27 try:
28 subprocess.check_call(['addr2line', '--help'],
29 stdout=subprocess.DEVNULL,
30 stderr=subprocess.DEVNULL)
31 except OSError:
32 print('addr2line not found on PATH. Skipping symbolization.')
33 return
34
35
36 # Stacktraces generally look like:
37 # /lib/x86_64-linux-gnu/libc.so.6(abort+0x16a) [0x7fa90e8d0c62]
38 # /b/s/w/irISUIyA/linux_vulkan_intel_driver_debug/./libvulkan_intel.so(+0x1f4d0a) [0x7fa909eead0a]
39 # /b/s/w/irISUIyA/out/Debug/dm() [0x17c3c5f]
40 # The stack_line regex splits those into three parts. Experimentation has
41 # shown that the address in () works best for external libraries, but our code
42 # doesn't have that. So, we capture both addresses and prefer using the first
43 # over the second, unless the first is blank or invalid. Relative offsets
44 # like abort+0x16a are ignored.
45 stack_line = r'^(?P<path>.+)\‍(\+?(?P<addr>.*)\‍) ?\[(?P<addr2>.+)\]'
46 # After performing addr2line, the result can be something obnoxious like:
47 # foo(bar) at /b/s/w/a39kd/Skia/out/Clang/../../src/gpu/Frobulator.cpp:13
48 # The extra_path strips off the not-useful prefix and leaves just the
49 # important src/gpu/Frobulator.cpp:13 bit.
50 extra_path = r'/.*\.\./'
51 is_first = True
52 last = ""
53 for line in logs:
54 line = line.strip()
55 # For unknown reasons, sometimes lines are duplicated in the stacktrace.
56 # This removes the duplication
57 if line == last:
58 continue
59 last = line
60
61 m = re.search(stack_line, line)
62 if m:
63 if is_first:
64 print('#######################################')
65 print('symbolized stacktrace follows')
66 print('#######################################')
67 is_first = False
68
69 path = m.group('path')
70 addr = m.group('addr')
71 addr2 = m.group('addr2')
72 if os.path.exists(path):
73 if not addr or not addr.startswith('0x'):
74 addr = addr2
75 try:
76 sym = subprocess.check_output([
77 'addr2line', '--demangle', '--pretty-print', '--functions',
78 '--exe='+path, addr
79 ]).decode('utf-8')
80 except subprocess.CalledProcessError:
81 sym = ''
82 sym = sym.strip()
83 # If addr2line doesn't return anything useful, we don't replace the
84 # original address, so the human can see it.
85 if sym and not sym.startswith('?'):
86 if path.startswith(basedir):
87 path = path[len(basedir) + 1:]
88 sym = re.sub(extra_path, '', sym)
89 line = path + ' ' + sym
90 print(line)
91
92 sys.exit(proc.returncode)
93
94
95if __name__ == '__main__':
96 if len(sys.argv) < 3:
97 print('USAGE: %s working_dir cmd_and_args...' % sys.argv[0],
98 file=sys.stderr)
99 sys.exit(1)
100 main(sys.argv[1], sys.argv[2:])
Definition: main.py:1
def print(*args, **kwargs)
Definition: run_tests.py:49
static DecodeResult decode(std::string path)
Definition: png_codec.cpp:124