You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
139 lines
4.4 KiB
139 lines
4.4 KiB
4 months ago
|
#!/usr/bin/python
|
||
|
#
|
||
|
# Copyright (C) 2018 The Android Open Source Project
|
||
|
#
|
||
|
# Licensed under the Apache License, Version 2.0(the "License");
|
||
|
# you may not use this file except in compliance with the License.
|
||
|
# You may obtain a copy of the License at
|
||
|
#
|
||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||
|
#
|
||
|
# Unless required by applicable law or agreed to in writing, software
|
||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
# See the License for the specific language governing permissions and
|
||
|
# limitations under the License.
|
||
|
#
|
||
|
"""Use addr2line to interpret tombstone contents
|
||
|
|
||
|
The defaults should work if this is run after running lunch.
|
||
|
"""
|
||
|
|
||
|
from __future__ import print_function
|
||
|
import argparse
|
||
|
import collections
|
||
|
import functools
|
||
|
import multiprocessing
|
||
|
import os
|
||
|
import re
|
||
|
import subprocess
|
||
|
import sys
|
||
|
|
||
|
|
||
|
# Patterns of things that we might want to match.
|
||
|
|
||
|
patterns = [
|
||
|
(re.compile('(.* pc )([0-9a-f]+) +([^ ]+) .*'), 1, 3, 2),
|
||
|
(re.compile('(.*)#[0-9]+ 0x[0-9a-f]+ +\((.*)\+0x([0-9a-f]+)\)'), 1, 2, 3)]
|
||
|
|
||
|
|
||
|
LookupInfo = collections.namedtuple('LookupInfo',
|
||
|
['line_number', 'details', 'file_name'])
|
||
|
|
||
|
|
||
|
def lookup_addr(args, object_path, address):
|
||
|
try:
|
||
|
if object_path[0] == os.path.sep:
|
||
|
object_path = object_path[1:]
|
||
|
parms = [args.addr2line, '-e',
|
||
|
os.path.join(args.symbols, object_path), address]
|
||
|
details = subprocess.check_output(parms).strip().split(':')
|
||
|
return LookupInfo(
|
||
|
line_number=details[-1],
|
||
|
details=details,
|
||
|
file_name=':'.join(details[:-1]))
|
||
|
except subprocess.CalledProcessError:
|
||
|
return None
|
||
|
|
||
|
|
||
|
def simple_match(line, info, indent, out_file):
|
||
|
print('{} // From {}:{}'.format(
|
||
|
line, info.file_name, info.line_number), file=out_file)
|
||
|
|
||
|
|
||
|
def source_match(line, info, indent, out_file):
|
||
|
source = ''
|
||
|
try:
|
||
|
with open(info.file_name, 'r') as f:
|
||
|
for i in range(int(info.line_number.split(' ')[0])):
|
||
|
source = f.readline()
|
||
|
# Fall back to the simple formatter on any error
|
||
|
except Exception:
|
||
|
simple_match(line, info, indent, out_file)
|
||
|
return
|
||
|
print(line, file=out_file)
|
||
|
print('{}// From {}:{}'.format(
|
||
|
' ' * indent, info.file_name, info.line_number), file=out_file)
|
||
|
print('{} {}'.format(' ' * indent, ' '.join(source.strip().split())),
|
||
|
file=out_file)
|
||
|
|
||
|
|
||
|
def process(in_file, out_file, args):
|
||
|
for line in in_file:
|
||
|
line = line.rstrip()
|
||
|
groups = None
|
||
|
for p in patterns:
|
||
|
groups = p[0].match(line)
|
||
|
if groups:
|
||
|
break
|
||
|
info = None
|
||
|
if groups is not None:
|
||
|
info = lookup_addr(args, groups.group(p[2]), groups.group(p[3]))
|
||
|
if info is None:
|
||
|
print(line, file=out_file)
|
||
|
continue
|
||
|
if args.source:
|
||
|
source_match(line, info, len(groups.group(p[1])), out_file)
|
||
|
else:
|
||
|
simple_match(line, info, len(groups.group(p[1])), out_file)
|
||
|
|
||
|
|
||
|
def process_file(path, args):
|
||
|
with open(path + args.suffix, 'w') as out_file:
|
||
|
with open(path, 'r') as in_file:
|
||
|
process(in_file, out_file, args)
|
||
|
|
||
|
|
||
|
def common_arg_parser():
|
||
|
parser = argparse.ArgumentParser(description=
|
||
|
'Add line information to a tombstone')
|
||
|
parser.add_argument('--addr2line', type=str,
|
||
|
help='Path to addr2line',
|
||
|
default=os.path.join(
|
||
|
os.environ.get('ANDROID_TOOLCHAIN', ''),
|
||
|
'x86_64-linux-android-addr2line'))
|
||
|
parser.add_argument('files', metavar='FILE', type=str, nargs='+',
|
||
|
help='a list of files to process')
|
||
|
parser.add_argument('--jobs', type=int, default=32,
|
||
|
help='Number of parallel jobs to run')
|
||
|
parser.add_argument('--source', default=False, action='store_true',
|
||
|
help='Attempt to print the source')
|
||
|
parser.add_argument('--suffix', type=str, default='.txt',
|
||
|
help='Suffix to add to the processed file')
|
||
|
return parser
|
||
|
|
||
|
|
||
|
|
||
|
def process_all(args):
|
||
|
multiprocessing.Pool(32).map(functools.partial(process_file, args=args),
|
||
|
args.files)
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
parser = common_arg_parser()
|
||
|
parser.add_argument('--symbols', type=str,
|
||
|
help='Path to the symbols',
|
||
|
default=os.path.join(
|
||
|
os.environ.get('ANDROID_PRODUCT_OUT', ''), 'symbols'))
|
||
|
process_all(parser.parse_args())
|