Add logic for replacing maps for zip files
For zip files, try to open the file in the current directory and insert the files as mappings. This enables the script to pick up embedded .so files. Added a check to look in current directory before the symbol dir. Added --app-symbols option to specify the directory containing the app APK and so files. Test: manual Bug: 111268230 Change-Id: Id1b1f13bac78911daa6a72c35ebfadfdc9c1700f
This commit is contained in:
@@ -21,6 +21,7 @@ import os.path
|
|||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
import zipfile
|
||||||
|
|
||||||
class Args:
|
class Args:
|
||||||
_usage = """
|
_usage = """
|
||||||
@@ -41,6 +42,8 @@ Usage:
|
|||||||
[--reverse]: reverse the backtraces (start the tree from the leaves)
|
[--reverse]: reverse the backtraces (start the tree from the leaves)
|
||||||
[--symbols SYMBOL_DIR] SYMBOL_DIR is the directory containing the .so files with symbols.
|
[--symbols SYMBOL_DIR] SYMBOL_DIR is the directory containing the .so files with symbols.
|
||||||
Defaults to $ANDROID_PRODUCT_OUT/symbols
|
Defaults to $ANDROID_PRODUCT_OUT/symbols
|
||||||
|
[--app-symbols SYMBOL_DIR] SYMBOL_DIR is the directory containing the app APK and so files.
|
||||||
|
Defaults to the current directory.
|
||||||
This outputs a file with lines of the form:
|
This outputs a file with lines of the form:
|
||||||
|
|
||||||
5831776 29.09% 100.00% 10532 71b07bc0b0 /system/lib64/libandroid_runtime.so Typeface_createFromArray frameworks/base/core/jni/android/graphics/Typeface.cpp:68
|
5831776 29.09% 100.00% 10532 71b07bc0b0 /system/lib64/libandroid_runtime.so Typeface_createFromArray frameworks/base/core/jni/android/graphics/Typeface.cpp:68
|
||||||
@@ -60,13 +63,17 @@ Usage:
|
|||||||
self.symboldir = product_out + "/symbols"
|
self.symboldir = product_out + "/symbols"
|
||||||
else:
|
else:
|
||||||
self.symboldir = "./symbols"
|
self.symboldir = "./symbols"
|
||||||
|
self.app_symboldir = ""
|
||||||
|
|
||||||
i = 1
|
i = 1
|
||||||
extra_args = []
|
extra_args = []
|
||||||
while i < len(sys.argv):
|
while i < len(sys.argv):
|
||||||
if sys.argv[i] == "--symbols":
|
if sys.argv[i] == "--symbols":
|
||||||
i += 1
|
i += 1
|
||||||
self.symboldir = args[i]
|
self.symboldir = sys.argv[i] + "/"
|
||||||
|
elif sys.argv[i] == "--app-symbols":
|
||||||
|
i += 1
|
||||||
|
self.app_symboldir = sys.argv[i] + "/"
|
||||||
elif sys.argv[i] == "--verbose":
|
elif sys.argv[i] == "--verbose":
|
||||||
self.verbose = True
|
self.verbose = True
|
||||||
elif sys.argv[i] == "--html":
|
elif sys.argv[i] == "--html":
|
||||||
@@ -166,7 +173,37 @@ def GetNumFieldValid(native_heap):
|
|||||||
else:
|
else:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def ParseNativeHeap(native_heap, reverse_frames, num_field_valid):
|
def GetMappingFromOffset(mapping, app_symboldir):
|
||||||
|
"""
|
||||||
|
If the input mapping is a zip file, translate the contained uncompressed files and add mapping
|
||||||
|
entries.
|
||||||
|
|
||||||
|
This is done to handle symbols for the uncompressed .so files inside APKs. With the replaced
|
||||||
|
mappings, the script looks up the .so files as separate files.
|
||||||
|
"""
|
||||||
|
basename = os.path.basename(mapping.name)
|
||||||
|
zip_name = app_symboldir + basename
|
||||||
|
if os.path.isfile(zip_name):
|
||||||
|
opened_zip = zipfile.ZipFile(zip_name)
|
||||||
|
if opened_zip:
|
||||||
|
# For all files in the zip, add mappings for the internal files.
|
||||||
|
for file_info in opened_zip.infolist():
|
||||||
|
# Only add stored files since it doesn't make sense to have PC into compressed ones.
|
||||||
|
if file_info.compress_type == zipfile.ZIP_STORED:
|
||||||
|
zip_header_entry_size = 30
|
||||||
|
data_offset = (file_info.header_offset
|
||||||
|
+ zip_header_entry_size
|
||||||
|
+ len(file_info.filename)
|
||||||
|
+ len(file_info.extra)
|
||||||
|
+ len(file_info.comment))
|
||||||
|
end_offset = data_offset + file_info.file_size
|
||||||
|
if mapping.offset >= data_offset and mapping.offset < end_offset:
|
||||||
|
mapping.name = file_info.filename
|
||||||
|
mapping.offset = data_offset - mapping.offset
|
||||||
|
break
|
||||||
|
return mapping
|
||||||
|
|
||||||
|
def ParseNativeHeap(native_heap, reverse_frames, num_field_valid, app_symboldir):
|
||||||
"""Parse the native heap into backtraces, maps.
|
"""Parse the native heap into backtraces, maps.
|
||||||
|
|
||||||
Returns two lists, the first is a list of all of the backtraces, the
|
Returns two lists, the first is a list of all of the backtraces, the
|
||||||
@@ -198,12 +235,14 @@ def ParseNativeHeap(native_heap, reverse_frames, num_field_valid):
|
|||||||
# 720de01000-720ded7000 r-xp 00000000 fd:00 495 /system/lib64/libc.so
|
# 720de01000-720ded7000 r-xp 00000000 fd:00 495 /system/lib64/libc.so
|
||||||
m = re_map.match(line)
|
m = re_map.match(line)
|
||||||
if m:
|
if m:
|
||||||
|
# Offset of mapping start
|
||||||
start = int(m.group('start'), 16)
|
start = int(m.group('start'), 16)
|
||||||
|
# Offset of mapping end
|
||||||
end = int(m.group('end'), 16)
|
end = int(m.group('end'), 16)
|
||||||
|
# Offset within file that is mapped
|
||||||
offset = int(m.group('offset'), 16)
|
offset = int(m.group('offset'), 16)
|
||||||
name = m.group('name')
|
name = m.group('name')
|
||||||
mappings.append(Mapping(start, end, offset, name))
|
mappings.append(GetMappingFromOffset(Mapping(start, end, offset, name), app_symboldir))
|
||||||
|
|
||||||
return backtraces, mappings
|
return backtraces, mappings
|
||||||
|
|
||||||
def FindMapping(mappings, addr):
|
def FindMapping(mappings, addr):
|
||||||
@@ -227,7 +266,7 @@ def FindMapping(mappings, addr):
|
|||||||
return mappings[mid]
|
return mappings[mid]
|
||||||
|
|
||||||
|
|
||||||
def ResolveAddrs(html_output, symboldir, backtraces, mappings):
|
def ResolveAddrs(html_output, symboldir, app_symboldir, backtraces, mappings):
|
||||||
"""Resolve address libraries and offsets.
|
"""Resolve address libraries and offsets.
|
||||||
|
|
||||||
addr_offsets maps addr to .so file offset
|
addr_offsets maps addr to .so file offset
|
||||||
@@ -259,7 +298,9 @@ def ResolveAddrs(html_output, symboldir, backtraces, mappings):
|
|||||||
print "Resolving symbols using directory %s..." % symboldir
|
print "Resolving symbols using directory %s..." % symboldir
|
||||||
|
|
||||||
for lib in addrs_by_lib:
|
for lib in addrs_by_lib:
|
||||||
sofile = symboldir + lib
|
sofile = app_symboldir + lib
|
||||||
|
if not os.path.isfile(sofile):
|
||||||
|
sofile = symboldir + lib
|
||||||
if os.path.isfile(sofile):
|
if os.path.isfile(sofile):
|
||||||
file_offset = 0
|
file_offset = 0
|
||||||
result = subprocess.check_output(["objdump", "-w", "-j", ".text", "-h", sofile])
|
result = subprocess.check_output(["objdump", "-w", "-j", ".text", "-h", sofile])
|
||||||
@@ -393,9 +434,11 @@ def main():
|
|||||||
|
|
||||||
num_field_valid = GetNumFieldValid(args.native_heap)
|
num_field_valid = GetNumFieldValid(args.native_heap)
|
||||||
|
|
||||||
backtraces, mappings = ParseNativeHeap(args.native_heap, args.reverse_frames, num_field_valid)
|
backtraces, mappings = ParseNativeHeap(args.native_heap, args.reverse_frames, num_field_valid,
|
||||||
|
args.app_symboldir)
|
||||||
# Resolve functions and line numbers
|
# Resolve functions and line numbers
|
||||||
resolved_addrs = ResolveAddrs(args.html_output, args.symboldir, backtraces, mappings)
|
resolved_addrs = ResolveAddrs(args.html_output, args.symboldir, args.app_symboldir, backtraces,
|
||||||
|
mappings)
|
||||||
|
|
||||||
app = AddrInfo("APP")
|
app = AddrInfo("APP")
|
||||||
zygote = AddrInfo("ZYGOTE")
|
zygote = AddrInfo("ZYGOTE")
|
||||||
|
|||||||
Reference in New Issue
Block a user