Home | History | Annotate | Download | only in python
      1 import lldb, re
      2 
      3 def parse_linespec (linespec, frame, result):
      4     """Handles a subset of GDB-style linespecs.  Specifically:
      5        
      6        number           - A line in the current file
      7        +offset          - The line /offset/ lines after this line
      8        -offset          - The line /offset/ lines before this line
      9        filename:number  - Line /number/ in file /filename/
     10        function         - The start of /function/
     11        *address         - The pointer target of /address/, which must be a literal (but see `` in LLDB)
     12 
     13        We explicitly do not handle filename:function because it is ambiguous in Objective-C.
     14 
     15        This function returns a list of addresses."""
     16 
     17     breakpoint = None
     18     target = frame.GetThread().GetProcess().GetTarget()
     19 
     20     matched = False
     21 
     22     if (not matched):
     23         mo = re.match("^([0-9]+)$", linespec)
     24         if (mo != None):
     25             matched = True
     26             #print "Matched <linenum>"
     27             line_number = int(mo.group(1))
     28             line_entry = frame.GetLineEntry()
     29             if not line_entry.IsValid():
     30                 result.AppendMessage("Specified a line in the current file, but the current frame doesn't have line table information.")
     31                 return
     32             breakpoint = target.BreakpointCreateByLocation (line_entry.GetFileSpec(), line_number)
     33 
     34     if (not matched):
     35         mo = re.match("^\+([0-9]+)$", linespec)
     36         if (mo != None):
     37             matched = True
     38             #print "Matched +<count>"
     39             line_number = int(mo.group(1))
     40             line_entry = frame.GetLineEntry()
     41             if not line_entry.IsValid():
     42                 result.AppendMessage("Specified a line in the current file, but the current frame doesn't have line table information.")
     43                 return
     44             breakpoint = target.BreakpointCreateByLocation(line_entry.GetFileSpec(), (line_entry.GetLine() + line_number))
     45      
     46     if (not matched):
     47         mo = re.match("^\-([0-9]+)$", linespec)
     48         if (mo != None):
     49             matched = True
     50             #print "Matched -<count>"
     51             line_number = int(mo.group(1))
     52             line_entry = frame.GetLineEntry()
     53             if not line_entry.IsValid():
     54                 result.AppendMessage("Specified a line in the current file, but the current frame doesn't have line table information.")
     55                 return
     56             breakpoint = target.BreakpointCreateByLocation(line_entry.GetFileSpec(), (line_entry.GetLine() - line_number))
     57 
     58     if (not matched):
     59         mo = re.match("^(.*):([0-9]+)$", linespec)
     60         if (mo != None):
     61             matched = True
     62             #print "Matched <filename>:<linenum>"
     63             file_name = mo.group(1)
     64             line_number = int(mo.group(2))
     65             breakpoint = target.BreakpointCreateByLocation(file_name, line_number)
     66 
     67     if (not matched):
     68         mo = re.match("\*((0x)?([0-9a-f]+))$", linespec)
     69         if (mo != None):
     70             matched = True
     71             #print "Matched <address-expression>"
     72             address = long(mo.group(1), base=0)
     73             breakpoint = target.BreakpointCreateByAddress(address)
     74 
     75     if (not matched):
     76         #print "Trying <function-name>"
     77         breakpoint = target.BreakpointCreateByName(linespec)
     78 
     79     num_locations = breakpoint.GetNumLocations()
     80 
     81     if (num_locations == 0):
     82         result.AppendMessage("The line specification provided doesn't resolve to any addresses.")
     83 
     84     addr_list = []
     85 
     86     for location_index in range(num_locations):
     87         location = breakpoint.GetLocationAtIndex(location_index)
     88         addr_list.append(location.GetAddress())
     89 
     90     target.BreakpointDelete(breakpoint.GetID())
     91 
     92     return addr_list
     93 
     94 def usage_string():
     95     return """   Sets the program counter to a specific address.
     96 
     97 Syntax: jump <linespec> [<location-id>]
     98 
     99 Command Options Usage:
    100   jump <linenum>
    101   jump +<count>
    102   jump -<count>
    103   jump <filename>:<linenum>
    104   jump <function-name>
    105   jump *<address-expression>
    106 
    107 <location-id> serves to disambiguate when multiple locations could be meant."""
    108 
    109 def jump (debugger, command, result, internal_dict):
    110     if (command == ""):
    111         result.AppendMessage(usage_string())
    112 
    113     args = command.split()
    114 
    115     if not debugger.IsValid():
    116         result.AppendMessage("Invalid debugger!")
    117         return
    118 
    119     target = debugger.GetSelectedTarget()
    120     if not target.IsValid():
    121         result.AppendMessage("jump requires a valid target.")
    122         return
    123 
    124     process = target.GetProcess()
    125     if not process.IsValid():
    126         result.AppendMessage("jump requires a valid process.")
    127         return
    128 
    129     thread = process.GetSelectedThread()
    130     if not thread.IsValid():
    131         result.AppendMessage("jump requires a valid thread.")
    132         return
    133 
    134     frame = thread.GetSelectedFrame()
    135     if not frame.IsValid():
    136         result.AppendMessage("jump requires a valid frame.")
    137         return
    138 
    139     addresses = parse_linespec(args[0], frame, result)
    140 
    141     stream = lldb.SBStream()
    142 
    143     if len(addresses) == 0:
    144         return
    145 
    146     desired_address = addresses[0]
    147 
    148     if len(addresses) > 1:
    149         if len(args) == 2:
    150             desired_index = int(args[1])
    151             if (desired_index >= 0) and (desired_index < len(addresses)):
    152                 desired_address = addresses[desired_index]
    153             else:
    154                 result.AppendMessage("Desired index " + args[1] + " is not one of the options.")
    155                 return
    156         else:
    157             index = 0
    158             result.AppendMessage("The specified location resolves to multiple targets.");
    159             for address in addresses:
    160                 stream.Clear()
    161                 address.GetDescription(stream)
    162                 result.AppendMessage("  Location ID " + str(index) + ": " + stream.GetData())
    163                 index = index + 1
    164             result.AppendMessage("Please type 'jump " + command + " <location-id>' to choose one.")
    165             return
    166 
    167     frame.SetPC(desired_address.GetLoadAddress(target))
    168 
    169 if lldb.debugger:
    170     # Module is being run inside the LLDB interpreter
    171     jump.__doc__ = usage_string()
    172     lldb.debugger.HandleCommand('command script add -f jump.jump jump')
    173     print 'The "jump" command has been installed, type "help jump" or "jump <ENTER>" for detailed help.'
    174