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 return 35 breakpoint = target.BreakpointCreateByLocation( 36 line_entry.GetFileSpec(), line_number) 37 38 if (not matched): 39 mo = re.match("^\+([0-9]+)$", linespec) 40 if (mo is not None): 41 matched = True 42 # print "Matched +<count>" 43 line_number = int(mo.group(1)) 44 line_entry = frame.GetLineEntry() 45 if not line_entry.IsValid(): 46 result.AppendMessage( 47 "Specified a line in the current file, but the current frame doesn't have line table information.") 48 return 49 breakpoint = target.BreakpointCreateByLocation( 50 line_entry.GetFileSpec(), (line_entry.GetLine() + line_number)) 51 52 if (not matched): 53 mo = re.match("^\-([0-9]+)$", linespec) 54 if (mo is not None): 55 matched = True 56 # print "Matched -<count>" 57 line_number = int(mo.group(1)) 58 line_entry = frame.GetLineEntry() 59 if not line_entry.IsValid(): 60 result.AppendMessage( 61 "Specified a line in the current file, but the current frame doesn't have line table information.") 62 return 63 breakpoint = target.BreakpointCreateByLocation( 64 line_entry.GetFileSpec(), (line_entry.GetLine() - line_number)) 65 66 if (not matched): 67 mo = re.match("^(.*):([0-9]+)$", linespec) 68 if (mo is not None): 69 matched = True 70 # print "Matched <filename>:<linenum>" 71 file_name = mo.group(1) 72 line_number = int(mo.group(2)) 73 breakpoint = target.BreakpointCreateByLocation( 74 file_name, line_number) 75 76 if (not matched): 77 mo = re.match("\*((0x)?([0-9a-f]+))$", linespec) 78 if (mo is not None): 79 matched = True 80 # print "Matched <address-expression>" 81 address = int(mo.group(1), base=0) 82 breakpoint = target.BreakpointCreateByAddress(address) 83 84 if (not matched): 85 # print "Trying <function-name>" 86 breakpoint = target.BreakpointCreateByName(linespec) 87 88 num_locations = breakpoint.GetNumLocations() 89 90 if (num_locations == 0): 91 result.AppendMessage( 92 "The line specification provided doesn't resolve to any addresses.") 93 94 addr_list = [] 95 96 for location_index in range(num_locations): 97 location = breakpoint.GetLocationAtIndex(location_index) 98 addr_list.append(location.GetAddress()) 99 100 target.BreakpointDelete(breakpoint.GetID()) 101 102 return addr_list 103 104 105def usage_string(): 106 return """ Sets the program counter to a specific address. 107 108Syntax: jump <linespec> [<location-id>] 109 110Command Options Usage: 111 jump <linenum> 112 jump +<count> 113 jump -<count> 114 jump <filename>:<linenum> 115 jump <function-name> 116 jump *<address-expression> 117 118<location-id> serves to disambiguate when multiple locations could be meant.""" 119 120 121def jump(debugger, command, result, internal_dict): 122 if (command == ""): 123 result.AppendMessage(usage_string()) 124 125 args = command.split() 126 127 if not debugger.IsValid(): 128 result.AppendMessage("Invalid debugger!") 129 return 130 131 target = debugger.GetSelectedTarget() 132 if not target.IsValid(): 133 result.AppendMessage("jump requires a valid target.") 134 return 135 136 process = target.GetProcess() 137 if not process.IsValid(): 138 result.AppendMessage("jump requires a valid process.") 139 return 140 141 thread = process.GetSelectedThread() 142 if not thread.IsValid(): 143 result.AppendMessage("jump requires a valid thread.") 144 return 145 146 frame = thread.GetSelectedFrame() 147 if not frame.IsValid(): 148 result.AppendMessage("jump requires a valid frame.") 149 return 150 151 addresses = parse_linespec(args[0], frame, result) 152 153 stream = lldb.SBStream() 154 155 if len(addresses) == 0: 156 return 157 158 desired_address = addresses[0] 159 160 if len(addresses) > 1: 161 if len(args) == 2: 162 desired_index = int(args[1]) 163 if (desired_index >= 0) and (desired_index < len(addresses)): 164 desired_address = addresses[desired_index] 165 else: 166 result.AppendMessage( 167 "Desired index " + 168 args[1] + 169 " is not one of the options.") 170 return 171 else: 172 index = 0 173 result.AppendMessage( 174 "The specified location resolves to multiple targets.") 175 for address in addresses: 176 stream.Clear() 177 address.GetDescription(stream) 178 result.AppendMessage( 179 " Location ID " + 180 str(index) + 181 ": " + 182 stream.GetData()) 183 index = index + 1 184 result.AppendMessage( 185 "Please type 'jump " + 186 command + 187 " <location-id>' to choose one.") 188 return 189 190 frame.SetPC(desired_address.GetLoadAddress(target)) 191 192def __lldb_init_module(debugger, internal_dict): 193 # Module is being run inside the LLDB interpreter 194 jump.__doc__ = usage_string() 195 debugger.HandleCommand('command script add -o -f jump.jump jump') 196 print('The "jump" command has been installed, type "help jump" or "jump <ENTER>" for detailed help.') 197