diff options
Diffstat (limited to 'lldb/examples/summaries/cocoa')
-rw-r--r-- | lldb/examples/summaries/cocoa/CFArray.py | 14 | ||||
-rw-r--r-- | lldb/examples/summaries/cocoa/CFBag.py | 10 | ||||
-rw-r--r-- | lldb/examples/summaries/cocoa/CFBinaryHeap.py | 10 | ||||
-rw-r--r-- | lldb/examples/summaries/cocoa/CFDictionary.py | 46 | ||||
-rw-r--r-- | lldb/examples/summaries/cocoa/CFString.py | 12 | ||||
-rw-r--r-- | lldb/examples/summaries/cocoa/NSBundle.py | 6 | ||||
-rw-r--r-- | lldb/examples/summaries/cocoa/NSData.py | 8 | ||||
-rw-r--r-- | lldb/examples/summaries/cocoa/NSDate.py | 171 | ||||
-rw-r--r-- | lldb/examples/summaries/cocoa/NSException.py | 6 | ||||
-rw-r--r-- | lldb/examples/summaries/cocoa/NSMachPort.py | 6 | ||||
-rw-r--r-- | lldb/examples/summaries/cocoa/NSNotification.py | 6 | ||||
-rw-r--r-- | lldb/examples/summaries/cocoa/NSNumber.py | 8 | ||||
-rw-r--r-- | lldb/examples/summaries/cocoa/NSSet.py | 22 | ||||
-rw-r--r-- | lldb/examples/summaries/cocoa/NSURL.py | 8 | ||||
-rw-r--r-- | lldb/examples/summaries/cocoa/objc_lldb.py | 4 | ||||
-rw-r--r-- | lldb/examples/summaries/cocoa/objc_runtime.py | 197 |
16 files changed, 350 insertions, 184 deletions
diff --git a/lldb/examples/summaries/cocoa/CFArray.py b/lldb/examples/summaries/cocoa/CFArray.py index 648737f7def..4545a1b2370 100644 --- a/lldb/examples/summaries/cocoa/CFArray.py +++ b/lldb/examples/summaries/cocoa/CFArray.py @@ -16,7 +16,7 @@ statistics.add_metric('code_notrun') class NSArrayKVC_SynthProvider: def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() @@ -51,7 +51,7 @@ class NSArrayKVC_SynthProvider: class NSArrayCF_SynthProvider: def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() self.cfruntime_size = self.size_of_cfruntime_base() @@ -61,7 +61,7 @@ class NSArrayCF_SynthProvider: # to get its size we add up sizeof(pointer)+4 # and then add 4 more bytes if we are on a 64bit system def size_of_cfruntime_base(self): - if self.lp64 == True: + if self.is_64_bit == True: return 8+4+4; else: return 4+4; @@ -93,7 +93,7 @@ class NSArrayCF_SynthProvider: class NSArrayI_SynthProvider: def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() @@ -133,7 +133,7 @@ class NSArrayI_SynthProvider: class NSArrayM_SynthProvider: def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() @@ -223,7 +223,7 @@ class NSArrayM_SynthProvider: class NSArray_SynthProvider: def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() self.id_type = self.valobj.GetType().GetBasicType(lldb.eBasicTypeObjCID) @@ -314,7 +314,7 @@ def CFArray_SummaryProvider (valobj,dict): summary = None if summary == None: summary = 'no valid array here' - return 'size='+summary + return summary + " objects" return '' def __lldb_init_module(debugger,dict): diff --git a/lldb/examples/summaries/cocoa/CFBag.py b/lldb/examples/summaries/cocoa/CFBag.py index 596114bd5df..1403a122eb6 100644 --- a/lldb/examples/summaries/cocoa/CFBag.py +++ b/lldb/examples/summaries/cocoa/CFBag.py @@ -15,7 +15,7 @@ statistics.add_metric('code_notrun') # obey the interface specification for synthetic children providers class CFBagRef_SummaryProvider: def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() @@ -26,7 +26,7 @@ class CFBagRef_SummaryProvider: def update(self): self.adjust_for_architecture(); self.id_type = self.valobj.GetType().GetBasicType(lldb.eBasicTypeObjCID) - if self.lp64: + if self.is_64_bit: self.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong) else: self.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt) @@ -35,7 +35,7 @@ class CFBagRef_SummaryProvider: # 20 bytes on x64 # most probably 2 pointers and 4 bytes of data def offset(self): - if self.lp64: + if self.is_64_bit: return 20 else: return 12 @@ -49,7 +49,7 @@ class CFBagRef_SummaryProvider: class CFBagUnknown_SummaryProvider: def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() @@ -120,7 +120,7 @@ def CFBag_SummaryProvider (valobj,dict): if summary == None: summary = 'no valid set here' else: - if provider.lp64: + if provider.is_64_bit: summary = summary & ~0x1fff000000000000 if summary == 1: return '1 item' diff --git a/lldb/examples/summaries/cocoa/CFBinaryHeap.py b/lldb/examples/summaries/cocoa/CFBinaryHeap.py index d0542abfcc7..0a120745c3c 100644 --- a/lldb/examples/summaries/cocoa/CFBinaryHeap.py +++ b/lldb/examples/summaries/cocoa/CFBinaryHeap.py @@ -15,7 +15,7 @@ statistics.add_metric('code_notrun') # obey the interface specification for synthetic children providers class CFBinaryHeapRef_SummaryProvider: def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() @@ -26,7 +26,7 @@ class CFBinaryHeapRef_SummaryProvider: def update(self): self.adjust_for_architecture(); self.id_type = self.valobj.GetType().GetBasicType(lldb.eBasicTypeObjCID) - if self.lp64: + if self.is_64_bit: self.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong) else: self.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt) @@ -35,7 +35,7 @@ class CFBinaryHeapRef_SummaryProvider: # 16 bytes on x64 # most probably 2 pointers def offset(self): - if self.lp64: + if self.is_64_bit: return 16 else: return 8 @@ -49,7 +49,7 @@ class CFBinaryHeapRef_SummaryProvider: class CFBinaryHeapUnknown_SummaryProvider: def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() @@ -117,7 +117,7 @@ def CFBinaryHeap_SummaryProvider (valobj,dict): if summary == None: summary = 'no valid set here' else: - if provider.lp64: + if provider.is_64_bit: summary = summary & ~0x1fff000000000000 if summary == 1: return '1 item' diff --git a/lldb/examples/summaries/cocoa/CFDictionary.py b/lldb/examples/summaries/cocoa/CFDictionary.py index 944e05aca59..5bd9e690b36 100644 --- a/lldb/examples/summaries/cocoa/CFDictionary.py +++ b/lldb/examples/summaries/cocoa/CFDictionary.py @@ -15,7 +15,7 @@ statistics.add_metric('code_notrun') # obey the interface specification for synthetic children providers class NSCFDictionary_SummaryProvider: def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() @@ -26,7 +26,7 @@ class NSCFDictionary_SummaryProvider: def update(self): self.adjust_for_architecture(); self.id_type = self.valobj.GetType().GetBasicType(lldb.eBasicTypeObjCID) - if self.lp64: + if self.is_64_bit: self.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong) else: self.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt) @@ -36,7 +36,7 @@ class NSCFDictionary_SummaryProvider: # the description of __CFDictionary is not readily available so most # of this is guesswork, plain and simple def offset(self): - if self.lp64: + if self.is_64_bit: return 20 else: return 12 @@ -50,7 +50,7 @@ class NSCFDictionary_SummaryProvider: class NSDictionaryI_SummaryProvider: def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() @@ -61,14 +61,14 @@ class NSDictionaryI_SummaryProvider: def update(self): self.adjust_for_architecture(); self.id_type = self.valobj.GetType().GetBasicType(lldb.eBasicTypeObjCID) - if self.lp64: + if self.is_64_bit: self.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong) else: self.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt) # we just need to skip the ISA and the count immediately follows def offset(self): - if self.lp64: + if self.is_64_bit: return 8 else: return 4 @@ -79,19 +79,18 @@ class NSDictionaryI_SummaryProvider: self.NSUInteger) value = num_children_vo.GetValueAsUnsigned(0) if value != None: - # the MSB on immutable dictionaries seems to be taken by the LSB of capacity - # not sure if it is a bug or some weird sort of feature, but masking it out - # gets the count right (unless, of course, someone's dictionaries grow - # too large - but I have not tested this) - if self.lp64: - value = value & ~0xFF00000000000000 + # the MS6bits on immutable dictionaries seem to be taken by the LSB of capacity + # not sure if it is a bug or some weird sort of feature, but masking that out + # gets the count right + if self.is_64_bit: + value = value & ~0xFC00000000000000 else: - value = value & ~0xFF000000 + value = value & ~0xFC000000 return value class NSDictionaryM_SummaryProvider: def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() @@ -102,14 +101,14 @@ class NSDictionaryM_SummaryProvider: def update(self): self.adjust_for_architecture(); self.id_type = self.valobj.GetType().GetBasicType(lldb.eBasicTypeObjCID) - if self.lp64: + if self.is_64_bit: self.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong) else: self.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt) # we just need to skip the ISA and the count immediately follows def offset(self): - if self.lp64: + if self.is_64_bit: return 8 else: return 4 @@ -118,12 +117,21 @@ class NSDictionaryM_SummaryProvider: num_children_vo = self.valobj.CreateChildAtOffset("count", self.offset(), self.NSUInteger) - return num_children_vo.GetValueAsUnsigned(0) + value = num_children_vo.GetValueAsUnsigned(0) + if value != None: + # the MS6bits on mutable dictionaries seem to be taken by flags for + # KVO and probably other features. however, masking it out does get + # the count right + if self.is_64_bit: + value = value & ~0xFC00000000000000 + else: + value = value & ~0xFC000000 + return value class NSDictionaryUnknown_SummaryProvider: def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() @@ -198,7 +206,7 @@ def CFDictionary_SummaryProvider2 (valobj,dict): if summary == None: summary = 'no valid dictionary here' # needed on OSX Mountain Lion - elif provider.lp64: + elif provider.is_64_bit: summary = int(summary) & ~0x0f1f000000000000 return str(summary) + " key/value pairs" return '' diff --git a/lldb/examples/summaries/cocoa/CFString.py b/lldb/examples/summaries/cocoa/CFString.py index 478f972e529..13d825ee715 100644 --- a/lldb/examples/summaries/cocoa/CFString.py +++ b/lldb/examples/summaries/cocoa/CFString.py @@ -76,7 +76,7 @@ class CFStringSynthProvider: # handle the special case strings # only use the custom code for the tested LP64 case def handle_special(self): - if self.lp64 == False: + if self.is_64_bit == False: # for 32bit targets, use safe ObjC code return self.handle_unicode_string_safe() offset = 12 @@ -127,7 +127,7 @@ class CFStringSynthProvider: "(char*)\"" + pystr.encode('utf-8') + "\"") def handle_inline_explicit(self): - if self.lp64: + if self.is_64_bit: offset = 24 else: offset = 12 @@ -136,7 +136,7 @@ class CFStringSynthProvider: "(char*)(" + str(offset) + ")") def handle_mutable_string(self): - if self.lp64: + if self.is_64_bit: offset = 16 else: offset = 8 @@ -223,7 +223,7 @@ class CFStringSynthProvider: # to get its size we add up sizeof(pointer)+4 # and then add 4 more bytes if we are on a 64bit system def size_of_cfruntime_base(self): - if self.lp64 == True: + if self.is_64_bit == True: return 8+4+4; else: return 4+4; @@ -234,7 +234,7 @@ class CFStringSynthProvider: # on big-endian this means going to byte 3, if we are on # little endian (OSX & iOS), this means reading byte 0 def offset_of_info_bits(self): - if self.lp64 == True: + if self.is_64_bit == True: offset = 8; else: offset = 4; @@ -282,7 +282,7 @@ class CFStringSynthProvider: # preparing ourselves to read into memory # by adjusting architecture-specific info def adjust_for_architecture(self): - self.lp64 = self.is_64bit(); + self.is_64_bit = self.is_64bit(); self.is_little = self.is_little_endian(); # reading info bits out of the CFString and computing diff --git a/lldb/examples/summaries/cocoa/NSBundle.py b/lldb/examples/summaries/cocoa/NSBundle.py index 5e6b11a6fc0..cb748f5217f 100644 --- a/lldb/examples/summaries/cocoa/NSBundle.py +++ b/lldb/examples/summaries/cocoa/NSBundle.py @@ -16,7 +16,7 @@ statistics.add_metric('code_notrun') # obey the interface specification for synthetic children providers class NSBundleKnown_SummaryProvider: def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() @@ -27,7 +27,7 @@ class NSBundleKnown_SummaryProvider: def update(self): self.adjust_for_architecture(); self.id_type = self.valobj.GetType().GetBasicType(lldb.eBasicTypeObjCID) - if self.lp64: + if self.is_64_bit: self.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong) self.pointer_size = 8 else: @@ -58,7 +58,7 @@ class NSBundleKnown_SummaryProvider: class NSBundleUnknown_SummaryProvider: def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() diff --git a/lldb/examples/summaries/cocoa/NSData.py b/lldb/examples/summaries/cocoa/NSData.py index 362bc81cd8d..9acb2fefb32 100644 --- a/lldb/examples/summaries/cocoa/NSData.py +++ b/lldb/examples/summaries/cocoa/NSData.py @@ -15,7 +15,7 @@ statistics.add_metric('code_notrun') # obey the interface specification for synthetic children providers class NSConcreteData_SummaryProvider: def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() @@ -26,7 +26,7 @@ class NSConcreteData_SummaryProvider: def update(self): self.adjust_for_architecture(); self.id_type = self.valobj.GetType().GetBasicType(lldb.eBasicTypeObjCID) - if self.lp64: + if self.is_64_bit: self.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong) else: self.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt) @@ -37,7 +37,7 @@ class NSConcreteData_SummaryProvider: # machine word long, which means we actually have two pointers # worth of data to skip def offset(self): - if self.lp64: + if self.is_64_bit: return 16 else: return 8 @@ -51,7 +51,7 @@ class NSConcreteData_SummaryProvider: class NSDataUnknown_SummaryProvider: def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() diff --git a/lldb/examples/summaries/cocoa/NSDate.py b/lldb/examples/summaries/cocoa/NSDate.py new file mode 100644 index 00000000000..aa059e2e79c --- /dev/null +++ b/lldb/examples/summaries/cocoa/NSDate.py @@ -0,0 +1,171 @@ +# summary provider for NSDate +import lldb +import ctypes +import objc_runtime +import metrics +import struct +import time +import datetime + +statistics = metrics.Metrics() +statistics.add_metric('invalid_isa') +statistics.add_metric('invalid_pointer') +statistics.add_metric('unknown_class') +statistics.add_metric('code_notrun') + +# Python promises to start counting time at midnight on Jan 1st on the epoch year +# hence, all we need to know is the epoch year +python_epoch = time.gmtime(0).tm_year + +osx_epoch = datetime.date(2001,1,1).timetuple() + +def mkgmtime(t): + return time.mktime(t)-time.timezone + +osx_epoch = mkgmtime(osx_epoch) + +def osx_to_python_time(osx): + if python_epoch <= 2011: + return osx + osx_epoch + else: + return osx - osx_epoch + + +# despite the similary to synthetic children providers, these classes are not +# trying to provide anything but the port number of an NSDate, so they need not +# obey the interface specification for synthetic children providers +class NSTaggedDate_SummaryProvider: + def adjust_for_architecture(self): + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) + self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() + + def __init__(self, valobj, info_bits, data): + self.valobj = valobj; + self.update(); + self.info_bits = info_bits + self.data = data + + def update(self): + self.adjust_for_architecture(); + self.id_type = self.valobj.GetType().GetBasicType(lldb.eBasicTypeObjCID) + + self.char = self.valobj.GetType().GetBasicType(lldb.eBasicTypeChar) + self.short = self.valobj.GetType().GetBasicType(lldb.eBasicTypeShort) + self.ushort = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedShort) + self.int = self.valobj.GetType().GetBasicType(lldb.eBasicTypeInt) + self.long = self.valobj.GetType().GetBasicType(lldb.eBasicTypeLong) + self.ulong = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong) + self.longlong = self.valobj.GetType().GetBasicType(lldb.eBasicTypeLongLong) + self.ulonglong = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLongLong) + self.float = self.valobj.GetType().GetBasicType(lldb.eBasicTypeFloat) + self.double = self.valobj.GetType().GetBasicType(lldb.eBasicTypeDouble) + + def value(self): + # the value of the date-time object is wrapped into the pointer value + # unfortunately, it is made as a time-delta after Jan 1 2011 midnight GMT + # while all Python knows about is the "epoch", which is a platform-dependent + # year (1970 of *nix) whose Jan 1 at midnight is taken as reference + return time.ctime(osx_to_python_time(self.data)) + + +class NSUntaggedDate_SummaryProvider: + def adjust_for_architecture(self): + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) + self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() + + def __init__(self, valobj): + self.valobj = valobj; + self.update() + + def update(self): + self.adjust_for_architecture(); + self.id_type = self.valobj.GetType().GetBasicType(lldb.eBasicTypeObjCID) + self.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong) + self.double = self.valobj.GetType().GetBasicType(lldb.eBasicTypeDouble) + + def offset(self): + if self.is_64_bit: + return 8 + else: + return 4 + + + def value(self): + value = self.valobj.CreateChildAtOffset("value", + self.offset(), + self.double) + value_double = struct.unpack('d', struct.pack('Q', value.GetValueAsUnsigned(0)))[0] + return time.ctime(osx_to_python_time(value_double)) + +class NSUnknownDate_SummaryProvider: + def adjust_for_architecture(self): + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) + self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() + + def __init__(self, valobj): + self.valobj = valobj; + self.update() + + def update(self): + self.adjust_for_architecture(); + self.id_type = self.valobj.GetType().GetBasicType(lldb.eBasicTypeObjCID) + + def value(self): + stream = lldb.SBStream() + self.valobj.GetExpressionPath(stream) + expr = "(NSString*)[" + stream.GetData() + " description]" + num_children_vo = self.valobj.CreateValueFromExpression("str",expr); + return num_children_vo.GetSummary() + +def GetSummary_Impl(valobj): + global statistics + class_data = objc_runtime.ObjCRuntime(valobj) + if class_data.is_valid() == False: + statistics.metric_hit('invalid_pointer',valobj) + wrapper = None + return + class_data = class_data.read_class_data() + if class_data.is_valid() == False: + statistics.metric_hit('invalid_isa',valobj) + wrapper = None + return + if class_data.is_kvo(): + class_data = class_data.get_superclass() + if class_data.is_valid() == False: + statistics.metric_hit('invalid_isa',valobj) + wrapper = None + return + + name_string = class_data.class_name() + if name_string == 'NSDate' or name_string == '__NSDate' or name_string == '__NSTaggedDate': + if class_data.is_tagged(): + wrapper = NSTaggedDate_SummaryProvider(valobj,class_data.info_bits(),class_data.value()) + statistics.metric_hit('code_notrun',valobj) + else: + wrapper = NSUntaggedDate_SummaryProvider(valobj) + statistics.metric_hit('code_notrun',valobj) + else: + wrapper = NSUnknownDate_SummaryProvider(valobj) + statistics.metric_hit('unknown_class',str(valobj) + " seen as " + name_string) + return wrapper; + + +def NSDate_SummaryProvider (valobj,dict): + provider = GetSummary_Impl(valobj); + if provider != None: + #try: + summary = provider.value(); + #except: + # summary = None + if summary == None: + summary = 'no valid number here' + return str(summary) + return '' + + +def __lldb_init_module(debugger,dict): + debugger.HandleCommand("type summary add -F NSDate.NSDate_SummaryProvider NSDate") + diff --git a/lldb/examples/summaries/cocoa/NSException.py b/lldb/examples/summaries/cocoa/NSException.py index e5f0418eed9..ac85fe8c143 100644 --- a/lldb/examples/summaries/cocoa/NSException.py +++ b/lldb/examples/summaries/cocoa/NSException.py @@ -12,7 +12,7 @@ statistics.add_metric('code_notrun') class NSKnownException_SummaryProvider: def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() @@ -27,7 +27,7 @@ class NSKnownException_SummaryProvider: # skip the ISA and go to the name pointer def offset(self): - if self.lp64: + if self.is_64_bit: return 8 else: return 4 @@ -44,7 +44,7 @@ class NSKnownException_SummaryProvider: class NSUnknownException_SummaryProvider: def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() diff --git a/lldb/examples/summaries/cocoa/NSMachPort.py b/lldb/examples/summaries/cocoa/NSMachPort.py index ca714bc38ae..eceb2d9ccfe 100644 --- a/lldb/examples/summaries/cocoa/NSMachPort.py +++ b/lldb/examples/summaries/cocoa/NSMachPort.py @@ -15,7 +15,7 @@ statistics.add_metric('code_notrun') # obey the interface specification for synthetic children providers class NSMachPortKnown_SummaryProvider: def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() @@ -32,7 +32,7 @@ class NSMachPortKnown_SummaryProvider: # then we have one other internal pointer, plus # 4 bytes worth of flags. hence, these values def offset(self): - if self.lp64: + if self.is_64_bit: return 20 else: return 12 @@ -46,7 +46,7 @@ class NSMachPortKnown_SummaryProvider: class NSMachPortUnknown_SummaryProvider: def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() diff --git a/lldb/examples/summaries/cocoa/NSNotification.py b/lldb/examples/summaries/cocoa/NSNotification.py index 6170110354c..0f8cccd322c 100644 --- a/lldb/examples/summaries/cocoa/NSNotification.py +++ b/lldb/examples/summaries/cocoa/NSNotification.py @@ -12,7 +12,7 @@ statistics.add_metric('code_notrun') class NSConcreteNotification_SummaryProvider: def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() @@ -27,7 +27,7 @@ class NSConcreteNotification_SummaryProvider: # skip the ISA and go to the name pointer def offset(self): - if self.lp64: + if self.is_64_bit: return 8 else: return 4 @@ -41,7 +41,7 @@ class NSConcreteNotification_SummaryProvider: class NSNotificationUnknown_SummaryProvider: def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() diff --git a/lldb/examples/summaries/cocoa/NSNumber.py b/lldb/examples/summaries/cocoa/NSNumber.py index 81f3d28dbc1..dfe0917b11d 100644 --- a/lldb/examples/summaries/cocoa/NSNumber.py +++ b/lldb/examples/summaries/cocoa/NSNumber.py @@ -16,7 +16,7 @@ statistics.add_metric('code_notrun') # obey the interface specification for synthetic children providers class NSTaggedNumber_SummaryProvider: def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() @@ -60,7 +60,7 @@ class NSTaggedNumber_SummaryProvider: class NSUntaggedNumber_SummaryProvider: def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() @@ -114,7 +114,7 @@ class NSUntaggedNumber_SummaryProvider: self.int) statistics.metric_hit('code_notrun',self.valobj) return '(int)' + str(data_vo.GetValueAsUnsigned(0) % (256*256*256*256)) - # apparently, on lp64 architectures, these are the only values that will ever + # apparently, on is_64_bit architectures, these are the only values that will ever # be represented by a non tagged pointers elif data_type == 0B10001 or data_type == 0B0100: data_offset = data_offset + self.pointer_size @@ -146,7 +146,7 @@ class NSUntaggedNumber_SummaryProvider: class NSUnknownNumber_SummaryProvider: def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() diff --git a/lldb/examples/summaries/cocoa/NSSet.py b/lldb/examples/summaries/cocoa/NSSet.py index 3ca561cd8f8..ee3072da2dc 100644 --- a/lldb/examples/summaries/cocoa/NSSet.py +++ b/lldb/examples/summaries/cocoa/NSSet.py @@ -15,7 +15,7 @@ statistics.add_metric('code_notrun') # obey the interface specification for synthetic children providers class NSCFSet_SummaryProvider: def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() @@ -32,7 +32,7 @@ class NSCFSet_SummaryProvider: # then we have one other internal pointer, plus # 4 bytes worth of flags. hence, these values def offset(self): - if self.lp64: + if self.is_64_bit: return 20 else: return 12 @@ -46,7 +46,7 @@ class NSCFSet_SummaryProvider: class NSSetUnknown_SummaryProvider: def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() @@ -67,7 +67,7 @@ class NSSetUnknown_SummaryProvider: class NSSetI_SummaryProvider: def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() @@ -78,14 +78,14 @@ class NSSetI_SummaryProvider: def update(self): self.adjust_for_architecture(); self.id_type = self.valobj.GetType().GetBasicType(lldb.eBasicTypeObjCID) - if self.lp64: + if self.is_64_bit: self.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong) else: self.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt) # we just need to skip the ISA and the count immediately follows def offset(self): - if self.lp64: + if self.is_64_bit: return 8 else: return 4 @@ -100,7 +100,7 @@ class NSSetI_SummaryProvider: # not sure if it is a bug or some weird sort of feature, but masking it out # gets the count right (unless, of course, someone's dictionaries grow # too large - but I have not tested this) - if self.lp64: + if self.is_64_bit: value = value & ~0xFF00000000000000 else: value = value & ~0xFF000000 @@ -108,7 +108,7 @@ class NSSetI_SummaryProvider: class NSSetM_SummaryProvider: def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() @@ -119,14 +119,14 @@ class NSSetM_SummaryProvider: def update(self): self.adjust_for_architecture(); self.id_type = self.valobj.GetType().GetBasicType(lldb.eBasicTypeObjCID) - if self.lp64: + if self.is_64_bit: self.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong) else: self.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt) # we just need to skip the ISA and the count immediately follows def offset(self): - if self.lp64: + if self.is_64_bit: return 8 else: return 4 @@ -200,7 +200,7 @@ def NSSet_SummaryProvider2 (valobj,dict): if summary == None: summary = 'no valid set here' else: - if provider.lp64: + if provider.is_64_bit: summary = int(summary) & ~0x1fff000000000000 return str(summary) + ' objects' return '' diff --git a/lldb/examples/summaries/cocoa/NSURL.py b/lldb/examples/summaries/cocoa/NSURL.py index 6c15b402213..b242323f4bf 100644 --- a/lldb/examples/summaries/cocoa/NSURL.py +++ b/lldb/examples/summaries/cocoa/NSURL.py @@ -16,7 +16,7 @@ statistics.add_metric('code_notrun') # obey the interface specification for synthetic children providers class NSURLKnown_SummaryProvider: def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() @@ -27,7 +27,7 @@ class NSURLKnown_SummaryProvider: def update(self): self.adjust_for_architecture(); self.id_type = self.valobj.GetType().GetBasicType(lldb.eBasicTypeObjCID) - if self.lp64: + if self.is_64_bit: self.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong) self.pointer_size = 8 else: @@ -41,7 +41,7 @@ class NSURLKnown_SummaryProvider: # (which are also present on a 32-bit system) # plus another pointer, and then the real data def offset(self): - if self.lp64: + if self.is_64_bit: return 24 else: return 16 @@ -61,7 +61,7 @@ class NSURLKnown_SummaryProvider: class NSURLUnknown_SummaryProvider: def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() diff --git a/lldb/examples/summaries/cocoa/objc_lldb.py b/lldb/examples/summaries/cocoa/objc_lldb.py index a81be013159..877674c24cd 100644 --- a/lldb/examples/summaries/cocoa/objc_lldb.py +++ b/lldb/examples/summaries/cocoa/objc_lldb.py @@ -15,7 +15,7 @@ class ObjCRuntime: self.adjust_for_architecture() def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() self.addr_type = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong) @@ -112,7 +112,7 @@ class ObjCRuntime: # read ro pointer ro_pointer = data + 12 + self.pointer_size - if self.lp64: + if self.is_64_bit: ro_pointer += 4 ro_object = self.valobj.CreateValueFromAddress("ro", ro_pointer, diff --git a/lldb/examples/summaries/cocoa/objc_runtime.py b/lldb/examples/summaries/cocoa/objc_runtime.py index f62898ff803..b60f6c837a4 100644 --- a/lldb/examples/summaries/cocoa/objc_runtime.py +++ b/lldb/examples/summaries/cocoa/objc_runtime.py @@ -4,42 +4,25 @@ import cache class Utilities: @staticmethod - def read_ascii(process, pointer,max_len=128,when_over_return_none=True): + def read_ascii(process, pointer,max_len=128): error = lldb.SBError() - pystr = '' - count = 0 - # there is not any length byte to tell us how much to read - # however, there are most probably ways to optimize this - # in order to avoid doing the read byte-by-byte (caching is - # still occurring, but we could just fetch a larger chunk - # of memory instead of going one byte at a time) - while True: - content = process.ReadMemory(pointer, 1, error) - new_bytes = bytearray(content) - if new_bytes == None or len(new_bytes) == 0: - break - b0 = new_bytes[0] - pointer = pointer + 1 - if b0 == 0: - break - count = count + 1 - if count > max_len: - if when_over_return_none: - return None - else: - return pystr - pystr = pystr + chr(b0) - return pystr + content = None + try: + content = process.ReadCStringFromMemory(pointer,max_len,error) + except: + pass + if content == None or len(content) == 0 or error.fail == True: + return None + return content @staticmethod - def is_valid_pointer(pointer, pointer_size, allow_tagged): + def is_valid_pointer(pointer, pointer_size, allow_tagged=False, allow_NULL=False): if pointer == None: return False if pointer == 0: - return False - if allow_tagged: - if (pointer % 2) == 1: - return True + return allow_NULL + if allow_tagged and (pointer % 2) == 1: + return True return ((pointer % pointer_size) == 0) # Objective-C runtime has a rule that pointers in a class_t will only have bits 0 thru 46 set @@ -48,10 +31,7 @@ class Utilities: def is_allowed_pointer(pointer): if pointer == None: return False - mask = 0xFFFF800000000000 - if (pointer & mask) != 0: - return False - return True + return ((pointer & 0xFFFF800000000000) == 0) @staticmethod def read_child_of(valobj,offset,type): @@ -66,32 +46,36 @@ class Utilities: return None if len(name) == 0: return None - return True - # the rules below make perfect sense for compile-time class names, but the runtime is free - # to create classes with arbitrary names to implement functionality (e.g -poseAsClass) - # hence, we cannot really outlaw anything appearing in an identifier - #ok_first = dict.fromkeys("$ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_") - #ok_others = dict.fromkeys("$ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_1234567890") - #if name[0] not in ok_first: - # return False - #return all(c in ok_others for c in name[1:]) + # technically, the ObjC runtime does not enforce any rules about what name a class can have + # in practice, the commonly used byte values for a class name are the letters, digits and some + # symbols: $, %, -, _, . + # WARNING: this means that you cannot use this runtime implementation if you need to deal + # with class names that use anything but what is allowed here + ok_values = dict.fromkeys("$%_.-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890") + return all(c in ok_values for c in name) + + @staticmethod + def check_is_osx_lion(target): + # assume the only thing that has a Foundation.framework is a Mac + # assume anything < Lion does not even exist + mod = target.module['Foundation'] + if mod == None or mod.IsValid() == False: + return None + ver = mod.GetVersion() + if ver == None or ver == []: + return None + return (ver[0] < 900) class RoT_Data: def __init__(self,rot_pointer,params): if (Utilities.is_valid_pointer(rot_pointer.GetValueAsUnsigned(),params.pointer_size, allow_tagged=False)): self.sys_params = params self.valobj = rot_pointer - self.flags = Utilities.read_child_of(self.valobj,0,self.sys_params.uint32_t) + #self.flags = Utilities.read_child_of(self.valobj,0,self.sys_params.uint32_t) self.instanceStart = Utilities.read_child_of(self.valobj,4,self.sys_params.uint32_t) self.instanceSize = Utilities.read_child_of(self.valobj,8,self.sys_params.uint32_t) - if self.sys_params.lp64: - self.reserved = Utilities.read_child_of(self.valobj,12,self.sys_params.uint32_t) - offset = 16 - else: - self.reserved = 0 - offset = 12 - self.ivarLayoutPtr = Utilities.read_child_of(self.valobj,offset,self.sys_params.addr_ptr_type) - offset = offset + self.sys_params.pointer_size + offset = 24 if self.sys_params.is_64_bit else 16 + #self.ivarLayoutPtr = Utilities.read_child_of(self.valobj,offset,self.sys_params.addr_ptr_type) self.namePointer = Utilities.read_child_of(self.valobj,offset,self.sys_params.addr_ptr_type) self.check_valid() else: @@ -110,11 +94,9 @@ class RoT_Data: # pass def __str__(self): - return 'flags = ' + str(self.flags) + "\n" + \ + return \ "instanceStart = " + hex(self.instanceStart) + "\n" + \ "instanceSize = " + hex(self.instanceSize) + "\n" + \ - "reserved = " + hex(self.reserved) + "\n" + \ - "ivarLayoutPtr = " + hex(self.ivarLayoutPtr) + "\n" + \ "namePointer = " + hex(self.namePointer) + " --> " + self.name def is_valid(self): @@ -126,8 +108,8 @@ class RwT_Data: if (Utilities.is_valid_pointer(rwt_pointer.GetValueAsUnsigned(),params.pointer_size, allow_tagged=False)): self.sys_params = params self.valobj = rwt_pointer - self.flags = Utilities.read_child_of(self.valobj,0,self.sys_params.uint32_t) - self.version = Utilities.read_child_of(self.valobj,4,self.sys_params.uint32_t) + #self.flags = Utilities.read_child_of(self.valobj,0,self.sys_params.uint32_t) + #self.version = Utilities.read_child_of(self.valobj,4,self.sys_params.uint32_t) self.roPointer = Utilities.read_child_of(self.valobj,8,self.sys_params.addr_ptr_type) self.check_valid() else: @@ -143,8 +125,7 @@ class RwT_Data: self.valid = False def __str__(self): - return 'flags = ' + str(self.flags) + "\n" + \ - "version = " + hex(self.version) + "\n" + \ + return \ "roPointer = " + hex(self.roPointer) def is_valid(self): @@ -207,12 +188,15 @@ class Class_Data_V2: self.valid = False return + # in general, KVO is implemented by transparently subclassing + # however, there could be exceptions where a class does something else + # internally to implement the feature - this method will have no clue that a class + # has been KVO'ed unless the standard implementation technique is used def is_kvo(self): if self.is_valid(): - if self.data.data.name.startswith("NSKVONotify"): + if self.class_name().startswith("NSKVONotifying_"): return True - else: - return None + return False def get_superclass(self): if self.is_valid(): @@ -249,7 +233,7 @@ class Class_Data_V2: return None if align: unalign = self.instance_size(False) - if self.sys_params.lp64: + if self.sys_params.is_64_bit: return ((unalign + 7) & ~7) % 0x100000000 else: return ((unalign + 3) & ~3) % 0x100000000 @@ -268,13 +252,6 @@ class Class_Data_V1: self.version = Utilities.read_child_of(self.valobj,3*self.sys_params.pointer_size,self.sys_params.addr_ptr_type) self.info = Utilities.read_child_of(self.valobj,4*self.sys_params.pointer_size,self.sys_params.addr_ptr_type) self.instanceSize = Utilities.read_child_of(self.valobj,5*self.sys_params.pointer_size,self.sys_params.addr_ptr_type) - # since we do not introspect ivars, methods, ... these four pointers need not be named in a meaningful way - # moreover, we do not care about their values, just that they are correctly aligned - self.ptr1 = Utilities.read_child_of(self.valobj,6*self.sys_params.pointer_size,self.sys_params.addr_ptr_type) - self.ptr2 = Utilities.read_child_of(self.valobj,7*self.sys_params.pointer_size,self.sys_params.addr_ptr_type) - self.ptr3 = Utilities.read_child_of(self.valobj,8*self.sys_params.pointer_size,self.sys_params.addr_ptr_type) - self.ptr4 = Utilities.read_child_of(self.valobj,9*self.sys_params.pointer_size,self.sys_params.addr_ptr_type) - self.check_valid() else: self.valid = False if self.valid: @@ -293,16 +270,19 @@ class Class_Data_V1: if self.superclassIsaPointer != 0: self.valid = False return - #if not(Utilities.is_valid_pointer(self.namePointer,self.sys_params.pointer_size,allow_tagged=False)): - # self.valid = False - # return + if not(Utilities.is_valid_pointer(self.namePointer,self.sys_params.pointer_size,allow_tagged=False,allow_NULL=True)): + self.valid = False + return + # in general, KVO is implemented by transparently subclassing + # however, there could be exceptions where a class does something else + # internally to implement the feature - this method will have no clue that a class + # has been KVO'ed unless the standard implementation technique is used def is_kvo(self): if self.is_valid(): - if self.name.startswith("NSKVONotify"): + if self.class_name().startswith("NSKVONotifying_"): return True - else: - return None + return False def get_superclass(self): if self.is_valid(): @@ -338,15 +318,19 @@ class Class_Data_V1: return None if align: unalign = self.instance_size(False) - if self.sys_params.lp64: + if self.sys_params.is_64_bit: return ((unalign + 7) & ~7) % 0x100000000 else: return ((unalign + 3) & ~3) % 0x100000000 else: return self.instanceSize +TaggedClass_Values_Lion = {3 : 'NSNumber', 6: 'NSDate'}; # double check NSDate +TaggedClass_Values_NMOS = {3 : 'NSNumber', 6: 'NSDate'}; # double check NSNumber + class TaggedClass_Data: def __init__(self,pointer,params): + global TaggedClass_Values_Lion, TaggedClass_Values_NMOS self.valid = True self.name = None self.sys_params = params @@ -354,28 +338,18 @@ class TaggedClass_Data: self.val = (pointer & ~0x0000000000000000FF) >> 8 self.class_bits = (pointer & 0xE) >> 1 self.i_bits = (pointer & 0xF0) >> 4 - # ignoring the LSB, NSNumber gets marked - # as 3 on Zin and as 1 on Lion - I can either make - # a difference or accept false positives - # ToT LLDB + some knowledge of framework versioning - # would let me do the right thing - for now I just - # act dumb and accept false positives - if self.class_bits == 0 or \ - self.class_bits == 5 or \ - self.class_bits == 7 or \ - self.class_bits == 9: - self.valid = False - return - elif self.class_bits == 3 or self.class_bits == 1: - self.name = 'NSNumber' - elif self.class_bits == 11: - self.name = 'NSManagedObject' - elif self.class_bits == 13: - self.name = 'NSDate' - elif self.class_bits == 15: - self.name = 'NSDateTS' # not sure what this is + + if self.sys_params.is_lion: + if self.class_bits in TaggedClass_Values_Lion: + self.name = TaggedClass_Values_Lion[self.class_bits] + else: + self.valid = False else: - self.valid = False + if self.class_bits in TaggedClass_Values_NMOS: + self.name = TaggedClass_Values_NMOS[self.class_bits] + else: + self.valid = False + def is_valid(self): return self.valid @@ -384,7 +358,7 @@ class TaggedClass_Data: if self.is_valid(): return self.name else: - return None + return False def value(self): return self.val if self.is_valid() else None @@ -409,7 +383,7 @@ class TaggedClass_Data: def instance_size(self,align=False): if self.is_valid() == False: return None - return 8 if self.sys_params.lp64 else 4 + return 8 if self.sys_params.is_64_bit else 4 class InvalidClass_Data: @@ -419,6 +393,7 @@ class InvalidClass_Data: return False runtime_version = cache.Cache() +os_version = cache.Cache() class SystemParameters: def __init__(self,valobj): @@ -426,19 +401,25 @@ class SystemParameters: def adjust_for_architecture(self,valobj): self.process = valobj.GetTarget().GetProcess() - self.lp64 = (self.process.GetAddressByteSize() == 8) + self.is_64_bit = (self.process.GetAddressByteSize() == 8) self.is_little = (self.process.GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.process.GetAddressByteSize() self.addr_type = valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong) self.addr_ptr_type = self.addr_type.GetPointerType() self.uint32_t = valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt) global runtime_version + global os_version pid = self.process.GetProcessID() if runtime_version.look_for_key(pid): self.runtime_version = runtime_version.get_value(pid) else: self.runtime_version = ObjCRuntime.runtime_version(self.process) runtime_version.add_item(pid,self.runtime_version) + if os_version.look_for_key(pid): + self.is_lion = os_version.get_value(pid) + else: + self.is_lion = Utilities.check_is_osx_lion(valobj.GetTarget()) + os_version.add_item(pid,self.is_lion) isa_cache = cache.Cache() @@ -476,9 +457,11 @@ class ObjCRuntime: self.valobj = valobj self.adjust_for_architecture() self.sys_params = SystemParameters(self.valobj) + self.unsigned_value = self.valobj.GetValueAsUnsigned() + self.isa_value = None def adjust_for_architecture(self): - self.lp64 = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) + self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8) self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle) self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() self.addr_type = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong) @@ -488,16 +471,19 @@ class ObjCRuntime: def is_tagged(self): if self.valobj is None: return False - return (Utilities.is_valid_pointer(self.valobj.GetValueAsUnsigned(),self.pointer_size, allow_tagged=True) and not(Utilities.is_valid_pointer(self.valobj.GetValueAsUnsigned(),self.pointer_size, allow_tagged=False))) + return (Utilities.is_valid_pointer(self.unsigned_value,self.pointer_size, allow_tagged=True) and \ + not(Utilities.is_valid_pointer(self.unsigned_value,self.pointer_size, allow_tagged=False))) def is_valid(self): if self.valobj is None: return False if self.valobj.IsInScope() == False: return False - return Utilities.is_valid_pointer(self.valobj.GetValueAsUnsigned(),self.pointer_size, allow_tagged=True) + return Utilities.is_valid_pointer(self.unsigned_value,self.pointer_size, allow_tagged=True) def read_isa(self): + if self.isa_value != None: + return self.isa_value isa_pointer = self.valobj.CreateChildAtOffset("cfisa", 0, self.addr_ptr_type) @@ -505,6 +491,7 @@ class ObjCRuntime: return None; if isa_pointer.GetValueAsUnsigned(1) == 1: return None; + self.isa_value = isa_pointer return isa_pointer def read_class_data(self): @@ -515,7 +502,7 @@ class ObjCRuntime: # not every odd-valued pointer is actually tagged. most are just plain wrong # we could try and predetect this before even creating a TaggedClass_Data object # but unless performance requires it, this seems a cleaner way to tackle the task - tentative_tagged = TaggedClass_Data(self.valobj.GetValueAsUnsigned(0),self.sys_params) + tentative_tagged = TaggedClass_Data(self.unsigned_value,self.sys_params) return tentative_tagged if tentative_tagged.is_valid() else InvalidClass_Data() else: return InvalidClass_Data() |