130 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			130 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Python
		
	
	
	
| # 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'\n   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:\n   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:])
 |