summaryrefslogtreecommitdiffstats
path: root/native_client_sdk/src/tools/lib/elf.py
diff options
context:
space:
mode:
authorbinji@chromium.org <binji@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-07 00:21:38 +0000
committerbinji@chromium.org <binji@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-07 00:21:38 +0000
commit4181c28ea5f37ef2acb87f850fac10791fbf9967 (patch)
tree4b17bea989429e68c8d7f56df7c4ff224eca56c1 /native_client_sdk/src/tools/lib/elf.py
parent6013c798adabecc868d3e42da8404652507ad694 (diff)
downloadchromium_src-4181c28ea5f37ef2acb87f850fac10791fbf9967.zip
chromium_src-4181c28ea5f37ef2acb87f850fac10791fbf9967.tar.gz
chromium_src-4181c28ea5f37ef2acb87f850fac10791fbf9967.tar.bz2
[NaCl SDK] Refactor create_nmf.py
Most of the complex logic is moved to elf.py or get_shared_deps.py (each with their own simpler tests). These changes will make it easier to handle generating a multi-platform NMF. BUG=none R=sbc@chromium.org Review URL: https://codereview.chromium.org/161613002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@255474 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'native_client_sdk/src/tools/lib/elf.py')
-rw-r--r--native_client_sdk/src/tools/lib/elf.py99
1 files changed, 99 insertions, 0 deletions
diff --git a/native_client_sdk/src/tools/lib/elf.py b/native_client_sdk/src/tools/lib/elf.py
new file mode 100644
index 0000000..2011a2b
--- /dev/null
+++ b/native_client_sdk/src/tools/lib/elf.py
@@ -0,0 +1,99 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Helper script for extracting information from ELF files"""
+
+import struct
+
+
+class Error(Exception):
+ '''Local Error class for this file.'''
+ pass
+
+
+def ParseElfHeader(path):
+ """Determine properties of a nexe by parsing elf header.
+ Return tuple of architecture and boolean signalling whether
+ the executable is dynamic (has INTERP header) or static.
+ """
+ # From elf.h:
+ # typedef struct
+ # {
+ # unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
+ # Elf64_Half e_type; /* Object file type */
+ # Elf64_Half e_machine; /* Architecture */
+ # ...
+ # } Elf32_Ehdr;
+ elf_header_format = '16s2H'
+ elf_header_size = struct.calcsize(elf_header_format)
+
+ with open(path, 'rb') as f:
+ header = f.read(elf_header_size)
+
+ try:
+ header = struct.unpack(elf_header_format, header)
+ except struct.error:
+ raise Error("error parsing elf header: %s" % path)
+ e_ident, _, e_machine = header[:3]
+
+ elf_magic = '\x7fELF'
+ if e_ident[:4] != elf_magic:
+ raise Error('Not a valid NaCl executable: %s' % path)
+
+ e_machine_mapping = {
+ 3 : 'x86-32',
+ 40 : 'arm',
+ 62 : 'x86-64'
+ }
+ if e_machine not in e_machine_mapping:
+ raise Error('Unknown machine type: %s' % e_machine)
+
+ # Set arch based on the machine type in the elf header
+ arch = e_machine_mapping[e_machine]
+
+ # Now read the full header in either 64bit or 32bit mode
+ dynamic = IsDynamicElf(path, arch == 'x86-64')
+ return arch, dynamic
+
+
+def IsDynamicElf(path, is64bit):
+ """Examine an elf file to determine if it is dynamically
+ linked or not.
+ This is determined by searching the program headers for
+ a header of type PT_INTERP.
+ """
+ if is64bit:
+ elf_header_format = '16s2HI3QI3H'
+ else:
+ elf_header_format = '16s2HI3II3H'
+
+ elf_header_size = struct.calcsize(elf_header_format)
+
+ with open(path, 'rb') as f:
+ header = f.read(elf_header_size)
+ header = struct.unpack(elf_header_format, header)
+ p_header_offset = header[5]
+ p_header_entry_size = header[9]
+ num_p_header = header[10]
+ f.seek(p_header_offset)
+ p_headers = f.read(p_header_entry_size*num_p_header)
+
+ # Read the first word of each Phdr to find out its type.
+ #
+ # typedef struct
+ # {
+ # Elf32_Word p_type; /* Segment type */
+ # ...
+ # } Elf32_Phdr;
+ elf_phdr_format = 'I'
+ PT_INTERP = 3
+
+ while p_headers:
+ p_header = p_headers[:p_header_entry_size]
+ p_headers = p_headers[p_header_entry_size:]
+ phdr_type = struct.unpack(elf_phdr_format, p_header[:4])[0]
+ if phdr_type == PT_INTERP:
+ return True
+
+ return False