1be691f3bSpatrick#!/usr/bin/env python 2061da546Spatrick 3061da546Spatrickimport lldb 4061da546Spatrickimport optparse 5061da546Spatrickimport shlex 6061da546Spatrickimport string 7061da546Spatrickimport sys 8061da546Spatrick 9061da546Spatrick 10061da546Spatrickclass DumpLineTables: 11061da546Spatrick command_name = "dump-line-tables" 12*f6aab3d8Srobert short_description = "Dumps full paths to compile unit files and optionally all line table files." 13061da546Spatrick 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.' 14061da546Spatrick usage = "usage: %prog [options] MODULE1 [MODULE2 ...]" 15061da546Spatrick def create_options(self): 16061da546Spatrick self.parser = optparse.OptionParser( 17061da546Spatrick description=self.description, 18061da546Spatrick prog=self.command_name, 19061da546Spatrick usage=self.usage) 20061da546Spatrick 21061da546Spatrick self.parser.add_option( 22061da546Spatrick '-v', 23061da546Spatrick '--verbose', 24061da546Spatrick action='store_true', 25061da546Spatrick dest='verbose', 26061da546Spatrick help='Display verbose output.', 27061da546Spatrick default=False) 28061da546Spatrick 29061da546Spatrick def get_short_help(self): 30*f6aab3d8Srobert return self.short_description 31061da546Spatrick 32061da546Spatrick def get_long_help(self): 33061da546Spatrick return self.help_string 34061da546Spatrick 35061da546Spatrick def __init__(self, debugger, unused): 36061da546Spatrick self.create_options() 37061da546Spatrick self.help_string = self.parser.format_help() 38061da546Spatrick 39061da546Spatrick def __call__(self, debugger, command, exe_ctx, result): 40061da546Spatrick # Use the Shell Lexer to properly parse up command options just like a 41061da546Spatrick # shell would 42061da546Spatrick command_args = shlex.split(command) 43061da546Spatrick 44061da546Spatrick try: 45061da546Spatrick (options, args) = self.parser.parse_args(command_args) 46061da546Spatrick except: 47061da546Spatrick # if you don't handle exceptions, passing an incorrect argument to the OptionParser will cause LLDB to exit 48061da546Spatrick # (courtesy of OptParse dealing with argument errors by throwing SystemExit) 49061da546Spatrick result.SetError("option parsing failed") 50061da546Spatrick return 51061da546Spatrick 52061da546Spatrick # Always get program state from the SBExecutionContext passed in as exe_ctx 53061da546Spatrick target = exe_ctx.GetTarget() 54061da546Spatrick if not target.IsValid(): 55061da546Spatrick result.SetError("invalid target") 56061da546Spatrick return 57061da546Spatrick 58061da546Spatrick for module_path in args: 59061da546Spatrick module = target.module[module_path] 60061da546Spatrick if not module: 61061da546Spatrick result.SetError('no module found that matches "%s".' % (module_path)) 62061da546Spatrick return 63061da546Spatrick num_cus = module.GetNumCompileUnits() 64061da546Spatrick print('Module: "%s"' % (module.file.fullpath), end=' ', file=result) 65061da546Spatrick if num_cus == 0: 66061da546Spatrick print('no debug info.', file=result) 67061da546Spatrick continue 68061da546Spatrick print('has %u compile units:' % (num_cus), file=result) 69061da546Spatrick for cu_idx in range(num_cus): 70061da546Spatrick cu = module.GetCompileUnitAtIndex(cu_idx) 71061da546Spatrick print(' Compile Unit: %s' % (cu.file.fullpath), file=result) 72061da546Spatrick for line_idx in range(cu.GetNumLineEntries()): 73061da546Spatrick line_entry = cu.GetLineEntryAtIndex(line_idx) 74061da546Spatrick start_file_addr = line_entry.addr.file_addr 75061da546Spatrick end_file_addr = line_entry.end_addr.file_addr 76061da546Spatrick # If the two addresses are equal, this line table entry 77061da546Spatrick # is a termination entry 78061da546Spatrick if options.verbose: 79061da546Spatrick if start_file_addr != end_file_addr: 80061da546Spatrick result.PutCString( 81061da546Spatrick ' [%#x - %#x): %s' % 82061da546Spatrick (start_file_addr, end_file_addr, line_entry)) 83061da546Spatrick else: 84061da546Spatrick if start_file_addr == end_file_addr: 85061da546Spatrick result.PutCString(' %#x: END' % 86061da546Spatrick (start_file_addr)) 87061da546Spatrick else: 88061da546Spatrick result.PutCString( 89061da546Spatrick ' %#x: %s' % 90061da546Spatrick (start_file_addr, line_entry)) 91061da546Spatrick if start_file_addr == end_file_addr: 92061da546Spatrick result.PutCString("\n") 93061da546Spatrick 94061da546Spatrick 95061da546Spatrickclass DumpFiles: 96061da546Spatrick command_name = "dump-files" 97061da546Spatrick short_description = "Dumps full paths to compile unit files and optionally all line table files." 98061da546Spatrick usage = "usage: %prog [options] MODULE1 [MODULE2 ...]" 99061da546Spatrick description = '''This class adds a dump-files command to the LLDB interpreter. 100061da546Spatrick 101061da546SpatrickThis command will dump all compile unit file paths found for each source file 102061da546Spatrickfor the binaries specified as arguments in the current target. Specify the 103061da546Spatrick--support-files or -s option to see all file paths that a compile unit uses in 104061da546Spatrickits lines tables. This is handy for troubleshooting why breakpoints aren't 105061da546Spatrickworking in IDEs that specify full paths to source files when setting file and 106061da546Spatrickline breakpoints. Sometimes symlinks cause the debug info to contain the symlink 107061da546Spatrickpath and an IDE will resolve the path to the actual file and use the resolved 108061da546Spatrickpath when setting breakpoints. 109061da546Spatrick''' 110061da546Spatrick def create_options(self): 111061da546Spatrick # Pass add_help_option = False, since this keeps the command in line with lldb commands, 112061da546Spatrick # and we wire up "help command" to work by providing the long & short help methods below. 113061da546Spatrick self.parser = optparse.OptionParser( 114061da546Spatrick description = self.description, 115061da546Spatrick prog = self.command_name, 116061da546Spatrick usage = self.usage, 117061da546Spatrick add_help_option = False) 118061da546Spatrick 119061da546Spatrick self.parser.add_option( 120061da546Spatrick '-s', 121061da546Spatrick '--support-files', 122061da546Spatrick action = 'store_true', 123061da546Spatrick dest = 'support_files', 124061da546Spatrick help = 'Dumps full paths to all files used in a compile unit.', 125061da546Spatrick default = False) 126061da546Spatrick 127061da546Spatrick def get_short_help(self): 128061da546Spatrick return self.short_description 129061da546Spatrick 130061da546Spatrick def get_long_help(self): 131061da546Spatrick return self.help_string 132061da546Spatrick 133061da546Spatrick def __init__(self, debugger, unused): 134061da546Spatrick self.create_options() 135061da546Spatrick self.help_string = self.parser.format_help() 136061da546Spatrick 137061da546Spatrick def __call__(self, debugger, command, exe_ctx, result): 138061da546Spatrick # Use the Shell Lexer to properly parse up command options just like a 139061da546Spatrick # shell would 140061da546Spatrick command_args = shlex.split(command) 141061da546Spatrick 142061da546Spatrick try: 143061da546Spatrick (options, args) = self.parser.parse_args(command_args) 144061da546Spatrick except: 145061da546Spatrick # if you don't handle exceptions, passing an incorrect argument to the OptionParser will cause LLDB to exit 146061da546Spatrick # (courtesy of OptParse dealing with argument errors by throwing SystemExit) 147061da546Spatrick result.SetError("option parsing failed") 148061da546Spatrick return 149061da546Spatrick 150061da546Spatrick # Always get program state from the SBExecutionContext passed in as exe_ctx 151061da546Spatrick target = exe_ctx.GetTarget() 152061da546Spatrick if not target.IsValid(): 153061da546Spatrick result.SetError("invalid target") 154061da546Spatrick return 155061da546Spatrick 156061da546Spatrick if len(args) == 0: 157061da546Spatrick result.SetError("one or more executable paths must be specified") 158061da546Spatrick return 159061da546Spatrick 160061da546Spatrick for module_path in args: 161061da546Spatrick module = target.module[module_path] 162061da546Spatrick if not module: 163061da546Spatrick result.SetError('no module found that matches "%s".' % (module_path)) 164061da546Spatrick return 165061da546Spatrick num_cus = module.GetNumCompileUnits() 166061da546Spatrick print('Module: "%s"' % (module.file.fullpath), end=' ', file=result) 167061da546Spatrick if num_cus == 0: 168061da546Spatrick print('no debug info.', file=result) 169061da546Spatrick continue 170061da546Spatrick print('has %u compile units:' % (num_cus), file=result) 171061da546Spatrick for i in range(num_cus): 172061da546Spatrick cu = module.GetCompileUnitAtIndex(i) 173061da546Spatrick print(' Compile Unit: %s' % (cu.file.fullpath), file=result) 174061da546Spatrick if options.support_files: 175061da546Spatrick num_support_files = cu.GetNumSupportFiles() 176061da546Spatrick for j in range(num_support_files): 177061da546Spatrick path = cu.GetSupportFileAtIndex(j).fullpath 178061da546Spatrick print(' file[%u]: %s' % (j, path), file=result) 179061da546Spatrick 180061da546Spatrick 181061da546Spatrickdef __lldb_init_module(debugger, dict): 182061da546Spatrick # This initializer is being run from LLDB in the embedded command interpreter 183061da546Spatrick 184061da546Spatrick # Add any commands contained in this module to LLDB 185061da546Spatrick debugger.HandleCommand( 186*f6aab3d8Srobert 'command script add -o -c %s.DumpLineTables %s' % (__name__, 187061da546Spatrick DumpLineTables.command_name)) 188061da546Spatrick debugger.HandleCommand( 189*f6aab3d8Srobert 'command script add -o -c %s.DumpFiles %s' % (__name__, DumpFiles.command_name)) 190061da546Spatrick print('The "%s" and "%s" commands have been installed.' % (DumpLineTables.command_name, 191061da546Spatrick DumpFiles.command_name)) 192