def build_from_git(cls, git_repo, make_target, bintool_path): """Build a bintool from a git repo This clones the repo in a temporary directory, builds it with 'make', then returns the filename of the resulting executable bintool Args: git_repo (str): URL of git repo make_target (str): Target to pass to 'make' to build the tool bintool_path (str): Relative path of the tool in the repo, after build is complete Returns: tuple: str: Filename of fetched file to copy to a suitable directory str: Name of temp directory to remove, or None or None on error """ tmpdir = tempfile.mkdtemp(prefix='binmanf.') print(f"- clone git repo '{git_repo}' to '{tmpdir}'") tools.run('git', 'clone', '--depth', '1', git_repo, tmpdir) print(f"- build target '{make_target}'") tools.run('make', '-C', tmpdir, '-j', f'{multiprocessing.cpu_count()}', make_target) fname = os.path.join(tmpdir, bintool_path) if not os.path.exists(fname): print(f"- File '{fname}' was not produced") return None return fname, tmpdir
def ReadBlobContents(self): if self._strip: uniq = self.GetUniqueName() out_fname = tools.get_output_filename('%s.stripped' % uniq) tools.write_file(out_fname, tools.read_file(self._pathname)) tools.run('strip', out_fname) self._pathname = out_fname super().ReadBlobContents() return True
def fetch_from_url(cls, url): """Fetch a bintool from a URL Args: url (str): URL to fetch from Returns: tuple: str: Filename of fetched file to copy to a suitable directory str: Name of temp directory to remove, or None """ fname, tmpdir = tools.download(url) tools.run('chmod', 'a+x', fname) return fname, tmpdir
def apt_install(cls, package): """Install a bintool using the 'aot' tool This requires use of servo so may request a password Args: package (str): Name of package to install Returns: True, assuming it completes without error """ args = ['sudo', 'apt', 'install', '-y', package] print('- %s' % ' '.join(args)) tools.run(*args) return True
def show_sym(fname, data, endian, evtype, sym): """Show information about an evspy entry Args: fname (str): Filename of ELF file data (bytes): Data for this symbol endian (str): Endianness to use ('little', 'big', 'auto') evtype (str): Event type, e.g. 'MISC_INIT_F' sym (elf.Symbol): Symbol to show """ def _unpack_val(sym_data, offset): start = offset * func_size val_data = sym_data[start:start + func_size] fmt = '%s%s' % ('>' if endian == 'big' else '<', 'L' if func_size == 4 else 'Q') val = struct.unpack(fmt, val_data)[0] return val # Get the data, which is a struct evspy_info sym_data = data[sym.offset:sym.offset + sym.size] # Figure out the word size of the struct func_size = 4 if sym.size < 16 else 8 # Read the function name for evspy_info->func while True: # Switch to big-endian if we see a failure func_addr = _unpack_val(sym_data, 0) func_name = elf.GetSymbolFromAddress(fname, func_addr) if not func_name and endian == 'auto': endian = 'big' else: break has_id = sym.size in [12, 24] if has_id: # Find the address of evspy_info->id in the ELF id_addr = _unpack_val(sym_data, 2) # Get the file offset for that address id_ofs = elf.GetFileOffset(fname, id_addr) # Read out a nul-terminated string id_data = data[id_ofs:id_ofs + 80] pos = id_data.find(0) if pos: id_data = id_data[:pos] id_str = id_data.decode('utf-8') else: id_str = None # Find the file/line for the function cmd = ['addr2line', '-e', fname, '%x' % func_addr] out = tools.run(*cmd).strip() # Drop the full path if it is the current directory if out.startswith(src_path): out = out[len(src_path) + 1:] print('%-20s %-30s %s' % (evtype, id_str or f'f:{func_name}', out))
def BuildElfTestFiles(target_dir): """Build ELF files used for testing in binman This compiles and links the test files into the specified directory. It uses the Makefile and source files in the binman test/ directory. Args: target_dir: Directory to put the files into """ if not os.path.exists(target_dir): os.mkdir(target_dir) testdir = os.path.join(binman_dir, 'test') # If binman is involved from the main U-Boot Makefile the -r and -R # flags are set in MAKEFLAGS. This prevents this Makefile from working # correctly. So drop any make flags here. if 'MAKEFLAGS' in os.environ: del os.environ['MAKEFLAGS'] try: tools.run('make', '-C', target_dir, '-f', os.path.join(testdir, 'Makefile'), 'SRC=%s/' % testdir) except ValueError as e: # The test system seems to suppress this in a strange way print(e)
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 = tools.run('objdump', '-t', fname) 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] if parts[2] != '.hidden' else parts[3] syms[name] = Symbol(section, int(value, 16), int(size, 16), flags[1] == 'w', None) # Sort dict by address return OrderedDict(sorted(syms.items(), key=lambda x: x[1].address))