From bb0794dbe36bea7e3b55f49dc2b774ec16c2072b Mon Sep 17 00:00:00 2001 From: Hsin-Yi Chen Date: Wed, 24 May 2017 15:34:17 +0800 Subject: Move ELF parser to utils Test: vts-tradefed run commandAndExit vts -m VtsVndkDependencyTest Bug: 37488823 Change-Id: I8b9f10011944f0c939375ce15079af8f7d1367d5 --- dependency/VtsVndkDependencyTest.py | 6 +- dependency/elf_parser.py | 275 ------------------------------------ 2 files changed, 3 insertions(+), 278 deletions(-) delete mode 100644 dependency/elf_parser.py diff --git a/dependency/VtsVndkDependencyTest.py b/dependency/VtsVndkDependencyTest.py index 26eb6ae..b51ee85 100644 --- a/dependency/VtsVndkDependencyTest.py +++ b/dependency/VtsVndkDependencyTest.py @@ -27,8 +27,8 @@ 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.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): @@ -149,12 +149,12 @@ class VtsVndkDependencyTest(base_test.BaseTestClass): 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)) 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 -- cgit v1.2.3