1*515bc8c1Sserge-sans-paille#!/usr/bin/env python 2525cd59fSSerge Gueltonfrom __future__ import print_function 3923bedf5SGreg Clayton 4923bedf5SGreg Claytonimport lldb 5923bedf5SGreg Claytonimport optparse 6923bedf5SGreg Claytonimport shlex 7923bedf5SGreg Claytonimport string 8923bedf5SGreg Claytonimport sys 9923bedf5SGreg Clayton 10b9c1b51eSKate Stone 1184a7333aSGreg Claytonclass DumpLineTables: 1284a7333aSGreg Clayton command_name = "dump-line-tables" 1384a7333aSGreg Clayton short_decription = "Dumps full paths to compile unit files and optionally all line table files." 1484a7333aSGreg Clayton 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.' 1584a7333aSGreg Clayton usage = "usage: %prog [options] MODULE1 [MODULE2 ...]" 1684a7333aSGreg Clayton def create_options(self): 1784a7333aSGreg Clayton self.parser = optparse.OptionParser( 1884a7333aSGreg Clayton description=self.description, 1984a7333aSGreg Clayton prog=self.command_name, 2084a7333aSGreg Clayton usage=self.usage) 2184a7333aSGreg Clayton 2284a7333aSGreg Clayton self.parser.add_option( 23b9c1b51eSKate Stone '-v', 24b9c1b51eSKate Stone '--verbose', 25b9c1b51eSKate Stone action='store_true', 26b9c1b51eSKate Stone dest='verbose', 27b9c1b51eSKate Stone help='Display verbose output.', 28b9c1b51eSKate Stone default=False) 29923bedf5SGreg Clayton 3084a7333aSGreg Clayton def get_short_help(self): 3184a7333aSGreg Clayton return self.short_decription 32b9c1b51eSKate Stone 3384a7333aSGreg Clayton def get_long_help(self): 3484a7333aSGreg Clayton return self.help_string 3584a7333aSGreg Clayton 3684a7333aSGreg Clayton def __init__(self, debugger, unused): 3784a7333aSGreg Clayton self.create_options() 3884a7333aSGreg Clayton self.help_string = self.parser.format_help() 3984a7333aSGreg Clayton 4084a7333aSGreg Clayton def __call__(self, debugger, command, exe_ctx, result): 4184a7333aSGreg Clayton # Use the Shell Lexer to properly parse up command options just like a 4284a7333aSGreg Clayton # shell would 43923bedf5SGreg Clayton command_args = shlex.split(command) 44923bedf5SGreg Clayton 45923bedf5SGreg Clayton try: 4684a7333aSGreg Clayton (options, args) = self.parser.parse_args(command_args) 47923bedf5SGreg Clayton except: 4884a7333aSGreg Clayton # if you don't handle exceptions, passing an incorrect argument to the OptionParser will cause LLDB to exit 4984a7333aSGreg Clayton # (courtesy of OptParse dealing with argument errors by throwing SystemExit) 5084a7333aSGreg Clayton result.SetError("option parsing failed") 51923bedf5SGreg Clayton return 5284a7333aSGreg Clayton 5384a7333aSGreg Clayton # Always get program state from the SBExecutionContext passed in as exe_ctx 5484a7333aSGreg Clayton target = exe_ctx.GetTarget() 5584a7333aSGreg Clayton if not target.IsValid(): 5684a7333aSGreg Clayton result.SetError("invalid target") 5784a7333aSGreg Clayton return 5884a7333aSGreg Clayton 5984a7333aSGreg Clayton for module_path in args: 6084a7333aSGreg Clayton module = target.module[module_path] 6184a7333aSGreg Clayton if not module: 6284a7333aSGreg Clayton result.SetError('no module found that matches "%s".' % (module_path)) 6384a7333aSGreg Clayton return 6484a7333aSGreg Clayton num_cus = module.GetNumCompileUnits() 65525cd59fSSerge Guelton print('Module: "%s"' % (module.file.fullpath), end=' ', file=result) 6684a7333aSGreg Clayton if num_cus == 0: 67525cd59fSSerge Guelton print('no debug info.', file=result) 6884a7333aSGreg Clayton continue 69525cd59fSSerge Guelton print('has %u compile units:' % (num_cus), file=result) 7084a7333aSGreg Clayton for cu_idx in range(num_cus): 71923bedf5SGreg Clayton cu = module.GetCompileUnitAtIndex(cu_idx) 72525cd59fSSerge Guelton print(' Compile Unit: %s' % (cu.file.fullpath), file=result) 73923bedf5SGreg Clayton for line_idx in range(cu.GetNumLineEntries()): 74923bedf5SGreg Clayton line_entry = cu.GetLineEntryAtIndex(line_idx) 75923bedf5SGreg Clayton start_file_addr = line_entry.addr.file_addr 76923bedf5SGreg Clayton end_file_addr = line_entry.end_addr.file_addr 77b9c1b51eSKate Stone # If the two addresses are equal, this line table entry 78b9c1b51eSKate Stone # is a termination entry 79923bedf5SGreg Clayton if options.verbose: 80923bedf5SGreg Clayton if start_file_addr != end_file_addr: 81b9c1b51eSKate Stone result.PutCString( 82b9c1b51eSKate Stone ' [%#x - %#x): %s' % 83b9c1b51eSKate Stone (start_file_addr, end_file_addr, line_entry)) 84923bedf5SGreg Clayton else: 85923bedf5SGreg Clayton if start_file_addr == end_file_addr: 86b9c1b51eSKate Stone result.PutCString(' %#x: END' % 87b9c1b51eSKate Stone (start_file_addr)) 88923bedf5SGreg Clayton else: 89b9c1b51eSKate Stone result.PutCString( 90b9c1b51eSKate Stone ' %#x: %s' % 91b9c1b51eSKate Stone (start_file_addr, line_entry)) 92923bedf5SGreg Clayton if start_file_addr == end_file_addr: 9384a7333aSGreg Clayton result.PutCString("\n") 94923bedf5SGreg Clayton 9584a7333aSGreg Clayton 9684a7333aSGreg Claytonclass DumpFiles: 9784a7333aSGreg Clayton command_name = "dump-files" 9884a7333aSGreg Clayton short_description = "Dumps full paths to compile unit files and optionally all line table files." 9984a7333aSGreg Clayton usage = "usage: %prog [options] MODULE1 [MODULE2 ...]" 10084a7333aSGreg Clayton description = '''This class adds a dump-files command to the LLDB interpreter. 10184a7333aSGreg Clayton 10284a7333aSGreg ClaytonThis command will dump all compile unit file paths found for each source file 10384a7333aSGreg Claytonfor the binaries specified as arguments in the current target. Specify the 10484a7333aSGreg Clayton--support-files or -s option to see all file paths that a compile unit uses in 10584a7333aSGreg Claytonits lines tables. This is handy for troubleshooting why breakpoints aren't 10684a7333aSGreg Claytonworking in IDEs that specify full paths to source files when setting file and 10784a7333aSGreg Claytonline breakpoints. Sometimes symlinks cause the debug info to contain the symlink 10884a7333aSGreg Claytonpath and an IDE will resolve the path to the actual file and use the resolved 10984a7333aSGreg Claytonpath when setting breakpoints. 11084a7333aSGreg Clayton''' 11184a7333aSGreg Clayton def create_options(self): 11284a7333aSGreg Clayton # Pass add_help_option = False, since this keeps the command in line with lldb commands, 11384a7333aSGreg Clayton # and we wire up "help command" to work by providing the long & short help methods below. 11484a7333aSGreg Clayton self.parser = optparse.OptionParser( 11584a7333aSGreg Clayton description = self.description, 11684a7333aSGreg Clayton prog = self.command_name, 11784a7333aSGreg Clayton usage = self.usage, 11884a7333aSGreg Clayton add_help_option = False) 11984a7333aSGreg Clayton 12084a7333aSGreg Clayton self.parser.add_option( 12184a7333aSGreg Clayton '-s', 12284a7333aSGreg Clayton '--support-files', 12384a7333aSGreg Clayton action = 'store_true', 12484a7333aSGreg Clayton dest = 'support_files', 12584a7333aSGreg Clayton help = 'Dumps full paths to all files used in a compile unit.', 12684a7333aSGreg Clayton default = False) 12784a7333aSGreg Clayton 12884a7333aSGreg Clayton def get_short_help(self): 12984a7333aSGreg Clayton return self.short_description 13084a7333aSGreg Clayton 13184a7333aSGreg Clayton def get_long_help(self): 13284a7333aSGreg Clayton return self.help_string 13384a7333aSGreg Clayton 13484a7333aSGreg Clayton def __init__(self, debugger, unused): 13584a7333aSGreg Clayton self.create_options() 13684a7333aSGreg Clayton self.help_string = self.parser.format_help() 13784a7333aSGreg Clayton 13884a7333aSGreg Clayton def __call__(self, debugger, command, exe_ctx, result): 13984a7333aSGreg Clayton # Use the Shell Lexer to properly parse up command options just like a 14084a7333aSGreg Clayton # shell would 14184a7333aSGreg Clayton command_args = shlex.split(command) 14284a7333aSGreg Clayton 14384a7333aSGreg Clayton try: 14484a7333aSGreg Clayton (options, args) = self.parser.parse_args(command_args) 14584a7333aSGreg Clayton except: 14684a7333aSGreg Clayton # if you don't handle exceptions, passing an incorrect argument to the OptionParser will cause LLDB to exit 14784a7333aSGreg Clayton # (courtesy of OptParse dealing with argument errors by throwing SystemExit) 14884a7333aSGreg Clayton result.SetError("option parsing failed") 14984a7333aSGreg Clayton return 15084a7333aSGreg Clayton 15184a7333aSGreg Clayton # Always get program state from the SBExecutionContext passed in as exe_ctx 15284a7333aSGreg Clayton target = exe_ctx.GetTarget() 15384a7333aSGreg Clayton if not target.IsValid(): 15484a7333aSGreg Clayton result.SetError("invalid target") 15584a7333aSGreg Clayton return 15684a7333aSGreg Clayton 15784a7333aSGreg Clayton if len(args) == 0: 15884a7333aSGreg Clayton result.SetError("one or more executable paths must be specified") 15984a7333aSGreg Clayton return 16084a7333aSGreg Clayton 16184a7333aSGreg Clayton for module_path in args: 16284a7333aSGreg Clayton module = target.module[module_path] 16384a7333aSGreg Clayton if not module: 16484a7333aSGreg Clayton result.SetError('no module found that matches "%s".' % (module_path)) 16584a7333aSGreg Clayton return 16684a7333aSGreg Clayton num_cus = module.GetNumCompileUnits() 167525cd59fSSerge Guelton print('Module: "%s"' % (module.file.fullpath), end=' ', file=result) 16884a7333aSGreg Clayton if num_cus == 0: 169525cd59fSSerge Guelton print('no debug info.', file=result) 17084a7333aSGreg Clayton continue 171525cd59fSSerge Guelton print('has %u compile units:' % (num_cus), file=result) 17284a7333aSGreg Clayton for i in range(num_cus): 17384a7333aSGreg Clayton cu = module.GetCompileUnitAtIndex(i) 174525cd59fSSerge Guelton print(' Compile Unit: %s' % (cu.file.fullpath), file=result) 17584a7333aSGreg Clayton if options.support_files: 17684a7333aSGreg Clayton num_support_files = cu.GetNumSupportFiles() 17784a7333aSGreg Clayton for j in range(num_support_files): 17884a7333aSGreg Clayton path = cu.GetSupportFileAtIndex(j).fullpath 179525cd59fSSerge Guelton print(' file[%u]: %s' % (j, path), file=result) 18084a7333aSGreg Clayton 18184a7333aSGreg Clayton 18284a7333aSGreg Claytondef __lldb_init_module(debugger, dict): 18384a7333aSGreg Clayton # This initializer is being run from LLDB in the embedded command interpreter 18484a7333aSGreg Clayton 18584a7333aSGreg Clayton # Add any commands contained in this module to LLDB 18684a7333aSGreg Clayton debugger.HandleCommand( 18784a7333aSGreg Clayton 'command script add -c %s.DumpLineTables %s' % (__name__, 18884a7333aSGreg Clayton DumpLineTables.command_name)) 18984a7333aSGreg Clayton debugger.HandleCommand( 19084a7333aSGreg Clayton 'command script add -c %s.DumpFiles %s' % (__name__, DumpFiles.command_name)) 191525cd59fSSerge Guelton print('The "%s" and "%s" commands have been installed.' % (DumpLineTables.command_name, 192525cd59fSSerge Guelton DumpFiles.command_name)) 193