Commit 4369df31 authored by Christopher Grant's avatar Christopher Grant Committed by Commit Bot

Android: Make stack.py work with secondary ABI on Clang

When Chromium changed to use Clang, the secondary ABI output directory
changed names.  Support that name, but also, return to using library
size as a means of matching up libraries.  This didn't work prior to
using lld, but does work now.  Preserve the original matching system as
a fallback.

Bug: 986622
Change-Id: Ia469eed5b0b69d8a4fe2840526ba817df362099d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1955821
Commit-Queue: Christopher Grant <cjgrant@chromium.org>
Reviewed-by: default avatarAndrew Grieve <agrieve@chromium.org>
Cr-Commit-Position: refs/heads/master@{#723062}
parent 1661f768
......@@ -29,7 +29,6 @@ import zipfile
import symbol
from pylib import constants
UNKNOWN = '<unknown>'
......@@ -518,11 +517,12 @@ def GetUncompressedSharedLibraryFromAPK(apkname, offset):
return soname, sosize
def _GetSharedLibraryInHost(soname, dirs):
def _GetSharedLibraryInHost(soname, sosize, dirs):
"""Find a shared library by name in a list of directories.
Args:
soname: library name (e.g. libfoo.so)
sosize: library file size to match.
dirs: list of directories to look for the corresponding file.
Returns:
host library path if found, or None
......@@ -531,6 +531,8 @@ def _GetSharedLibraryInHost(soname, dirs):
host_so_file = os.path.join(dir, os.path.basename(soname))
if not os.path.isfile(host_so_file):
continue
if os.path.getsize(host_so_file) != sosize:
continue
logging.debug("%s match to the one in APK" % host_so_file)
return host_so_file
......@@ -587,17 +589,12 @@ def _FindSharedLibraryFromAPKs(output_directory, apks_directory, offset):
soname, sosize = GetUncompressedSharedLibraryFromAPK(apk, offset)
if soname == "":
continue
# The relocation section of libraries in APK is packed, we can't
# detect library by its size, and have to rely on the order of lib
# directories; for a specific ARCH, the libraries are in either
# output_directory or output_directory/android_ARCH, and android_ARCH
# directory could exists or not, so having android_ARCH directory be in
# first, we will find the correct lib.
dirs = [
os.path.join(output_directory, "android_%s" % symbol.ARCH),
output_directory,
dirs = [output_directory] + [
os.path.join(output_directory, x)
for x in os.listdir(output_directory)
if os.path.exists(os.path.join(output_directory, x, 'lib.unstripped'))
]
host_so_file = _GetSharedLibraryInHost(soname, dirs)
host_so_file = _GetSharedLibraryInHost(soname, sosize, dirs)
if host_so_file:
shared_libraries += [(soname, host_so_file)]
# If there are more than one libraries found, it means detecting
......
......@@ -70,22 +70,36 @@ class FakeSymbolizer:
return [('??', '??:0:0')]
namespace = basename.split('.')[0].replace('lib', '', 1)
# Determine if the lib is a secondary ABI library, in which case, preface
# its namespace with '32'.
if 'android_clang_' in file:
namespace += '32'
method_name = '{}::Func_{:X}'.format(namespace, address)
return [(method_name, '{}.cc:1:1'.format(namespace))]
class StackDecodeTest(unittest.TestCase):
def setUp(self):
self._num_libraries = 0
self._temp_dir = tempfile.mkdtemp()
def tearDown(self):
shutil.rmtree(self._temp_dir)
def _MakeElf(self, file):
# Make the unstripped lib directory in case stack.py looks for it.
dir = os.path.join(os.path.dirname(file), 'lib.unstripped')
if not os.path.exists(dir):
os.makedirs(dir)
# Create a library slightly less than 4K in size, so that when added to an
# APK archive, all libraries end up on 4K boundaries.
data = '\x7fELF' + ' ' * 0xE00
# APK archive, all libraries end up on 4K boundaries. Also, make each
# library a slightly different size, since stack.py may utilize size when
# matching up libraries.
data = '\x7fELF' + ' ' * (0xE00 - self._num_libraries)
self._num_libraries += 1
with open(file, 'wb') as f:
f.write(data)
......@@ -229,6 +243,41 @@ class StackDecodeTest(unittest.TestCase):
''')
self._RunCase(input, expected, apks)
def test_MultiArchPrimaryAbi(self):
apks = {
'monochrome.apk': [
'libmonochrome.so', 'android_clang_arm/libmonochrome.so'
],
}
# With both architectures present, verify that the correct ABI output and
# directory is chosen, even if identically-named libraries exist in both.
input = textwrap.dedent('''
DEBUG : #01 pc 00000174 /path==/base.apk (offset 0x00001000)
''')
expected = textwrap.dedent('''
00000174 monochrome::Func_174 monochrome.cc:1:1
''')
self._RunCase(input, expected, apks)
def test_MultiArchSecondary(self):
apks = {
'monochrome.apk': [
'libmonochrome.so', 'android_clang_arm/libmonochrome.so'
],
}
# With both architectures present, verify that the secondary ABI output
# directory is chosen when appropriate, even if identically-named libraries
# exist in both. This must be a different test from the primary ABI case,
# since in practice, traces are from a single ABI (and the script relies on
# this).
input = textwrap.dedent('''
DEBUG : #02 pc 00000274 /path==/base.apk (offset 0x00002000)
''')
expected = textwrap.dedent('''
00000274 monochrome32::Func_274 monochrome32.cc:1:1
''')
self._RunCase(input, expected, apks)
if __name__ == '__main__':
unittest.main()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment