xref: /aosp_15_r20/test/vts/vndk_utils/library/elf_parser.py (revision 9a74111979c139a065a9a7e4d45972320c5732c7)
1*9a741119SAndroid Build Coastguard Worker#
2*9a741119SAndroid Build Coastguard Worker# Copyright (C) 2017 The Android Open Source Project
3*9a741119SAndroid Build Coastguard Worker#
4*9a741119SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
5*9a741119SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
6*9a741119SAndroid Build Coastguard Worker# You may obtain a copy of the License at
7*9a741119SAndroid Build Coastguard Worker#
8*9a741119SAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
9*9a741119SAndroid Build Coastguard Worker#
10*9a741119SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
11*9a741119SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
12*9a741119SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*9a741119SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
14*9a741119SAndroid Build Coastguard Worker# limitations under the License.
15*9a741119SAndroid Build Coastguard Worker#
16*9a741119SAndroid Build Coastguard Workerr"""This file contains an ELF parser and ELF header structures.
17*9a741119SAndroid Build Coastguard Worker
18*9a741119SAndroid Build Coastguard WorkerExample usage:
19*9a741119SAndroid Build Coastguard Worker    import elf_parser
20*9a741119SAndroid Build Coastguard Worker    with elf_parser.ElfParser(file) as e:
21*9a741119SAndroid Build Coastguard Worker        print('\n'.join(e.ListGlobalDynamicSymbols()))
22*9a741119SAndroid Build Coastguard Worker        print('\n'.join(e.ListDependencies()[0]))
23*9a741119SAndroid Build Coastguard Worker"""
24*9a741119SAndroid Build Coastguard Worker
25*9a741119SAndroid Build Coastguard Workerimport ctypes
26*9a741119SAndroid Build Coastguard Workerimport os
27*9a741119SAndroid Build Coastguard Workerimport struct
28*9a741119SAndroid Build Coastguard Worker
29*9a741119SAndroid Build Coastguard Workerfrom vts.utils.python.library.elf import consts
30*9a741119SAndroid Build Coastguard Workerfrom vts.utils.python.library.elf import structs
31*9a741119SAndroid Build Coastguard Workerfrom vts.utils.python.library.elf import utils
32*9a741119SAndroid Build Coastguard Worker
33*9a741119SAndroid Build Coastguard Worker
34*9a741119SAndroid Build Coastguard Workerclass ElfError(Exception):
35*9a741119SAndroid Build Coastguard Worker    """The exception raised by ElfParser."""
36*9a741119SAndroid Build Coastguard Worker    pass
37*9a741119SAndroid Build Coastguard Worker
38*9a741119SAndroid Build Coastguard Worker
39*9a741119SAndroid Build Coastguard Workerclass ElfParser(object):
40*9a741119SAndroid Build Coastguard Worker    """The class reads information from an ELF file.
41*9a741119SAndroid Build Coastguard Worker
42*9a741119SAndroid Build Coastguard Worker    Attributes:
43*9a741119SAndroid Build Coastguard Worker        _file: The ELF file object.
44*9a741119SAndroid Build Coastguard Worker        _begin_offset: The offset of the ELF object in the file. The value is
45*9a741119SAndroid Build Coastguard Worker                       non-zero if the ELF is in an archive, such as .a file.
46*9a741119SAndroid Build Coastguard Worker        _file_size: Size of the file.
47*9a741119SAndroid Build Coastguard Worker        bitness: Bitness of the ELF.
48*9a741119SAndroid Build Coastguard Worker        Ehdr: An Elf_Endr, the ELF header structure of the file.
49*9a741119SAndroid Build Coastguard Worker        Shdr: A list of Elf_Shdr, the section headers of the file.
50*9a741119SAndroid Build Coastguard Worker        Elf_Addr: ELF unsigned program address type.
51*9a741119SAndroid Build Coastguard Worker        Elf_Off: ELF unsigned file offset type.
52*9a741119SAndroid Build Coastguard Worker        Elf_Half: ELF unsigned medium integer type.
53*9a741119SAndroid Build Coastguard Worker        Elf_Word: ELF unsigned integer type.
54*9a741119SAndroid Build Coastguard Worker        Elf_Sword: ELF signed integer type.
55*9a741119SAndroid Build Coastguard Worker        Elf_Ehdr: ELF header class.
56*9a741119SAndroid Build Coastguard Worker        Elf_Shdr: ELF section header class.
57*9a741119SAndroid Build Coastguard Worker        Elf_Dyn: ELF dynamic entry class.
58*9a741119SAndroid Build Coastguard Worker        Elf_Sym: ELF symbol entry class.
59*9a741119SAndroid Build Coastguard Worker        Elf_Rel: ELF relocation entry class.
60*9a741119SAndroid Build Coastguard Worker        Elf_Rela: ELF relocation entry class with explicit addend.
61*9a741119SAndroid Build Coastguard Worker        Elf_Phdr: ELF program header class.
62*9a741119SAndroid Build Coastguard Worker        Elf_Nhdr: ELF note header class.
63*9a741119SAndroid Build Coastguard Worker    """
64*9a741119SAndroid Build Coastguard Worker
65*9a741119SAndroid Build Coastguard Worker    def __init__(self, file_path, begin_offset=0):
66*9a741119SAndroid Build Coastguard Worker        """Creates a parser to open and read an ELF file.
67*9a741119SAndroid Build Coastguard Worker
68*9a741119SAndroid Build Coastguard Worker        Args:
69*9a741119SAndroid Build Coastguard Worker            file_path: The path to the file.
70*9a741119SAndroid Build Coastguard Worker            begin_offset: The offset of the ELF object in the file.
71*9a741119SAndroid Build Coastguard Worker
72*9a741119SAndroid Build Coastguard Worker        Raises:
73*9a741119SAndroid Build Coastguard Worker            ElfError: File is not a valid ELF.
74*9a741119SAndroid Build Coastguard Worker        """
75*9a741119SAndroid Build Coastguard Worker        self._begin_offset = begin_offset
76*9a741119SAndroid Build Coastguard Worker        try:
77*9a741119SAndroid Build Coastguard Worker            self._file = open(file_path, 'rb')
78*9a741119SAndroid Build Coastguard Worker        except IOError as e:
79*9a741119SAndroid Build Coastguard Worker            raise ElfError(e)
80*9a741119SAndroid Build Coastguard Worker        try:
81*9a741119SAndroid Build Coastguard Worker            self._file_size = os.fstat(self._file.fileno()).st_size
82*9a741119SAndroid Build Coastguard Worker        except OSError as e:
83*9a741119SAndroid Build Coastguard Worker            self.Close()
84*9a741119SAndroid Build Coastguard Worker            raise ElfError(e)
85*9a741119SAndroid Build Coastguard Worker
86*9a741119SAndroid Build Coastguard Worker        try:
87*9a741119SAndroid Build Coastguard Worker            e_ident = self._SeekRead(0, consts.EI_NIDENT)
88*9a741119SAndroid Build Coastguard Worker
89*9a741119SAndroid Build Coastguard Worker            if e_ident[:4] != consts.ELF_MAGIC_NUMBER:
90*9a741119SAndroid Build Coastguard Worker                raise ElfError('Unexpected magic bytes: {}'.format(e_ident[:4]))
91*9a741119SAndroid Build Coastguard Worker
92*9a741119SAndroid Build Coastguard Worker            if utils.ByteToInt(e_ident[consts.EI_CLASS]) not in (
93*9a741119SAndroid Build Coastguard Worker                    consts.ELFCLASS32, consts.ELFCLASS64):
94*9a741119SAndroid Build Coastguard Worker                raise ElfError('Unexpected file class: {}'
95*9a741119SAndroid Build Coastguard Worker                               .format(e_ident[consts.EI_CLASS]))
96*9a741119SAndroid Build Coastguard Worker
97*9a741119SAndroid Build Coastguard Worker            if utils.ByteToInt(e_ident[consts.EI_DATA]) != consts.ELFDATA2LSB:
98*9a741119SAndroid Build Coastguard Worker                raise ElfError('Unexpected data encoding: {}'
99*9a741119SAndroid Build Coastguard Worker                               .format(e_ident[consts.EI_DATA]))
100*9a741119SAndroid Build Coastguard Worker        except ElfError:
101*9a741119SAndroid Build Coastguard Worker            self.Close()
102*9a741119SAndroid Build Coastguard Worker            raise
103*9a741119SAndroid Build Coastguard Worker
104*9a741119SAndroid Build Coastguard Worker        if utils.ByteToInt(e_ident[consts.EI_CLASS]) == consts.ELFCLASS32:
105*9a741119SAndroid Build Coastguard Worker            self.bitness = 32
106*9a741119SAndroid Build Coastguard Worker            self.Elf_Addr = structs.Elf32_Addr
107*9a741119SAndroid Build Coastguard Worker            self.Elf_Off = structs.Elf32_Off
108*9a741119SAndroid Build Coastguard Worker            self.Elf_Half = structs.Elf32_Half
109*9a741119SAndroid Build Coastguard Worker            self.Elf_Word = structs.Elf32_Word
110*9a741119SAndroid Build Coastguard Worker            self.Elf_Sword = structs.Elf32_Sword
111*9a741119SAndroid Build Coastguard Worker            self.Elf_Ehdr = structs.Elf32_Ehdr
112*9a741119SAndroid Build Coastguard Worker            self.Elf_Shdr = structs.Elf32_Shdr
113*9a741119SAndroid Build Coastguard Worker            self.Elf_Dyn = structs.Elf32_Dyn
114*9a741119SAndroid Build Coastguard Worker            self.Elf_Sym = structs.Elf32_Sym
115*9a741119SAndroid Build Coastguard Worker            self.Elf_Rel = structs.Elf32_Rel
116*9a741119SAndroid Build Coastguard Worker            self.Elf_Rela = structs.Elf32_Rela
117*9a741119SAndroid Build Coastguard Worker            self.Elf_Phdr = structs.Elf32_Phdr
118*9a741119SAndroid Build Coastguard Worker            self.Elf_Nhdr = structs.Elf32_Nhdr
119*9a741119SAndroid Build Coastguard Worker        else:
120*9a741119SAndroid Build Coastguard Worker            self.bitness = 64
121*9a741119SAndroid Build Coastguard Worker            self.Elf_Addr = structs.Elf64_Addr
122*9a741119SAndroid Build Coastguard Worker            self.Elf_Off = structs.Elf64_Off
123*9a741119SAndroid Build Coastguard Worker            self.Elf_Half = structs.Elf64_Half
124*9a741119SAndroid Build Coastguard Worker            self.Elf_Word = structs.Elf64_Word
125*9a741119SAndroid Build Coastguard Worker            self.Elf_Sword = structs.Elf64_Sword
126*9a741119SAndroid Build Coastguard Worker            self.Elf_Ehdr = structs.Elf64_Ehdr
127*9a741119SAndroid Build Coastguard Worker            self.Elf_Shdr = structs.Elf64_Shdr
128*9a741119SAndroid Build Coastguard Worker            self.Elf_Dyn = structs.Elf64_Dyn
129*9a741119SAndroid Build Coastguard Worker            self.Elf_Sym = structs.Elf64_Sym
130*9a741119SAndroid Build Coastguard Worker            self.Elf_Rel = structs.Elf64_Rel
131*9a741119SAndroid Build Coastguard Worker            self.Elf_Rela = structs.Elf64_Rela
132*9a741119SAndroid Build Coastguard Worker            self.Elf_Phdr = structs.Elf64_Phdr
133*9a741119SAndroid Build Coastguard Worker            self.Elf_Nhdr = structs.Elf64_Nhdr
134*9a741119SAndroid Build Coastguard Worker
135*9a741119SAndroid Build Coastguard Worker        try:
136*9a741119SAndroid Build Coastguard Worker            self.Ehdr = self._SeekReadStruct(0, self.Elf_Ehdr)
137*9a741119SAndroid Build Coastguard Worker            shoff = self.Ehdr.e_shoff
138*9a741119SAndroid Build Coastguard Worker            shentsize = self.Ehdr.e_shentsize
139*9a741119SAndroid Build Coastguard Worker            self.Shdr = [self._SeekReadStruct(shoff + i * shentsize,
140*9a741119SAndroid Build Coastguard Worker                                              self.Elf_Shdr)
141*9a741119SAndroid Build Coastguard Worker                         for i in range(self.Ehdr.e_shnum)]
142*9a741119SAndroid Build Coastguard Worker        except ElfError:
143*9a741119SAndroid Build Coastguard Worker            self.Close()
144*9a741119SAndroid Build Coastguard Worker            raise
145*9a741119SAndroid Build Coastguard Worker
146*9a741119SAndroid Build Coastguard Worker    def __del__(self):
147*9a741119SAndroid Build Coastguard Worker        """Closes the ELF file."""
148*9a741119SAndroid Build Coastguard Worker        self.Close()
149*9a741119SAndroid Build Coastguard Worker
150*9a741119SAndroid Build Coastguard Worker    def __enter__(self):
151*9a741119SAndroid Build Coastguard Worker        return self
152*9a741119SAndroid Build Coastguard Worker
153*9a741119SAndroid Build Coastguard Worker    def __exit__(self, exc_type, exc_value, traceback):
154*9a741119SAndroid Build Coastguard Worker        """Closes the ELF file."""
155*9a741119SAndroid Build Coastguard Worker        self.Close()
156*9a741119SAndroid Build Coastguard Worker
157*9a741119SAndroid Build Coastguard Worker    def Close(self):
158*9a741119SAndroid Build Coastguard Worker        """Closes the ELF file."""
159*9a741119SAndroid Build Coastguard Worker        if hasattr(self, "_file"):
160*9a741119SAndroid Build Coastguard Worker            self._file.close()
161*9a741119SAndroid Build Coastguard Worker
162*9a741119SAndroid Build Coastguard Worker    def _SeekRead(self, offset, read_size):
163*9a741119SAndroid Build Coastguard Worker        """Reads a byte string at specific offset in the file.
164*9a741119SAndroid Build Coastguard Worker
165*9a741119SAndroid Build Coastguard Worker        Args:
166*9a741119SAndroid Build Coastguard Worker            offset: An integer, the offset from the beginning of the ELF.
167*9a741119SAndroid Build Coastguard Worker            read_size: An integer, number of bytes to read.
168*9a741119SAndroid Build Coastguard Worker
169*9a741119SAndroid Build Coastguard Worker        Returns:
170*9a741119SAndroid Build Coastguard Worker            A bytes object which is the file content.
171*9a741119SAndroid Build Coastguard Worker
172*9a741119SAndroid Build Coastguard Worker        Raises:
173*9a741119SAndroid Build Coastguard Worker            ElfError: Fails to seek and read.
174*9a741119SAndroid Build Coastguard Worker        """
175*9a741119SAndroid Build Coastguard Worker        if offset + read_size > self._file_size:
176*9a741119SAndroid Build Coastguard Worker            raise ElfError("Read beyond end of file.")
177*9a741119SAndroid Build Coastguard Worker        try:
178*9a741119SAndroid Build Coastguard Worker            self._file.seek(self._begin_offset + offset)
179*9a741119SAndroid Build Coastguard Worker            return self._file.read(read_size)
180*9a741119SAndroid Build Coastguard Worker        except IOError as e:
181*9a741119SAndroid Build Coastguard Worker            raise ElfError(e)
182*9a741119SAndroid Build Coastguard Worker
183*9a741119SAndroid Build Coastguard Worker    def _SeekRead8(self, offset):
184*9a741119SAndroid Build Coastguard Worker        """Reads an 1-byte integer from file."""
185*9a741119SAndroid Build Coastguard Worker        return struct.unpack("B", self._SeekRead(offset, 1))[0]
186*9a741119SAndroid Build Coastguard Worker
187*9a741119SAndroid Build Coastguard Worker    def _SeekRead16(self, offset):
188*9a741119SAndroid Build Coastguard Worker        """Reads a 2-byte integer from file."""
189*9a741119SAndroid Build Coastguard Worker        return struct.unpack("H", self._SeekRead(offset, 2))[0]
190*9a741119SAndroid Build Coastguard Worker
191*9a741119SAndroid Build Coastguard Worker    def _SeekRead32(self, offset):
192*9a741119SAndroid Build Coastguard Worker        """Reads a 4-byte integer from file."""
193*9a741119SAndroid Build Coastguard Worker        return struct.unpack("I", self._SeekRead(offset, 4))[0]
194*9a741119SAndroid Build Coastguard Worker
195*9a741119SAndroid Build Coastguard Worker    def _SeekRead64(self, offset):
196*9a741119SAndroid Build Coastguard Worker        """Reads an 8-byte integer from file."""
197*9a741119SAndroid Build Coastguard Worker        return struct.unpack("Q", self._SeekRead(offset, 8))[0]
198*9a741119SAndroid Build Coastguard Worker
199*9a741119SAndroid Build Coastguard Worker    def _SeekReadString(self, offset):
200*9a741119SAndroid Build Coastguard Worker        """Reads a null-terminated string starting from specific offset.
201*9a741119SAndroid Build Coastguard Worker
202*9a741119SAndroid Build Coastguard Worker        Args:
203*9a741119SAndroid Build Coastguard Worker            offset: The offset from the beginning of the ELF object.
204*9a741119SAndroid Build Coastguard Worker
205*9a741119SAndroid Build Coastguard Worker        Returns:
206*9a741119SAndroid Build Coastguard Worker            A string, excluding the null character.
207*9a741119SAndroid Build Coastguard Worker
208*9a741119SAndroid Build Coastguard Worker        Raises:
209*9a741119SAndroid Build Coastguard Worker            ElfError: String reaches end of file without null terminator.
210*9a741119SAndroid Build Coastguard Worker        """
211*9a741119SAndroid Build Coastguard Worker        ret = b""
212*9a741119SAndroid Build Coastguard Worker        buf_size = 16
213*9a741119SAndroid Build Coastguard Worker        self._file.seek(self._begin_offset + offset)
214*9a741119SAndroid Build Coastguard Worker        while True:
215*9a741119SAndroid Build Coastguard Worker            try:
216*9a741119SAndroid Build Coastguard Worker                buf = self._file.read(buf_size)
217*9a741119SAndroid Build Coastguard Worker            except IOError as e:
218*9a741119SAndroid Build Coastguard Worker                raise ElfError(e)
219*9a741119SAndroid Build Coastguard Worker            end_index = buf.find(b"\0")
220*9a741119SAndroid Build Coastguard Worker            if end_index < 0:
221*9a741119SAndroid Build Coastguard Worker                ret += buf
222*9a741119SAndroid Build Coastguard Worker            else:
223*9a741119SAndroid Build Coastguard Worker                ret += buf[:end_index]
224*9a741119SAndroid Build Coastguard Worker                return utils.BytesToString(ret)
225*9a741119SAndroid Build Coastguard Worker            if len(buf) != buf_size:
226*9a741119SAndroid Build Coastguard Worker                raise ElfError("Null-terminated string reaches end of file.")
227*9a741119SAndroid Build Coastguard Worker
228*9a741119SAndroid Build Coastguard Worker    def _SeekReadStruct(self, offset, struct_type):
229*9a741119SAndroid Build Coastguard Worker        """Reads a ctypes.Structure / ctypes.Union from file.
230*9a741119SAndroid Build Coastguard Worker
231*9a741119SAndroid Build Coastguard Worker        Args:
232*9a741119SAndroid Build Coastguard Worker            offset: An integer, the offset from the beginning of the ELF.
233*9a741119SAndroid Build Coastguard Worker            struct_type: A class, the structure type to read.
234*9a741119SAndroid Build Coastguard Worker
235*9a741119SAndroid Build Coastguard Worker        Returns:
236*9a741119SAndroid Build Coastguard Worker            An object of struct_type.
237*9a741119SAndroid Build Coastguard Worker
238*9a741119SAndroid Build Coastguard Worker        Raises:
239*9a741119SAndroid Build Coastguard Worker            ElfError: Fails to seek and read.
240*9a741119SAndroid Build Coastguard Worker                      Fails to create struct_type instance.
241*9a741119SAndroid Build Coastguard Worker        """
242*9a741119SAndroid Build Coastguard Worker        raw_bytes = self._SeekRead(offset, ctypes.sizeof(struct_type))
243*9a741119SAndroid Build Coastguard Worker        try:
244*9a741119SAndroid Build Coastguard Worker            return struct_type.from_buffer_copy(raw_bytes)
245*9a741119SAndroid Build Coastguard Worker        except ValueError as e:
246*9a741119SAndroid Build Coastguard Worker            raise ElfError(e)
247*9a741119SAndroid Build Coastguard Worker
248*9a741119SAndroid Build Coastguard Worker    def GetString(self, strtab, offset):
249*9a741119SAndroid Build Coastguard Worker        """Retrieves a null-terminated string from string table.
250*9a741119SAndroid Build Coastguard Worker
251*9a741119SAndroid Build Coastguard Worker        Args:
252*9a741119SAndroid Build Coastguard Worker            strtab: Section header of the string table.
253*9a741119SAndroid Build Coastguard Worker            offset: Section offset (string index) to start reading from.
254*9a741119SAndroid Build Coastguard Worker
255*9a741119SAndroid Build Coastguard Worker        Returns:
256*9a741119SAndroid Build Coastguard Worker            A string without the null terminator.
257*9a741119SAndroid Build Coastguard Worker
258*9a741119SAndroid Build Coastguard Worker        Raises:
259*9a741119SAndroid Build Coastguard Worker            ElfError: Fails to seek and read.
260*9a741119SAndroid Build Coastguard Worker        """
261*9a741119SAndroid Build Coastguard Worker        return self._SeekReadString(strtab.sh_offset + offset)
262*9a741119SAndroid Build Coastguard Worker
263*9a741119SAndroid Build Coastguard Worker    def GetSectionName(self, sh):
264*9a741119SAndroid Build Coastguard Worker        """Returns a section name.
265*9a741119SAndroid Build Coastguard Worker
266*9a741119SAndroid Build Coastguard Worker        Args:
267*9a741119SAndroid Build Coastguard Worker            sh: A section header.
268*9a741119SAndroid Build Coastguard Worker
269*9a741119SAndroid Build Coastguard Worker        Returns:
270*9a741119SAndroid Build Coastguard Worker            A String.
271*9a741119SAndroid Build Coastguard Worker
272*9a741119SAndroid Build Coastguard Worker        Raises:
273*9a741119SAndroid Build Coastguard Worker            ElfError: Fails to seek and read.
274*9a741119SAndroid Build Coastguard Worker        """
275*9a741119SAndroid Build Coastguard Worker        strtab = self.Shdr[self.Ehdr.e_shstrndx]
276*9a741119SAndroid Build Coastguard Worker        return self.GetString(strtab, sh.sh_name)
277*9a741119SAndroid Build Coastguard Worker
278*9a741119SAndroid Build Coastguard Worker    def GetSectionsByName(self, name):
279*9a741119SAndroid Build Coastguard Worker        """Returns a generator of section headers from a given name.
280*9a741119SAndroid Build Coastguard Worker
281*9a741119SAndroid Build Coastguard Worker        If multiple sections have the same name, yield them all.
282*9a741119SAndroid Build Coastguard Worker
283*9a741119SAndroid Build Coastguard Worker        Args:
284*9a741119SAndroid Build Coastguard Worker            name: The section name to search for.
285*9a741119SAndroid Build Coastguard Worker
286*9a741119SAndroid Build Coastguard Worker        Returns:
287*9a741119SAndroid Build Coastguard Worker            A generator of Elf_Shdr.
288*9a741119SAndroid Build Coastguard Worker
289*9a741119SAndroid Build Coastguard Worker        Raises:
290*9a741119SAndroid Build Coastguard Worker            ElfError: Fails to seek and read.
291*9a741119SAndroid Build Coastguard Worker        """
292*9a741119SAndroid Build Coastguard Worker        return (sh for sh in self.Shdr if name == self.GetSectionName(sh))
293*9a741119SAndroid Build Coastguard Worker
294*9a741119SAndroid Build Coastguard Worker    def GetSectionByName(self, name):
295*9a741119SAndroid Build Coastguard Worker        """Returns a section header whose name equals a given name.
296*9a741119SAndroid Build Coastguard Worker
297*9a741119SAndroid Build Coastguard Worker        Returns only the first match, assuming the section name is unique.
298*9a741119SAndroid Build Coastguard Worker
299*9a741119SAndroid Build Coastguard Worker        Args:
300*9a741119SAndroid Build Coastguard Worker            name: The section name to search for.
301*9a741119SAndroid Build Coastguard Worker
302*9a741119SAndroid Build Coastguard Worker        Returns:
303*9a741119SAndroid Build Coastguard Worker            An Elf_Shdr if found.
304*9a741119SAndroid Build Coastguard Worker            None if no sections have the given name.
305*9a741119SAndroid Build Coastguard Worker
306*9a741119SAndroid Build Coastguard Worker        Raises:
307*9a741119SAndroid Build Coastguard Worker            ElfError: Fails to seek and read.
308*9a741119SAndroid Build Coastguard Worker        """
309*9a741119SAndroid Build Coastguard Worker        for sh in self.GetSectionsByName(name):
310*9a741119SAndroid Build Coastguard Worker            return sh
311*9a741119SAndroid Build Coastguard Worker        return None
312*9a741119SAndroid Build Coastguard Worker
313*9a741119SAndroid Build Coastguard Worker    def GetDynamic(self, dynamic):
314*9a741119SAndroid Build Coastguard Worker        """Yields the _DYNAMIC array.
315*9a741119SAndroid Build Coastguard Worker
316*9a741119SAndroid Build Coastguard Worker        Args:
317*9a741119SAndroid Build Coastguard Worker            dynamic: Section header of the dynamic section.
318*9a741119SAndroid Build Coastguard Worker
319*9a741119SAndroid Build Coastguard Worker        Yields:
320*9a741119SAndroid Build Coastguard Worker            Elf_Dyn.
321*9a741119SAndroid Build Coastguard Worker
322*9a741119SAndroid Build Coastguard Worker        Raises:
323*9a741119SAndroid Build Coastguard Worker            ElfError: Fails to seek and read.
324*9a741119SAndroid Build Coastguard Worker        """
325*9a741119SAndroid Build Coastguard Worker        off = dynamic.sh_offset
326*9a741119SAndroid Build Coastguard Worker        num = int(dynamic.sh_size // dynamic.sh_entsize)
327*9a741119SAndroid Build Coastguard Worker        for _ in range(num):
328*9a741119SAndroid Build Coastguard Worker            dyn = self._SeekReadStruct(off, self.Elf_Dyn)
329*9a741119SAndroid Build Coastguard Worker            yield dyn
330*9a741119SAndroid Build Coastguard Worker            if dyn.d_tag == consts.DT_NULL:
331*9a741119SAndroid Build Coastguard Worker                break
332*9a741119SAndroid Build Coastguard Worker            off += dynamic.sh_entsize
333*9a741119SAndroid Build Coastguard Worker
334*9a741119SAndroid Build Coastguard Worker    def GetSymbol(self, symtab, idx):
335*9a741119SAndroid Build Coastguard Worker        """Retrieves a Elf_Sym entry from symbol table.
336*9a741119SAndroid Build Coastguard Worker
337*9a741119SAndroid Build Coastguard Worker        Args:
338*9a741119SAndroid Build Coastguard Worker            symtab: A symbol table.
339*9a741119SAndroid Build Coastguard Worker            idx: An integer, symbol table index.
340*9a741119SAndroid Build Coastguard Worker
341*9a741119SAndroid Build Coastguard Worker        Returns:
342*9a741119SAndroid Build Coastguard Worker            An Elf_Sym.
343*9a741119SAndroid Build Coastguard Worker
344*9a741119SAndroid Build Coastguard Worker        Raises:
345*9a741119SAndroid Build Coastguard Worker            ElfError: Fails to seek and read.
346*9a741119SAndroid Build Coastguard Worker        """
347*9a741119SAndroid Build Coastguard Worker        off = symtab.sh_offset + idx * symtab.sh_entsize
348*9a741119SAndroid Build Coastguard Worker        return self._SeekReadStruct(off, self.Elf_Sym)
349*9a741119SAndroid Build Coastguard Worker
350*9a741119SAndroid Build Coastguard Worker    def GetSymbols(self, symtab):
351*9a741119SAndroid Build Coastguard Worker        """Returns a generator of Elf_Sym in symbol table.
352*9a741119SAndroid Build Coastguard Worker
353*9a741119SAndroid Build Coastguard Worker        Args:
354*9a741119SAndroid Build Coastguard Worker            symtab: A symbol table.
355*9a741119SAndroid Build Coastguard Worker
356*9a741119SAndroid Build Coastguard Worker        Returns:
357*9a741119SAndroid Build Coastguard Worker            A generator of Elf_Sym.
358*9a741119SAndroid Build Coastguard Worker
359*9a741119SAndroid Build Coastguard Worker        Raises:
360*9a741119SAndroid Build Coastguard Worker            ElfError: Fails to seek and read.
361*9a741119SAndroid Build Coastguard Worker        """
362*9a741119SAndroid Build Coastguard Worker        num = int(symtab.sh_size // symtab.sh_entsize)
363*9a741119SAndroid Build Coastguard Worker        return (self.GetSymbol(symtab, i) for i in range(num))
364*9a741119SAndroid Build Coastguard Worker
365*9a741119SAndroid Build Coastguard Worker    def GetRelocationSymbol(self, symtab, rel):
366*9a741119SAndroid Build Coastguard Worker        """Retrieves the Elf_Sym with respect to an Elf_Rel / Elf_Rela.
367*9a741119SAndroid Build Coastguard Worker
368*9a741119SAndroid Build Coastguard Worker        Args:
369*9a741119SAndroid Build Coastguard Worker            symtab: A symbol table.
370*9a741119SAndroid Build Coastguard Worker            rel: A Elf_Rel or Elf_Rela.
371*9a741119SAndroid Build Coastguard Worker
372*9a741119SAndroid Build Coastguard Worker        Returns:
373*9a741119SAndroid Build Coastguard Worker            An Elf_Sym.
374*9a741119SAndroid Build Coastguard Worker
375*9a741119SAndroid Build Coastguard Worker        Raises:
376*9a741119SAndroid Build Coastguard Worker            ElfError: Fails to seek and read.
377*9a741119SAndroid Build Coastguard Worker        """
378*9a741119SAndroid Build Coastguard Worker        return self.GetSymbol(symtab, rel.GetSymbol())
379*9a741119SAndroid Build Coastguard Worker
380*9a741119SAndroid Build Coastguard Worker    def _CreateElfRel(self, offset, info):
381*9a741119SAndroid Build Coastguard Worker        """Creates an instance of Elf_Rel.
382*9a741119SAndroid Build Coastguard Worker
383*9a741119SAndroid Build Coastguard Worker        Args:
384*9a741119SAndroid Build Coastguard Worker            offset: The initial value of r_offset.
385*9a741119SAndroid Build Coastguard Worker            info: The initial value of r_info.
386*9a741119SAndroid Build Coastguard Worker
387*9a741119SAndroid Build Coastguard Worker        Returns:
388*9a741119SAndroid Build Coastguard Worker            An Elf_Rel.
389*9a741119SAndroid Build Coastguard Worker        """
390*9a741119SAndroid Build Coastguard Worker        elf_rel = self.Elf_Rel()
391*9a741119SAndroid Build Coastguard Worker        elf_rel.r_offset = offset
392*9a741119SAndroid Build Coastguard Worker        elf_rel.r_info = info
393*9a741119SAndroid Build Coastguard Worker        return elf_rel
394*9a741119SAndroid Build Coastguard Worker
395*9a741119SAndroid Build Coastguard Worker    def _DecodeAndroidRelr(self, rel):
396*9a741119SAndroid Build Coastguard Worker        """Decodes a SHT_RELR / SHT_ANDROID_RELR section.
397*9a741119SAndroid Build Coastguard Worker
398*9a741119SAndroid Build Coastguard Worker        Args:
399*9a741119SAndroid Build Coastguard Worker            rel: A relocation table.
400*9a741119SAndroid Build Coastguard Worker
401*9a741119SAndroid Build Coastguard Worker        Yields:
402*9a741119SAndroid Build Coastguard Worker            Elf_Rel.
403*9a741119SAndroid Build Coastguard Worker
404*9a741119SAndroid Build Coastguard Worker        Raises:
405*9a741119SAndroid Build Coastguard Worker            ElfError: Fails to seek and read.
406*9a741119SAndroid Build Coastguard Worker        """
407*9a741119SAndroid Build Coastguard Worker        if self.bitness == 32:
408*9a741119SAndroid Build Coastguard Worker            addr_size = 4
409*9a741119SAndroid Build Coastguard Worker            seek_read_entry = self._SeekRead32
410*9a741119SAndroid Build Coastguard Worker        else:
411*9a741119SAndroid Build Coastguard Worker            addr_size = 8
412*9a741119SAndroid Build Coastguard Worker            seek_read_entry = self._SeekRead64
413*9a741119SAndroid Build Coastguard Worker
414*9a741119SAndroid Build Coastguard Worker        rel_offset = 0
415*9a741119SAndroid Build Coastguard Worker        for ent_offset in range(rel.sh_offset, rel.sh_offset + rel.sh_size,
416*9a741119SAndroid Build Coastguard Worker                                rel.sh_entsize):
417*9a741119SAndroid Build Coastguard Worker            relr_entry = seek_read_entry(ent_offset)
418*9a741119SAndroid Build Coastguard Worker            if (relr_entry & 1) == 0:
419*9a741119SAndroid Build Coastguard Worker                # The entry is an address.
420*9a741119SAndroid Build Coastguard Worker                yield self._CreateElfRel(relr_entry, 0)
421*9a741119SAndroid Build Coastguard Worker                rel_offset = relr_entry + addr_size
422*9a741119SAndroid Build Coastguard Worker            else:
423*9a741119SAndroid Build Coastguard Worker                # The entry is a bitmap.
424*9a741119SAndroid Build Coastguard Worker                for bit_idx in range(1, rel.sh_entsize * 8):
425*9a741119SAndroid Build Coastguard Worker                    if (relr_entry >> bit_idx) & 1:
426*9a741119SAndroid Build Coastguard Worker                        yield self._CreateElfRel(rel_offset, 0)
427*9a741119SAndroid Build Coastguard Worker                    rel_offset += addr_size
428*9a741119SAndroid Build Coastguard Worker
429*9a741119SAndroid Build Coastguard Worker    def GetRelocation(self, rel, idx):
430*9a741119SAndroid Build Coastguard Worker        """Retrieves a Elf_Rel / Elf_Rela entry from relocation table.
431*9a741119SAndroid Build Coastguard Worker
432*9a741119SAndroid Build Coastguard Worker        Args:
433*9a741119SAndroid Build Coastguard Worker            rel: A relocation table.
434*9a741119SAndroid Build Coastguard Worker            idx: An integer, relocation table index.
435*9a741119SAndroid Build Coastguard Worker
436*9a741119SAndroid Build Coastguard Worker        Returns:
437*9a741119SAndroid Build Coastguard Worker            An Elf_Rel or Elf_Rela.
438*9a741119SAndroid Build Coastguard Worker
439*9a741119SAndroid Build Coastguard Worker        Raises:
440*9a741119SAndroid Build Coastguard Worker            ElfError: Fails to seek and read.
441*9a741119SAndroid Build Coastguard Worker        """
442*9a741119SAndroid Build Coastguard Worker        off = rel.sh_offset + idx * rel.sh_entsize
443*9a741119SAndroid Build Coastguard Worker        if rel.sh_type == consts.SHT_RELA:
444*9a741119SAndroid Build Coastguard Worker            return self._SeekReadStruct(off, self.Elf_Rela)
445*9a741119SAndroid Build Coastguard Worker        return self._SeekReadStruct(off, self.Elf_Rel)
446*9a741119SAndroid Build Coastguard Worker
447*9a741119SAndroid Build Coastguard Worker    def GetRelocations(self, rel):
448*9a741119SAndroid Build Coastguard Worker        """Returns a generator of Elf_Rel / Elf_Rela in relocation table.
449*9a741119SAndroid Build Coastguard Worker
450*9a741119SAndroid Build Coastguard Worker        Args:
451*9a741119SAndroid Build Coastguard Worker            rel: A relocation table.
452*9a741119SAndroid Build Coastguard Worker
453*9a741119SAndroid Build Coastguard Worker        Returns:
454*9a741119SAndroid Build Coastguard Worker            A generator of Elf_Rel or Elf_Rela.
455*9a741119SAndroid Build Coastguard Worker
456*9a741119SAndroid Build Coastguard Worker        Raises:
457*9a741119SAndroid Build Coastguard Worker            ElfError: Fails to seek and read.
458*9a741119SAndroid Build Coastguard Worker        """
459*9a741119SAndroid Build Coastguard Worker        if rel.sh_type in (consts.SHT_ANDROID_REL, consts.SHT_ANDROID_RELA):
460*9a741119SAndroid Build Coastguard Worker            relocations = self._UnpackAndroidRela(rel)
461*9a741119SAndroid Build Coastguard Worker            if rel.sh_type == consts.SHT_ANDROID_REL:
462*9a741119SAndroid Build Coastguard Worker                return (self.Elf_Rel(r_offset=rela.r_offset, r_info=rela.r_info)
463*9a741119SAndroid Build Coastguard Worker                        for rela in relocations)
464*9a741119SAndroid Build Coastguard Worker            return relocations
465*9a741119SAndroid Build Coastguard Worker        elif rel.sh_type in (consts.SHT_RELR, consts.SHT_ANDROID_RELR):
466*9a741119SAndroid Build Coastguard Worker            return self._DecodeAndroidRelr(rel)
467*9a741119SAndroid Build Coastguard Worker        else:
468*9a741119SAndroid Build Coastguard Worker            num = int(rel.sh_size // rel.sh_entsize)
469*9a741119SAndroid Build Coastguard Worker            return (self.GetRelocation(rel, i) for i in range(num))
470*9a741119SAndroid Build Coastguard Worker
471*9a741119SAndroid Build Coastguard Worker    def _UnpackAndroidRela(self, android_rela):
472*9a741119SAndroid Build Coastguard Worker        """Unpacks a SHT_ANDROID_REL / SHT_ANDROID_RELA section.
473*9a741119SAndroid Build Coastguard Worker
474*9a741119SAndroid Build Coastguard Worker        Args:
475*9a741119SAndroid Build Coastguard Worker            android_rela: The packed section's section header.
476*9a741119SAndroid Build Coastguard Worker
477*9a741119SAndroid Build Coastguard Worker        Yields:
478*9a741119SAndroid Build Coastguard Worker            Elf_Rela.
479*9a741119SAndroid Build Coastguard Worker
480*9a741119SAndroid Build Coastguard Worker        Raises:
481*9a741119SAndroid Build Coastguard Worker            ElfError: Fails to decode android rela section.
482*9a741119SAndroid Build Coastguard Worker        """
483*9a741119SAndroid Build Coastguard Worker        data = self._SeekRead(android_rela.sh_offset, android_rela.sh_size)
484*9a741119SAndroid Build Coastguard Worker        # Check packed section header.
485*9a741119SAndroid Build Coastguard Worker        if len(data) < 4 or data[:4] != b'APS2':
486*9a741119SAndroid Build Coastguard Worker            raise ElfError('Unexpected SHT_ANDROID_RELA header: {}'
487*9a741119SAndroid Build Coastguard Worker                           .format(data[:4]))
488*9a741119SAndroid Build Coastguard Worker        # Decode SLEB128 word stream.
489*9a741119SAndroid Build Coastguard Worker        def _PackedWordsGen():
490*9a741119SAndroid Build Coastguard Worker            cur = 4
491*9a741119SAndroid Build Coastguard Worker            while cur < len(data):
492*9a741119SAndroid Build Coastguard Worker                try:
493*9a741119SAndroid Build Coastguard Worker                    value, num = utils.DecodeSLEB128(data, cur)
494*9a741119SAndroid Build Coastguard Worker                except IndexError:
495*9a741119SAndroid Build Coastguard Worker                    raise ElfError('Decoding pass end of section.')
496*9a741119SAndroid Build Coastguard Worker                yield value
497*9a741119SAndroid Build Coastguard Worker                cur += num
498*9a741119SAndroid Build Coastguard Worker            raise ElfError('Decoding pass end of section.')
499*9a741119SAndroid Build Coastguard Worker
500*9a741119SAndroid Build Coastguard Worker        _packed_words_gen = _PackedWordsGen()
501*9a741119SAndroid Build Coastguard Worker        _PopWord = lambda: next(_packed_words_gen)
502*9a741119SAndroid Build Coastguard Worker        # Decode delta encoded relocation data.
503*9a741119SAndroid Build Coastguard Worker        current_count = 0
504*9a741119SAndroid Build Coastguard Worker        total_count = _PopWord()
505*9a741119SAndroid Build Coastguard Worker        offset = _PopWord()
506*9a741119SAndroid Build Coastguard Worker        addend = 0
507*9a741119SAndroid Build Coastguard Worker        while current_count < total_count:
508*9a741119SAndroid Build Coastguard Worker            # Read relocaiton group info.
509*9a741119SAndroid Build Coastguard Worker            group_size = _PopWord()
510*9a741119SAndroid Build Coastguard Worker            group_flags = _PopWord()
511*9a741119SAndroid Build Coastguard Worker            group_offset_delta = 0
512*9a741119SAndroid Build Coastguard Worker            # Read group flag and prepare delta values.
513*9a741119SAndroid Build Coastguard Worker            grouped_by_info = (
514*9a741119SAndroid Build Coastguard Worker                group_flags & consts.RELOCATION_GROUPED_BY_INFO_FLAG)
515*9a741119SAndroid Build Coastguard Worker            grouped_by_offset_delta = (
516*9a741119SAndroid Build Coastguard Worker                group_flags & consts.RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG)
517*9a741119SAndroid Build Coastguard Worker            grouped_by_addend = (
518*9a741119SAndroid Build Coastguard Worker                group_flags & consts.RELOCATION_GROUPED_BY_ADDEND_FLAG)
519*9a741119SAndroid Build Coastguard Worker            group_has_addend = (
520*9a741119SAndroid Build Coastguard Worker                group_flags & consts.RELOCATION_GROUP_HAS_ADDEND_FLAG)
521*9a741119SAndroid Build Coastguard Worker            if grouped_by_offset_delta:
522*9a741119SAndroid Build Coastguard Worker                group_offset_delta = _PopWord()
523*9a741119SAndroid Build Coastguard Worker            if grouped_by_info:
524*9a741119SAndroid Build Coastguard Worker                info = _PopWord()
525*9a741119SAndroid Build Coastguard Worker            if group_has_addend and grouped_by_addend:
526*9a741119SAndroid Build Coastguard Worker                addend += _PopWord()
527*9a741119SAndroid Build Coastguard Worker            if not group_has_addend:
528*9a741119SAndroid Build Coastguard Worker                addend = 0
529*9a741119SAndroid Build Coastguard Worker            # Handle each relocation entry in group.
530*9a741119SAndroid Build Coastguard Worker            for _ in range(group_size):
531*9a741119SAndroid Build Coastguard Worker                if grouped_by_offset_delta:
532*9a741119SAndroid Build Coastguard Worker                    offset += group_offset_delta
533*9a741119SAndroid Build Coastguard Worker                else:
534*9a741119SAndroid Build Coastguard Worker                    offset += _PopWord()
535*9a741119SAndroid Build Coastguard Worker                if not grouped_by_info:
536*9a741119SAndroid Build Coastguard Worker                    info = _PopWord()
537*9a741119SAndroid Build Coastguard Worker                if group_has_addend and not grouped_by_addend:
538*9a741119SAndroid Build Coastguard Worker                    addend += _PopWord()
539*9a741119SAndroid Build Coastguard Worker
540*9a741119SAndroid Build Coastguard Worker                relocation = self.Elf_Rela(r_offset=offset,
541*9a741119SAndroid Build Coastguard Worker                                           r_info=info,
542*9a741119SAndroid Build Coastguard Worker                                           r_addend=addend)
543*9a741119SAndroid Build Coastguard Worker                yield relocation
544*9a741119SAndroid Build Coastguard Worker            current_count += group_size
545*9a741119SAndroid Build Coastguard Worker
546*9a741119SAndroid Build Coastguard Worker    def _LoadDynamicSection(self, dynamic):
547*9a741119SAndroid Build Coastguard Worker        """Reads entries from dynamic section.
548*9a741119SAndroid Build Coastguard Worker
549*9a741119SAndroid Build Coastguard Worker        Args:
550*9a741119SAndroid Build Coastguard Worker            dynamic: Section header of the dynamic section.
551*9a741119SAndroid Build Coastguard Worker
552*9a741119SAndroid Build Coastguard Worker        Returns:
553*9a741119SAndroid Build Coastguard Worker            A dict of {DT_NEEDED: [libraries names], DT_RUNPATH: [paths]}
554*9a741119SAndroid Build Coastguard Worker            where the library names and the paths are strings.
555*9a741119SAndroid Build Coastguard Worker
556*9a741119SAndroid Build Coastguard Worker        Raises:
557*9a741119SAndroid Build Coastguard Worker            ElfError: Fails to find dynamic string table.
558*9a741119SAndroid Build Coastguard Worker        """
559*9a741119SAndroid Build Coastguard Worker        strtab_addr = None
560*9a741119SAndroid Build Coastguard Worker        dt_needed_offsets = []
561*9a741119SAndroid Build Coastguard Worker        dt_runpath_offsets = []
562*9a741119SAndroid Build Coastguard Worker        for dyn in self.GetDynamic(dynamic):
563*9a741119SAndroid Build Coastguard Worker            if dyn.d_tag == consts.DT_NEEDED:
564*9a741119SAndroid Build Coastguard Worker                dt_needed_offsets.append(dyn.d_un.d_val)
565*9a741119SAndroid Build Coastguard Worker            elif dyn.d_tag == consts.DT_RUNPATH:
566*9a741119SAndroid Build Coastguard Worker                dt_runpath_offsets.append(dyn.d_un.d_val)
567*9a741119SAndroid Build Coastguard Worker            elif dyn.d_tag == consts.DT_STRTAB:
568*9a741119SAndroid Build Coastguard Worker                strtab_addr = dyn.d_un.d_ptr
569*9a741119SAndroid Build Coastguard Worker
570*9a741119SAndroid Build Coastguard Worker        if strtab_addr is None:
571*9a741119SAndroid Build Coastguard Worker            raise ElfError("Cannot find string table address in dynamic "
572*9a741119SAndroid Build Coastguard Worker                           "section.")
573*9a741119SAndroid Build Coastguard Worker        try:
574*9a741119SAndroid Build Coastguard Worker            strtab = next(sh for sh in self.Shdr if sh.sh_addr == strtab_addr)
575*9a741119SAndroid Build Coastguard Worker        except StopIteration:
576*9a741119SAndroid Build Coastguard Worker            raise ElfError("Cannot find dynamic string table.")
577*9a741119SAndroid Build Coastguard Worker        dt_needed = [self.GetString(strtab, off) for off in dt_needed_offsets]
578*9a741119SAndroid Build Coastguard Worker        dt_runpath = []
579*9a741119SAndroid Build Coastguard Worker        for off in dt_runpath_offsets:
580*9a741119SAndroid Build Coastguard Worker            dt_runpath.extend(self.GetString(strtab, off).split(":"))
581*9a741119SAndroid Build Coastguard Worker        return {consts.DT_NEEDED: dt_needed, consts.DT_RUNPATH: dt_runpath}
582*9a741119SAndroid Build Coastguard Worker
583*9a741119SAndroid Build Coastguard Worker    def IsExecutable(self):
584*9a741119SAndroid Build Coastguard Worker        """Returns whether the ELF is executable."""
585*9a741119SAndroid Build Coastguard Worker        return self.Ehdr.e_type == consts.ET_EXEC
586*9a741119SAndroid Build Coastguard Worker
587*9a741119SAndroid Build Coastguard Worker    def IsSharedObject(self):
588*9a741119SAndroid Build Coastguard Worker        """Returns whether the ELF is a shared object."""
589*9a741119SAndroid Build Coastguard Worker        return self.Ehdr.e_type == consts.ET_DYN
590*9a741119SAndroid Build Coastguard Worker
591*9a741119SAndroid Build Coastguard Worker    def HasAndroidIdent(self):
592*9a741119SAndroid Build Coastguard Worker        """Returns whether the ELF has a .note.android.ident section."""
593*9a741119SAndroid Build Coastguard Worker        for sh in self.GetSectionsByName(".note.android.ident"):
594*9a741119SAndroid Build Coastguard Worker            nh = self._SeekReadStruct(sh.sh_offset, self.Elf_Nhdr)
595*9a741119SAndroid Build Coastguard Worker            name = self._SeekRead(sh.sh_offset + ctypes.sizeof(self.Elf_Nhdr),
596*9a741119SAndroid Build Coastguard Worker                                  nh.n_namesz)
597*9a741119SAndroid Build Coastguard Worker            if name == b"Android\0":
598*9a741119SAndroid Build Coastguard Worker                return True
599*9a741119SAndroid Build Coastguard Worker        return False
600*9a741119SAndroid Build Coastguard Worker
601*9a741119SAndroid Build Coastguard Worker    def MatchCpuAbi(self, abi):
602*9a741119SAndroid Build Coastguard Worker        """Returns whether the ELF matches the ABI.
603*9a741119SAndroid Build Coastguard Worker
604*9a741119SAndroid Build Coastguard Worker        Args:
605*9a741119SAndroid Build Coastguard Worker            abi: A string, the name of the ABI.
606*9a741119SAndroid Build Coastguard Worker
607*9a741119SAndroid Build Coastguard Worker        Returns:
608*9a741119SAndroid Build Coastguard Worker            A boolean, whether the ELF matches the ABI.
609*9a741119SAndroid Build Coastguard Worker        """
610*9a741119SAndroid Build Coastguard Worker        for abi_prefix, machine in (("arm64", consts.EM_AARCH64),
611*9a741119SAndroid Build Coastguard Worker                                    ("arm", consts.EM_ARM),
612*9a741119SAndroid Build Coastguard Worker                                    ("x86_64", consts.EM_X86_64),
613*9a741119SAndroid Build Coastguard Worker                                    ("x86", consts.EM_386)):
614*9a741119SAndroid Build Coastguard Worker            if abi.startswith(abi_prefix):
615*9a741119SAndroid Build Coastguard Worker                return self.Ehdr.e_machine == machine
616*9a741119SAndroid Build Coastguard Worker        return False
617*9a741119SAndroid Build Coastguard Worker
618*9a741119SAndroid Build Coastguard Worker    def ListDependencies(self):
619*9a741119SAndroid Build Coastguard Worker        """Lists the shared libraries that the ELF depends on.
620*9a741119SAndroid Build Coastguard Worker
621*9a741119SAndroid Build Coastguard Worker        Returns:
622*9a741119SAndroid Build Coastguard Worker            2 lists of strings, the names of the depended libraries and the
623*9a741119SAndroid Build Coastguard Worker            search paths.
624*9a741119SAndroid Build Coastguard Worker        """
625*9a741119SAndroid Build Coastguard Worker        deps = []
626*9a741119SAndroid Build Coastguard Worker        runpaths = []
627*9a741119SAndroid Build Coastguard Worker        for sh in self.Shdr:
628*9a741119SAndroid Build Coastguard Worker            if sh.sh_type == consts.SHT_DYNAMIC:
629*9a741119SAndroid Build Coastguard Worker                dynamic = self._LoadDynamicSection(sh)
630*9a741119SAndroid Build Coastguard Worker                deps.extend(dynamic[consts.DT_NEEDED])
631*9a741119SAndroid Build Coastguard Worker                runpaths.extend(dynamic[consts.DT_RUNPATH])
632*9a741119SAndroid Build Coastguard Worker        return deps, runpaths
633*9a741119SAndroid Build Coastguard Worker
634*9a741119SAndroid Build Coastguard Worker    def ListGlobalSymbols(self, include_weak=False,
635*9a741119SAndroid Build Coastguard Worker                          symtab_name=consts.SYMTAB,
636*9a741119SAndroid Build Coastguard Worker                          strtab_name=consts.STRTAB):
637*9a741119SAndroid Build Coastguard Worker        """Lists the global symbols defined in the ELF.
638*9a741119SAndroid Build Coastguard Worker
639*9a741119SAndroid Build Coastguard Worker        Args:
640*9a741119SAndroid Build Coastguard Worker            include_weak: A boolean, whether to include weak symbols.
641*9a741119SAndroid Build Coastguard Worker            symtab_name: A string, the name of the symbol table.
642*9a741119SAndroid Build Coastguard Worker            strtab_name: A string, the name of the string table.
643*9a741119SAndroid Build Coastguard Worker
644*9a741119SAndroid Build Coastguard Worker        Returns:
645*9a741119SAndroid Build Coastguard Worker            A list of strings, the names of the symbols.
646*9a741119SAndroid Build Coastguard Worker
647*9a741119SAndroid Build Coastguard Worker        Raises:
648*9a741119SAndroid Build Coastguard Worker            ElfError: Fails to find symbol table.
649*9a741119SAndroid Build Coastguard Worker        """
650*9a741119SAndroid Build Coastguard Worker        symtab = self.GetSectionByName(symtab_name)
651*9a741119SAndroid Build Coastguard Worker        strtab = self.GetSectionByName(strtab_name)
652*9a741119SAndroid Build Coastguard Worker        if not symtab or not strtab or symtab.sh_size == 0:
653*9a741119SAndroid Build Coastguard Worker            raise ElfError("Cannot find symbol table.")
654*9a741119SAndroid Build Coastguard Worker
655*9a741119SAndroid Build Coastguard Worker        include_bindings = [consts.STB_GLOBAL]
656*9a741119SAndroid Build Coastguard Worker        if include_weak:
657*9a741119SAndroid Build Coastguard Worker            include_bindings.append(consts.STB_WEAK)
658*9a741119SAndroid Build Coastguard Worker
659*9a741119SAndroid Build Coastguard Worker        sym_names = []
660*9a741119SAndroid Build Coastguard Worker        for sym in self.GetSymbols(symtab):
661*9a741119SAndroid Build Coastguard Worker            # Global symbols can be defined at most once at link time,
662*9a741119SAndroid Build Coastguard Worker            # while weak symbols may have multiple definitions.
663*9a741119SAndroid Build Coastguard Worker            if sym.GetType() == consts.STT_NOTYPE:
664*9a741119SAndroid Build Coastguard Worker                continue
665*9a741119SAndroid Build Coastguard Worker            if sym.GetBinding() not in include_bindings:
666*9a741119SAndroid Build Coastguard Worker                continue
667*9a741119SAndroid Build Coastguard Worker            if sym.st_shndx == consts.SHN_UNDEF:
668*9a741119SAndroid Build Coastguard Worker                continue
669*9a741119SAndroid Build Coastguard Worker            sym_names.append(self.GetString(strtab, sym.st_name))
670*9a741119SAndroid Build Coastguard Worker        return sym_names
671*9a741119SAndroid Build Coastguard Worker
672*9a741119SAndroid Build Coastguard Worker    def ListGlobalDynamicSymbols(self, include_weak=False):
673*9a741119SAndroid Build Coastguard Worker        """Lists the global dynamic symbols defined in the ELF.
674*9a741119SAndroid Build Coastguard Worker
675*9a741119SAndroid Build Coastguard Worker        Args:
676*9a741119SAndroid Build Coastguard Worker            include_weak: A boolean, whether to include weak symbols.
677*9a741119SAndroid Build Coastguard Worker
678*9a741119SAndroid Build Coastguard Worker        Returns:
679*9a741119SAndroid Build Coastguard Worker            A list of strings, the names of the symbols.
680*9a741119SAndroid Build Coastguard Worker
681*9a741119SAndroid Build Coastguard Worker        Raises:
682*9a741119SAndroid Build Coastguard Worker            ElfError: Fails to find symbol table.
683*9a741119SAndroid Build Coastguard Worker        """
684*9a741119SAndroid Build Coastguard Worker        return self.ListGlobalSymbols(include_weak,
685*9a741119SAndroid Build Coastguard Worker                                      consts.DYNSYM, consts.DYNSTR)
686*9a741119SAndroid Build Coastguard Worker
687*9a741119SAndroid Build Coastguard Worker    def GetProgramInterpreter(self):
688*9a741119SAndroid Build Coastguard Worker        """Gets the path to the program interpreter of the ELF.
689*9a741119SAndroid Build Coastguard Worker
690*9a741119SAndroid Build Coastguard Worker        Returns:
691*9a741119SAndroid Build Coastguard Worker            A string, the contents of .interp section.
692*9a741119SAndroid Build Coastguard Worker            None if the section is not found.
693*9a741119SAndroid Build Coastguard Worker        """
694*9a741119SAndroid Build Coastguard Worker        for ph_index in range(self.Ehdr.e_phnum):
695*9a741119SAndroid Build Coastguard Worker            ph = self._SeekReadStruct(
696*9a741119SAndroid Build Coastguard Worker                self.Ehdr.e_phoff + ph_index * self.Ehdr.e_phentsize,
697*9a741119SAndroid Build Coastguard Worker                self.Elf_Phdr)
698*9a741119SAndroid Build Coastguard Worker            if ph.p_type == consts.PT_INTERP:
699*9a741119SAndroid Build Coastguard Worker                return self._SeekReadString(ph.p_offset)
700