Blame view

tools/binman/elf.py 4.25 KB
d41ce506b   Eric Lee   Initial Release, ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
  # Copyright (c) 2016 Google, Inc
  # Written by Simon Glass <sjg@chromium.org>
  #
  # SPDX-License-Identifier:      GPL-2.0+
  #
  # Handle various things related to ELF images
  #
  
  from collections import namedtuple, OrderedDict
  import command
  import os
  import re
  import struct
  
  import tools
  
  # This is enabled from control.py
  debug = False
  
  Symbol = namedtuple('Symbol', ['section', 'address', 'size', 'weak'])
  
  
  def GetSymbols(fname, patterns):
      """Get the symbols from an ELF file
  
      Args:
          fname: Filename of the ELF file to read
          patterns: List of regex patterns to search for, each a string
  
      Returns:
          None, if the file does not exist, or Dict:
            key: Name of symbol
            value: Hex value of symbol
      """
      stdout = command.Output('objdump', '-t', fname, raise_on_error=False)
      lines = stdout.splitlines()
      if patterns:
          re_syms = re.compile('|'.join(patterns))
      else:
          re_syms = None
      syms = {}
      syms_started = False
      for line in lines:
          if not line or not syms_started:
              if 'SYMBOL TABLE' in line:
                  syms_started = True
              line = None  # Otherwise code coverage complains about 'continue'
              continue
          if re_syms and not re_syms.search(line):
              continue
  
          space_pos = line.find(' ')
          value, rest = line[:space_pos], line[space_pos + 1:]
          flags = rest[:7]
          parts = rest[7:].split()
          section, size =  parts[:2]
          if len(parts) > 2:
              name = parts[2]
              syms[name] = Symbol(section, int(value, 16), int(size,16),
                                  flags[1] == 'w')
      return syms
  
  def GetSymbolAddress(fname, sym_name):
      """Get a value of a symbol from an ELF file
  
      Args:
          fname: Filename of the ELF file to read
          patterns: List of regex patterns to search for, each a string
  
      Returns:
          Symbol value (as an integer) or None if not found
      """
      syms = GetSymbols(fname, [sym_name])
      sym = syms.get(sym_name)
      if not sym:
          return None
      return sym.address
  
  def LookupAndWriteSymbols(elf_fname, entry, image):
      """Replace all symbols in an entry with their correct values
  
      The entry contents is updated so that values for referenced symbols will be
      visible at run time. This is done by finding out the symbols positions in
      the entry (using the ELF file) and replacing them with values from binman's
      data structures.
  
      Args:
          elf_fname: Filename of ELF image containing the symbol information for
              entry
          entry: Entry to process
          image: Image which can be used to lookup symbol values
      """
      fname = tools.GetInputFilename(elf_fname)
      syms = GetSymbols(fname, ['image', 'binman'])
      if not syms:
          return
      base = syms.get('__image_copy_start')
      if not base:
          return
      for name, sym in syms.iteritems():
          if name.startswith('_binman'):
              msg = ("Image '%s': Symbol '%s'
     in entry '%s'" %
                     (image.GetPath(), name, entry.GetPath()))
              offset = sym.address - base.address
              if offset < 0 or offset + sym.size > entry.contents_size:
                  raise ValueError('%s has offset %x (size %x) but the contents '
                                   'size is %x' % (entry.GetPath(), offset,
                                                   sym.size, entry.contents_size))
              if sym.size == 4:
                  pack_string = '<I'
              elif sym.size == 8:
                  pack_string = '<Q'
              else:
                  raise ValueError('%s has size %d: only 4 and 8 are supported' %
                                   (msg, sym.size))
  
              # Look up the symbol in our entry tables.
              value = image.LookupSymbol(name, sym.weak, msg)
              if value is not None:
                  value += base.address
              else:
                  value = -1
                  pack_string = pack_string.lower()
              value_bytes = struct.pack(pack_string, value)
              if debug:
                  print('%s:
     insert %s, offset %x, value %x, length %d' %
                        (msg, name, offset, value, len(value_bytes)))
              entry.data = (entry.data[:offset] + value_bytes +
                          entry.data[offset + sym.size:])