Add ElfParser.IsExecutable and GetProgramInterpreter
This commit adds:
- Types and structure of program header
- ElfParser.IsExecutable
- ElfParser.GetProgramInterpreter
- Unit tests for the above methods and MatchCpuAbi.
Bug: 115567177
Test: python -m vts.utils.python.library.elf_parser_test
Test: vts-tradefed run vts -m VtsVndkDependency
Change-Id: Id5656c2d80b528eb08e8daf972ea6000d8989e54
Merged-In: Id5656c2d80b528eb08e8daf972ea6000d8989e54
(cherry picked from commit e08f2cab91d0cf0a5bc583e4969834f4b79bd8cc)
diff --git a/utils/python/library/elf/consts.py b/utils/python/library/elf/consts.py
index 43b19e8..8f95584 100644
--- a/utils/python/library/elf/consts.py
+++ b/utils/python/library/elf/consts.py
@@ -133,6 +133,32 @@
STT_LOPROC = 13
STT_HIPROC = 15
+# Segment types
+PT_NULL = 0
+PT_LOAD = 1
+PT_DYNAMIC = 2
+PT_INTERP = 3
+PT_NOTE = 4
+PT_SHLIB = 5
+PT_PHDR = 6
+PT_TLS = 7
+PT_LOOS = 0x60000000
+PT_HIOS = 0x6fffffff
+PT_LOPROC = 0x70000000
+PT_HIPROC = 0x7fffffff
+PT_GNU_EH_FRAME = 0x6474e550
+PT_SUNW_EH_FRAME = 0x6474e550
+PT_SUNW_UNWIND = 0x6464e550
+PT_GNU_STACK = 0x6474e551
+PT_GNU_RELRO = 0x6474e552
+PT_ARM_ARCHEXT = 0x70000000
+PT_ARM_EXIDX = 0x70000001
+PT_ARM_UNWIND = 0x70000001
+PT_MIPS_REGINFO = 0x70000000
+PT_MIPS_RTPROC = 0x70000001
+PT_MIPS_OPTIONS = 0x70000002
+PT_MIPS_ABIFLAGS = 0x70000003
+
# Dynamic array tags
# Name Value d_un Executable Shared Object
DT_NULL = 0 # ignored mandatory mandatory
diff --git a/utils/python/library/elf/structs.py b/utils/python/library/elf/structs.py
index 4508152..ac55b2f 100644
--- a/utils/python/library/elf/structs.py
+++ b/utils/python/library/elf/structs.py
@@ -306,3 +306,27 @@
_fields_ = [('r_offset', Elf64_Addr),
('r_info', Elf64_Xword),
('r_addend', Elf64_Sxword)]
+
+
+class Elf32_Phdr(CStructure):
+ """ELF 32-bit program header."""
+ _fields_ = [('p_type', Elf32_Word),
+ ('p_offset', Elf32_Off),
+ ('p_vaddr', Elf32_Addr),
+ ('p_paddr', Elf32_Addr),
+ ('p_filesz', Elf32_Word),
+ ('p_memsz', Elf32_Word),
+ ('p_flags', Elf32_Word),
+ ('p_align', Elf32_Word)]
+
+
+class Elf64_Phdr(CStructure):
+ """ELF 64-bit program header."""
+ _fields_ = [('p_type', Elf64_Word),
+ ('p_flags', Elf64_Word),
+ ('p_offset', Elf64_Off),
+ ('p_vaddr', Elf64_Addr),
+ ('p_paddr', Elf64_Addr),
+ ('p_filesz', Elf64_Xword),
+ ('p_memsz', Elf64_Xword),
+ ('p_align', Elf64_Xword)]
diff --git a/utils/python/library/elf/testing/libtest.so b/utils/python/library/elf/testing/libtest.so
index f21d0b3..74448dd 100755
--- a/utils/python/library/elf/testing/libtest.so
+++ b/utils/python/library/elf/testing/libtest.so
Binary files differ
diff --git a/utils/python/library/elf/testing/test-section-2.s b/utils/python/library/elf/testing/test-section-2.s
index cab44f6..4e88b55 100644
--- a/utils/python/library/elf/testing/test-section-2.s
+++ b/utils/python/library/elf/testing/test-section-2.s
@@ -17,3 +17,8 @@
.section test.dup,"",@note
nop
+
+# Test path name of program interpreter:
+
+.section .interp,"a",@progbits
+.string "/lib64/ld-linux-x86-64.so.2"
diff --git a/utils/python/library/elf_parser.py b/utils/python/library/elf_parser.py
index 616e5cf..90efe79 100644
--- a/utils/python/library/elf_parser.py
+++ b/utils/python/library/elf_parser.py
@@ -58,6 +58,7 @@
Elf_Sym: ELF symbol entry class.
Elf_Rel: ELF relocation entry class.
Elf_Rela: ELF relocation entry class with explicit addend.
+ Elf_Phdr: ELF program header class.
"""
def __init__(self, file_path, begin_offset=0):
@@ -112,6 +113,7 @@
self.Elf_Sym = structs.Elf32_Sym
self.Elf_Rel = structs.Elf32_Rel
self.Elf_Rela = structs.Elf32_Rela
+ self.Elf_Phdr = structs.Elf32_Phdr
else:
self.bitness = 64
self.Elf_Addr = structs.Elf64_Addr
@@ -125,6 +127,7 @@
self.Elf_Sym = structs.Elf64_Sym
self.Elf_Rel = structs.Elf64_Rel
self.Elf_Rela = structs.Elf64_Rela
+ self.Elf_Phdr = structs.Elf64_Phdr
try:
self.Ehdr = self._SeekReadStruct(0, self.Elf_Ehdr)
@@ -515,6 +518,10 @@
raise ElfError("Cannot find dynamic string table.")
return [self.GetString(strtab, off) for off in name_offsets]
+ def IsExecutable(self):
+ """Returns whether the ELF is executable."""
+ return self.Ehdr.e_type == consts.ET_EXEC
+
def MatchCpuAbi(self, abi):
"""Returns whether the ELF matches the ABI.
@@ -598,3 +605,17 @@
"""
return self.ListGlobalSymbols(include_weak,
consts.DYNSYM, consts.DYNSTR)
+
+ def GetProgramInterpreter(self):
+ """Gets the path to the program interpreter of the ELF.
+
+ Returns:
+ A string, the contents of .interp section.
+ None if the section is not found.
+ """
+ for ph_index in range(self.Ehdr.e_phnum):
+ ph = self._SeekReadStruct(
+ self.Ehdr.e_phoff + ph_index * self.Ehdr.e_phentsize,
+ self.Elf_Phdr)
+ if ph.p_type == consts.PT_INTERP:
+ return self._SeekReadString(ph.p_offset)
diff --git a/utils/python/library/elf_parser_test.py b/utils/python/library/elf_parser_test.py
index d8c3d5c..5b23b11 100644
--- a/utils/python/library/elf_parser_test.py
+++ b/utils/python/library/elf_parser_test.py
@@ -107,6 +107,16 @@
relocs.append((rela.r_offset, rela.r_info, rela.r_addend))
self.assertEqual(relocs, _ANDROID_RELOCATIONS)
+ def testIsExecutable(self):
+ """Tests that IsExecutable determines file type correctly."""
+ is_executable = self.elf_file.IsExecutable()
+ self.assertFalse(is_executable)
+
+ def testMatchCpuAbi(self):
+ """Tests that MatchCpuAbi determines machine type correctly."""
+ self.assertTrue(self.elf_file.MatchCpuAbi("x86_64"))
+ self.assertFalse(self.elf_file.MatchCpuAbi("x86"))
+
def testListDependencies(self):
"""Tests that ListDependencies lists ELF dependencies correctly."""
deps = self.elf_file.ListDependencies()
@@ -117,6 +127,11 @@
syms = self.elf_file.ListGlobalSymbols(False, '.dynsym', '.dynstr')
self.assertFalse(_EXPORTED_SYMBOLS.difference(syms))
+ def testGetProgramInterpreter(self):
+ """Tests that GetProgramInterpreter parses segment type correctly."""
+ interp = self.elf_file.GetProgramInterpreter()
+ self.assertEqual(interp, "/lib64/ld-linux-x86-64.so.2")
+
if __name__ == '__main__':
unittest.main()