xref: /openbsd/gnu/llvm/lldb/examples/python/jump.py (revision 3bef86f7)
1import lldb
2import re
3
4
5def parse_linespec(linespec, frame, result):
6    """Handles a subset of GDB-style linespecs.  Specifically:
7
8       number           - A line in the current file
9       +offset          - The line /offset/ lines after this line
10       -offset          - The line /offset/ lines before this line
11       filename:number  - Line /number/ in file /filename/
12       function         - The start of /function/
13       *address         - The pointer target of /address/, which must be a literal (but see `` in LLDB)
14
15       We explicitly do not handle filename:function because it is ambiguous in Objective-C.
16
17       This function returns a list of addresses."""
18
19    breakpoint = None
20    target = frame.GetThread().GetProcess().GetTarget()
21
22    matched = False
23
24    if (not matched):
25        mo = re.match("^([0-9]+)$", linespec)
26        if (mo is not None):
27            matched = True
28            # print "Matched <linenum>"
29            line_number = int(mo.group(1))
30            line_entry = frame.GetLineEntry()
31            if not line_entry.IsValid():
32                result.AppendMessage(
33                    "Specified a line in the current file, but the current frame doesn't have line table information.")
34                return
35            breakpoint = target.BreakpointCreateByLocation(
36                line_entry.GetFileSpec(), line_number)
37
38    if (not matched):
39        mo = re.match("^\+([0-9]+)$", linespec)
40        if (mo is not None):
41            matched = True
42            # print "Matched +<count>"
43            line_number = int(mo.group(1))
44            line_entry = frame.GetLineEntry()
45            if not line_entry.IsValid():
46                result.AppendMessage(
47                    "Specified a line in the current file, but the current frame doesn't have line table information.")
48                return
49            breakpoint = target.BreakpointCreateByLocation(
50                line_entry.GetFileSpec(), (line_entry.GetLine() + line_number))
51
52    if (not matched):
53        mo = re.match("^\-([0-9]+)$", linespec)
54        if (mo is not None):
55            matched = True
56            # print "Matched -<count>"
57            line_number = int(mo.group(1))
58            line_entry = frame.GetLineEntry()
59            if not line_entry.IsValid():
60                result.AppendMessage(
61                    "Specified a line in the current file, but the current frame doesn't have line table information.")
62                return
63            breakpoint = target.BreakpointCreateByLocation(
64                line_entry.GetFileSpec(), (line_entry.GetLine() - line_number))
65
66    if (not matched):
67        mo = re.match("^(.*):([0-9]+)$", linespec)
68        if (mo is not None):
69            matched = True
70            # print "Matched <filename>:<linenum>"
71            file_name = mo.group(1)
72            line_number = int(mo.group(2))
73            breakpoint = target.BreakpointCreateByLocation(
74                file_name, line_number)
75
76    if (not matched):
77        mo = re.match("\*((0x)?([0-9a-f]+))$", linespec)
78        if (mo is not None):
79            matched = True
80            # print "Matched <address-expression>"
81            address = int(mo.group(1), base=0)
82            breakpoint = target.BreakpointCreateByAddress(address)
83
84    if (not matched):
85        # print "Trying <function-name>"
86        breakpoint = target.BreakpointCreateByName(linespec)
87
88    num_locations = breakpoint.GetNumLocations()
89
90    if (num_locations == 0):
91        result.AppendMessage(
92            "The line specification provided doesn't resolve to any addresses.")
93
94    addr_list = []
95
96    for location_index in range(num_locations):
97        location = breakpoint.GetLocationAtIndex(location_index)
98        addr_list.append(location.GetAddress())
99
100    target.BreakpointDelete(breakpoint.GetID())
101
102    return addr_list
103
104
105def usage_string():
106    return """   Sets the program counter to a specific address.
107
108Syntax: jump <linespec> [<location-id>]
109
110Command Options Usage:
111  jump <linenum>
112  jump +<count>
113  jump -<count>
114  jump <filename>:<linenum>
115  jump <function-name>
116  jump *<address-expression>
117
118<location-id> serves to disambiguate when multiple locations could be meant."""
119
120
121def jump(debugger, command, result, internal_dict):
122    if (command == ""):
123        result.AppendMessage(usage_string())
124
125    args = command.split()
126
127    if not debugger.IsValid():
128        result.AppendMessage("Invalid debugger!")
129        return
130
131    target = debugger.GetSelectedTarget()
132    if not target.IsValid():
133        result.AppendMessage("jump requires a valid target.")
134        return
135
136    process = target.GetProcess()
137    if not process.IsValid():
138        result.AppendMessage("jump requires a valid process.")
139        return
140
141    thread = process.GetSelectedThread()
142    if not thread.IsValid():
143        result.AppendMessage("jump requires a valid thread.")
144        return
145
146    frame = thread.GetSelectedFrame()
147    if not frame.IsValid():
148        result.AppendMessage("jump requires a valid frame.")
149        return
150
151    addresses = parse_linespec(args[0], frame, result)
152
153    stream = lldb.SBStream()
154
155    if len(addresses) == 0:
156        return
157
158    desired_address = addresses[0]
159
160    if len(addresses) > 1:
161        if len(args) == 2:
162            desired_index = int(args[1])
163            if (desired_index >= 0) and (desired_index < len(addresses)):
164                desired_address = addresses[desired_index]
165            else:
166                result.AppendMessage(
167                    "Desired index " +
168                    args[1] +
169                    " is not one of the options.")
170                return
171        else:
172            index = 0
173            result.AppendMessage(
174                "The specified location resolves to multiple targets.")
175            for address in addresses:
176                stream.Clear()
177                address.GetDescription(stream)
178                result.AppendMessage(
179                    "  Location ID " +
180                    str(index) +
181                    ": " +
182                    stream.GetData())
183                index = index + 1
184            result.AppendMessage(
185                "Please type 'jump " +
186                command +
187                " <location-id>' to choose one.")
188            return
189
190    frame.SetPC(desired_address.GetLoadAddress(target))
191
192def __lldb_init_module(debugger, internal_dict):
193    # Module is being run inside the LLDB interpreter
194    jump.__doc__ = usage_string()
195    debugger.HandleCommand('command script add -o -f jump.jump jump')
196    print('The "jump" command has been installed, type "help jump" or "jump <ENTER>" for detailed help.')
197