--- /dev/null
+import lldb, re
+
+def parse_linespec (linespec, frame, result):
+ """Handles a subset of GDB-style linespecs. Specifically:
+
+ number - A line in the current file
+ +offset - The line /offset/ lines after this line
+ -offset - The line /offset/ lines before this line
+ filename:number - Line /number/ in file /filename/
+ function - The start of /function/
+ *address - The pointer target of /address/, which must be a literal (but see `` in LLDB)
+
+ We explicitly do not handle filename:function because it is ambiguous in Objective-C.
+
+ This function returns a list of addresses."""
+
+ breakpoint = None
+ target = frame.GetThread().GetProcess().GetTarget()
+
+ matched = False
+
+ if (not matched):
+ mo = re.match("^([0-9]+)$", linespec)
+ if (mo != None):
+ matched = True
+ #print "Matched <linenum>"
+ line_number = int(mo.group(1))
+ line_entry = frame.GetLineEntry()
+ if not line_entry.IsValid():
+ result.AppendMessage("Specified a line in the current file, but the current frame doesn't have line table information.")
+ return
+ breakpoint = target.BreakpointCreateByLocation (line_entry.GetFileSpec(), line_number)
+
+ if (not matched):
+ mo = re.match("^\+([0-9]+)$", linespec)
+ if (mo != None):
+ matched = True
+ #print "Matched +<count>"
+ line_number = int(mo.group(1))
+ line_entry = frame.GetLineEntry()
+ if not line_entry.IsValid():
+ result.AppendMessage("Specified a line in the current file, but the current frame doesn't have line table information.")
+ return
+ breakpoint = target.BreakpointCreateByLocation(line_entry.GetFileSpec(), (line_entry.GetLine() + line_number))
+
+ if (not matched):
+ mo = re.match("^\-([0-9]+)$", linespec)
+ if (mo != None):
+ matched = True
+ #print "Matched -<count>"
+ line_number = int(mo.group(1))
+ line_entry = frame.GetLineEntry()
+ if not line_entry.IsValid():
+ result.AppendMessage("Specified a line in the current file, but the current frame doesn't have line table information.")
+ return
+ breakpoint = target.BreakpointCreateByLocation(line_entry.GetFileSpec(), (line_entry.GetLine() - line_number))
+
+ if (not matched):
+ mo = re.match("^(.*):([0-9]+)$", linespec)
+ if (mo != None):
+ matched = True
+ #print "Matched <filename>:<linenum>"
+ file_name = mo.group(1)
+ line_number = int(mo.group(2))
+ breakpoint = target.BreakpointCreateByLocation(file_name, line_number)
+
+ if (not matched):
+ mo = re.match("\*((0x)?([0-9a-f]+))$", linespec)
+ if (mo != None):
+ matched = True
+ #print "Matched <address-expression>"
+ address = long(mo.group(1), base=0)
+ breakpoint = target.BreakpointCreateByAddress(address)
+
+ if (not matched):
+ #print "Trying <function-name>"
+ breakpoint = target.BreakpointCreateByName(linespec)
+
+ num_locations = breakpoint.GetNumLocations()
+
+ if (num_locations == 0):
+ result.AppendMessage("The line specification provided doesn't resolve to any addresses.")
+
+ addr_list = []
+
+ for location_index in range(num_locations):
+ location = breakpoint.GetLocationAtIndex(location_index)
+ addr_list.append(location.GetAddress())
+
+ target.BreakpointDelete(breakpoint.GetID())
+
+ return addr_list
+
+def usage_string():
+ return """ Sets the program counter to a specific address.
+
+Syntax: jump <linespec> [<location-id>]
+
+Command Options Usage:
+ jump <linenum>
+ jump +<count>
+ jump -<count>
+ jump <filename>:<linenum>
+ jump <function-name>
+ jump *<address-expression>
+
+<location-id> serves to disambiguate when multiple locations could be meant."""
+
+def jump (debugger, command, result, internal_dict):
+ if (command == ""):
+ result.AppendMessage(usage_string())
+
+ args = command.split()
+
+ if not debugger.IsValid():
+ result.AppendMessage("Invalid debugger!")
+ return
+
+ target = debugger.GetSelectedTarget()
+ if not target.IsValid():
+ result.AppendMessage("jump requires a valid target.")
+ return
+
+ process = target.GetProcess()
+ if not process.IsValid():
+ result.AppendMessage("jump requires a valid process.")
+ return
+
+ thread = process.GetSelectedThread()
+ if not thread.IsValid():
+ result.AppendMessage("jump requires a valid thread.")
+ return
+
+ frame = thread.GetSelectedFrame()
+ if not frame.IsValid():
+ result.AppendMessage("jump requires a valid frame.")
+ return
+
+ addresses = parse_linespec(args[0], frame, result)
+
+ stream = lldb.SBStream()
+
+ if len(addresses) == 0:
+ return
+
+ desired_address = addresses[0]
+
+ if len(addresses) > 1:
+ if len(args) == 2:
+ desired_index = int(args[1])
+ if (desired_index >= 0) and (desired_index < len(addresses)):
+ desired_address = addresses[desired_index]
+ else:
+ result.AppendMessage("Desired index " + args[1] + " is not one of the options.")
+ return
+ else:
+ index = 0
+ result.AppendMessage("The specified location resolves to multiple targets.");
+ for address in addresses:
+ stream.Clear()
+ address.GetDescription(stream)
+ result.AppendMessage(" Location ID " + str(index) + ": " + stream.GetData())
+ index = index + 1
+ result.AppendMessage("Please type 'jump " + command + " <location-id>' to choose one.")
+ return
+
+ frame.SetPC(desired_address.GetLoadAddress(target))
+
+if lldb.debugger:
+ # Module is being run inside the LLDB interpreter
+ jump.__doc__ = usage_string()
+ lldb.debugger.HandleCommand('command script add -f jump.jump jump')
+ print 'The "jump" command has been installed, type "help jump" or "jump <ENTER>" for detailed help.'