Loading...
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
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