Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / native_client_sdk / src / tools / lib / elf.py
1 # Copyright 2014 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 """Helper script for extracting information from ELF files"""
6
7 import struct
8
9
10 class Error(Exception):
11   '''Local Error class for this file.'''
12   pass
13
14
15 def ParseElfHeader(path):
16   """Determine properties of a nexe by parsing elf header.
17   Return tuple of architecture and boolean signalling whether
18   the executable is dynamic (has INTERP header) or static.
19   """
20   # From elf.h:
21   # typedef struct
22   # {
23   #   unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
24   #   Elf64_Half e_type; /* Object file type */
25   #   Elf64_Half e_machine; /* Architecture */
26   #   ...
27   # } Elf32_Ehdr;
28   elf_header_format = '16s2H'
29   elf_header_size = struct.calcsize(elf_header_format)
30
31   with open(path, 'rb') as f:
32     header = f.read(elf_header_size)
33
34   try:
35     header = struct.unpack(elf_header_format, header)
36   except struct.error:
37     raise Error("error parsing elf header: %s" % path)
38   e_ident, _, e_machine = header[:3]
39
40   elf_magic = '\x7fELF'
41   if e_ident[:4] != elf_magic:
42     raise Error('Not a valid NaCl executable: %s' % path)
43
44   e_machine_mapping = {
45     3 : 'x86-32',
46     8 : 'mips32',
47     40 : 'arm',
48     62 : 'x86-64'
49   }
50   if e_machine not in e_machine_mapping:
51     raise Error('Unknown machine type: %s' % e_machine)
52
53   # Set arch based on the machine type in the elf header
54   arch = e_machine_mapping[e_machine]
55
56   # Now read the full header in either 64bit or 32bit mode
57   dynamic = IsDynamicElf(path, arch == 'x86-64')
58   return arch, dynamic
59
60
61 def IsDynamicElf(path, is64bit):
62   """Examine an elf file to determine if it is dynamically
63   linked or not.
64   This is determined by searching the program headers for
65   a header of type PT_INTERP.
66   """
67   if is64bit:
68     elf_header_format = '16s2HI3QI3H'
69   else:
70     elf_header_format = '16s2HI3II3H'
71
72   elf_header_size = struct.calcsize(elf_header_format)
73
74   with open(path, 'rb') as f:
75     header = f.read(elf_header_size)
76     header = struct.unpack(elf_header_format, header)
77     p_header_offset = header[5]
78     p_header_entry_size = header[9]
79     num_p_header = header[10]
80     f.seek(p_header_offset)
81     p_headers = f.read(p_header_entry_size*num_p_header)
82
83   # Read the first word of each Phdr to find out its type.
84   #
85   # typedef struct
86   # {
87   #   Elf32_Word  p_type;     /* Segment type */
88   #   ...
89   # } Elf32_Phdr;
90   elf_phdr_format = 'I'
91   PT_INTERP = 3
92
93   while p_headers:
94     p_header = p_headers[:p_header_entry_size]
95     p_headers = p_headers[p_header_entry_size:]
96     phdr_type = struct.unpack(elf_phdr_format, p_header[:4])[0]
97     if phdr_type == PT_INTERP:
98       return True
99
100   return False