from __future__ import print_function import lldb import 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 is not None): matched = True # print "Matched " 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 is not None): matched = True # print "Matched +" 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 is not None): matched = True # print "Matched -" 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 is not None): matched = True # print "Matched :" 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 is not None): matched = True # print "Matched " address = int(mo.group(1), base=0) breakpoint = target.BreakpointCreateByAddress(address) if (not matched): # print "Trying " 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 [] Command Options Usage: jump jump + jump - jump : jump jump * 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 + " ' 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 " for detailed help.')