xref: /openbsd-src/gnu/llvm/lldb/examples/python/lldb_module_utils.py (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
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