X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/bd504ef0e0b883cdd7917b73b3574eb9ce669905..39236c6e673c41db228275375ab7fdb0f837b292:/tools/lldbmacros/core/cvalue.py diff --git a/tools/lldbmacros/core/cvalue.py b/tools/lldbmacros/core/cvalue.py new file mode 100644 index 000000000..07bc25aec --- /dev/null +++ b/tools/lldbmacros/core/cvalue.py @@ -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() + # 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 + # + 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