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