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 arg_parser
.add_argument('--bits-endian', metavar
='<little/big>', type=str,
63 choices
=['little', 'big'],
64 help='Print out bits in specified endianness (little or big); defaults to big')
65 format_group
.add_argument('-h', dest
='format', action
='store_const', const
='hex',
66 help='Print out in hexadecimal')
67 arg_parser
.add_argument('--hex-width', metavar
='<# of bytes>', type=int,
68 help='The width (in byte) of every element in hex printing mode')
70 arg_parser
.add_argument('--help', action
='help')
71 arg_parser
.set_defaults(format
='bits', tool_path
='llvm-readobj', input_file
='-',
72 byte_indicator
=False, hex_width
=4, bits_endian
='big')
73 args
= arg_parser
.parse_args()
75 raw_section
= get_raw_section_dump(args
.tool_path
, args
.section
, args
.input_file
)
78 for line
in raw_section
.splitlines(False):
79 if line
.startswith('Hex dump'):
81 parts
= line
.strip().split(' ')[1:]
82 for part
in parts
[:4]:
83 # exclude any non-hex dump string
86 if args
.format
== 'bits':
87 # divided into bytes first
88 offsets
= (24, 16, 8, 0)
89 if args
.bits_endian
== 'little':
90 offsets
= (0, 8, 16, 24)
91 for byte
in [(val
>> off
) & 0xFF for off
in offsets
]:
92 for bit
in [(byte
>> off
) & 1 for off
in range(7, -1, -1)]:
93 results
.append(str(bit
))
94 if args
.byte_indicator
:
96 elif args
.format
== 'hex':
97 assert args
.hex_width
<= 4 and args
.hex_width
> 0
98 width_bits
= args
.hex_width
* 8
99 offsets
= [off
for off
in range(32 - width_bits
, -1, -width_bits
)]
100 mask
= (1 << width_bits
) - 1
101 format_str
= "{:0" + str(args
.hex_width
* 2) + "x}"
102 for word
in [(val
>> i
) & mask
for i
in offsets
]:
103 results
.append(format_str
.format(word
))
106 print(' '.join(results
), end
='')