summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHsin-Yi Chen <hsinyichen@google.com>2017-05-31 14:35:36 +0000
committerandroid-build-merger <android-build-merger@google.com>2017-05-31 14:35:36 +0000
commitfc20030808dfaa0783ceede99913b8deb938502f (patch)
tree3a77fd0e6189fcb9cbb62bd83e1d8cbbb19ec755
parente1e37d160c7ace0c8af65d824485c955054c1e7a (diff)
parentebdd869462e0c62f95edb7eba587e0ef856e2afb (diff)
downloadvndk-fc20030808dfaa0783ceede99913b8deb938502f.tar.gz
Move ELF parser to utils am: bb0794dbe3 am: fd7373ce68 am: d99db09ccd
am: ebdd869462 Change-Id: Ibda0546074786274322a0f9b510b47dabdcc48c0
-rw-r--r--dependency/VtsVndkDependencyTest.py6
-rw-r--r--dependency/elf_parser.py275
2 files changed, 3 insertions, 278 deletions
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