154 lines · python
1#!/usr/bin/env python2from __future__ import print_function3 4"""5Helper script to print out the raw content of an ELF section.6Example usages:7```8# print out as bits by default9extract-section.py .text --input-file=foo.o10```11```12# read from stdin and print out in hex13cat foo.o | extract-section.py -h .text14```15This is merely a wrapper around `llvm-readobj` that focuses on the binary16content as well as providing more formatting options.17"""18 19# Unfortunately reading binary from stdin is not so trivial in Python...20def read_raw_stdin():21 import sys22 23 if sys.version_info >= (3, 0):24 reading_source = sys.stdin.buffer25 else:26 # Windows will always read as string so we need some27 # special handling28 if sys.platform == "win32":29 import os, msvcrt30 31 msvcrt.setformat(sys.stdin.fileno(), os.O_BINARY)32 reading_source = sys.stdin33 return reading_source.read()34 35 36def get_raw_section_dump(readobj_path, section_name, input_file):37 import subprocess38 39 cmd = [40 readobj_path,41 "--elf-output-style=GNU",42 "--hex-dump={}".format(section_name),43 input_file,44 ]45 proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)46 47 if input_file == "-":48 # From stdin49 out, _ = proc.communicate(input=read_raw_stdin())50 else:51 out, _ = proc.communicate()52 53 return out.decode("utf-8") if type(out) is not str else out54 55 56if __name__ == "__main__":57 import argparse58 59 # The default '-h' (--help) will conflict with our '-h' (hex) format60 arg_parser = argparse.ArgumentParser(add_help=False)61 arg_parser.add_argument(62 "--readobj-path",63 metavar="<executable path>",64 type=str,65 help="Path to llvm-readobj",66 )67 arg_parser.add_argument(68 "--input-file",69 metavar="<file>",70 type=str,71 help="Input object file, or '-' to read from stdin",72 )73 arg_parser.add_argument(74 "section", metavar="<name>", type=str, help="Name of the section to extract"75 )76 # Output format77 format_group = arg_parser.add_mutually_exclusive_group()78 format_group.add_argument(79 "-b",80 dest="format",81 action="store_const",82 const="bits",83 help="Print out in bits",84 )85 arg_parser.add_argument(86 "--byte-indicator",87 action="store_true",88 help="Whether to print a '.' every 8 bits in bits printing mode",89 )90 arg_parser.add_argument(91 "--bits-endian",92 metavar="<little/big>",93 type=str,94 choices=["little", "big"],95 help="Print out bits in specified endianness (little or big); defaults to big",96 )97 format_group.add_argument(98 "-h",99 dest="format",100 action="store_const",101 const="hex",102 help="Print out in hexadecimal",103 )104 arg_parser.add_argument(105 "--hex-width",106 metavar="<# of bytes>",107 type=int,108 help="The width (in byte) of every element in hex printing mode",109 )110 111 arg_parser.add_argument("--help", action="help")112 arg_parser.set_defaults(113 format="bits",114 tool_path="llvm-readobj",115 input_file="-",116 byte_indicator=False,117 hex_width=4,118 bits_endian="big",119 )120 args = arg_parser.parse_args()121 122 raw_section = get_raw_section_dump(args.tool_path, args.section, args.input_file)123 124 results = []125 for line in raw_section.splitlines(False):126 if line.startswith("Hex dump"):127 continue128 parts = line.strip().split(" ")[1:]129 for part in parts[:4]:130 # exclude any non-hex dump string131 try:132 val = int(part, 16)133 if args.format == "bits":134 # divided into bytes first135 offsets = (24, 16, 8, 0)136 if args.bits_endian == "little":137 offsets = (0, 8, 16, 24)138 for byte in [(val >> off) & 0xFF for off in offsets]:139 for bit in [(byte >> off) & 1 for off in range(7, -1, -1)]:140 results.append(str(bit))141 if args.byte_indicator:142 results.append(".")143 elif args.format == "hex":144 assert args.hex_width <= 4 and args.hex_width > 0145 width_bits = args.hex_width * 8146 offsets = [off for off in range(32 - width_bits, -1, -width_bits)]147 mask = (1 << width_bits) - 1148 format_str = "{:0" + str(args.hex_width * 2) + "x}"149 for word in [(val >> i) & mask for i in offsets]:150 results.append(format_str.format(word))151 except:152 break153 print(" ".join(results), end="")154