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