2 from __future__
import print_function
4 Helper script to print out the raw content of an ELF section.
7 # print out as bits by default
8 extract-section.py .text --input-file=foo.o
11 # read from stdin and print out in hex
12 cat foo.o | extract-section.py -h .text
14 This is merely a wrapper around `llvm-readobj` that focuses on the binary
15 content as well as providing more formatting options.
18 # Unfortunately reading binary from stdin is not so trivial in Python...
21 if sys
.version_info
>= (3, 0):
22 reading_source
= sys
.stdin
.buffer
24 # Windows will always read as string so we need some
26 if sys
.platform
== 'win32':
28 msvcrt
.setformat(sys
.stdin
.fileno(), os
.O_BINARY
)
29 reading_source
= sys
.stdin
30 return reading_source
.read()
32 def get_raw_section_dump(readobj_path
, section_name
, input_file
):
34 cmd
= [readobj_path
, '--elf-output-style=GNU', '--hex-dump={}'.format(section_name
),
36 proc
= subprocess
.Popen(cmd
, stdin
=subprocess
.PIPE
, stdout
=subprocess
.PIPE
)
40 out
,_
= proc
.communicate(input=read_raw_stdin())
42 out
,_
= proc
.communicate()
44 return out
.decode('utf-8') if type(out
) is not str else out
46 if __name__
== '__main__':
48 # The default '-h' (--help) will conflict with our '-h' (hex) format
49 arg_parser
= argparse
.ArgumentParser(add_help
=False)
50 arg_parser
.add_argument('--readobj-path', metavar
='<executable path>', type=str,
51 help='Path to llvm-readobj')
52 arg_parser
.add_argument('--input-file', metavar
='<file>', type=str,
53 help='Input object file, or \'-\' to read from stdin')
54 arg_parser
.add_argument('section', metavar
='<name>', type=str,
55 help='Name of the section to extract')
57 format_group
= arg_parser
.add_mutually_exclusive_group()
58 format_group
.add_argument('-b', dest
='format', action
='store_const', const
='bits',
59 help='Print out in bits')
60 arg_parser
.add_argument('--byte-indicator', action
='store_true',
61 help='Whether to print a \'.\' every 8 bits in bits printing mode')
62 format_group
.add_argument('-h', dest
='format', action
='store_const', const
='hex',
63 help='Print out in hexadecimal')
64 arg_parser
.add_argument('--hex-width', metavar
='<# of bytes>', type=int,
65 help='The width (in byte) of every element in hex printing mode')
67 arg_parser
.add_argument('--help', action
='help')
68 arg_parser
.set_defaults(format
='bits', tool_path
='llvm-readobj', input_file
='-',
69 byte_indicator
=False, hex_width
=4)
70 args
= arg_parser
.parse_args()
72 raw_section
= get_raw_section_dump(args
.tool_path
, args
.section
, args
.input_file
)
75 for line
in raw_section
.splitlines(False):
76 if line
.startswith('Hex dump'):
78 parts
= line
.strip().split(' ')[1:]
79 for part
in parts
[:4]:
80 # exclude any non-hex dump string
83 if args
.format
== 'bits':
84 # divided into bytes first
85 for byte
in [(val
>> off
) & 0xFF for off
in (24,16,8,0)]:
86 for bit
in [(byte
>> off
) & 1 for off
in range(7, -1, -1)]:
87 results
.append(str(bit
))
88 if args
.byte_indicator
:
90 elif args
.format
== 'hex':
91 assert args
.hex_width
<= 4 and args
.hex_width
> 0
92 width_bits
= args
.hex_width
* 8
93 offsets
= [off
for off
in range(32 - width_bits
, -1, -width_bits
)]
94 mask
= (1 << width_bits
) - 1
95 format_str
= "{:0" + str(args
.hex_width
* 2) + "x}"
96 for word
in [(val
>> i
) & mask
for i
in offsets
]:
97 results
.append(format_str
.format(word
))
100 print(' '.join(results
), end
='')