2 from __future__
import print_function
5 Helper script to print out the raw content of an ELF section.
8 # print out as bits by default
9 extract-section.py .text --input-file=foo.o
12 # read from stdin and print out in hex
13 cat foo.o | extract-section.py -h .text
15 This is merely a wrapper around `llvm-readobj` that focuses on the binary
16 content as well as providing more formatting options.
19 # Unfortunately reading binary from stdin is not so trivial in Python...
23 if sys
.version_info
>= (3, 0):
24 reading_source
= sys
.stdin
.buffer
26 # Windows will always read as string so we need some
28 if sys
.platform
== "win32":
31 msvcrt
.setformat(sys
.stdin
.fileno(), os
.O_BINARY
)
32 reading_source
= sys
.stdin
33 return reading_source
.read()
36 def get_raw_section_dump(readobj_path
, section_name
, input_file
):
41 "--elf-output-style=GNU",
42 "--hex-dump={}".format(section_name
),
45 proc
= subprocess
.Popen(cmd
, stdin
=subprocess
.PIPE
, stdout
=subprocess
.PIPE
)
49 out
, _
= proc
.communicate(input=read_raw_stdin())
51 out
, _
= proc
.communicate()
53 return out
.decode("utf-8") if type(out
) is not str else out
56 if __name__
== "__main__":
59 # The default '-h' (--help) will conflict with our '-h' (hex) format
60 arg_parser
= argparse
.ArgumentParser(add_help
=False)
61 arg_parser
.add_argument(
63 metavar
="<executable path>",
65 help="Path to llvm-readobj",
67 arg_parser
.add_argument(
71 help="Input object file, or '-' to read from stdin",
73 arg_parser
.add_argument(
74 "section", metavar
="<name>", type=str, help="Name of the section to extract"
77 format_group
= arg_parser
.add_mutually_exclusive_group()
78 format_group
.add_argument(
83 help="Print out in bits",
85 arg_parser
.add_argument(
88 help="Whether to print a '.' every 8 bits in bits printing mode",
90 arg_parser
.add_argument(
92 metavar
="<little/big>",
94 choices
=["little", "big"],
95 help="Print out bits in specified endianness (little or big); defaults to big",
97 format_group
.add_argument(
100 action
="store_const",
102 help="Print out in hexadecimal",
104 arg_parser
.add_argument(
106 metavar
="<# of bytes>",
108 help="The width (in byte) of every element in hex printing mode",
111 arg_parser
.add_argument("--help", action
="help")
112 arg_parser
.set_defaults(
114 tool_path
="llvm-readobj",
116 byte_indicator
=False,
120 args
= arg_parser
.parse_args()
122 raw_section
= get_raw_section_dump(args
.tool_path
, args
.section
, args
.input_file
)
125 for line
in raw_section
.splitlines(False):
126 if line
.startswith("Hex dump"):
128 parts
= line
.strip().split(" ")[1:]
129 for part
in parts
[:4]:
130 # exclude any non-hex dump string
133 if args
.format
== "bits":
134 # divided into bytes first
135 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
:
143 elif args
.format
== "hex":
144 assert args
.hex_width
<= 4 and args
.hex_width
> 0
145 width_bits
= args
.hex_width
* 8
146 offsets
= [off
for off
in range(32 - width_bits
, -1, -width_bits
)]
147 mask
= (1 << width_bits
) - 1
148 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
))
153 print(" ".join(results
), end
="")