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