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