def BuildIdFromElf(elf_path, tool_prefix): """Returns the Build ID for the given binary.""" args = [path_util.GetReadElfPath(tool_prefix), '-n', elf_path] stdout = subprocess.check_output(args, encoding='ascii') match = re.search(r'Build ID: (\w+)', stdout) assert match, 'Build ID not found from running: ' + ' '.join(args) return match.group(1)
def CollectRelocationAddresses(elf_path, tool_prefix): """Returns the list of addresses that are targets for relative relocations.""" cmd = [path_util.GetReadElfPath(tool_prefix), '--relocs', elf_path] ret = subprocess.check_output(cmd, encoding='ascii').splitlines() # Grab first column from (sample output) '02de6d5c 00000017 R_ARM_RELATIVE' return [ int(l.split(maxsplit=1)[0], 16) for l in ret if 'R_ARM_RELATIVE' in l ]
def _SectionSizesFromElf(elf_path, tool_prefix): args = [path_util.GetReadElfPath(tool_prefix), '-S', '--wide', elf_path] stdout = subprocess.check_output(args) section_sizes = {} # Matches [ 2] .hash HASH 00000000006681f0 0001f0 003154 04 A 3 0 8 for match in re.finditer(r'\[[\s\d]+\] (\..*)$', stdout, re.MULTILINE): items = match.group(1).split() section_sizes[items[0]] = int(items[4], 16) return section_sizes
def LookupElfRodataInfo(elf_path, tool_prefix): """Returns (address, offset, size) for the .rodata section.""" args = [path_util.GetReadElfPath(tool_prefix), '-S', '--wide', elf_path] output = subprocess.check_output(args) lines = output.splitlines() for line in lines: # [Nr] Name Type Addr Off Size ES Flg Lk Inf Al # [07] .rodata PROGBITS 025e7000 237c000 5ec4f6 00 A 0 0 256 if '.rodata ' in line: fields = line[line.index(models.SECTION_RODATA):].split() return int(fields[2], 16), int(fields[3], 16), int(fields[4], 16) raise AssertionError('No .rodata for command: ' + repr(args))
def _ArchFromElf(elf_path, tool_prefix): args = [path_util.GetReadElfPath(tool_prefix), '-h', elf_path] stdout = subprocess.check_output(args) machine = re.search('Machine:\s*(.+)', stdout).group(1) if machine == 'Intel 80386': return 'x86' if machine == 'Advanced Micro Devices X86-64': return 'x64' elif machine == 'ARM': return 'arm' elif machine == 'AArch64': return 'arm64' return machine
def SectionInfoFromElf(elf_path, tool_prefix): """Finds the address and size of all ELF sections Returns: A dict of section_name->(start_address, size). """ args = [path_util.GetReadElfPath(tool_prefix), '-S', '--wide', elf_path] stdout = subprocess.check_output(args, encoding='ascii') section_ranges = {} # Matches [ 2] .hash HASH 00000000006681f0 0001f0 003154 04 A 3 0 8 for match in re.finditer(r'\[[\s\d]+\] (\..*)$', stdout, re.MULTILINE): items = match.group(1).split() section_ranges[items[0]] = (int(items[2], 16), int(items[4], 16)) return section_ranges
def ArchFromElf(elf_path, tool_prefix): """Returns the GN architecture for the given binary.""" args = [path_util.GetReadElfPath(tool_prefix), '-h', elf_path] stdout = subprocess.check_output(args, encoding='ascii') machine = re.search('Machine:\s*(.+)', stdout).group(1) if machine == 'Intel 80386': return 'x86' if machine == 'Advanced Micro Devices X86-64': return 'x64' elif machine == 'ARM': return 'arm' elif machine == 'AArch64': return 'arm64' return machine
def _LookupStringSectionPositions(target, tool_prefix, output_directory): """Returns a dict of object_path -> [(offset, size)...] of .rodata sections. Args: target: An archive path string (e.g., "foo.a") or a list of object paths. """ is_archive = isinstance(target, str) args = [path_util.GetReadElfPath(tool_prefix), '-S', '--wide'] if is_archive: args.append(target) else: # Assign path for when len(target) == 1, (no File: line exists). path = target[0] args.extend(target) output = subprocess.check_output(args, cwd=output_directory).decode('ascii') lines = output.splitlines() section_positions_by_path = {} cur_offsets = [] for line in lines: # File: base/third_party/libevent/libevent.a(buffer.o) # [Nr] Name Type Addr Off Size ES Flg Lk Inf Al # [11] .rodata.str1.1 PROGBITS 00000000 0000b4 000004 01 AMS 0 0 1 # [11] .rodata.str4.4 PROGBITS 00000000 0000b4 000004 01 AMS 0 0 4 # [11] .rodata.str8.8 PROGBITS 00000000 0000b4 000004 01 AMS 0 0 8 # [80] .rodata..L.str PROGBITS 00000000 000530 000002 00 A 0 0 1 # The various string sections differ by alignment. # The presence of a wchar_t literal (L"asdf") seems to make a str4 section. # When multiple sections exist, nm gives us no indication as to which # section each string corresponds to. if line.startswith('File: '): if cur_offsets: section_positions_by_path[path] = cur_offsets cur_offsets = [] path = line[6:] elif '.rodata.' in line: progbits_idx = line.find('PROGBITS ') if progbits_idx != -1: fields = line[progbits_idx:].split() position = (int(fields[2], 16), int(fields[3], 16)) # The heuristics in _IterStringLiterals rely on str1 coming first. if fields[-1] == '1': cur_offsets.insert(0, position) else: cur_offsets.append(position) if cur_offsets: section_positions_by_path[path] = cur_offsets return section_positions_by_path
def BuildIdFromElf(elf_path, tool_prefix): args = [path_util.GetReadElfPath(tool_prefix), '-n', elf_path] stdout = subprocess.check_output(args) match = re.search(r'Build ID: (\w+)', stdout) assert match, 'Build ID not found from running: ' + ' '.join(args) return match.group(1)