183d290c5STom Rini# SPDX-License-Identifier: GPL-2.0+ 2b50e5611SSimon Glass# Copyright (c) 2016 Google, Inc 3b50e5611SSimon Glass# Written by Simon Glass <sjg@chromium.org> 4b50e5611SSimon Glass# 5b50e5611SSimon Glass# Handle various things related to ELF images 6b50e5611SSimon Glass# 7b50e5611SSimon Glass 8b50e5611SSimon Glassfrom collections import namedtuple, OrderedDict 9b50e5611SSimon Glassimport command 10b50e5611SSimon Glassimport os 11b50e5611SSimon Glassimport re 12b50e5611SSimon Glassimport struct 13b50e5611SSimon Glass 14b50e5611SSimon Glassimport tools 15b50e5611SSimon Glass 167fe9173bSSimon Glass# This is enabled from control.py 177fe9173bSSimon Glassdebug = False 187fe9173bSSimon Glass 19b50e5611SSimon GlassSymbol = namedtuple('Symbol', ['section', 'address', 'size', 'weak']) 20b50e5611SSimon Glass 21b50e5611SSimon Glass 22b50e5611SSimon Glassdef GetSymbols(fname, patterns): 23b50e5611SSimon Glass """Get the symbols from an ELF file 24b50e5611SSimon Glass 25b50e5611SSimon Glass Args: 26b50e5611SSimon Glass fname: Filename of the ELF file to read 27b50e5611SSimon Glass patterns: List of regex patterns to search for, each a string 28b50e5611SSimon Glass 29b50e5611SSimon Glass Returns: 30b50e5611SSimon Glass None, if the file does not exist, or Dict: 31b50e5611SSimon Glass key: Name of symbol 32b50e5611SSimon Glass value: Hex value of symbol 33b50e5611SSimon Glass """ 34b50e5611SSimon Glass stdout = command.Output('objdump', '-t', fname, raise_on_error=False) 35b50e5611SSimon Glass lines = stdout.splitlines() 36b50e5611SSimon Glass if patterns: 37b50e5611SSimon Glass re_syms = re.compile('|'.join(patterns)) 38b50e5611SSimon Glass else: 39b50e5611SSimon Glass re_syms = None 40b50e5611SSimon Glass syms = {} 41b50e5611SSimon Glass syms_started = False 42b50e5611SSimon Glass for line in lines: 43b50e5611SSimon Glass if not line or not syms_started: 44b50e5611SSimon Glass if 'SYMBOL TABLE' in line: 45b50e5611SSimon Glass syms_started = True 46b50e5611SSimon Glass line = None # Otherwise code coverage complains about 'continue' 47b50e5611SSimon Glass continue 48b50e5611SSimon Glass if re_syms and not re_syms.search(line): 49b50e5611SSimon Glass continue 50b50e5611SSimon Glass 51b50e5611SSimon Glass space_pos = line.find(' ') 52b50e5611SSimon Glass value, rest = line[:space_pos], line[space_pos + 1:] 53b50e5611SSimon Glass flags = rest[:7] 54b50e5611SSimon Glass parts = rest[7:].split() 55b50e5611SSimon Glass section, size = parts[:2] 56b50e5611SSimon Glass if len(parts) > 2: 57b50e5611SSimon Glass name = parts[2] 58b50e5611SSimon Glass syms[name] = Symbol(section, int(value, 16), int(size,16), 59b50e5611SSimon Glass flags[1] == 'w') 6046d61a2fSSimon Glass 6146d61a2fSSimon Glass # Sort dict by address 6246d61a2fSSimon Glass return OrderedDict(sorted(syms.iteritems(), key=lambda x: x[1].address)) 63b50e5611SSimon Glass 64b50e5611SSimon Glassdef GetSymbolAddress(fname, sym_name): 65b50e5611SSimon Glass """Get a value of a symbol from an ELF file 66b50e5611SSimon Glass 67b50e5611SSimon Glass Args: 68b50e5611SSimon Glass fname: Filename of the ELF file to read 69b50e5611SSimon Glass patterns: List of regex patterns to search for, each a string 70b50e5611SSimon Glass 71b50e5611SSimon Glass Returns: 72b50e5611SSimon Glass Symbol value (as an integer) or None if not found 73b50e5611SSimon Glass """ 74b50e5611SSimon Glass syms = GetSymbols(fname, [sym_name]) 75b50e5611SSimon Glass sym = syms.get(sym_name) 76b50e5611SSimon Glass if not sym: 77b50e5611SSimon Glass return None 78b50e5611SSimon Glass return sym.address 7919790632SSimon Glass 80f55382b5SSimon Glassdef LookupAndWriteSymbols(elf_fname, entry, section): 8119790632SSimon Glass """Replace all symbols in an entry with their correct values 8219790632SSimon Glass 8319790632SSimon Glass The entry contents is updated so that values for referenced symbols will be 84*3ab9598dSSimon Glass visible at run time. This is done by finding out the symbols offsets in the 85*3ab9598dSSimon Glass entry (using the ELF file) and replacing them with values from binman's data 86*3ab9598dSSimon Glass structures. 8719790632SSimon Glass 8819790632SSimon Glass Args: 8919790632SSimon Glass elf_fname: Filename of ELF image containing the symbol information for 9019790632SSimon Glass entry 9119790632SSimon Glass entry: Entry to process 92f55382b5SSimon Glass section: Section which can be used to lookup symbol values 9319790632SSimon Glass """ 9419790632SSimon Glass fname = tools.GetInputFilename(elf_fname) 9519790632SSimon Glass syms = GetSymbols(fname, ['image', 'binman']) 9619790632SSimon Glass if not syms: 9719790632SSimon Glass return 9819790632SSimon Glass base = syms.get('__image_copy_start') 9919790632SSimon Glass if not base: 10019790632SSimon Glass return 10119790632SSimon Glass for name, sym in syms.iteritems(): 10219790632SSimon Glass if name.startswith('_binman'): 103f55382b5SSimon Glass msg = ("Section '%s': Symbol '%s'\n in entry '%s'" % 104f55382b5SSimon Glass (section.GetPath(), name, entry.GetPath())) 10519790632SSimon Glass offset = sym.address - base.address 10619790632SSimon Glass if offset < 0 or offset + sym.size > entry.contents_size: 10719790632SSimon Glass raise ValueError('%s has offset %x (size %x) but the contents ' 10819790632SSimon Glass 'size is %x' % (entry.GetPath(), offset, 10919790632SSimon Glass sym.size, entry.contents_size)) 11019790632SSimon Glass if sym.size == 4: 11119790632SSimon Glass pack_string = '<I' 11219790632SSimon Glass elif sym.size == 8: 11319790632SSimon Glass pack_string = '<Q' 11419790632SSimon Glass else: 11519790632SSimon Glass raise ValueError('%s has size %d: only 4 and 8 are supported' % 11619790632SSimon Glass (msg, sym.size)) 11719790632SSimon Glass 11819790632SSimon Glass # Look up the symbol in our entry tables. 119f55382b5SSimon Glass value = section.LookupSymbol(name, sym.weak, msg) 12019790632SSimon Glass if value is not None: 12119790632SSimon Glass value += base.address 12219790632SSimon Glass else: 12319790632SSimon Glass value = -1 12419790632SSimon Glass pack_string = pack_string.lower() 12519790632SSimon Glass value_bytes = struct.pack(pack_string, value) 12619790632SSimon Glass if debug: 12719790632SSimon Glass print('%s:\n insert %s, offset %x, value %x, length %d' % 12819790632SSimon Glass (msg, name, offset, value, len(value_bytes))) 12919790632SSimon Glass entry.data = (entry.data[:offset] + value_bytes + 13019790632SSimon Glass entry.data[offset + sym.size:]) 131