xref: /openbsd-src/gnu/llvm/lldb/examples/python/jump.py (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1061da546Spatrickimport lldb
2061da546Spatrickimport re
3061da546Spatrick
4061da546Spatrick
5061da546Spatrickdef parse_linespec(linespec, frame, result):
6061da546Spatrick    """Handles a subset of GDB-style linespecs.  Specifically:
7061da546Spatrick
8061da546Spatrick       number           - A line in the current file
9061da546Spatrick       +offset          - The line /offset/ lines after this line
10061da546Spatrick       -offset          - The line /offset/ lines before this line
11061da546Spatrick       filename:number  - Line /number/ in file /filename/
12061da546Spatrick       function         - The start of /function/
13061da546Spatrick       *address         - The pointer target of /address/, which must be a literal (but see `` in LLDB)
14061da546Spatrick
15061da546Spatrick       We explicitly do not handle filename:function because it is ambiguous in Objective-C.
16061da546Spatrick
17061da546Spatrick       This function returns a list of addresses."""
18061da546Spatrick
19061da546Spatrick    breakpoint = None
20061da546Spatrick    target = frame.GetThread().GetProcess().GetTarget()
21061da546Spatrick
22061da546Spatrick    matched = False
23061da546Spatrick
24061da546Spatrick    if (not matched):
25061da546Spatrick        mo = re.match("^([0-9]+)$", linespec)
26061da546Spatrick        if (mo is not None):
27061da546Spatrick            matched = True
28061da546Spatrick            # print "Matched <linenum>"
29061da546Spatrick            line_number = int(mo.group(1))
30061da546Spatrick            line_entry = frame.GetLineEntry()
31061da546Spatrick            if not line_entry.IsValid():
32061da546Spatrick                result.AppendMessage(
33061da546Spatrick                    "Specified a line in the current file, but the current frame doesn't have line table information.")
34061da546Spatrick                return
35061da546Spatrick            breakpoint = target.BreakpointCreateByLocation(
36061da546Spatrick                line_entry.GetFileSpec(), line_number)
37061da546Spatrick
38061da546Spatrick    if (not matched):
39061da546Spatrick        mo = re.match("^\+([0-9]+)$", linespec)
40061da546Spatrick        if (mo is not None):
41061da546Spatrick            matched = True
42061da546Spatrick            # print "Matched +<count>"
43061da546Spatrick            line_number = int(mo.group(1))
44061da546Spatrick            line_entry = frame.GetLineEntry()
45061da546Spatrick            if not line_entry.IsValid():
46061da546Spatrick                result.AppendMessage(
47061da546Spatrick                    "Specified a line in the current file, but the current frame doesn't have line table information.")
48061da546Spatrick                return
49061da546Spatrick            breakpoint = target.BreakpointCreateByLocation(
50061da546Spatrick                line_entry.GetFileSpec(), (line_entry.GetLine() + line_number))
51061da546Spatrick
52061da546Spatrick    if (not matched):
53061da546Spatrick        mo = re.match("^\-([0-9]+)$", linespec)
54061da546Spatrick        if (mo is not None):
55061da546Spatrick            matched = True
56061da546Spatrick            # print "Matched -<count>"
57061da546Spatrick            line_number = int(mo.group(1))
58061da546Spatrick            line_entry = frame.GetLineEntry()
59061da546Spatrick            if not line_entry.IsValid():
60061da546Spatrick                result.AppendMessage(
61061da546Spatrick                    "Specified a line in the current file, but the current frame doesn't have line table information.")
62061da546Spatrick                return
63061da546Spatrick            breakpoint = target.BreakpointCreateByLocation(
64061da546Spatrick                line_entry.GetFileSpec(), (line_entry.GetLine() - line_number))
65061da546Spatrick
66061da546Spatrick    if (not matched):
67061da546Spatrick        mo = re.match("^(.*):([0-9]+)$", linespec)
68061da546Spatrick        if (mo is not None):
69061da546Spatrick            matched = True
70061da546Spatrick            # print "Matched <filename>:<linenum>"
71061da546Spatrick            file_name = mo.group(1)
72061da546Spatrick            line_number = int(mo.group(2))
73061da546Spatrick            breakpoint = target.BreakpointCreateByLocation(
74061da546Spatrick                file_name, line_number)
75061da546Spatrick
76061da546Spatrick    if (not matched):
77061da546Spatrick        mo = re.match("\*((0x)?([0-9a-f]+))$", linespec)
78061da546Spatrick        if (mo is not None):
79061da546Spatrick            matched = True
80061da546Spatrick            # print "Matched <address-expression>"
81061da546Spatrick            address = int(mo.group(1), base=0)
82061da546Spatrick            breakpoint = target.BreakpointCreateByAddress(address)
83061da546Spatrick
84061da546Spatrick    if (not matched):
85061da546Spatrick        # print "Trying <function-name>"
86061da546Spatrick        breakpoint = target.BreakpointCreateByName(linespec)
87061da546Spatrick
88061da546Spatrick    num_locations = breakpoint.GetNumLocations()
89061da546Spatrick
90061da546Spatrick    if (num_locations == 0):
91061da546Spatrick        result.AppendMessage(
92061da546Spatrick            "The line specification provided doesn't resolve to any addresses.")
93061da546Spatrick
94061da546Spatrick    addr_list = []
95061da546Spatrick
96061da546Spatrick    for location_index in range(num_locations):
97061da546Spatrick        location = breakpoint.GetLocationAtIndex(location_index)
98061da546Spatrick        addr_list.append(location.GetAddress())
99061da546Spatrick
100061da546Spatrick    target.BreakpointDelete(breakpoint.GetID())
101061da546Spatrick
102061da546Spatrick    return addr_list
103061da546Spatrick
104061da546Spatrick
105061da546Spatrickdef usage_string():
106061da546Spatrick    return """   Sets the program counter to a specific address.
107061da546Spatrick
108061da546SpatrickSyntax: jump <linespec> [<location-id>]
109061da546Spatrick
110061da546SpatrickCommand Options Usage:
111061da546Spatrick  jump <linenum>
112061da546Spatrick  jump +<count>
113061da546Spatrick  jump -<count>
114061da546Spatrick  jump <filename>:<linenum>
115061da546Spatrick  jump <function-name>
116061da546Spatrick  jump *<address-expression>
117061da546Spatrick
118061da546Spatrick<location-id> serves to disambiguate when multiple locations could be meant."""
119061da546Spatrick
120061da546Spatrick
121061da546Spatrickdef jump(debugger, command, result, internal_dict):
122061da546Spatrick    if (command == ""):
123061da546Spatrick        result.AppendMessage(usage_string())
124061da546Spatrick
125061da546Spatrick    args = command.split()
126061da546Spatrick
127061da546Spatrick    if not debugger.IsValid():
128061da546Spatrick        result.AppendMessage("Invalid debugger!")
129061da546Spatrick        return
130061da546Spatrick
131061da546Spatrick    target = debugger.GetSelectedTarget()
132061da546Spatrick    if not target.IsValid():
133061da546Spatrick        result.AppendMessage("jump requires a valid target.")
134061da546Spatrick        return
135061da546Spatrick
136061da546Spatrick    process = target.GetProcess()
137061da546Spatrick    if not process.IsValid():
138061da546Spatrick        result.AppendMessage("jump requires a valid process.")
139061da546Spatrick        return
140061da546Spatrick
141061da546Spatrick    thread = process.GetSelectedThread()
142061da546Spatrick    if not thread.IsValid():
143061da546Spatrick        result.AppendMessage("jump requires a valid thread.")
144061da546Spatrick        return
145061da546Spatrick
146061da546Spatrick    frame = thread.GetSelectedFrame()
147061da546Spatrick    if not frame.IsValid():
148061da546Spatrick        result.AppendMessage("jump requires a valid frame.")
149061da546Spatrick        return
150061da546Spatrick
151061da546Spatrick    addresses = parse_linespec(args[0], frame, result)
152061da546Spatrick
153061da546Spatrick    stream = lldb.SBStream()
154061da546Spatrick
155061da546Spatrick    if len(addresses) == 0:
156061da546Spatrick        return
157061da546Spatrick
158061da546Spatrick    desired_address = addresses[0]
159061da546Spatrick
160061da546Spatrick    if len(addresses) > 1:
161061da546Spatrick        if len(args) == 2:
162061da546Spatrick            desired_index = int(args[1])
163061da546Spatrick            if (desired_index >= 0) and (desired_index < len(addresses)):
164061da546Spatrick                desired_address = addresses[desired_index]
165061da546Spatrick            else:
166061da546Spatrick                result.AppendMessage(
167061da546Spatrick                    "Desired index " +
168061da546Spatrick                    args[1] +
169061da546Spatrick                    " is not one of the options.")
170061da546Spatrick                return
171061da546Spatrick        else:
172061da546Spatrick            index = 0
173061da546Spatrick            result.AppendMessage(
174061da546Spatrick                "The specified location resolves to multiple targets.")
175061da546Spatrick            for address in addresses:
176061da546Spatrick                stream.Clear()
177061da546Spatrick                address.GetDescription(stream)
178061da546Spatrick                result.AppendMessage(
179061da546Spatrick                    "  Location ID " +
180061da546Spatrick                    str(index) +
181061da546Spatrick                    ": " +
182061da546Spatrick                    stream.GetData())
183061da546Spatrick                index = index + 1
184061da546Spatrick            result.AppendMessage(
185061da546Spatrick                "Please type 'jump " +
186061da546Spatrick                command +
187061da546Spatrick                " <location-id>' to choose one.")
188061da546Spatrick            return
189061da546Spatrick
190061da546Spatrick    frame.SetPC(desired_address.GetLoadAddress(target))
191061da546Spatrick
192*f6aab3d8Srobertdef __lldb_init_module(debugger, internal_dict):
193061da546Spatrick    # Module is being run inside the LLDB interpreter
194061da546Spatrick    jump.__doc__ = usage_string()
195*f6aab3d8Srobert    debugger.HandleCommand('command script add -o -f jump.jump jump')
196061da546Spatrick    print('The "jump" command has been installed, type "help jump" or "jump <ENTER>" for detailed help.')
197