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