4 Run gdb to disassemble a function, feed the bytes to 'llvm-mc -disassemble' command,
5 and display the disassembly result.
11 from optparse import OptionParser
14 """Check whether fpath is an executable."""
15 return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
18 """Find the full path to a program, or return None."""
19 fpath, fname = os.path.split(program)
24 for path in os.environ["PATH"].split(os.pathsep):
25 exe_file = os.path.join(path, program)
30 def do_llvm_mc_disassembly(gdb_commands, gdb_options, exe, func, mc, mc_options):
31 from cStringIO import StringIO
34 gdb_prompt = "\r\n\(gdb\) "
35 gdb = pexpect.spawn(('gdb %s' % gdb_options) if gdb_options else 'gdb')
36 # Turn on logging for what gdb sends back.
37 gdb.logfile_read = sys.stdout
38 gdb.expect(gdb_prompt)
40 # See if there any extra command(s) to execute before we issue the file command.
41 for cmd in gdb_commands:
43 gdb.expect(gdb_prompt)
45 # Now issue the file command.
46 gdb.sendline('file %s' % exe)
47 gdb.expect(gdb_prompt)
49 # Send the disassemble command.
50 gdb.sendline('disassemble %s' % func)
51 gdb.expect(gdb_prompt)
53 # Get the output from gdb.
54 gdb_output = gdb.before
56 # Use StringIO to record the memory dump as well as the gdb assembler code.
59 # These keep track of the states of our simple gdb_output parser.
65 for line in gdb_output.split(os.linesep):
66 if line.startswith('Dump of assembler code'):
70 if line.startswith('End of assembler dump.'):
73 if mc_options and mc_options.find('arm') != -1:
75 if mc_options and mc_options.find('thumb') != -1:
76 # It is obviously wrong to assume the last instruction of the
77 # function has two bytes.
81 if looking and line.startswith('0x'):
82 # It's an assembler code dump.
84 curr_addr = line.split(None, 1)[0]
85 if prev_addr and curr_addr:
86 addr_diff = int(curr_addr, 16) - int(prev_addr, 16)
88 if prev_addr and addr_diff > 0:
89 # Feed the examining memory command to gdb.
90 gdb.sendline('x /%db %s' % (addr_diff, prev_addr))
91 gdb.expect(gdb_prompt)
93 # Get the last output line from the gdb examine memory command,
94 # split the string into a 3-tuple with separator '>:' to handle
96 memory_dump = x_output.split(os.linesep)[-1].partition('>:')[2].strip()
97 #print "\nbytes:", memory_dump
98 disasm_str = prev_line.partition('>:')[2]
99 print >> mc_input, '%s # %s' % (memory_dump, disasm_str)
101 # We're done with the processing. Assign the current line to be prev_line.
104 # Close the gdb session now that we are done with it.
106 gdb.expect(pexpect.EOF)
109 # Write the memory dump into a file.
110 with open('disasm-input.txt', 'w') as f:
111 f.write(mc_input.getvalue())
113 mc_cmd = '%s -disassemble %s disasm-input.txt' % (mc, mc_options)
114 print "\nExecuting command:", mc_cmd
117 # And invoke llvm-mc with the just recorded file.
118 #mc = pexpect.spawn('%s -disassemble %s disasm-input.txt' % (mc, mc_options))
119 #mc.logfile_read = sys.stdout
125 # This is to set up the Python path to include the pexpect-2.4 dir.
126 # Remember to update this when/if things change.
127 scriptPath = sys.path[0]
128 sys.path.append(os.path.join(scriptPath, os.pardir, os.pardir, 'test', 'pexpect-2.4'))
130 parser = OptionParser(usage="""\
131 Run gdb to disassemble a function, feed the bytes to 'llvm-mc -disassemble' command,
132 and display the disassembly result.
134 Usage: %prog [options]
136 parser.add_option('-C', '--gdb-command',
137 type='string', action='append', metavar='COMMAND',
138 default=[], dest='gdb_commands',
139 help='Command(s) gdb executes after starting up (can be empty)')
140 parser.add_option('-O', '--gdb-options',
141 type='string', action='store',
143 help="""The options passed to 'gdb' command if specified.""")
144 parser.add_option('-e', '--executable',
145 type='string', action='store',
147 help="""The executable to do disassembly on.""")
148 parser.add_option('-f', '--function',
149 type='string', action='store',
151 help="""The function name (could be an address to gdb) for disassembly.""")
152 parser.add_option('-m', '--llvm-mc',
153 type='string', action='store',
155 help="""The llvm-mc executable full path, if specified.
156 Otherwise, it must be present in your PATH environment.""")
158 parser.add_option('-o', '--options',
159 type='string', action='store',
160 dest='llvm_mc_options',
161 help="""The options passed to 'llvm-mc -disassemble' command if specified.""")
163 opts, args = parser.parse_args()
165 gdb_commands = opts.gdb_commands
166 gdb_options = opts.gdb_options
168 if not opts.executable:
171 executable = opts.executable
173 if not opts.function:
176 function = opts.function
178 llvm_mc = opts.llvm_mc if opts.llvm_mc else which('llvm-mc')
183 # This is optional. For example:
184 # --options='-triple=arm-apple-darwin -debug-only=arm-disassembler'
185 llvm_mc_options = opts.llvm_mc_options
187 # We have parsed the options.
188 print "gdb commands:", gdb_commands
189 print "gdb options:", gdb_options
190 print "executable:", executable
191 print "function:", function
192 print "llvm-mc:", llvm_mc
193 print "llvm-mc options:", llvm_mc_options
195 do_llvm_mc_disassembly(gdb_commands, gdb_options, executable, function, llvm_mc, llvm_mc_options)
197 if __name__ == '__main__':