1import lldb 2import re 3 4 5def parse_linespec(linespec, frame, result): 6 """Handles a subset of GDB-style linespecs. Specifically: 7 8 number - A line in the current file 9 +offset - The line /offset/ lines after this line 10 -offset - The line /offset/ lines before this line 11 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 = None 20 target = frame.GetThread().GetProcess().GetTarget() 21 22 matched = False 23 24 if not matched: 25 mo = re.match("^([0-9]+)$", linespec) 26 if mo is not None: 27 matched = True 28 # 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 return 36 breakpoint = target.BreakpointCreateByLocation( 37 line_entry.GetFileSpec(), line_number 38 ) 39 40 if not matched: 41 mo = re.match("^\+([0-9]+)$", linespec) 42 if mo is not None: 43 matched = True 44 # 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 return 52 breakpoint = target.BreakpointCreateByLocation( 53 line_entry.GetFileSpec(), (line_entry.GetLine() + line_number) 54 ) 55 56 if not matched: 57 mo = re.match("^\-([0-9]+)$", linespec) 58 if mo is not None: 59 matched = True 60 # 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 return 68 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 = True 76 # 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("\*((0x)?([0-9a-f]+))$", linespec) 83 if mo is not None: 84 matched = True 85 # 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_list 109 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 return 136 137 target = debugger.GetSelectedTarget() 138 if not target.IsValid(): 139 result.AppendMessage("jump requires a valid target.") 140 return 141 142 process = target.GetProcess() 143 if not process.IsValid(): 144 result.AppendMessage("jump requires a valid process.") 145 return 146 147 thread = process.GetSelectedThread() 148 if not thread.IsValid(): 149 result.AppendMessage("jump requires a valid thread.") 150 return 151 152 frame = thread.GetSelectedFrame() 153 if not frame.IsValid(): 154 result.AppendMessage("jump requires a valid frame.") 155 return 156 157 addresses = parse_linespec(args[0], frame, result) 158 159 stream = lldb.SBStream() 160 161 if len(addresses) == 0: 162 return 163 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 return 176 else: 177 index = 0 178 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 + 1 186 result.AppendMessage( 187 "Please type 'jump " + command + " <location-id>' to choose one." 188 ) 189 return 190 191 frame.SetPC(desired_address.GetLoadAddress(target)) 192 193 194def __lldb_init_module(debugger, internal_dict): 195 # Module is being run inside the LLDB interpreter 196 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