xref: /openbsd-src/gnu/llvm/lldb/examples/python/lldb_module_utils.py (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1#!/usr/bin/env python
2
3import lldb
4import optparse
5import shlex
6import string
7import sys
8
9
10class DumpLineTables:
11    command_name = "dump-line-tables"
12    short_description = "Dumps full paths to compile unit files and optionally all line table files."
13    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.'
14    usage = "usage: %prog [options] MODULE1 [MODULE2 ...]"
15    def create_options(self):
16        self.parser = optparse.OptionParser(
17            description=self.description,
18            prog=self.command_name,
19            usage=self.usage)
20
21        self.parser.add_option(
22            '-v',
23            '--verbose',
24            action='store_true',
25            dest='verbose',
26            help='Display verbose output.',
27            default=False)
28
29    def get_short_help(self):
30        return self.short_description
31
32    def get_long_help(self):
33        return self.help_string
34
35    def __init__(self, debugger, unused):
36        self.create_options()
37        self.help_string = self.parser.format_help()
38
39    def __call__(self, debugger, command, exe_ctx, result):
40        # Use the Shell Lexer to properly parse up command options just like a
41        # shell would
42        command_args = shlex.split(command)
43
44        try:
45            (options, args) = self.parser.parse_args(command_args)
46        except:
47            # if you don't handle exceptions, passing an incorrect argument to the OptionParser will cause LLDB to exit
48            # (courtesy of OptParse dealing with argument errors by throwing SystemExit)
49            result.SetError("option parsing failed")
50            return
51
52        # Always get program state from the SBExecutionContext passed in as exe_ctx
53        target = exe_ctx.GetTarget()
54        if not target.IsValid():
55            result.SetError("invalid target")
56            return
57
58        for module_path in args:
59            module = target.module[module_path]
60            if not module:
61                result.SetError('no module found that matches "%s".' % (module_path))
62                return
63            num_cus = module.GetNumCompileUnits()
64            print('Module: "%s"' % (module.file.fullpath), end=' ', file=result)
65            if num_cus == 0:
66                print('no debug info.', file=result)
67                continue
68            print('has %u compile units:' % (num_cus), file=result)
69            for cu_idx in range(num_cus):
70                cu = module.GetCompileUnitAtIndex(cu_idx)
71                print('  Compile Unit: %s' % (cu.file.fullpath), file=result)
72                for line_idx in range(cu.GetNumLineEntries()):
73                    line_entry = cu.GetLineEntryAtIndex(line_idx)
74                    start_file_addr = line_entry.addr.file_addr
75                    end_file_addr = line_entry.end_addr.file_addr
76                    # If the two addresses are equal, this line table entry
77                    # is a termination entry
78                    if options.verbose:
79                        if start_file_addr != end_file_addr:
80                            result.PutCString(
81                                '    [%#x - %#x): %s' %
82                                (start_file_addr, end_file_addr, line_entry))
83                    else:
84                        if start_file_addr == end_file_addr:
85                            result.PutCString('    %#x: END' %
86                                              (start_file_addr))
87                        else:
88                            result.PutCString(
89                                '    %#x: %s' %
90                                (start_file_addr, line_entry))
91                    if start_file_addr == end_file_addr:
92                        result.PutCString("\n")
93
94
95class DumpFiles:
96    command_name = "dump-files"
97    short_description = "Dumps full paths to compile unit files and optionally all line table files."
98    usage = "usage: %prog [options] MODULE1 [MODULE2 ...]"
99    description = '''This class adds a dump-files command to the LLDB interpreter.
100
101This command will dump all compile unit file paths found for each source file
102for the binaries specified as arguments in the current target. Specify the
103--support-files or -s option to see all file paths that a compile unit uses in
104its lines tables. This is handy for troubleshooting why breakpoints aren't
105working in IDEs that specify full paths to source files when setting file and
106line breakpoints. Sometimes symlinks cause the debug info to contain the symlink
107path and an IDE will resolve the path to the actual file and use the resolved
108path when setting breakpoints.
109'''
110    def create_options(self):
111        # Pass add_help_option = False, since this keeps the command in line with lldb commands,
112        # and we wire up "help command" to work by providing the long & short help methods below.
113        self.parser = optparse.OptionParser(
114            description = self.description,
115            prog = self.command_name,
116            usage = self.usage,
117            add_help_option = False)
118
119        self.parser.add_option(
120            '-s',
121            '--support-files',
122            action = 'store_true',
123            dest = 'support_files',
124            help = 'Dumps full paths to all files used in a compile unit.',
125            default = False)
126
127    def get_short_help(self):
128        return self.short_description
129
130    def get_long_help(self):
131        return self.help_string
132
133    def __init__(self, debugger, unused):
134        self.create_options()
135        self.help_string = self.parser.format_help()
136
137    def __call__(self, debugger, command, exe_ctx, result):
138        # Use the Shell Lexer to properly parse up command options just like a
139        # shell would
140        command_args = shlex.split(command)
141
142        try:
143            (options, args) = self.parser.parse_args(command_args)
144        except:
145            # if you don't handle exceptions, passing an incorrect argument to the OptionParser will cause LLDB to exit
146            # (courtesy of OptParse dealing with argument errors by throwing SystemExit)
147            result.SetError("option parsing failed")
148            return
149
150        # Always get program state from the SBExecutionContext passed in as exe_ctx
151        target = exe_ctx.GetTarget()
152        if not target.IsValid():
153            result.SetError("invalid target")
154            return
155
156        if len(args) == 0:
157            result.SetError("one or more executable paths must be specified")
158            return
159
160        for module_path in args:
161            module = target.module[module_path]
162            if not module:
163                result.SetError('no module found that matches "%s".' % (module_path))
164                return
165            num_cus = module.GetNumCompileUnits()
166            print('Module: "%s"' % (module.file.fullpath), end=' ', file=result)
167            if num_cus == 0:
168                print('no debug info.', file=result)
169                continue
170            print('has %u compile units:' % (num_cus), file=result)
171            for i in range(num_cus):
172                cu = module.GetCompileUnitAtIndex(i)
173                print('  Compile Unit: %s' % (cu.file.fullpath), file=result)
174                if options.support_files:
175                    num_support_files = cu.GetNumSupportFiles()
176                    for j in range(num_support_files):
177                        path = cu.GetSupportFileAtIndex(j).fullpath
178                        print('    file[%u]: %s' % (j, path), file=result)
179
180
181def __lldb_init_module(debugger, dict):
182    # This initializer is being run from LLDB in the embedded command interpreter
183
184    # Add any commands contained in this module to LLDB
185    debugger.HandleCommand(
186        'command script add -o -c %s.DumpLineTables %s' % (__name__,
187                                                        DumpLineTables.command_name))
188    debugger.HandleCommand(
189        'command script add -o -c %s.DumpFiles %s' % (__name__, DumpFiles.command_name))
190    print('The "%s" and "%s" commands have been installed.' % (DumpLineTables.command_name,
191                                                               DumpFiles.command_name))
192