diff options
-rw-r--r-- | .clang-format | 13 | ||||
-rw-r--r-- | OWNERS | 3 | ||||
-rw-r--r-- | PREUPLOAD.cfg | 6 | ||||
-rw-r--r-- | dependency/VtsVndkDependencyTest.py | 116 | ||||
-rw-r--r-- | dependency/elf_parser.py | 275 | ||||
-rwxr-xr-x | golden/dump_abi.py | 260 |
6 files changed, 335 insertions, 338 deletions
diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..6027082 --- /dev/null +++ b/.clang-format @@ -0,0 +1,13 @@ +--- +Language: Cpp +BasedOnStyle: Google +ColumnLimit: 80 +IndentWidth: 2 +ContinuationIndentWidth: 4 +--- +Language: Java +BasedOnStyle: Google +ColumnLimit: 100 +IndentWidth: 4 +ContinuationIndentWidth: 8 +... @@ -0,0 +1,3 @@ +hsinyichen@google.com +yim@google.com +yuexima@google.com diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg new file mode 100644 index 0000000..6be6e5f --- /dev/null +++ b/PREUPLOAD.cfg @@ -0,0 +1,6 @@ +[Builtin Hooks] +clang_format = true + +[Builtin Hooks Options] +clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp,java + diff --git a/dependency/VtsVndkDependencyTest.py b/dependency/VtsVndkDependencyTest.py index 9c52276..4ccea2a 100644 --- a/dependency/VtsVndkDependencyTest.py +++ b/dependency/VtsVndkDependencyTest.py @@ -26,9 +26,9 @@ from vts.runners.host import base_test from vts.runners.host import test_runner from vts.runners.host import utils from vts.utils.python.controllers import android_device -from vts.utils.python.file import file_utils +from vts.utils.python.file import target_file_utils +from vts.utils.python.library import elf_parser from vts.utils.python.os import path_utils -from vts.testcases.vndk.dependency import elf_parser class VtsVndkDependencyTest(base_test.BaseTestClass): @@ -52,45 +52,28 @@ class VtsVndkDependencyTest(base_test.BaseTestClass): # copied from development/vndk/tools/definition-tool/vndk_definition_tool.py _LOW_LEVEL_NDK = [ - "libandroid_net.so", - "libc.so", - "libdl.so", - "liblog.so", - "libm.so", - "libstdc++.so", - "libvndksupport.so", - "libz.so" + "libandroid_net.so", "libc.so", "libdl.so", "liblog.so", "libm.so", + "libstdc++.so", "libvndksupport.so", "libz.so" + ] + _SAME_PROCESS_HAL = [ + re.compile(p) + for p in [ + "android\\.hardware\\.graphics\\.mapper@\\d+\\.\\d+-impl\\.so$", + "gralloc\\..*\\.so$", "libEGL_.*\\.so$", "libGLES_.*\\.so$", + "libGLESv1_CM_.*\\.so$", "libGLESv2_.*\\.so$", + "libGLESv3_.*\\.so$", "libPVRRS\\.so$", "libRSDriver.*\\.so$", + "vulkan.*\\.so$" + ] ] - _SAME_PROCESS_HAL = [re.compile(p) for p in [ - "android\\.hardware\\.graphics\\.mapper@\\d+\\.\\d+-impl\\.so$", - "gralloc\\..*\\.so$", - "libEGL_.*\\.so$", - "libGLES_.*\\.so$", - "libGLESv1_CM_.*\\.so$", - "libGLESv2_.*\\.so$", - "libGLESv3_.*\\.so$", - "libPVRRS\\.so$", - "libRSDriver.*\\.so$", - "vulkan.*\\.so$" - ]] _SAME_PROCESS_NDK = [ - "libEGL.so", - "libGLESv1_CM.so", - "libGLESv2.so", - "libGLESv3.so", - "libnativewindow.so", - "libsync.so", - "libvulkan.so" + "libEGL.so", "libGLESv1_CM.so", "libGLESv2.so", "libGLESv3.so", + "libnativewindow.so", "libsync.so", "libvulkan.so" ] _SP_HAL_LINK_PATHS_32 = [ - "/vendor/lib/egl", - "/vendor/lib/hw", - "/vendor/lib" + "/vendor/lib/egl", "/vendor/lib/hw", "/vendor/lib" ] _SP_HAL_LINK_PATHS_64 = [ - "/vendor/lib64/egl", - "/vendor/lib64/hw", - "/vendor/lib64" + "/vendor/lib64/egl", "/vendor/lib64/hw", "/vendor/lib64" ] class ElfObject(object): @@ -103,6 +86,7 @@ class VtsVndkDependencyTest(base_test.BaseTestClass): bitness: Integer. Bitness of the ELF. deps: List of strings. The names of the depended libraries. """ + def __init__(self, target_path, bitness, deps): self.target_path = target_path self.name = path_utils.TargetBaseName(target_path) @@ -117,8 +101,8 @@ class VtsVndkDependencyTest(base_test.BaseTestClass): self._shell = self._dut.shell.one self._temp_dir = tempfile.mkdtemp() logging.info("adb pull %s %s", self._TARGET_VENDOR_DIR, self._temp_dir) - pull_output = self._dut.adb.pull( - self._TARGET_VENDOR_DIR, self._temp_dir) + pull_output = self._dut.adb.pull(self._TARGET_VENDOR_DIR, + self._temp_dir) logging.debug(pull_output) def tearDownClass(self): @@ -144,25 +128,26 @@ class VtsVndkDependencyTest(base_test.BaseTestClass): full_path = os.path.join(root_dir, file_name) rel_path = os.path.relpath(full_path, host_dir) target_path = path_utils.JoinTargetPath( - target_dir, *rel_path.split(os.path.sep)); + target_dir, *rel_path.split(os.path.sep)) try: elf = elf_parser.ElfParser(full_path) except elf_parser.ElfError: logging.debug("%s is not an ELF file", target_path) continue try: - deps = elf.listDependencies() + deps = elf.ListDependencies() except elf_parser.ElfError as e: elf_error_handler(target_path, e) continue finally: - elf.close() + elf.Close() logging.info("%s depends on: %s", target_path, ", ".join(deps)) objs.append(self.ElfObject(target_path, elf.bitness, deps)) return objs - def _isAllowedSpHalDependency(self, lib_name, vndk_sp_names, linkable_libs): + def _isAllowedSpHalDependency(self, lib_name, vndk_sp_names, + linkable_libs): """Checks whether a same-process HAL library dependency is allowed. A same-process HAL library is allowed to depend on @@ -182,9 +167,8 @@ class VtsVndkDependencyTest(base_test.BaseTestClass): A boolean representing whether the dependency is allowed. """ if (lib_name in self._LOW_LEVEL_NDK or - lib_name in self._SAME_PROCESS_NDK or - lib_name in vndk_sp_names or - lib_name in linkable_libs): + lib_name in self._SAME_PROCESS_NDK or + lib_name in vndk_sp_names or lib_name in linkable_libs): return True return False @@ -242,8 +226,8 @@ class VtsVndkDependencyTest(base_test.BaseTestClass): searched.add(lib) for dep_name in lib.deps: if dep_name in searchable: - self._dfsDependencies( - searchable[dep_name], searched, searchable) + self._dfsDependencies(searchable[dep_name], searched, + searchable) def _testSpHalDependency(self, bitness, objs): """Scans same-process HAL dependency on vendor partition. @@ -253,32 +237,38 @@ class VtsVndkDependencyTest(base_test.BaseTestClass): disallowed dependencies and list of the dependencies. """ vndk_sp_dir = self._getTargetVndkSpDir(bitness) - vndk_sp_paths = file_utils.FindFiles(self._shell, vndk_sp_dir, "*.so") - vndk_sp_names = set(path_utils.TargetBaseName(x) for x in vndk_sp_paths) - logging.info("%s libraries: %s" % ( - vndk_sp_dir, ", ".join(vndk_sp_names))) + vndk_sp_paths = target_file_utils.FindFiles(self._shell, vndk_sp_dir, + "*.so") + vndk_sp_names = set( + path_utils.TargetBaseName(x) for x in vndk_sp_paths) + logging.info("%s libraries: %s" % (vndk_sp_dir, + ", ".join(vndk_sp_names))) # map file names to libraries which can be linked to same-process HAL linkable_libs = dict() - for obj in [x for x in objs - if x.bitness == bitness and self._isInSpHalLinkPaths(x)]: + for obj in [ + x for x in objs + if x.bitness == bitness and self._isInSpHalLinkPaths(x) + ]: if obj.name not in linkable_libs: linkable_libs[obj.name] = obj else: - linkable_libs[obj.name] = min(linkable_libs[obj.name], obj, - key=self._spHalLinkOrder) + linkable_libs[obj.name] = min( + linkable_libs[obj.name], obj, key=self._spHalLinkOrder) # find same-process HAL and dependencies sp_hal_libs = set() for file_name, obj in linkable_libs.iteritems(): if any([x.match(file_name) for x in self._SAME_PROCESS_HAL]): self._dfsDependencies(obj, sp_hal_libs, linkable_libs) - logging.info("%d-bit SP HAL libraries: %s" % ( - bitness, ", ".join([x.name for x in sp_hal_libs]))) + logging.info("%d-bit SP HAL libraries: %s" % + (bitness, ", ".join([x.name for x in sp_hal_libs]))) # check disallowed dependencies dep_errors = [] for obj in sp_hal_libs: - disallowed_libs = [x for x in obj.deps - if not self._isAllowedSpHalDependency(x, vndk_sp_names, - linkable_libs)] + disallowed_libs = [ + x for x in obj.deps + if not self._isAllowedSpHalDependency(x, vndk_sp_names, + linkable_libs) + ] if disallowed_libs: dep_errors.append((obj.target_path, disallowed_libs)) return dep_errors @@ -287,9 +277,9 @@ class VtsVndkDependencyTest(base_test.BaseTestClass): """Scans library/executable dependency on vendor partition.""" read_errors = [] objs = self._loadElfObjects( - self._temp_dir, - path_utils.TargetDirName(self._TARGET_VENDOR_DIR), - lambda p, e: read_errors.append((p, str(e)))) + self._temp_dir, + path_utils.TargetDirName(self._TARGET_VENDOR_DIR), + lambda p, e: read_errors.append((p, str(e)))) dep_errors = self._testSpHalDependency(32, objs) if self._dut.is64Bit: @@ -306,7 +296,7 @@ class VtsVndkDependencyTest(base_test.BaseTestClass): logging.error("%s: %s", x[0], ", ".join(x[1])) error_count = len(read_errors) + len(dep_errors) asserts.assertEqual(error_count, 0, - "Total number of errors: " + str(error_count)) + "Total number of errors: " + str(error_count)) if __name__ == "__main__": diff --git a/dependency/elf_parser.py b/dependency/elf_parser.py deleted file mode 100644 index 1d3c7e5..0000000 --- a/dependency/elf_parser.py +++ /dev/null @@ -1,275 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (C) 2017 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. -# - -import os -import struct - - -class ElfError(Exception): - """The exception raised by ElfParser.""" - pass - - -class ElfParser(object): - """The class reads information from an ELF file. - - Attributes: - _file: The ELF file object. - _file_size: Size of the ELF. - bitness: Bitness of the ELF. - _address_size: Size of address or offset in the ELF. - _offsets: Offset of each entry in the ELF. - _seek_read_address: The function to read an address or offset entry - from the ELF. - _sh_offset: Offset of section header table in the file. - _sh_size: Size of section header table entry. - _sh_count: Number of section header table entries. - _section_headers: List of SectionHeader objects read from the ELF. - """ - _MAGIC_OFFSET = 0 - _MAGIC_BYTES = b"\x7fELF" - _BITNESS_OFFSET = 4 - _BITNESS_32 = 1 - _BITNESS_64 = 2 - # Section type - _SHT_DYNAMIC = 6 - # Tag in dynamic section - _DT_NULL = 0 - _DT_NEEDED = 1 - _DT_STRTAB = 5 - - class ElfOffsets32(object): - """Offset of each entry in 32-bit ELF""" - # offset from ELF header - SECTION_HEADER_OFFSET = 0x20 - SECTION_HEADER_SIZE = 0x2e - SECTION_HEADER_COUNT = 0x30 - # offset from section header - SECTION_TYPE = 0x04 - SECTION_ADDRESS = 0x0c - SECTION_OFFSET = 0x10 - - class ElfOffsets64(object): - """Offset of each entry in 64-bit ELF""" - # offset from ELF header - SECTION_HEADER_OFFSET = 0x28 - SECTION_HEADER_SIZE = 0x3a - SECTION_HEADER_COUNT = 0x3c - # offset from section header - SECTION_TYPE = 0x04 - SECTION_ADDRESS = 0x10 - SECTION_OFFSET = 0x18 - - class SectionHeader(object): - """Contains section header entries as attributes. - - Attributes: - type: Type of the section. - address: The virtual memory address where the section is loaded. - offset: The offset of the section in the ELF file. - """ - def __init__(self, type, address, offset): - self.type = type - self.address = address - self.offset = offset - - def __init__(self, file_path): - """Creates a parser to open and read an ELF file. - - Args: - file_path: The path to the ELF. - - Raises: - ElfError if the file is not a valid ELF. - """ - try: - self._file = open(file_path, "rb") - except IOError as e: - raise ElfError(e) - try: - self._loadElfHeader() - self._section_headers = [ - self._loadSectionHeader(self._sh_offset + i * self._sh_size) - for i in range(self._sh_count)] - except: - self._file.close() - raise - - def __del__(self): - """Closes the ELF file.""" - self.close() - - def close(self): - """Closes the ELF file.""" - self._file.close() - - def _seekRead(self, offset, read_size): - """Reads a byte string at specific offset in the file. - - Args: - offset: An integer, the offset from the beginning of the file. - read_size: An integer, number of bytes to read. - - Returns: - A byte string which is the file content. - - Raises: - ElfError if fails to seek and read. - """ - if offset + read_size > self._file_size: - raise ElfError("Read beyond end of file.") - try: - self._file.seek(offset) - return self._file.read(read_size) - except IOError as e: - raise ElfError(e) - - def _seekRead8(self, offset): - """Reads an 1-byte integer from file.""" - return struct.unpack("B", self._seekRead(offset, 1))[0] - - def _seekRead16(self, offset): - """Reads a 2-byte integer from file.""" - return struct.unpack("H", self._seekRead(offset, 2))[0] - - def _seekRead32(self, offset): - """Reads a 4-byte integer from file.""" - return struct.unpack("I", self._seekRead(offset, 4))[0] - - def _seekRead64(self, offset): - """Reads an 8-byte integer from file.""" - return struct.unpack("Q", self._seekRead(offset, 8))[0] - - def _seekReadString(self, offset): - """Reads a null-terminated string starting from specific offset. - - Args: - offset: The offset from the beginning of the file. - - Returns: - A byte string, excluding the null character. - """ - ret = "" - buf_size = 16 - self._file.seek(offset) - while True: - try: - buf = self._file.read(buf_size) - except IOError as e: - raise ElfError(e) - end_index = buf.find('\0') - if end_index < 0: - ret += buf - else: - ret += buf[:end_index] - return ret - if len(buf) != buf_size: - raise ElfError("Null-terminated string reaches end of file.") - - def _loadElfHeader(self): - """Loads ElfHeader and initializes attributes""" - try: - self._file_size = os.fstat(self._file.fileno()).st_size - except OSError as e: - raise ElfError(e) - - magic = self._seekRead(self._MAGIC_OFFSET, 4) - if magic != self._MAGIC_BYTES: - raise ElfError("Wrong magic bytes.") - bitness = self._seekRead8(self._BITNESS_OFFSET) - if bitness == self._BITNESS_32: - self.bitness = 32 - self._address_size = 4 - self._offsets = self.ElfOffsets32 - self._seek_read_address = self._seekRead32 - elif bitness == self._BITNESS_64: - self.bitness = 64 - self._address_size = 8 - self._offsets = self.ElfOffsets64 - self._seek_read_address = self._seekRead64 - else: - raise ElfError("Wrong bitness value.") - - self._sh_offset = self._seek_read_address( - self._offsets.SECTION_HEADER_OFFSET) - self._sh_size = self._seekRead16(self._offsets.SECTION_HEADER_SIZE) - self._sh_count = self._seekRead16(self._offsets.SECTION_HEADER_COUNT) - return True - - def _loadSectionHeader(self, offset): - """Loads a section header from ELF file. - - Args: - offset: The starting offset of the section header. - - Returns: - An instance of SectionHeader. - """ - return self.SectionHeader( - self._seekRead32(offset + self._offsets.SECTION_TYPE), - self._seek_read_address(offset + self._offsets.SECTION_ADDRESS), - self._seek_read_address(offset + self._offsets.SECTION_OFFSET)) - - def _loadDtNeeded(self, offset): - """Reads DT_NEEDED entries from dynamic section. - - Args: - offset: The offset of the dynamic section from the beginning of - the file - - Returns: - A list of strings, the names of libraries. - """ - strtab_address = None - name_offsets = [] - while True: - tag = self._seek_read_address(offset) - offset += self._address_size - value = self._seek_read_address(offset) - offset += self._address_size - - if tag == self._DT_NULL: - break - if tag == self._DT_NEEDED: - name_offsets.append(value) - if tag == self._DT_STRTAB: - strtab_address = value - - if strtab_address is None: - raise ElfError("Cannot find string table offset in dynamic section") - - try: - strtab_offset = next(x.offset for x in self._section_headers - if x.address == strtab_address) - except StopIteration: - raise ElfError("Cannot find dynamic string table.") - - names = [self._seekReadString(strtab_offset + x) - for x in name_offsets] - return names - - def listDependencies(self): - """Lists the shared libraries that the ELF depends on. - - Returns: - A list of strings, the names of the depended libraries. - """ - deps = [] - for sh in self._section_headers: - if sh.type == self._SHT_DYNAMIC: - deps.extend(self._loadDtNeeded(sh.offset)) - return deps diff --git a/golden/dump_abi.py b/golden/dump_abi.py new file mode 100755 index 0000000..e4202d1 --- /dev/null +++ b/golden/dump_abi.py @@ -0,0 +1,260 @@ +#!/usr/bin/env python +# +# Copyright (C) 2017 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. +# + +import argparse +import importlib +import os +import subprocess +import sys + + +class ExternalModules(object): + """This class imports modules dynamically and keeps them as attributes. + + Assume the user runs this script in the source directory. The VTS modules + are outside the search path and thus have to be imported dynamically. + + Attribtues: + elf_parser: The elf_parser module. + vtable_parser: The vtable_parser module. + """ + @classmethod + def ImportParsers(cls, import_dir): + """Imports elf_parser and vtable_parser. + + Args: + import_dir: The directory containing vts.utils.python.library.*. + """ + sys.path.append(import_dir) + cls.elf_parser = importlib.import_module( + "vts.utils.python.library.elf_parser") + cls.vtable_parser = importlib.import_module( + "vts.utils.python.library.vtable_parser") + + +def GetBuildVariable(build_top_dir, var): + """Gets value of a variable from build config. + + Args: + build_top_dir: The path to root directory of Android source. + var: The name of the variable. + + Returns: + A string which is the value of the variable. + """ + build_core = os.path.join(build_top_dir, "build", "core") + env = dict(os.environ) + env["CALLED_FROM_SETUP"] = "true" + env["BUILD_SYSTEM"] = build_core + cmd = ["make", "--no-print-directory", + "-f", os.path.join(build_core, "config.mk"), + "dumpvar-" + var] + proc = subprocess.Popen(cmd, env=env, cwd=build_top_dir, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + stdout, stderr = proc.communicate() + if stderr: + sys.exit("Cannot get variable: cmd=%s\nstdout=%s\nstderr=%s" % ( + cmd, stdout, stderr)) + return stdout.strip() + + +def FindBinary(file_name): + """Finds an executable binary in environment variable PATH. + + Args: + file_name: The file name to find. + + Returns: + A string which is the path to the binary. + """ + cmd = ["which", file_name] + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + stdout, stderr = proc.communicate() + if proc.returncode: + sys.exit("Cannot find file: cmd=%s\nstdout=%s\nstderr=%s" % ( + cmd, stdout, stderr)) + return stdout + + +def DumpSymbols(lib_path, dump_path): + """Dump symbols from a library to a dump file. + + The dump file is a sorted list of symbols. Each line contains one symbol. + + Args: + lib_path: The path to the library. + dump_path: The path to the dump file. + + Returns: + A string which is the description about the result. + + Raises: + elf_parser.ElfError if fails to load the library. + IOError if fails to write to the dump. + """ + elf_parser = ExternalModules.elf_parser + parser = None + try: + parser = elf_parser.ElfParser(lib_path) + symbols = parser.ListGlobalDynamicSymbols() + finally: + if parser: + parser.Close() + if not symbols: + return "No symbols" + symbols.sort() + with open(dump_path, "w") as dump_file: + dump_file.write("\n".join(symbols) + "\n") + return "Output: " + dump_path + + +def DumpVtables(lib_path, dump_path, dumper_dir): + """Dump vtables from a library to a dump file. + + The dump file is the raw output of vndk-vtable-dumper. + + Args: + lib_path: The path to the library. + dump_path: The path to the text file. + dumper_dir: The path to the directory containing the dumper executable + and library. + + Returns: + A string which is the description about the result. + + Raises: + vtable_parser.VtableError if fails to load the library. + IOError if fails to write to the dump. + """ + vtable_parser = ExternalModules.vtable_parser + parser = vtable_parser.VtableParser(dumper_dir) + vtables = parser.CallVtableDumper(lib_path) + if not vtables: + return "No vtables" + with open(dump_path, "w+") as dump_file: + dump_file.write(vtables) + return "Output: " + dump_path + + +def GetSystemLibDirByArch(product_dir, arch_name): + """Returns the directory containing libraries for specific architecture. + + Args: + product_dir: The path to the product output directory in Android source. + arch_name: The name of the CPU architecture. + + Returns: + The path to the directory containing the libraries. + """ + if arch_name in ("arm", "x86", "mips"): + src_dir = os.path.join(product_dir, "system", "lib") + elif arch_name in ("arm64", "x86_64", "mips64"): + src_dir = os.path.join(product_dir, "system", "lib64") + else: + sys.exit("Unknown target arch " + str(target_arch)) + return src_dir + + +def DumpAbi(output_dir, input_files, product_dir, archs, dumper_dir): + """Generates dump from libraries. + + Args: + output_dir: The output directory of dump files. + input_files: A list of strings. Each element can be .so file or a text + file which contains list of libraries. + product_dir: The path to the product output directory in Android source. + archs: A list of strings which are the CPU architectures of the + libraries. + dumper_dir: The path to the directory containing the vtable dumper + executable and library. + """ + # Get names of the libraries to dump + lib_names = [] + for input_file in input_files: + if input_file.endswith(".so"): + lib_names.append(input_file) + else: + with open(input_file, "r") as lib_list: + lib_names.extend(line.strip() for line in lib_list + if line.strip()) + # Create the dumps + for arch in archs: + lib_dir = GetSystemLibDirByArch(product_dir, arch) + dump_dir = os.path.join(output_dir, arch) + if not os.path.exists(dump_dir): + os.makedirs(dump_dir) + for lib_name in lib_names: + lib_path = os.path.join(lib_dir, lib_name) + symbol_dump_path = os.path.join(dump_dir, lib_name + "_symbol.dump") + vtable_dump_path = os.path.join(dump_dir, lib_name + "_vtable.dump") + print(lib_path) + print(DumpSymbols(lib_path, symbol_dump_path)) + print(DumpVtables(lib_path, vtable_dump_path, dumper_dir)) + print("") + + +def main(): + # Parse arguments + arg_parser = argparse.ArgumentParser() + arg_parser.add_argument("file", nargs="*", + help="the library to dump. Can be .so file or a" + "text file containing list of libraries.") + arg_parser.add_argument("--dumper-dir", "-d", action="store", + help="the path to the directory containing " + "bin/vndk-vtable-dumper.") + arg_parser.add_argument("--import-path", "-i", action="store", + help="the directory for VTS python modules. " + "Default value is $ANDROID_BUILD_TOP/test") + arg_parser.add_argument("--output", "-o", action="store", required=True, + help="output directory for ABI reference dump.") + args = arg_parser.parse_args() + + # Get product directory + product_dir = os.getenv("ANDROID_PRODUCT_OUT") + if not product_dir: + sys.exit("env var ANDROID_PRODUCT_OUT is not set") + print("ANDROID_PRODUCT_OUT=" + product_dir) + + # Get target architectures + build_top_dir = os.getenv("ANDROID_BUILD_TOP") + if not build_top_dir: + sys.exit("env var ANDROID_BUILD_TOP is not set") + target_arch = GetBuildVariable(build_top_dir, "TARGET_ARCH") + target_2nd_arch = GetBuildVariable(build_top_dir, "TARGET_2ND_ARCH") + print("TARGET_ARCH=" + target_arch) + print("TARGET_2ND_ARCH=" + target_2nd_arch) + archs = [target_arch] + if target_2nd_arch: + archs.append(target_2nd_arch) + + # Import elf_parser and vtable_parser + ExternalModules.ImportParsers(args.import_path if args.import_path else + os.path.join(build_top_dir, "test")) + + # Find vtable dumper + if args.dumper_dir: + dumper_dir = args.dumper_dir + else: + dumper_path = FindBinary(vtable_parser.VtableParser.VNDK_VTABLE_DUMPER) + dumper_dir = os.path.dirname(os.path.dirname(dumper_path)) + print("DUMPER_DIR=" + dumper_dir) + + DumpAbi(args.output, args.file, product_dir, archs, dumper_dir) + + +if __name__ == "__main__": + main() |