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