]> git.saurik.com Git - apple/xnu.git/blobdiff - tools/lldbmacros/core/cvalue.py
xnu-2422.1.72.tar.gz
[apple/xnu.git] / tools / lldbmacros / core / cvalue.py
diff --git a/tools/lldbmacros/core/cvalue.py b/tools/lldbmacros/core/cvalue.py
new file mode 100644 (file)
index 0000000..07bc25a
--- /dev/null
@@ -0,0 +1,463 @@
+"""
+Defines a class value which encapsulates the basic lldb Scripting Bridge APIs. This provides an easy
+wrapper to extract information from C based constructs. 
+ |------- core.value------------|
+ | |--lldb Scripting Bridge--|  |
+ | |    |--lldb core--|      |  |   
+ | |-------------------------|  |
+ |------------------------------|
+Use the member function GetSBValue() to access the base Scripting Bridge value.
+"""
+import lldb
+import re
+from lazytarget import *
+
+_cstring_rex = re.compile("((?:\s*|const\s+)\s*char(?:\s+\*|\s+[A-Za-z_0-9]*\s*\[|)\s*)",re.MULTILINE|re.DOTALL)
+
+class value(object):
+    '''A class designed to wrap lldb.SBValue() objects so the resulting object
+    can be used as a variable would be in code. So if you have a Point structure
+    variable in your code in the current frame named "pt", you can initialize an instance
+    of this class with it:
+    
+    pt = lldb.value(lldb.frame.FindVariable("pt"))
+    print pt
+    print pt.x
+    print pt.y
+
+    pt = lldb.value(lldb.frame.FindVariable("rectangle_array"))
+    print rectangle_array[12]
+    print rectangle_array[5].origin.x'''
+    def __init__(self, sbvalue):
+        #_sbval19k84obscure747 is specifically chosen to be obscure. 
+        #This avoids conflicts when attributes could mean any field value in code
+        self._sbval19k84obscure747 = sbvalue
+        self._sbval19k84obscure747_type = sbvalue.GetType()
+        self._sbval19k84obscure747_is_ptr = sbvalue.GetType().IsPointerType()
+        self.sbvalue = sbvalue
+
+    def __nonzero__(self):
+        return ( self._sbval19k84obscure747.__nonzero__() and self._GetValueAsUnsigned() != 0 )
+
+    def __repr__(self):
+        return self._sbval19k84obscure747.__str__()
+    
+    def __cmp__(self, other):
+        if type(other) is int:
+            me = int(self)
+            if type(me) is long:
+                other = long(other)
+            return me.__cmp__(other)
+        if type(other) is value:
+            return int(self).__cmp__(int(other))
+        raise TypeError("Cannot compare value with this type")
+    
+    def __str__(self):
+        global _cstring_rex
+        type_name = self._sbval19k84obscure747_type.GetName()
+        if len(_cstring_rex.findall(type_name)) > 0 :
+            return self._GetValueAsString()
+        summary = self._sbval19k84obscure747.GetSummary()
+        if summary:
+            return summary.strip('"')
+        return self._sbval19k84obscure747.__str__()
+
+    def __getitem__(self, key):
+        # Allow array access if this value has children...
+        if type(key) is slice:
+            _start = int(key.start)
+            _end = int(key.stop)
+            _step = 1
+            if key.step != None:
+                _step = int(key.step)
+            retval = []
+            while _start < _end:
+                retval.append(self[_start])
+                _start += _step
+            return retval
+        if type(key) in (int, long):
+            return value(self._sbval19k84obscure747.GetValueForExpressionPath("[%i]" % key))
+        if type(key) is value:
+            return value(self._sbval19k84obscure747.GetValueForExpressionPath("[%i]" % int(key)))
+        raise TypeError("Cannot fetch Array item for this type")
+
+    def __getattr__(self, name):
+        child_sbvalue = self._sbval19k84obscure747.GetChildMemberWithName (name)
+        if child_sbvalue:
+            return value(child_sbvalue)
+        raise AttributeError("No field by name: "+name )
+
+    def __add__(self, other):
+        return int(self) + int(other)
+    
+    def __radd__(self, other):
+        return int(self) + int(other)
+        
+    def __sub__(self, other):
+        return int(self) - int(other)
+    
+    def __rsub__(self, other):
+        return int(other) - int(self)
+        
+    def __mul__(self, other):
+        return int(self) * int(other)
+    
+    def __rmul__(self, other):
+        return int(self) * int(other)
+    
+    def __floordiv__(self, other):
+        return int(self) // int(other)
+        
+    def __mod__(self, other):
+        return int(self) % int(other)
+    
+    def __rmod__(self, other):
+        return int(other) % int(self)
+        
+    def __divmod__(self, other):
+        return int(self) % int(other)
+    
+    def __rdivmod__(self, other):
+        return int(other) % int(self)
+        
+    def __pow__(self, other):
+        return int(self) ** int(other)
+        
+    def __lshift__(self, other):
+        return int(self) << int(other)
+        
+    def __rshift__(self, other):
+        return int(self) >> int(other)
+        
+    def __and__(self, other):
+        return int(self) & int(other)
+    
+    def __rand(self, other):
+        return int(self) & int(other)
+        
+    def __xor__(self, other):
+        return int(self) ^ int(other)
+        
+    def __or__(self, other):
+        return int(self) | int(other)
+        
+    def __div__(self, other):
+        return int(self) / int(other)
+    
+    def __rdiv__(self, other):
+        return int(other)/int(self)
+        
+    def __truediv__(self, other):
+        return int(self) / int(other)
+        
+    def __iadd__(self, other):
+        result = self.__add__(other)
+        self._sbval19k84obscure747.SetValueFromCString (str(result))
+        return result
+        
+    def __isub__(self, other):
+        result = self.__sub__(other)
+        self._sbval19k84obscure747.SetValueFromCString (str(result))
+        return result
+        
+    def __imul__(self, other):
+        result = self.__mul__(other)
+        self._sbval19k84obscure747.SetValueFromCString (str(result))
+        return result
+        
+    def __idiv__(self, other):
+        result = self.__div__(other)
+        self._sbval19k84obscure747.SetValueFromCString (str(result))
+        return result
+        
+    def __itruediv__(self, other):
+        result = self.__truediv__(other)
+        self._sbval19k84obscure747.SetValueFromCString (str(result))
+        return result
+        
+    def __ifloordiv__(self, other):
+        result =  self.__floordiv__(self, other)
+        self._sbval19k84obscure747.SetValueFromCString (str(result))
+        return result
+        
+    def __imod__(self, other):
+        result =  self.__and__(self, other)
+        self._sbval19k84obscure747.SetValueFromCString (str(result))
+        return result
+        
+    def __ipow__(self, other):
+        result = self.__pow__(self, other)
+        self._sbval19k84obscure747.SetValueFromCString (str(result))
+        return result
+        
+    def __ipow__(self, other, modulo):
+        result = self.__pow__(self, other, modulo)
+        self._sbval19k84obscure747.SetValueFromCString (str(result))
+        return result
+        
+    def __ilshift__(self, other):
+        result = self.__lshift__(other)
+        self._sbval19k84obscure747.SetValueFromCString (str(result))
+        return result
+        
+    def __irshift__(self, other):
+        result =  self.__rshift__(other)
+        self._sbval19k84obscure747.SetValueFromCString (str(result))
+        return result
+        
+    def __iand__(self, other):
+        result =  self.__and__(self, other)
+        self._sbval19k84obscure747.SetValueFromCString (str(result))
+        return result
+        
+    def __ixor__(self, other):
+        result =  self.__xor__(self, other)
+        self._sbval19k84obscure747.SetValueFromCString (str(result))
+        return result
+        
+    def __ior__(self, other):
+        result =  self.__ior__(self, other)
+        self._sbval19k84obscure747.SetValueFromCString (str(result))
+        return result
+        
+    def __neg__(self):
+        return -int(self)
+        
+    def __pos__(self):
+        return +int(self)
+        
+    def __abs__(self):
+        return abs(int(self))
+        
+    def __invert__(self):
+        return ~int(self)
+        
+    def __complex__(self):
+        return complex (int(self))
+        
+    def __int__(self):
+        if self._sbval19k84obscure747_is_ptr:
+            return self._GetValueAsUnsigned()
+        tname= self._sbval19k84obscure747_type.GetName()
+        if tname.find('uint') >= 0 or tname.find('unsigned') >= 0:
+            return self._GetValueAsUnsigned()
+        retval = self._sbval19k84obscure747.GetValueAsSigned()
+        # <rdar://problem/12481949> lldb python: GetValueAsSigned does not return the correct value
+        if (retval & 0x80000000):
+            retval = retval - 0x100000000
+        return retval
+        
+    def __long__(self):
+        return self._sbval19k84obscure747.GetValueAsSigned()
+        
+    def __float__(self):
+        return float (self._sbval19k84obscure747.GetValueAsSigned())
+        
+    def __oct__(self):
+        return '0%o' % self._GetValueAsUnsigned()
+        
+    def __hex__(self):
+        return '0x%x' % self._GetValueAsUnsigned()
+
+    def __eq__(self, other):
+        self_err = lldb.SBError()
+        other_err = lldb.SBError()
+        self_val = self._sbval19k84obscure747.GetValueAsUnsigned(self_err)
+        if self_err.fail:
+                raise ValueError("unable to extract value of self")
+        if type(other) is value:
+            other_val = other._sbval19k84obscure747.GetValueAsUnsigned(other_err)
+            if other_err.fail:
+                raise ValueError("unable to extract value of other")
+            return self_val == other_val
+        if type(other) is int:
+            return int(self) == other
+        raise TypeError("Equality operation is not defined for this type.")
+                                                                    
+    def __neq__(self, other):
+        return not self.__eq__(other)
+    
+    def GetSBValue(self):
+        return self._sbval19k84obscure747
+    
+    def _GetValueAsSigned(self):
+        serr = lldb.SBError()
+        retval = self._sbval19k84obscure747.GetValueAsSigned(serr)
+        if serr.success:
+            return retval
+        raise ValueError("Failed to read signed data. "+ str(self._sbval19k84obscure747) +"(type =" + str(self._sbval19k84obscure747_type) + ") Error description: " + serr.GetCString())
+    
+    def _GetValueAsUnsigned(self):
+        serr = lldb.SBError()
+        retval = self._sbval19k84obscure747.GetValueAsUnsigned(serr)
+        if serr.success:
+            return retval
+        raise ValueError("Failed to read unsigned data. "+ str(self._sbval19k84obscure747) +"(type =" + str(self._sbval19k84obscure747_type) + ") Error description: " + serr.GetCString())
+    
+    def _GetValueAsString(self, offset = 0, maxlen = 1024):
+        serr = lldb.SBError()
+        sbdata = None
+        if self._sbval19k84obscure747.TypeIsPointerType():
+            sbdata = self._sbval19k84obscure747.GetPointeeData(offset, maxlen)
+        else:
+            sbdata = self._sbval19k84obscure747.GetData()
+        
+        retval = ''
+        bytesize = sbdata.GetByteSize()
+        if bytesize == 0 :
+            #raise ValueError('Unable to read value as string')
+            return ''
+        for i in range(0, bytesize) :
+            serr.Clear()
+            ch = chr(sbdata.GetUnsignedInt8(serr, i))
+            if serr.fail :
+                raise ValueError("Unable to read string data: " + serr.GetCString())
+            if ch == '\0':
+                break
+            retval += ch
+        return retval 
+    
+    def __format__(self, format_spec):
+        ret_format = "{0:"+format_spec+"}"
+        # typechar is last char. see http://www.python.org/dev/peps/pep-3101/
+        type_spec=format_spec.strip().lower()[-1]
+        if type_spec == 'x':
+            return ret_format.format(self._GetValueAsUnsigned())
+        if type_spec == 'd':
+            return ret_format.format(int(self))
+        if type_spec == 's':
+            return ret_format.format(str(self))
+        if type_spec == 'o':
+            return ret_format.format(int(oct(self)))
+        if type_spec == 'c':
+            return ret_format.format(int(self))
+        
+        return "unknown format " + format_spec + str(self)
+        
+        
+def unsigned(val):
+    """ Helper function to get unsigned value from core.value
+        params: val - value (see value class above) representation of an integer type
+        returns: int which is unsigned. 
+        raises : ValueError if the type cannot be represented as unsigned int.
+    """
+    if type(val) is value:
+        return val._GetValueAsUnsigned()
+    return int(val)
+
+def sizeof(t):
+    """ Find the byte size of a type. 
+        params: t - str : ex 'time_spec' returns equivalent of sizeof(time_spec) in C
+                t - value: ex a value object. returns size of the object
+        returns: int - byte size length 
+    """
+    if type(t) is value :
+        return t.GetSBValue().GetByteSize()
+    if type(t) is str:
+        return gettype(t).GetByteSize()
+    raise ValueError("Cannot get sizeof. Invalid argument")
+    
+        
+def dereference(val):
+    """ Get a dereferenced obj for a pointer type obj
+        params: val - value object representing a pointer type C construct in lldb
+        returns: value - value
+        ex. val = dereference(ptr_obj) #python
+        is same as
+            obj_ptr = (int *)0x1234  #C
+            val = *obj_ptr           #C
+    """
+    if type(val) is value and val.GetSBValue().TypeIsPointerType():
+        return value(val.GetSBValue().Dereference())
+    raise TypeError('Cannot dereference this type.')
+        
+def addressof(val):
+    """ Get address of a core.value object. 
+        params: val - value object representing a C construct in lldb
+        returns: value - value object referring to 'type(val) *' type
+        ex. addr = addressof(hello_obj)  #python 
+        is same as
+           uintptr_t addr = (uintptr_t)&hello_obj  #C
+    """
+    if type(val) is value:
+        return value(val.GetSBValue().AddressOf())
+    raise TypeError("Cannot do addressof for non-value type objects")
+
+def cast(obj, target_type):
+    """ Type cast an object to another C type.
+        params:
+            obj - core.value  object representing some C construct in lldb
+            target_type - str : ex 'char *'
+                        - lldb.SBType :
+    """
+    dest_type = target_type
+    if type(target_type) is str:
+        dest_type = gettype(target_type)
+    elif type(target_type) is value:
+        dest_type = target_type.GetSBValue().GetType()
+
+    if type(obj) is value :
+        return value(obj.GetSBValue().Cast(dest_type))
+    elif type(obj) is int:
+        print "ERROR: You cannot cast an 'int' to %s, please use kern.GetValueFromAddress() for such purposes." % str(target_type) 
+    raise TypeError("object of type %s cannot be casted to %s" % (str(type(obj)), str(target_type)))
+
+_value_types_cache={}
+
+def gettype(target_type):
+    """ Returns lldb.SBType of the given target_type
+        params:
+            target_type - str, ex. 'char', 'uint32_t' etc
+        returns:
+            lldb.SBType - SBType corresponding to the given target_type
+        raises:
+            NameError  - Incase the type is not identified
+    """
+    global _value_types_cache
+    # LLDB Somehow does not support finding types for 'struct pmap' while 'pmap' works fine
+    # <rdar://problem/12473003> 
+    target_type = target_type.replace('struct', '') 
+    target_type = str(target_type).strip()
+    if target_type not in _value_types_cache:
+        tmp_type = None
+        if target_type.endswith('*') :
+            tmp_type = LazyTarget.GetTarget().FindFirstType(target_type.rstrip('*').strip())
+            if not tmp_type.IsValid():
+                raise NameError('Unable to Cast to type '+target_type)
+            tmp_type = tmp_type.GetPointerType()
+        else :
+            tmp_type = LazyTarget.GetTarget().FindFirstType(target_type)
+            if not tmp_type.IsValid():
+                raise NameError('Unable to Cast to type '+target_type)
+        _value_types_cache[target_type] = tmp_type
+    return _value_types_cache[target_type]
+
+def getfieldoffset(struct_type, field_name):
+    """ Returns the byte offset of a field inside a given struct
+        params:
+            struct_type - str or lldb.SBType, ex. 'struct ipc_port *' or port.gettype()
+            field_name  - str, name of the field inside the struct ex. 'ip_messages'
+        returns:
+            int - byte offset of the field_name inside the struct_type
+        raises:
+            TypeError  - - In case the struct_type has no field with the name field_name
+    """
+    if type(struct_type) == str:
+        struct_type = gettype(struct_type)
+    offset = 0
+    for field in struct_type.get_fields_array():
+        if str(field.GetName()) == field_name:
+            return field.GetOffsetInBytes()
+    raise TypeError('Field name "%s" not found in type "%s"' % (field_name, str(struct_type)))
+
+def islong(x):
+    """ Returns True if a string represents a long integer, False otherwise
+    """
+    try:
+        long(x,16)
+    except ValueError:
+        try:
+            long(x)
+        except ValueError:
+            return False
+    return True