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