xref: /xnu-12377.41.6/tools/lldbmacros/core/cvalue.py (revision bbb1b6f9e71b8cdde6e5cd6f4841f207dee3d828)
1"""
2Defines a class value which encapsulates the basic lldb Scripting Bridge APIs. This provides an easy
3wrapper to extract information from C based constructs.
4
5 |------- core.value------------|
6 | |--lldb Scripting Bridge--|  |
7 | |    |--lldb core--|      |  |
8 | |-------------------------|  |
9 |------------------------------|
10
11Use the member function GetSBValue() to access the base Scripting Bridge value.
12"""
13import contextlib
14# The value class is designed to be Python 2/3 compatible. Pulling in more
15# builtins classes may break it.
16import numbers
17from typing import Optional
18
19import lldb
20import re
21from .caching import (
22    cache_statically,
23)
24from .pointer import PointerPolicy
25
26_CSTRING_REX = re.compile(r"((?:\s*|const\s+)\s*char(?:\s+\*|\s+[A-Za-z_0-9]*\s*\[|)\s*)", re.MULTILINE | re.DOTALL)
27
28
29# pragma pylint: disable=hex-method, div-method, rdiv-method, idiv-method, oct-method, nonzero-method
30class value(object):
31    """A class designed to wrap lldb.SBValue() objects so the resulting object
32    can be used as a variable would be in code. So if you have a Point structure
33    variable in your code in the current frame named "pt", you can initialize an instance
34    of this class with it:
35
36    pt = lldb.value(lldb.frame.FindVariable("pt"))
37    print pt
38    print pt.x
39    print pt.y
40
41    pt = lldb.value(lldb.frame.FindVariable("rectangle_array"))
42    print rectangle_array[12]
43    print rectangle_array[5].origin.x
44    """
45
46    __slots__ = ('__sbval', '__ptr')
47
48    def __init__(self, sbvalue, usePtrPolicy=True):
49        # Using a double `__` means this will be hidden from getattr()
50        # and can't conflict with C/C++ type field names.
51        self.__sbval = sbvalue
52        self.__ptr = PointerPolicy.match(sbvalue) if usePtrPolicy else None
53
54    @property
55    def sbvalue(self):
56        """backward compability for the old .sbvalue property"""
57        return self.GetSBValue()
58
59    @property
60    def ptrpolicy(self):
61        return self.__ptr
62
63    @ptrpolicy.setter
64    def ptrpolicy(self, policy):
65        self.__ptr = policy
66
67    def __bool__(self):
68        return self.__sbval.__bool__() and self._GetValueAsUnsigned() != 0
69
70    def __nonzero__(self):
71        return self.__sbval.__nonzero__() and self._GetValueAsUnsigned() != 0
72
73    def __repr__(self):
74        return self.__sbval.__str__()
75
76    #
77    # Compare operators
78    #
79
80    def __eq__(self, other):
81        if isinstance(other, value):
82            self_val = self._GetValueAsUnsigned()
83            other_val = other._GetValueAsUnsigned()
84            return self_val == other_val
85        if isinstance(other, numbers.Integral):
86            return int(self) == other
87        raise TypeError("EQ operator is not defined for this type.")
88
89    def __ne__(self, other):
90        return not self == other
91
92    def __lt__(self, other):
93        if isinstance(other, value):
94            self_val = self._GetValueAsUnsigned()
95            other_val = other._GetValueAsUnsigned()
96            return self_val < other_val
97        if isinstance(other, numbers.Integral):
98            return int(self) < int(other)
99        raise TypeError("LT operator is not defined for this type")
100
101    def __le__(self, other):
102        return self < other or self == other
103
104    def __gt__(self, other):
105        return not self <= other
106
107    def __ge__(self, other):
108        return not self < other
109
110    def __str__(self):
111        global _CSTRING_REX
112        sbv = self.__sbval
113        type_name = sbv.GetType().GetCanonicalType().GetName()
114        if len(_CSTRING_REX.findall(type_name)) > 0:
115            return self._GetValueAsString()
116        summary = sbv.GetSummary()
117        if summary:
118            return summary.strip('"')
119        return sbv.__str__()
120
121    def __getitem__(self, key):
122        # Allow array access if this value has children...
123        if type(key) is slice:
124            _start = int(key.start)
125            _end = int(key.stop)
126            _step = 1
127            if key.step is not None:
128                _step = int(key.step)
129            retval = []
130            while _start < _end:
131                retval.append(self[_start])
132                _start += _step
133            return retval
134        if type(key) is value:
135            key = int(key)
136        if isinstance(key, numbers.Integral):
137            sbv = self.__sbval
138            if self.__ptr:
139                sbv = self.__ptr.GetPointerSBValue(sbv)
140            child_sbvalue = sbv.GetValueForExpressionPath("[%i]" % key)
141            if child_sbvalue and child_sbvalue.IsValid():
142                return value(child_sbvalue)
143            raise IndexError("Index '%d' is out of range" % key)
144        raise TypeError("Cannot fetch array item for key of type {}".format(str(type(key))))
145
146    def __getattr__(self, name):
147        sbv = self.__sbval
148        if self.__ptr:
149            sbv = self.__ptr.GetPointerSBValue(sbv)
150        child_sbvalue = sbv.GetChildMemberWithName(name)
151        if child_sbvalue and child_sbvalue.IsValid():
152            return value(child_sbvalue)
153        raise AttributeError("No field by name: " + name)
154
155    def __add__(self, other):
156        return int(self) + int(other)
157
158    def __radd__(self, other):
159        return int(self) + int(other)
160
161    def __sub__(self, other):
162        return int(self) - int(other)
163
164    def __rsub__(self, other):
165        return int(other) - int(self)
166
167    def __mul__(self, other):
168        return int(self) * int(other)
169
170    def __rmul__(self, other):
171        return int(self) * int(other)
172
173    def __floordiv__(self, other):
174        return int(self) // int(other)
175
176    def __rfloordiv__(self, other):
177        return int(other) // int(self)
178
179    def __mod__(self, other):
180        return int(self) % int(other)
181
182    def __rmod__(self, other):
183        return int(other) % int(self)
184
185    def __divmod__(self, other):
186        return divmod(int(self), int(other))
187
188    def __rdivmod__(self, other):
189        return divmod(int(other), int(self))
190
191    def __pow__(self, other):
192        return int(self) ** int(other)
193
194    def __lshift__(self, other):
195        return int(self) << int(other)
196
197    def __rshift__(self, other):
198        return int(self) >> int(other)
199
200    def __and__(self, other):
201        return int(self) & int(other)
202
203    def __rand__(self, other):
204        return int(other) & int(self)
205
206    def __xor__(self, other):
207        return int(self) ^ int(other)
208
209    def __or__(self, other):
210        return int(self) | int(other)
211
212    def __truediv__(self, other):
213        return int(self) / int(other)
214
215    def __rtruediv__(self, other):
216        return int(other) / int(self)
217
218    def __iadd__(self, other):
219        result = self.__add__(other)
220        self.__sbval.SetValueFromCString(str(result))
221        return result
222
223    def __isub__(self, other):
224        result = self.__sub__(other)
225        self.__sbval.SetValueFromCString(str(result))
226        return result
227
228    def __imul__(self, other):
229        result = self.__mul__(other)
230        self.__sbval.SetValueFromCString(str(result))
231        return result
232
233    def __idiv__(self, other):
234        result = self.__div__(other)
235        self.__sbval.SetValueFromCString(str(result))
236        return result
237
238    def __itruediv__(self, other):
239        result = self.__truediv__(other)
240        self.__sbval.SetValueFromCString(str(result))
241        return result
242
243    def __ifloordiv__(self, other):
244        result = self.__floordiv__(other)
245        self.__sbval.SetValueFromCString(str(result))
246        return result
247
248    def __imod__(self, other):
249        result = self.__mod__(other)
250        self.__sbval.SetValueFromCString(str(result))
251        return result
252
253    def __ipow__(self, other):
254        result = self.__pow__(other)
255        self.__sbval.SetValueFromCString(str(result))
256        return result
257
258    def __ilshift__(self, other):
259        result = self.__lshift__(other)
260        self.__sbval.SetValueFromCString(str(result))
261        return result
262
263    def __irshift__(self, other):
264        result = self.__rshift__(other)
265        self.__sbval.SetValueFromCString(str(result))
266        return result
267
268    def __iand__(self, other):
269        result = self.__and__(other)
270        self.__sbval.SetValueFromCString(str(result))
271        return result
272
273    def __ixor__(self, other):
274        result = self.__xor__(other)
275        self.__sbval.SetValueFromCString(str(result))
276        return result
277
278    def __ior__(self, other):
279        result = self.__or__(other)
280        self.__sbval.SetValueFromCString(str(result))
281        return result
282
283    def __neg__(self):
284        return -int(self)
285
286    def __pos__(self):
287        return +int(self)
288
289    def __abs__(self):
290        return abs(int(self))
291
292    def __invert__(self):
293        return ~int(self)
294
295    def __complex__(self):
296        return complex(int(self))
297
298    def __int__(self):
299        sbv = self.__sbval
300        if self.__ptr:
301            sbv = self.__ptr.GetPointerSBValue(sbv)
302
303        flags = sbv.GetType().GetTypeFlags()
304        if flags & lldb.eTypeIsPointer:
305            return sbv.GetValueAsAddress()
306        if not flags & lldb.eTypeIsSigned:
307            return self._GetValueAsUnsigned()
308
309        return sbv.GetValueAsSigned()
310
311    # Python 3 conversion to int calls this.
312    def __index__(self):
313        return self.__int__()
314
315    def __long__(self):
316        sbv = self.__sbval
317        if self.__ptr:
318            sbv = self.__ptr.GetPointerSBValue(sbv)
319
320        flags = sbv.GetType().GetTypeFlags()
321        if flags & lldb.eTypeIsPointer:
322            return sbv.GetValueAsAddress()
323        if not flags & lldb.eTypeIsSigned:
324            return self._GetValueAsUnsigned()
325
326        return sbv.GetValueAsSigned()
327
328    def __float__(self):
329        return float(self.__sbval.GetValueAsSigned())
330
331    # Python 2 must return native string.
332    def __oct__(self):
333        return '0%o' % self._GetValueAsUnsigned()
334
335    # Python 2 must return native string.
336    def __hex__(self):
337        return '0x%x' % self._GetValueAsUnsigned()
338
339    def __hash__(self):
340        return hash(self.__sbval)
341
342    def GetRawSBValue(self):
343        return self.__sbval
344
345    def GetSBValue(self):
346        sbv = self.__sbval
347        if self.__ptr:
348            sbv = self.__ptr.GetPointerSBValue(sbv)
349
350        return sbv
351
352    def __getstate__(self):
353        err = lldb.SBError()
354        sbv = self.__sbval
355        if self.__ptr:
356            sbv = self.__ptr.GetPointerSBValue(sbv)
357            addr = sbv.GetValueAsAddress()
358            size = sbv.GetType().GetPointeeType().GetByteSize()
359        else:
360            addr = sbv.GetLoadAddress()
361            size = sbv.GetType().GetByteSize()
362
363        content = sbv.GetProcess().ReadMemory(addr, size, err)
364        if err.fail:
365            content = ''
366        return content
367
368    def _GetValueAsSigned(self):
369        sbv = self.__sbval
370        if self.__ptr:
371            print("ERROR: You cannot get 'int' from pointer type %s, please use unsigned(obj) for such purposes." % sbv.GetType().GetDisplayTypeName())
372            raise ValueError("Cannot get signed int for pointer data.")
373        serr = lldb.SBError()
374        retval = sbv.GetValueAsSigned(serr)
375        if serr.success:
376            return retval
377        raise ValueError("Failed to read signed data. {} (type = {}) Error description: {}".format(
378            str(sbv), sbv.GetType().GetDisplayTypeName(), serr.GetCString()))
379
380    def _GetValueAsCast(self, dest_type):
381        if not isinstance(dest_type, lldb.SBType):
382            raise ValueError("Invalid type for dest_type: {}".format(type(dest_type)))
383        val = value(self.__sbval.Cast(dest_type))
384        return val
385
386    def _GetValueAsUnsigned(self):
387        sbv = self.__sbval
388        if self.__ptr:
389            sbv = self.__ptr.GetPointerSBValue(sbv)
390            return sbv.GetValueAsAddress()
391        serr = lldb.SBError()
392        retval = sbv.GetValueAsUnsigned(serr)
393        if serr.success:
394            return retval
395        raise ValueError("Failed to read unsigned data. {} (type = {}) Error description: {}".format(
396            str(sbv), sbv.GetType().GetDisplayTypeName(), serr.GetCString()))
397
398    def _GetValueAsString(self, offset=0, maxlen=1024):
399        sbv = self.__sbval
400        serr = lldb.SBError()
401        sbdata = None
402        if self.__ptr:
403            sbv = self.__ptr.GetPointerSBValue(sbv)
404            sbdata = sbv.GetPointeeData(offset, maxlen)
405        else:
406            sbdata = sbv.GetData()
407
408        retval = ''
409        bytesize = sbdata.GetByteSize()
410        if bytesize == 0:
411            # raise ValueError('Unable to read value as string')
412            return ''
413        for i in range(0, bytesize):
414            serr.Clear()
415            ch = chr(sbdata.GetUnsignedInt8(serr, i))
416            if serr.fail:
417                raise ValueError("Unable to read string data: " + serr.GetCString())
418            if ch == '\0':
419                break
420            retval += ch
421        return retval
422
423    def __format__(self, format_spec):
424        # typechar is last char. see http://www.python.org/dev/peps/pep-3101/
425        typechar = format_spec[-1] if len(format_spec) else ''
426
427        if typechar in 'bcdoxX': # requires integral conversion
428            return format(int(self), format_spec)
429
430        if typechar in 'eEfFgG%': # requires float conversion
431            return format(float(self), format_spec)
432
433        if typechar in 's': # requires string conversion
434            return format(str(self), format_spec)
435
436        # 'n' or '' mean "whatever you got for me"
437        flags = self.__sbval.GetType().GetTypeFlags()
438        if flags & lldb.eTypeIsFloat:
439            return format(float(self), format_spec)
440        elif flags & lldb.eTypeIsScalar:
441            return format(int(self), format_spec)
442        else:
443            return format(str(self), format_spec)
444
445def unsigned(val):
446    """ Helper function to get unsigned value from core.value
447        params: val - value (see value class above) representation of an integer type
448        returns: int which is unsigned.
449        raises : ValueError if the type cannot be represented as unsigned int.
450    """
451    if type(val) is value:
452        return int(val._GetValueAsUnsigned())
453    return int(val)
454
455
456def signed(val):
457    """ Helper function to get signed value from core.value
458        params: val - value (see value class above) representation of an integer type
459        returns: int which is signed.
460        raises: ValueError if the type cannot be represented as signed int.
461    """
462    if type(val) is value:
463        return val.GetSBValue().GetValueAsSigned()
464    return int(val)
465
466
467def sizeof(t):
468    """ Find the byte size of a type.
469        params: t - str : ex 'time_spec' returns equivalent of sizeof(time_spec) in C
470                t - value: ex a value object. returns size of the object
471        returns: int - byte size length
472    """
473    if type(t) is value:
474        return t.GetSBValue().GetByteSize()
475    if isinstance(t, str):
476        return gettype(t).GetByteSize()
477    raise ValueError("Cannot get sizeof. Invalid argument")
478
479
480def dereference(val):
481    """ Get a dereferenced obj for a pointer type obj
482        params: val - value object representing a pointer type C construct in lldb
483        returns: value - value
484        ex. val = dereference(ptr_obj) #python
485        is same as
486            obj_ptr = (int *)0x1234  #C
487            val = *obj_ptr           #C
488    """
489    if type(val) is value:
490        sbv = val.GetSBValue()
491        return value(sbv.Dereference())
492    raise TypeError('Cannot dereference this type.')
493
494
495def wrapped(val):
496    """ Get original pointer value without aplying pointer policy.
497        param: val - value object representing a pointer
498        returns: value - value
499    """
500    if isinstance(val, value):
501        policy = val.ptrpolicy
502        val.ptrpolicy = None
503        newval = value(val.GetSBValue(), False)
504        val.ptrpolicy = policy
505        return newval
506    raise TypeError("Cannot do wrapped for non-value type objects")
507
508
509def addressof(val):
510    """ Get address of a core.value object.
511        params: val - value object representing a C construct in lldb
512        returns: value - value object referring to 'type(val) *' type
513        ex. addr = addressof(hello_obj)  #python
514        is same as
515           uintptr_t addr = (uintptr_t)&hello_obj  #C
516    """
517    if type(val) is value:
518        return value(val.GetSBValue().AddressOf())
519    raise TypeError("Cannot do addressof for non-value type objects")
520
521
522def cast(obj, target_type):
523    """ Type cast an object to another C type.
524        params:
525            obj - core.value  object representing some C construct in lldb
526            target_type - str : ex 'char *'
527                        - lldb.SBType :
528    """
529    dest_type = target_type
530    if isinstance(target_type, str):
531        dest_type = gettype(target_type)
532    elif type(target_type) is value:
533        dest_type = target_type.GetSBValue().GetType()
534
535    if type(obj) is value:
536        return obj._GetValueAsCast(dest_type)
537    elif type(obj) is int:
538        print("ERROR: You cannot cast an 'int' to %s, please use kern.GetValueFromAddress() for such purposes." % str(target_type))
539    raise TypeError("object of type %s cannot be casted to %s" % (str(type(obj)), str(target_type)))
540
541def containerof(obj, target_type, field_name):
542    """ Type cast an object to another C type from a pointer to a field.
543        params:
544            obj - core.value  object representing some C construct in lldb
545            target_type - str : ex 'struct thread'
546                        - lldb.SBType :
547            field_name - the field name within the target_type obj is a pointer to
548    """
549    addr = int(obj) - getfieldoffset(target_type, field_name)
550    sbv  = obj.GetSBValue()
551    sbv  = sbv.chkCreateValueFromAddress(None, addr, gettype(target_type))
552    return value(sbv.AddressOf())
553
554
555@cache_statically
556def gettype(target_type, target=None):
557    """ Returns lldb.SBType of the given target_type
558        params:
559            target_type - str, ex. 'char', 'uint32_t' etc
560        returns:
561            lldb.SBType - SBType corresponding to the given target_type
562        raises:
563            NameError  - Incase the type is not identified
564    """
565
566    #
567    # If the type was qualified with a `struct` or `class`, ...
568    # make sure we pick up the proper definition in case of clashes.
569    #
570    want = 0
571    name = str(target_type).strip()
572
573    if name.startswith("struct"):
574        want = lldb.eTypeClassStruct
575    elif name.startswith("union"):
576        want = lldb.eTypeClassUnion
577    elif name.startswith("class"):
578        want = lldb.eTypeClassClass
579    elif name.startswith("enum"):
580        want = lldb.eTypeClassEnumeration
581    elif name.startswith("typedef"):
582        want = lldb.eTypeClassTypedef
583
584    #
585    # Now remove constness and speficiers, and pointers
586    #
587    tmpname  = re.sub(r'\bconst\b', '', name).strip(" ")
588    tmpname  = re.sub(r'^(struct|class|union|enum|typedef) ', '', tmpname)
589    basename = tmpname.rstrip(" *")
590    ptrlevel = tmpname.count('*', len(basename))
591
592    def resolve_pointee_type(t: lldb.SBType):
593        while t.IsPointerType():
594            t = t.GetPointeeType()
595        return t
596
597    def type_sort_heuristic(t: lldb.SBType) -> int:
598        """ prioritizes types with more fields, and prefers fields with complete
599        types
600            params:
601                t - lldb.SBType, type to score
602            returns:
603                int - heuristic score
604        """
605        # we care about the underlying type, not the pointer
606        resolved_type: lldb.SBType = resolve_pointee_type(t)
607
608        # heuristic score
609        score = 0
610        for field in resolved_type.fields:
611            resolved_field_type = resolve_pointee_type(field.GetType())
612            score += 3 if resolved_field_type.IsTypeComplete() else 1
613
614        return score
615
616    type_arr = [t for t in target.chkFindTypes(basename)]
617    # After the sort, the best matching struct will be at index [0].
618    # This heuristic selects a struct type with more fields (with complete types)
619    # compared to ones with "opaque" members
620    type_arr.sort(reverse=True, key=type_sort_heuristic)
621
622    for tyobj in type_arr:
623        if want and tyobj.GetTypeClass() != want:
624            continue
625
626        for _ in range(ptrlevel):
627            tyobj = tyobj.GetPointerType()
628
629        return tyobj
630
631    raise NameError('Unable to find type {}'.format(target_type))
632
633
634@cache_statically
635def getfieldoffset(struct_type, field_name_or_path, target=None):
636    """ Returns the byte offset of a field inside a given struct
637        Understands anonymous unions and field names in sub-structs
638        params:
639            field_name_or_path  - str, name or path to the field inside the struct ex. 'ip_messages'
640        returns:
641            int - byte offset of the field_name inside the struct_type
642    """
643
644    return gettype(struct_type).xGetFieldOffset(field_name_or_path)
645
646
647def islong(x):
648    """ Returns True if a string represents a long integer, False otherwise
649    """
650    try:
651        int(x, 16)
652    except ValueError:
653        try:
654            int(x)
655        except ValueError:
656            return False
657    return True
658
659
660def readmemory(val):
661    """ Returns a string of hex data that is referenced by the value.
662        params: val - a value object.
663        return: str - string of hex bytes.
664        raises: TypeError if val is not a valid type
665    """
666    if not type(val) is value:
667        raise TypeError('%s is not of type value' % str(type(val)))
668    return val.__getstate__()
669
670
671def getOSPtr(cpp_obj):
672    """ Returns a core.value created from an intrusive_shared_ptr or itself, cpp_obj
673        params: cpp_obj - core.value object representing a C construct in lldb
674        return: core.value - newly created core.value or cpp_obj
675    """
676    child = cpp_obj.GetSBValue().GetChildAtIndex(0)
677    if 'intrusive_shared_ptr' in str(child):
678        return value(child.GetChildMemberWithName('ptr_'))
679    return cpp_obj
680
681
682def get_field(val: value, field: str) -> Optional[value]:
683    """
684    Attempts getting a value's field.
685    Returns None (suppressing the exception) in case of failure
686    """
687    with contextlib.suppress(AttributeError):
688        return val.__getattr__(field)
689    return None