2013-03-07 10:57:54 +08:00
#!/usr/bin/python
import lldb
import optparse
import shlex
import string
import sys
2016-09-07 04:57:50 +08:00
2017-11-17 01:14:48 +08:00
class DumpLineTables :
command_name = " dump-line-tables "
short_decription = " Dumps full paths to compile unit files and optionally all line table files. "
description = ' Dumps all line tables from all compile units for any modules specified as arguments. Specifying the --verbose flag will output address ranges for each line entry. '
usage = " usage: % prog [options] MODULE1 [MODULE2 ...] "
def create_options ( self ) :
self . parser = optparse . OptionParser (
description = self . description ,
prog = self . command_name ,
usage = self . usage )
self . parser . add_option (
' -v ' ,
' --verbose ' ,
action = ' store_true ' ,
dest = ' verbose ' ,
help = ' Display verbose output. ' ,
default = False )
def get_short_help ( self ) :
return self . short_decription
def get_long_help ( self ) :
return self . help_string
def __init__ ( self , debugger , unused ) :
self . create_options ( )
self . help_string = self . parser . format_help ( )
def __call__ ( self , debugger , command , exe_ctx , result ) :
# Use the Shell Lexer to properly parse up command options just like a
# shell would
command_args = shlex . split ( command )
try :
( options , args ) = self . parser . parse_args ( command_args )
except :
# if you don't handle exceptions, passing an incorrect argument to the OptionParser will cause LLDB to exit
# (courtesy of OptParse dealing with argument errors by throwing SystemExit)
result . SetError ( " option parsing failed " )
return
# Always get program state from the SBExecutionContext passed in as exe_ctx
target = exe_ctx . GetTarget ( )
if not target . IsValid ( ) :
result . SetError ( " invalid target " )
return
for module_path in args :
module = target . module [ module_path ]
if not module :
result . SetError ( ' no module found that matches " %s " . ' % ( module_path ) )
return
num_cus = module . GetNumCompileUnits ( )
print >> result , ' Module: " %s " ' % ( module . file . fullpath ) ,
if num_cus == 0 :
print >> result , ' no debug info. '
continue
print >> result , ' has %u compile units: ' % ( num_cus )
for cu_idx in range ( num_cus ) :
cu = module . GetCompileUnitAtIndex ( cu_idx )
print >> result , ' Compile Unit: %s ' % ( cu . file . fullpath )
for line_idx in range ( cu . GetNumLineEntries ( ) ) :
line_entry = cu . GetLineEntryAtIndex ( line_idx )
start_file_addr = line_entry . addr . file_addr
end_file_addr = line_entry . end_addr . file_addr
# If the two addresses are equal, this line table entry
# is a termination entry
if options . verbose :
if start_file_addr != end_file_addr :
result . PutCString (
' [ %#x - %#x ): %s ' %
( start_file_addr , end_file_addr , line_entry ) )
else :
2013-03-07 10:57:54 +08:00
if start_file_addr == end_file_addr :
2017-11-17 01:14:48 +08:00
result . PutCString ( ' %#x : END ' %
( start_file_addr ) )
else :
result . PutCString (
' %#x : %s ' %
( start_file_addr , line_entry ) )
if start_file_addr == end_file_addr :
result . PutCString ( " \n " )
class DumpFiles :
command_name = " dump-files "
short_description = " Dumps full paths to compile unit files and optionally all line table files. "
usage = " usage: % prog [options] MODULE1 [MODULE2 ...] "
description = ''' This class adds a dump-files command to the LLDB interpreter.
This command will dump all compile unit file paths found for each source file
for the binaries specified as arguments in the current target . Specify the
- - support - files or - s option to see all file paths that a compile unit uses in
its lines tables . This is handy for troubleshooting why breakpoints aren ' t
working in IDEs that specify full paths to source files when setting file and
line breakpoints . Sometimes symlinks cause the debug info to contain the symlink
path and an IDE will resolve the path to the actual file and use the resolved
path when setting breakpoints .
'''
def create_options ( self ) :
# Pass add_help_option = False, since this keeps the command in line with lldb commands,
# and we wire up "help command" to work by providing the long & short help methods below.
self . parser = optparse . OptionParser (
description = self . description ,
prog = self . command_name ,
usage = self . usage ,
add_help_option = False )
self . parser . add_option (
' -s ' ,
' --support-files ' ,
action = ' store_true ' ,
dest = ' support_files ' ,
help = ' Dumps full paths to all files used in a compile unit. ' ,
default = False )
def get_short_help ( self ) :
return self . short_description
def get_long_help ( self ) :
return self . help_string
def __init__ ( self , debugger , unused ) :
self . create_options ( )
self . help_string = self . parser . format_help ( )
def __call__ ( self , debugger , command , exe_ctx , result ) :
# Use the Shell Lexer to properly parse up command options just like a
# shell would
command_args = shlex . split ( command )
try :
( options , args ) = self . parser . parse_args ( command_args )
except :
# if you don't handle exceptions, passing an incorrect argument to the OptionParser will cause LLDB to exit
# (courtesy of OptParse dealing with argument errors by throwing SystemExit)
result . SetError ( " option parsing failed " )
return
# Always get program state from the SBExecutionContext passed in as exe_ctx
target = exe_ctx . GetTarget ( )
if not target . IsValid ( ) :
result . SetError ( " invalid target " )
return
if len ( args ) == 0 :
result . SetError ( " one or more executable paths must be specified " )
return
for module_path in args :
module = target . module [ module_path ]
if not module :
result . SetError ( ' no module found that matches " %s " . ' % ( module_path ) )
return
num_cus = module . GetNumCompileUnits ( )
print >> result , ' Module: " %s " ' % ( module . file . fullpath ) ,
if num_cus == 0 :
print >> result , ' no debug info. '
continue
print >> result , ' has %u compile units: ' % ( num_cus )
for i in range ( num_cus ) :
cu = module . GetCompileUnitAtIndex ( i )
print >> result , ' Compile Unit: %s ' % ( cu . file . fullpath )
if options . support_files :
num_support_files = cu . GetNumSupportFiles ( )
for j in range ( num_support_files ) :
path = cu . GetSupportFileAtIndex ( j ) . fullpath
print >> result , ' file[ %u ]: %s ' % ( j , path )
def __lldb_init_module ( debugger , dict ) :
# This initializer is being run from LLDB in the embedded command interpreter
# Add any commands contained in this module to LLDB
debugger . HandleCommand (
' command script add -c %s .DumpLineTables %s ' % ( __name__ ,
DumpLineTables . command_name ) )
debugger . HandleCommand (
' command script add -c %s .DumpFiles %s ' % ( __name__ , DumpFiles . command_name ) )
print ' The " %s " and " %s " commands have been installed. ' % ( DumpLineTables . command_name ,
DumpFiles . command_name )