This commit:
a) adds a Python summary provider for NSDate
b) changes the initialization for ScriptInterpreter so that we are not passing a bulk of Python-specific function pointers around
c) provides a new ScriptInterpreterObject class that allows for ref-count safe wrapping of scripting objects on the C++ side
d) contains much needed performance improvements:
1) the pointer to the Python function generating a scripted summary is now cached instead of looked up every time
2) redundant memory reads in the Python ObjC runtime wrapper are eliminated
3) summaries now use the m_summary_str in ValueObject to store their data instead of passing around ( == copying) an std::string object
e) contains other minor fixes, such as adding descriptive error messages for some cases of summary generation failure
llvm-svn: 151703
This commit is contained in:
parent
3203f6b9da
commit
7bc0ec3aad
30 changed files with 871 additions and 456 deletions
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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 ''
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
171
lldb/examples/summaries/cocoa/NSDate.py
Normal file
171
lldb/examples/summaries/cocoa/NSDate.py
Normal file
|
|
@ -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")
|
||||
|
||||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ''
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -1158,8 +1158,9 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
virtual std::string
|
||||
FormatObject (lldb::ValueObjectSP object) = 0;
|
||||
virtual bool
|
||||
FormatObject (lldb::ValueObjectSP object,
|
||||
std::string& dest) = 0;
|
||||
|
||||
virtual std::string
|
||||
GetDescription () = 0;
|
||||
|
|
@ -1211,8 +1212,9 @@ struct StringSummaryFormat : public TypeSummaryImpl
|
|||
{
|
||||
}
|
||||
|
||||
virtual std::string
|
||||
FormatObject(lldb::ValueObjectSP object);
|
||||
virtual bool
|
||||
FormatObject(lldb::ValueObjectSP object,
|
||||
std::string& dest);
|
||||
|
||||
virtual std::string
|
||||
GetDescription();
|
||||
|
|
@ -1232,6 +1234,7 @@ struct ScriptSummaryFormat : public TypeSummaryImpl
|
|||
{
|
||||
std::string m_function_name;
|
||||
std::string m_python_script;
|
||||
lldb::ScriptInterpreterObjectSP m_script_function_sp;
|
||||
|
||||
ScriptSummaryFormat(const TypeSummaryImpl::Flags& flags,
|
||||
const char *function_name,
|
||||
|
|
@ -1273,8 +1276,9 @@ struct ScriptSummaryFormat : public TypeSummaryImpl
|
|||
{
|
||||
}
|
||||
|
||||
virtual std::string
|
||||
FormatObject(lldb::ValueObjectSP object);
|
||||
virtual bool
|
||||
FormatObject(lldb::ValueObjectSP object,
|
||||
std::string& dest);
|
||||
|
||||
virtual std::string
|
||||
GetDescription();
|
||||
|
|
|
|||
|
|
@ -20,6 +20,43 @@
|
|||
|
||||
namespace lldb_private {
|
||||
|
||||
class ScriptInterpreterObject
|
||||
{
|
||||
public:
|
||||
ScriptInterpreterObject() :
|
||||
m_object(NULL)
|
||||
{}
|
||||
|
||||
ScriptInterpreterObject(void* obj) :
|
||||
m_object(obj)
|
||||
{}
|
||||
|
||||
ScriptInterpreterObject(const ScriptInterpreterObject& rhs)
|
||||
: m_object(rhs.m_object)
|
||||
{}
|
||||
|
||||
virtual void*
|
||||
GetObject()
|
||||
{
|
||||
return m_object;
|
||||
}
|
||||
|
||||
ScriptInterpreterObject&
|
||||
operator = (const ScriptInterpreterObject& rhs)
|
||||
{
|
||||
if (this != &rhs)
|
||||
m_object = rhs.m_object;
|
||||
return *this;
|
||||
}
|
||||
|
||||
virtual
|
||||
~ScriptInterpreterObject()
|
||||
{}
|
||||
|
||||
protected:
|
||||
void* m_object;
|
||||
};
|
||||
|
||||
class ScriptInterpreter
|
||||
{
|
||||
public:
|
||||
|
|
@ -31,9 +68,11 @@ public:
|
|||
const lldb::StackFrameSP& frame_sp,
|
||||
const lldb::BreakpointLocationSP &bp_loc_sp);
|
||||
|
||||
typedef std::string (*SWIGPythonTypeScriptCallbackFunction) (const char *python_function_name,
|
||||
const char *session_dictionary_name,
|
||||
const lldb::ValueObjectSP& valobj_sp);
|
||||
typedef bool (*SWIGPythonTypeScriptCallbackFunction) (const char *python_function_name,
|
||||
void *session_dictionary,
|
||||
const lldb::ValueObjectSP& valobj_sp,
|
||||
void** pyfunct_wrapper,
|
||||
std::string& retval);
|
||||
|
||||
typedef void* (*SWIGPythonCreateSyntheticProvider) (const std::string python_class_name,
|
||||
const char *session_dictionary_name,
|
||||
|
|
@ -163,6 +202,15 @@ public:
|
|||
return;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
GetScriptedSummary (const char *function_name,
|
||||
lldb::ValueObjectSP valobj,
|
||||
lldb::ScriptInterpreterObjectSP& callee_wrapper_sp,
|
||||
std::string& retval)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual uint32_t
|
||||
CalculateNumChildren (void *implementor)
|
||||
{
|
||||
|
|
@ -211,6 +259,12 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
virtual lldb::ScriptInterpreterObjectSP
|
||||
MakeScriptObject (void* object)
|
||||
{
|
||||
return lldb::ScriptInterpreterObjectSP(new ScriptInterpreterObject(object));
|
||||
}
|
||||
|
||||
const char *
|
||||
GetScriptInterpreterPtyName ();
|
||||
|
||||
|
|
@ -224,17 +278,7 @@ public:
|
|||
LanguageToString (lldb::ScriptLanguage language);
|
||||
|
||||
static void
|
||||
InitializeInterpreter (SWIGInitCallback python_swig_init_callback,
|
||||
SWIGBreakpointCallbackFunction python_swig_breakpoint_callback,
|
||||
SWIGPythonTypeScriptCallbackFunction python_swig_typescript_callback,
|
||||
SWIGPythonCreateSyntheticProvider python_swig_synthetic_script,
|
||||
SWIGPythonCalculateNumChildren python_swig_calc_children,
|
||||
SWIGPythonGetChildAtIndex python_swig_get_child_index,
|
||||
SWIGPythonGetIndexOfChildWithName python_swig_get_index_child,
|
||||
SWIGPythonCastPyObjectToSBValue python_swig_cast_to_sbvalue,
|
||||
SWIGPythonUpdateSynthProviderInstance python_swig_update_provider,
|
||||
SWIGPythonCallCommand python_swig_call_command,
|
||||
SWIGPythonCallModuleInit python_swig_call_mod_init);
|
||||
InitializeInterpreter (SWIGInitCallback python_swig_init_callback);
|
||||
|
||||
static void
|
||||
TerminateInterpreter ();
|
||||
|
|
|
|||
|
|
@ -113,9 +113,11 @@ public:
|
|||
lldb::user_id_t break_id,
|
||||
lldb::user_id_t break_loc_id);
|
||||
|
||||
static std::string
|
||||
CallPythonScriptFunction (const char *python_function_name,
|
||||
lldb::ValueObjectSP valobj);
|
||||
virtual bool
|
||||
GetScriptedSummary (const char *function_name,
|
||||
lldb::ValueObjectSP valobj,
|
||||
lldb::ScriptInterpreterObjectSP& callee_wrapper_sp,
|
||||
std::string& retval);
|
||||
|
||||
virtual std::string
|
||||
GetDocumentationForItem (const char* item);
|
||||
|
|
@ -124,7 +126,10 @@ public:
|
|||
LoadScriptingModule (const char* filename,
|
||||
bool can_reload,
|
||||
lldb_private::Error& error);
|
||||
|
||||
|
||||
virtual lldb::ScriptInterpreterObjectSP
|
||||
MakeScriptObject (void* object);
|
||||
|
||||
void
|
||||
CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options,
|
||||
CommandReturnObject &result);
|
||||
|
|
@ -147,17 +152,7 @@ public:
|
|||
InitializePrivate ();
|
||||
|
||||
static void
|
||||
InitializeInterpreter (SWIGInitCallback python_swig_init_callback,
|
||||
SWIGBreakpointCallbackFunction python_swig_breakpoint_callback,
|
||||
SWIGPythonTypeScriptCallbackFunction python_swig_typescript_callback,
|
||||
SWIGPythonCreateSyntheticProvider python_swig_synthetic_script,
|
||||
SWIGPythonCalculateNumChildren python_swig_calc_children,
|
||||
SWIGPythonGetChildAtIndex python_swig_get_child_index,
|
||||
SWIGPythonGetIndexOfChildWithName python_swig_get_index_child,
|
||||
SWIGPythonCastPyObjectToSBValue python_swig_cast_to_sbvalue,
|
||||
SWIGPythonUpdateSynthProviderInstance python_swig_update_provider,
|
||||
SWIGPythonCallCommand python_swig_call_command,
|
||||
SWIGPythonCallModuleInit python_swig_call_mod_init);
|
||||
InitializeInterpreter (SWIGInitCallback python_swig_init_callback);
|
||||
|
||||
protected:
|
||||
|
||||
|
|
@ -187,6 +182,29 @@ private:
|
|||
~SynchronicityHandler();
|
||||
};
|
||||
|
||||
class ScriptInterpreterPythonObject : public ScriptInterpreterObject
|
||||
{
|
||||
public:
|
||||
ScriptInterpreterPythonObject() :
|
||||
ScriptInterpreterObject()
|
||||
{}
|
||||
|
||||
ScriptInterpreterPythonObject(void* obj) :
|
||||
ScriptInterpreterObject(obj)
|
||||
{
|
||||
Py_XINCREF(m_object);
|
||||
}
|
||||
|
||||
virtual
|
||||
~ScriptInterpreterPythonObject()
|
||||
{
|
||||
Py_XDECREF(m_object);
|
||||
m_object = NULL;
|
||||
}
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN (ScriptInterpreterPythonObject);
|
||||
};
|
||||
|
||||
class Locker
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -136,6 +136,7 @@ class RegisterValue;
|
|||
class RegularExpression;
|
||||
class Scalar;
|
||||
class ScriptInterpreter;
|
||||
class ScriptInterpreterObject;
|
||||
#ifndef LLDB_DISABLE_PYTHON
|
||||
class ScriptInterpreterPython;
|
||||
struct ScriptSummaryFormat;
|
||||
|
|
@ -276,6 +277,7 @@ namespace lldb {
|
|||
typedef std::tr1::shared_ptr<lldb_private::Section> SectionSP;
|
||||
typedef std::tr1::weak_ptr<lldb_private::Section> SectionWP;
|
||||
typedef std::tr1::shared_ptr<lldb_private::SearchFilter> SearchFilterSP;
|
||||
typedef std::tr1::shared_ptr<lldb_private::ScriptInterpreterObject> ScriptInterpreterObjectSP;
|
||||
#ifndef LLDB_DISABLE_PYTHON
|
||||
typedef std::tr1::shared_ptr<lldb_private::ScriptSummaryFormat> ScriptSummaryFormatSP;
|
||||
#endif // #ifndef LLDB_DISABLE_PYTHON
|
||||
|
|
|
|||
|
|
@ -382,6 +382,20 @@ else
|
|||
fi
|
||||
fi
|
||||
|
||||
if [ -f "${SRC_ROOT}/examples/summaries/cocoa/NSDate.py" ]
|
||||
then
|
||||
if [ $Debug == 1 ]
|
||||
then
|
||||
echo "Copying NSDate.py to ${framework_python_dir}"
|
||||
fi
|
||||
cp "${SRC_ROOT}/examples/summaries/cocoa/NSDate.py" "${framework_python_dir}"
|
||||
else
|
||||
if [ $Debug == 1 ]
|
||||
then
|
||||
echo "Unable to find ${SRC_ROOT}/examples/summaries/cocoa/NSDate.py"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -f "${SRC_ROOT}/examples/summaries/cocoa/cache.py" ]
|
||||
then
|
||||
if [ $Debug == 1 ]
|
||||
|
|
|
|||
|
|
@ -31,10 +31,7 @@ static PyObject*
|
|||
ResolvePythonName(const char* name,
|
||||
PyObject* pmodule = NULL)
|
||||
{
|
||||
|
||||
//printf("Resolving %s\n", name);
|
||||
|
||||
if (!name || !name[0])
|
||||
if (!name)
|
||||
return pmodule;
|
||||
|
||||
PyErr_Cleaner pyerr_cleanup(true); // show Python errors
|
||||
|
|
@ -65,40 +62,33 @@ ResolvePythonName(const char* name,
|
|||
|
||||
if (!dot_pos)
|
||||
{
|
||||
if (PyDict_Check (main_dict))
|
||||
dest_object = NULL;
|
||||
while (PyDict_Next (main_dict, &pos, &key, &value))
|
||||
{
|
||||
dest_object = NULL;
|
||||
while (PyDict_Next (main_dict, &pos, &key, &value))
|
||||
// We have stolen references to the key and value objects in the dictionary; we need to increment
|
||||
// them now so that Python's garbage collector doesn't collect them out from under us.
|
||||
Py_INCREF (key);
|
||||
Py_INCREF (value);
|
||||
if (strcmp (PyString_AsString (key), name) == 0)
|
||||
{
|
||||
// We have stolen references to the key and value objects in the dictionary; we need to increment
|
||||
// them now so that Python's garbage collector doesn't collect them out from under us.
|
||||
Py_INCREF (key);
|
||||
Py_INCREF (value);
|
||||
//printf("Comparing %s and %s\n", name, PyString_AsString (key));
|
||||
if (strcmp (PyString_AsString (key), name) == 0)
|
||||
{
|
||||
dest_object = value;
|
||||
break;
|
||||
}
|
||||
dest_object = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (!dest_object || dest_object == Py_None)
|
||||
return NULL;
|
||||
return dest_object;
|
||||
}
|
||||
// foo.bar.ba
|
||||
// 0123456789
|
||||
// len = 3 - 0
|
||||
size_t len = dot_pos - name;
|
||||
std::string piece(name,len);
|
||||
dest_object = ResolvePythonName(piece.c_str(), main_dict);
|
||||
//printf("Resolved %s to %p\n", piece.c_str(), dest_object);
|
||||
if (!dest_object)
|
||||
return NULL;
|
||||
//printf("Now moving to resolve %s\n", dot_pos+1);
|
||||
return ResolvePythonName(dot_pos+1,dest_object); // tail recursion.. should be optimized by the compiler
|
||||
|
||||
else
|
||||
{
|
||||
size_t len = dot_pos - name;
|
||||
std::string piece(name,len);
|
||||
pmodule = ResolvePythonName(piece.c_str(), main_dict);
|
||||
if (!pmodule)
|
||||
return NULL;
|
||||
name = dot_pos+1;
|
||||
return ResolvePythonName(dot_pos+1,pmodule); // tail recursion.. should be optimized by the compiler
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
|
|
@ -186,85 +176,69 @@ LLDBSwigPythonBreakpointCallbackFunction
|
|||
return stop_at_breakpoint;
|
||||
}
|
||||
|
||||
SWIGEXPORT std::string
|
||||
SWIGEXPORT bool
|
||||
LLDBSwigPythonCallTypeScript
|
||||
(
|
||||
const char *python_function_name,
|
||||
const char *session_dictionary_name,
|
||||
const lldb::ValueObjectSP& valobj_sp
|
||||
const void *session_dictionary,
|
||||
const lldb::ValueObjectSP& valobj_sp,
|
||||
void** pyfunct_wrapper,
|
||||
std::string& retval
|
||||
)
|
||||
{
|
||||
lldb::SBValue sb_value (valobj_sp);
|
||||
|
||||
std::string retval = "";
|
||||
|
||||
PyObject *ValObj_PyObj = SWIG_NewPointerObj((void *) &sb_value, SWIGTYPE_p_lldb__SBValue, 0);
|
||||
|
||||
if (ValObj_PyObj == NULL)
|
||||
return retval;
|
||||
return false;
|
||||
|
||||
if (!python_function_name || !session_dictionary_name)
|
||||
return retval;
|
||||
if (!python_function_name || !session_dictionary)
|
||||
return false;
|
||||
|
||||
PyObject *session_dict, *pfunc;
|
||||
PyObject *pargs, *pvalue;
|
||||
PyObject *session_dict = (PyObject*)session_dictionary, *pfunc = NULL, *pargs = NULL, *pvalue = NULL;
|
||||
|
||||
session_dict = FindSessionDictionary (session_dictionary_name);
|
||||
if (session_dict != NULL)
|
||||
if (pyfunct_wrapper && *pyfunct_wrapper && PyFunction_Check (*pyfunct_wrapper))
|
||||
{
|
||||
pfunc = ResolvePythonName (python_function_name, session_dict);
|
||||
if (pfunc != NULL)
|
||||
pfunc = (PyObject*)(*pyfunct_wrapper);
|
||||
if (pfunc->ob_refcnt == 1)
|
||||
{
|
||||
// Set up the arguments and call the function.
|
||||
|
||||
if (PyCallable_Check (pfunc))
|
||||
{
|
||||
pargs = PyTuple_New (2);
|
||||
if (pargs == NULL)
|
||||
{
|
||||
if (PyErr_Occurred())
|
||||
PyErr_Clear();
|
||||
return retval;
|
||||
}
|
||||
|
||||
PyTuple_SetItem (pargs, 0, ValObj_PyObj); // This "steals" a reference to ValObj_PyObj
|
||||
PyTuple_SetItem (pargs, 1, session_dict); // This "steals" a reference to session_dict
|
||||
pvalue = PyObject_CallObject (pfunc, pargs);
|
||||
Py_DECREF (pargs);
|
||||
|
||||
if (pvalue != NULL)
|
||||
{
|
||||
if (pvalue != Py_None && PyString_CheckExact(pvalue))
|
||||
retval = std::string(PyString_AsString(pvalue));
|
||||
else
|
||||
retval = "None";
|
||||
Py_DECREF (pvalue);
|
||||
}
|
||||
else if (PyErr_Occurred ())
|
||||
{
|
||||
PyErr_Print();
|
||||
PyErr_Clear();
|
||||
}
|
||||
Py_INCREF (session_dict);
|
||||
}
|
||||
else if (PyErr_Occurred())
|
||||
{
|
||||
PyErr_Print();
|
||||
PyErr_Clear();
|
||||
}
|
||||
}
|
||||
else if (PyErr_Occurred())
|
||||
{
|
||||
PyErr_Print();
|
||||
PyErr_Clear();
|
||||
Py_XDECREF(pfunc);
|
||||
pfunc = NULL;
|
||||
}
|
||||
}
|
||||
else if (PyErr_Occurred ())
|
||||
|
||||
if (PyDict_Check(session_dict))
|
||||
{
|
||||
PyErr_Print();
|
||||
PyErr_Clear ();
|
||||
PyErr_Cleaner pyerr_cleanup(true); // show Python errors
|
||||
|
||||
if (!pfunc)
|
||||
{
|
||||
pfunc = ResolvePythonName (python_function_name, session_dict);
|
||||
if (!pfunc || !PyFunction_Check (pfunc))
|
||||
return false;
|
||||
else
|
||||
{
|
||||
if (pyfunct_wrapper)
|
||||
*pyfunct_wrapper = pfunc;
|
||||
}
|
||||
}
|
||||
/*else
|
||||
printf("caching works!!!!\n");*/
|
||||
|
||||
pargs = PyTuple_Pack(2, ValObj_PyObj, session_dict);
|
||||
if (pargs == NULL)
|
||||
return false;
|
||||
|
||||
pvalue = PyObject_CallObject (pfunc, pargs);
|
||||
Py_DECREF (pargs);
|
||||
|
||||
if (pvalue != NULL && pvalue != Py_None && PyString_Check(pvalue))
|
||||
retval.assign(PyString_AsString(pvalue));
|
||||
Py_XDECREF (pvalue);
|
||||
Py_INCREF (session_dict);
|
||||
}
|
||||
return retval;
|
||||
return true;
|
||||
}
|
||||
|
||||
SWIGEXPORT void*
|
||||
|
|
|
|||
|
|
@ -312,59 +312,11 @@ SBCommandInterpreter::GetArgumentDescriptionAsCString (const lldb::CommandArgume
|
|||
|
||||
|
||||
#ifndef LLDB_DISABLE_PYTHON
|
||||
extern "C" bool
|
||||
LLDBSwigPythonBreakpointCallbackFunction
|
||||
(
|
||||
const char *python_function_name,
|
||||
const char *session_dictionary_name,
|
||||
const lldb::StackFrameSP& sb_frame,
|
||||
const lldb::BreakpointLocationSP& sb_bp_loc
|
||||
);
|
||||
|
||||
extern "C" std::string
|
||||
LLDBSwigPythonCallTypeScript
|
||||
(
|
||||
const char *python_function_name,
|
||||
const char *session_dictionary_name,
|
||||
const lldb::ValueObjectSP& valobj_sp
|
||||
);
|
||||
|
||||
extern "C" void*
|
||||
LLDBSwigPythonCreateSyntheticProvider
|
||||
(
|
||||
const std::string python_class_name,
|
||||
const char *session_dictionary_name,
|
||||
const lldb::ValueObjectSP& valobj_sp
|
||||
);
|
||||
|
||||
|
||||
extern "C" uint32_t LLDBSwigPython_CalculateNumChildren (void *implementor);
|
||||
extern "C" void* LLDBSwigPython_GetChildAtIndex (void *implementor, uint32_t idx);
|
||||
extern "C" int LLDBSwigPython_GetIndexOfChildWithName (void *implementor, const char* child_name);
|
||||
extern "C" void* LLDBSWIGPython_CastPyObjectToSBValue (void* data);
|
||||
extern "C" void LLDBSwigPython_UpdateSynthProviderInstance (void* implementor);
|
||||
|
||||
extern "C" bool LLDBSwigPythonCallCommand
|
||||
(
|
||||
const char *python_function_name,
|
||||
const char *session_dictionary_name,
|
||||
lldb::DebuggerSP& debugger,
|
||||
const char* args,
|
||||
std::string& err_msg,
|
||||
lldb_private::CommandReturnObject& cmd_retobj
|
||||
);
|
||||
|
||||
// Defined in the SWIG source file
|
||||
extern "C" void
|
||||
init_lldb(void);
|
||||
|
||||
extern "C" bool LLDBSwigPythonCallModuleInit
|
||||
(
|
||||
const std::string python_module_name,
|
||||
const char *session_dictionary_name,
|
||||
lldb::DebuggerSP& debugger
|
||||
);
|
||||
|
||||
#else
|
||||
|
||||
extern "C" void init_lldb(void);
|
||||
|
|
@ -385,17 +337,7 @@ SBCommandInterpreter::InitializeSWIG ()
|
|||
{
|
||||
g_initialized = true;
|
||||
#ifndef LLDB_DISABLE_PYTHON
|
||||
ScriptInterpreter::InitializeInterpreter (init_lldb,
|
||||
LLDBSwigPythonBreakpointCallbackFunction,
|
||||
LLDBSwigPythonCallTypeScript,
|
||||
LLDBSwigPythonCreateSyntheticProvider,
|
||||
LLDBSwigPython_CalculateNumChildren,
|
||||
LLDBSwigPython_GetChildAtIndex,
|
||||
LLDBSwigPython_GetIndexOfChildWithName,
|
||||
LLDBSWIGPython_CastPyObjectToSBValue,
|
||||
LLDBSwigPython_UpdateSynthProviderInstance,
|
||||
LLDBSwigPythonCallCommand,
|
||||
LLDBSwigPythonCallModuleInit);
|
||||
ScriptInterpreter::InitializeInterpreter (init_lldb);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ struct PyObject;
|
|||
#include "lldb/Core/Debugger.h"
|
||||
#include "lldb/Core/FormatClasses.h"
|
||||
#include "lldb/Core/StreamString.h"
|
||||
#include "lldb/Core/Timer.h"
|
||||
#include "lldb/Core/ValueObjectConstResult.h"
|
||||
#include "lldb/Interpreter/CommandInterpreter.h"
|
||||
#include "lldb/Symbol/ClangASTType.h"
|
||||
|
|
@ -78,11 +79,15 @@ StringSummaryFormat::StringSummaryFormat(const TypeSummaryImpl::Flags& flags,
|
|||
m_format.assign(format_cstr);
|
||||
}
|
||||
|
||||
std::string
|
||||
StringSummaryFormat::FormatObject(lldb::ValueObjectSP object)
|
||||
bool
|
||||
StringSummaryFormat::FormatObject(lldb::ValueObjectSP object,
|
||||
std::string& retval)
|
||||
{
|
||||
if (!object.get())
|
||||
return "NULL";
|
||||
{
|
||||
retval.assign("NULL sp");
|
||||
return false;
|
||||
}
|
||||
|
||||
StreamString s;
|
||||
ExecutionContext exe_ctx (object->GetExecutionContextRef());
|
||||
|
|
@ -117,18 +122,28 @@ StringSummaryFormat::FormatObject(lldb::ValueObjectSP object)
|
|||
|
||||
s.PutChar(')');
|
||||
|
||||
return s.GetString();
|
||||
retval.assign(s.GetString());
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return "";
|
||||
{
|
||||
retval.assign("error: oneliner for no children");
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Debugger::FormatPrompt(m_format.c_str(), &sc, &exe_ctx, &sc.line_entry.range.GetBaseAddress(), s, NULL, object.get()))
|
||||
return s.GetString();
|
||||
{
|
||||
retval.assign(s.GetString());
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return "";
|
||||
{
|
||||
retval.assign("error: summary string parsing error");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -156,7 +171,8 @@ ScriptSummaryFormat::ScriptSummaryFormat(const TypeSummaryImpl::Flags& flags,
|
|||
const char * python_script) :
|
||||
TypeSummaryImpl(flags),
|
||||
m_function_name(),
|
||||
m_python_script()
|
||||
m_python_script(),
|
||||
m_script_function_sp()
|
||||
{
|
||||
if (function_name)
|
||||
m_function_name.assign(function_name);
|
||||
|
|
@ -164,11 +180,26 @@ ScriptSummaryFormat::ScriptSummaryFormat(const TypeSummaryImpl::Flags& flags,
|
|||
m_python_script.assign(python_script);
|
||||
}
|
||||
|
||||
std::string
|
||||
ScriptSummaryFormat::FormatObject(lldb::ValueObjectSP object)
|
||||
bool
|
||||
ScriptSummaryFormat::FormatObject(lldb::ValueObjectSP object,
|
||||
std::string& retval)
|
||||
{
|
||||
return std::string(ScriptInterpreterPython::CallPythonScriptFunction(m_function_name.c_str(),
|
||||
object).c_str());
|
||||
Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
|
||||
|
||||
Debugger& dbg = object->GetTargetSP()->GetDebugger();
|
||||
ScriptInterpreter *script_interpreter = dbg.GetCommandInterpreter().GetScriptInterpreter();
|
||||
|
||||
if (!script_interpreter)
|
||||
{
|
||||
retval.assign("error: no ScriptInterpreter");
|
||||
return false;
|
||||
}
|
||||
|
||||
return script_interpreter->GetScriptedSummary(m_function_name.c_str(),
|
||||
object,
|
||||
m_script_function_sp,
|
||||
retval);
|
||||
|
||||
}
|
||||
|
||||
std::string
|
||||
|
|
|
|||
|
|
@ -854,6 +854,8 @@ FormatManager::LoadObjCFormatters()
|
|||
AddScriptSummary(appkit_category_sp, "NSURL.NSURL_SummaryProvider", ConstString("NSURL"), appkit_flags);
|
||||
AddScriptSummary(appkit_category_sp, "NSURL.NSURL_SummaryProvider", ConstString("CFURLRef"), appkit_flags);
|
||||
|
||||
AddScriptSummary(appkit_category_sp, "NSDate.NSDate_SummaryProvider", ConstString("NSDate"), appkit_flags);
|
||||
|
||||
TypeCategoryImpl::SharedPointer vectors_category_sp = GetCategory(m_vectortypes_category_name);
|
||||
|
||||
TypeSummaryImpl::Flags vector_flags;
|
||||
|
|
|
|||
|
|
@ -674,7 +674,8 @@ ValueObject::GetSummaryAsCString ()
|
|||
|
||||
if (summary_format)
|
||||
{
|
||||
m_summary_str = summary_format->FormatObject(GetSP());
|
||||
summary_format->FormatObject(GetSP(),
|
||||
m_summary_str);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -69,30 +69,10 @@ ScriptInterpreter::LanguageToString (lldb::ScriptLanguage language)
|
|||
}
|
||||
|
||||
void
|
||||
ScriptInterpreter::InitializeInterpreter (SWIGInitCallback python_swig_init_callback,
|
||||
SWIGBreakpointCallbackFunction python_swig_breakpoint_callback,
|
||||
SWIGPythonTypeScriptCallbackFunction python_swig_typescript_callback,
|
||||
SWIGPythonCreateSyntheticProvider python_swig_synthetic_script,
|
||||
SWIGPythonCalculateNumChildren python_swig_calc_children,
|
||||
SWIGPythonGetChildAtIndex python_swig_get_child_index,
|
||||
SWIGPythonGetIndexOfChildWithName python_swig_get_index_child,
|
||||
SWIGPythonCastPyObjectToSBValue python_swig_cast_to_sbvalue,
|
||||
SWIGPythonUpdateSynthProviderInstance python_swig_update_provider,
|
||||
SWIGPythonCallCommand python_swig_call_command,
|
||||
SWIGPythonCallModuleInit python_swig_call_mod_init)
|
||||
ScriptInterpreter::InitializeInterpreter (SWIGInitCallback python_swig_init_callback)
|
||||
{
|
||||
#ifndef LLDB_DISABLE_PYTHON
|
||||
ScriptInterpreterPython::InitializeInterpreter (python_swig_init_callback,
|
||||
python_swig_breakpoint_callback,
|
||||
python_swig_typescript_callback,
|
||||
python_swig_synthetic_script,
|
||||
python_swig_calc_children,
|
||||
python_swig_get_child_index,
|
||||
python_swig_get_index_child,
|
||||
python_swig_cast_to_sbvalue,
|
||||
python_swig_update_provider,
|
||||
python_swig_call_command,
|
||||
python_swig_call_mod_init);
|
||||
ScriptInterpreterPython::InitializeInterpreter (python_swig_init_callback);
|
||||
#endif // #ifndef LLDB_DISABLE_PYTHON
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -54,6 +54,62 @@ static ScriptInterpreter::SWIGPythonUpdateSynthProviderInstance g_swig_update_pr
|
|||
static ScriptInterpreter::SWIGPythonCallCommand g_swig_call_command = NULL;
|
||||
static ScriptInterpreter::SWIGPythonCallModuleInit g_swig_call_module_init = NULL;
|
||||
|
||||
// these are the Pythonic implementations of the required callbacks
|
||||
// these are scripting-language specific, which is why they belong here
|
||||
// we still need to use function pointers to them instead of relying
|
||||
// on linkage-time resolution because the SWIG stuff and this file
|
||||
// get built at different times
|
||||
extern "C" bool
|
||||
LLDBSwigPythonBreakpointCallbackFunction
|
||||
(
|
||||
const char *python_function_name,
|
||||
const char *session_dictionary_name,
|
||||
const lldb::StackFrameSP& sb_frame,
|
||||
const lldb::BreakpointLocationSP& sb_bp_loc
|
||||
);
|
||||
|
||||
extern "C" bool
|
||||
LLDBSwigPythonCallTypeScript
|
||||
(
|
||||
const char *python_function_name,
|
||||
void *session_dictionary,
|
||||
const lldb::ValueObjectSP& valobj_sp,
|
||||
void** pyfunct_wrapper,
|
||||
std::string& retval
|
||||
);
|
||||
|
||||
extern "C" void*
|
||||
LLDBSwigPythonCreateSyntheticProvider
|
||||
(
|
||||
const std::string python_class_name,
|
||||
const char *session_dictionary_name,
|
||||
const lldb::ValueObjectSP& valobj_sp
|
||||
);
|
||||
|
||||
|
||||
extern "C" uint32_t LLDBSwigPython_CalculateNumChildren (void *implementor);
|
||||
extern "C" void* LLDBSwigPython_GetChildAtIndex (void *implementor, uint32_t idx);
|
||||
extern "C" int LLDBSwigPython_GetIndexOfChildWithName (void *implementor, const char* child_name);
|
||||
extern "C" void* LLDBSWIGPython_CastPyObjectToSBValue (void* data);
|
||||
extern "C" void LLDBSwigPython_UpdateSynthProviderInstance (void* implementor);
|
||||
|
||||
extern "C" bool LLDBSwigPythonCallCommand
|
||||
(
|
||||
const char *python_function_name,
|
||||
const char *session_dictionary_name,
|
||||
lldb::DebuggerSP& debugger,
|
||||
const char* args,
|
||||
std::string& err_msg,
|
||||
lldb_private::CommandReturnObject& cmd_retobj
|
||||
);
|
||||
|
||||
extern "C" bool LLDBSwigPythonCallModuleInit
|
||||
(
|
||||
const std::string python_module_name,
|
||||
const char *session_dictionary_name,
|
||||
lldb::DebuggerSP& debugger
|
||||
);
|
||||
|
||||
static int
|
||||
_check_and_flush (FILE *stream)
|
||||
{
|
||||
|
|
@ -226,7 +282,7 @@ ScriptInterpreterPython::ScriptInterpreterPython (CommandInterpreter &interprete
|
|||
// WARNING: temporary code that loads Cocoa formatters - this should be done on a per-platform basis rather than loading the whole set
|
||||
// and letting the individual formatter classes exploit APIs to check whether they can/cannot do their task
|
||||
run_string.Clear();
|
||||
run_string.Printf ("run_one_line (%s, 'import CFString, CFArray, CFDictionary, NSData, NSMachPort, NSSet, NSNotification, NSException, CFBag, CFBinaryHeap, NSURL, NSBundle, NSNumber')", m_dictionary_name.c_str());
|
||||
run_string.Printf ("run_one_line (%s, 'import CFString, CFArray, CFDictionary, NSData, NSMachPort, NSSet, NSNotification, NSException, CFBag, CFBinaryHeap, NSURL, NSBundle, NSNumber, NSDate')", m_dictionary_name.c_str());
|
||||
PyRun_SimpleString (run_string.GetData());
|
||||
|
||||
int new_count = Debugger::TestDebuggerRefCount();
|
||||
|
|
@ -1454,44 +1510,88 @@ ScriptInterpreterPython::GenerateBreakpointCommandCallbackData (StringList &user
|
|||
return true;
|
||||
}
|
||||
|
||||
std::string
|
||||
ScriptInterpreterPython::CallPythonScriptFunction (const char *python_function_name,
|
||||
lldb::ValueObjectSP valobj)
|
||||
static PyObject*
|
||||
FindSessionDictionary(const char* dict_name)
|
||||
{
|
||||
static std::map<ConstString,PyObject*> g_dict_map;
|
||||
|
||||
ConstString dict(dict_name);
|
||||
|
||||
std::map<ConstString,PyObject*>::iterator iter = g_dict_map.find(dict);
|
||||
|
||||
if (iter != g_dict_map.end())
|
||||
return iter->second;
|
||||
|
||||
PyObject *main_mod = PyImport_AddModule ("__main__");
|
||||
if (main_mod != NULL)
|
||||
{
|
||||
PyObject *main_dict = PyModule_GetDict (main_mod);
|
||||
if ((main_dict != NULL)
|
||||
&& PyDict_Check (main_dict))
|
||||
{
|
||||
// Go through the main dictionary looking for the correct python script interpreter dictionary
|
||||
PyObject *key, *value;
|
||||
Py_ssize_t pos = 0;
|
||||
|
||||
while (PyDict_Next (main_dict, &pos, &key, &value))
|
||||
{
|
||||
// We have stolen references to the key and value objects in the dictionary; we need to increment
|
||||
// them now so that Python's garbage collector doesn't collect them out from under us.
|
||||
Py_INCREF (key);
|
||||
Py_INCREF (value);
|
||||
if (strcmp (PyString_AsString (key), dict_name) == 0)
|
||||
{
|
||||
g_dict_map[dict] = value;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
ScriptInterpreterPython::GetScriptedSummary (const char *python_function_name,
|
||||
lldb::ValueObjectSP valobj,
|
||||
lldb::ScriptInterpreterObjectSP& callee_wrapper_sp,
|
||||
std::string& retval)
|
||||
{
|
||||
|
||||
if (!python_function_name || !(*python_function_name))
|
||||
return "<no function>";
|
||||
Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
|
||||
|
||||
if (!valobj.get())
|
||||
return "<no object>";
|
||||
{
|
||||
retval.assign("<no object>");
|
||||
return false;
|
||||
}
|
||||
|
||||
ExecutionContext exe_ctx (valobj->GetExecutionContextRef());
|
||||
Target *target = exe_ctx.GetTargetPtr();
|
||||
|
||||
if (!target)
|
||||
return "<no target>";
|
||||
|
||||
Debugger &debugger = target->GetDebugger();
|
||||
ScriptInterpreter *script_interpreter = debugger.GetCommandInterpreter().GetScriptInterpreter();
|
||||
ScriptInterpreterPython *python_interpreter = (ScriptInterpreterPython *) script_interpreter;
|
||||
|
||||
if (!script_interpreter)
|
||||
return "<no python>";
|
||||
|
||||
std::string ret_val;
|
||||
void* old_callee = (callee_wrapper_sp ? callee_wrapper_sp->GetObject() : NULL);
|
||||
void* new_callee = old_callee;
|
||||
|
||||
bool ret_val;
|
||||
if (python_function_name
|
||||
&& *python_function_name)
|
||||
{
|
||||
{
|
||||
Locker py_lock(python_interpreter);
|
||||
ret_val = g_swig_typescript_callback (python_function_name,
|
||||
python_interpreter->m_dictionary_name.c_str(),
|
||||
valobj);
|
||||
Locker py_lock(this);
|
||||
{
|
||||
Timer scoped_timer ("g_swig_typescript_callback","g_swig_typescript_callback");
|
||||
ret_val = g_swig_typescript_callback (python_function_name,
|
||||
FindSessionDictionary(m_dictionary_name.c_str()),
|
||||
valobj,
|
||||
&new_callee,
|
||||
retval);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
return "<no function name>";
|
||||
{
|
||||
retval.assign("<no function name>");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (new_callee && old_callee != new_callee)
|
||||
callee_wrapper_sp = MakeScriptObject(new_callee);
|
||||
|
||||
return ret_val;
|
||||
|
||||
|
|
@ -1822,6 +1922,12 @@ ScriptInterpreterPython::LoadScriptingModule (const char* pathname,
|
|||
}
|
||||
}
|
||||
|
||||
lldb::ScriptInterpreterObjectSP
|
||||
ScriptInterpreterPython::MakeScriptObject (void* object)
|
||||
{
|
||||
return lldb::ScriptInterpreterObjectSP(new ScriptInterpreterPythonObject(object));
|
||||
}
|
||||
|
||||
ScriptInterpreterPython::SynchronicityHandler::SynchronicityHandler (lldb::DebuggerSP debugger_sp,
|
||||
ScriptedCommandSynchronicity synchro) :
|
||||
m_debugger_sp(debugger_sp),
|
||||
|
|
@ -1914,29 +2020,19 @@ ScriptInterpreterPython::GetDocumentationForItem(const char* item)
|
|||
}
|
||||
|
||||
void
|
||||
ScriptInterpreterPython::InitializeInterpreter (SWIGInitCallback python_swig_init_callback,
|
||||
SWIGBreakpointCallbackFunction python_swig_breakpoint_callback,
|
||||
SWIGPythonTypeScriptCallbackFunction python_swig_typescript_callback,
|
||||
SWIGPythonCreateSyntheticProvider python_swig_synthetic_script,
|
||||
SWIGPythonCalculateNumChildren python_swig_calc_children,
|
||||
SWIGPythonGetChildAtIndex python_swig_get_child_index,
|
||||
SWIGPythonGetIndexOfChildWithName python_swig_get_index_child,
|
||||
SWIGPythonCastPyObjectToSBValue python_swig_cast_to_sbvalue,
|
||||
SWIGPythonUpdateSynthProviderInstance python_swig_update_provider,
|
||||
SWIGPythonCallCommand python_swig_call_command,
|
||||
SWIGPythonCallModuleInit python_swig_call_mod_init)
|
||||
ScriptInterpreterPython::InitializeInterpreter (SWIGInitCallback python_swig_init_callback)
|
||||
{
|
||||
g_swig_init_callback = python_swig_init_callback;
|
||||
g_swig_breakpoint_callback = python_swig_breakpoint_callback;
|
||||
g_swig_typescript_callback = python_swig_typescript_callback;
|
||||
g_swig_synthetic_script = python_swig_synthetic_script;
|
||||
g_swig_calc_children = python_swig_calc_children;
|
||||
g_swig_get_child_index = python_swig_get_child_index;
|
||||
g_swig_get_index_child = python_swig_get_index_child;
|
||||
g_swig_cast_to_sbvalue = python_swig_cast_to_sbvalue;
|
||||
g_swig_update_provider = python_swig_update_provider;
|
||||
g_swig_call_command = python_swig_call_command;
|
||||
g_swig_call_module_init = python_swig_call_mod_init;
|
||||
g_swig_breakpoint_callback = LLDBSwigPythonBreakpointCallbackFunction;
|
||||
g_swig_typescript_callback = LLDBSwigPythonCallTypeScript;
|
||||
g_swig_synthetic_script = LLDBSwigPythonCreateSyntheticProvider;
|
||||
g_swig_calc_children = LLDBSwigPython_CalculateNumChildren;
|
||||
g_swig_get_child_index = LLDBSwigPython_GetChildAtIndex;
|
||||
g_swig_get_index_child = LLDBSwigPython_GetIndexOfChildWithName;
|
||||
g_swig_cast_to_sbvalue = LLDBSWIGPython_CastPyObjectToSBValue;
|
||||
g_swig_update_provider = LLDBSwigPython_UpdateSynthProviderInstance;
|
||||
g_swig_call_command = LLDBSwigPythonCallCommand;
|
||||
g_swig_call_module_init = LLDBSwigPythonCallModuleInit;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ class ObjCDataFormatterTestCase(TestBase):
|
|||
self.buildDsym()
|
||||
self.plain_data_formatter_commands()
|
||||
|
||||
@unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
|
||||
def test_plain_objc_with_dwarf_and_run_command(self):
|
||||
"""Test basic ObjC formatting behavior."""
|
||||
self.buildDwarf()
|
||||
|
|
@ -28,6 +29,7 @@ class ObjCDataFormatterTestCase(TestBase):
|
|||
self.buildDsym()
|
||||
self.appkit_data_formatter_commands()
|
||||
|
||||
@unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
|
||||
def test_appkit_with_dwarf_and_run_command(self):
|
||||
"""Test formatters for AppKit classes."""
|
||||
self.buildDwarf()
|
||||
|
|
@ -39,11 +41,24 @@ class ObjCDataFormatterTestCase(TestBase):
|
|||
self.buildDsym()
|
||||
self.cf_data_formatter_commands()
|
||||
|
||||
@unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
|
||||
def test_coreframeworks_with_dwarf_and_run_command(self):
|
||||
"""Test formatters for Core OSX frameworks."""
|
||||
self.buildDwarf()
|
||||
self.cf_data_formatter_commands()
|
||||
|
||||
@unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
|
||||
def test_kvo_with_dsym_and_run_command(self):
|
||||
"""Test the behavior of formatters when KVO is in use."""
|
||||
self.buildDsym()
|
||||
self.kvo_data_formatter_commands()
|
||||
|
||||
@unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
|
||||
def test_kvo_with_dwarf_and_run_command(self):
|
||||
"""Test the behavior of formatters when KVO is in use."""
|
||||
self.buildDwarf()
|
||||
self.kvo_data_formatter_commands()
|
||||
|
||||
def setUp(self):
|
||||
# Call super's setUp().
|
||||
TestBase.setUp(self)
|
||||
|
|
@ -153,7 +168,6 @@ class ObjCDataFormatterTestCase(TestBase):
|
|||
self.runCmd('type category disable CoreServices', check=False)
|
||||
self.runCmd('type category disable AppKit', check=False)
|
||||
|
||||
|
||||
# Execute the cleanup function during test case tear down.
|
||||
self.addTearDownHook(cleanup)
|
||||
|
||||
|
|
@ -189,13 +203,13 @@ class ObjCDataFormatterTestCase(TestBase):
|
|||
'(NSString *) str12 = ',' @"Process Name: a.out Process Id:'])
|
||||
|
||||
self.expect('frame variable newArray newDictionary newMutableDictionary cfdict_ref mutable_dict_ref cfarray_ref mutable_array_ref',
|
||||
substrs = ['(NSArray *) newArray = ',' size=50',
|
||||
substrs = ['(NSArray *) newArray = ',' 50 objects',
|
||||
'(NSDictionary *) newDictionary = ',' 12 key/value pairs',
|
||||
'(NSDictionary *) newMutableDictionary = ',' 21 key/value pairs',
|
||||
'(CFDictionaryRef) cfdict_ref = ',' 3 key/value pairs',
|
||||
'(CFMutableDictionaryRef) mutable_dict_ref = ',' 12 key/value pairs',
|
||||
'(CFArrayRef) cfarray_ref = ',' size=3',
|
||||
'(CFMutableArrayRef) mutable_array_ref = ',' size=11'])
|
||||
'(CFArrayRef) cfarray_ref = ',' 3 objects',
|
||||
'(CFMutableArrayRef) mutable_array_ref = ',' 11 objects'])
|
||||
|
||||
self.expect('frame variable attrString mutableAttrString mutableGetConst',
|
||||
substrs = ['(NSAttributedString *) attrString = ',' @"hello world from foo"',
|
||||
|
|
@ -278,6 +292,7 @@ class ObjCDataFormatterTestCase(TestBase):
|
|||
self.runCmd('type category disable CoreGraphics', check=False)
|
||||
self.runCmd('type category disable CoreServices', check=False)
|
||||
self.runCmd('type category disable AppKit', check=False)
|
||||
self.runCmd('log timers disable', check=False)
|
||||
|
||||
|
||||
# Execute the cleanup function during test case tear down.
|
||||
|
|
@ -287,6 +302,8 @@ class ObjCDataFormatterTestCase(TestBase):
|
|||
self.runCmd('type category enable CoreFoundation')
|
||||
self.runCmd('type category enable CoreGraphics')
|
||||
self.runCmd('type category enable CoreServices')
|
||||
self.runCmd("type category enable AppKit")
|
||||
self.runCmd("log timers enable")
|
||||
self.expect("frame variable",
|
||||
substrs = ['(CFGregorianUnits) cf_greg_units = 1 years, 3 months, 5 days, 12 hours, 5 minutes 7 seconds',
|
||||
'(CFRange) cf_range = location=4 length=4',
|
||||
|
|
@ -307,9 +324,60 @@ class ObjCDataFormatterTestCase(TestBase):
|
|||
'(Point) point = (v=7, h=12)',
|
||||
'(Point *) point_ptr = (v=7, h=12)',
|
||||
'(HIPoint) hi_point = (x=7, y=12)',
|
||||
'(HIRect) hi_rect = origin=(x=3, y=5) size=(width=4, height=6)'])
|
||||
'(HIRect) hi_rect = origin=(x=3, y=5) size=(width=4, height=6)',
|
||||
'@"TheGuyWhoHasNoName" @"cuz it\'s funny"'])
|
||||
self.runCmd('log timers dump')
|
||||
|
||||
|
||||
def kvo_data_formatter_commands(self):
|
||||
"""Test the behavior of formatters when KVO is in use."""
|
||||
self.runCmd("file a.out", CURRENT_EXECUTABLE_SET)
|
||||
|
||||
self.expect("breakpoint set -f main.m -l %d" % self.line,
|
||||
BREAKPOINT_CREATED,
|
||||
startstr = "Breakpoint created: 1: file ='main.m', line = %d, locations = 1" %
|
||||
self.line)
|
||||
|
||||
self.runCmd("run", RUN_SUCCEEDED)
|
||||
|
||||
# The stop reason of the thread should be breakpoint.
|
||||
self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
|
||||
substrs = ['stopped',
|
||||
'stop reason = breakpoint'])
|
||||
|
||||
# This is the function to remove the custom formats in order to have a
|
||||
# clean slate for the next test case.
|
||||
def cleanup():
|
||||
self.runCmd('type format clear', check=False)
|
||||
self.runCmd('type summary clear', check=False)
|
||||
self.runCmd('type synth clear', check=False)
|
||||
self.runCmd('type category disable CoreFoundation', check=False)
|
||||
self.runCmd('type category disable CoreGraphics', check=False)
|
||||
self.runCmd('type category disable CoreServices', check=False)
|
||||
self.runCmd('type category disable AppKit', check=False)
|
||||
|
||||
|
||||
# Execute the cleanup function during test case tear down.
|
||||
self.addTearDownHook(cleanup)
|
||||
|
||||
# check formatters for common Objective-C types
|
||||
self.runCmd('type category enable AppKit')
|
||||
|
||||
# as long as KVO is implemented by subclassing, this test should succeed
|
||||
# we should be able to dynamically figure out that the KVO implementor class
|
||||
# is a subclass of Molecule, and use the appropriate summary for it
|
||||
self.runCmd("type summary add -s JustAMoleculeHere Molecule")
|
||||
self.expect('frame variable molecule', substrs = ['JustAMoleculeHere'])
|
||||
self.runCmd("next")
|
||||
self.expect("thread list",
|
||||
substrs = ['stopped',
|
||||
'step over'])
|
||||
self.expect('frame variable molecule', substrs = ['JustAMoleculeHere'])
|
||||
|
||||
self.runCmd("next")
|
||||
# check that NSMutableDictionary's formatter is not confused when dealing with a KVO'd dictionary
|
||||
self.expect('frame variable newMutableDictionary', substrs = ['(NSDictionary *) newMutableDictionary = ',' 21 key/value pairs'])
|
||||
|
||||
if __name__ == '__main__':
|
||||
import atexit
|
||||
lldb.SBDebugger.Initialize()
|
||||
|
|
|
|||
|
|
@ -66,6 +66,70 @@
|
|||
|
||||
@end
|
||||
|
||||
@interface Atom : NSObject {
|
||||
float mass;
|
||||
}
|
||||
-(void)setMass:(float)newMass;
|
||||
-(float)mass;
|
||||
@end
|
||||
|
||||
@interface Molecule : NSObject {
|
||||
NSArray *atoms;
|
||||
}
|
||||
-(void)setAtoms:(NSArray *)newAtoms;
|
||||
-(NSArray *)atoms;
|
||||
@end
|
||||
|
||||
@implementation Atom
|
||||
|
||||
-(void)setMass:(float)newMass
|
||||
{
|
||||
mass = newMass;
|
||||
}
|
||||
-(float)mass
|
||||
{
|
||||
return mass;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation Molecule
|
||||
|
||||
-(void)setAtoms:(NSArray *)newAtoms
|
||||
{
|
||||
atoms = newAtoms;
|
||||
}
|
||||
-(NSArray *)atoms
|
||||
{
|
||||
return atoms;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface My_KVO_Observer : NSObject
|
||||
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change
|
||||
context:(void *)context;
|
||||
- (id) init;
|
||||
- (void) dealloc;
|
||||
@end
|
||||
|
||||
@implementation My_KVO_Observer
|
||||
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change
|
||||
context:(void *)context {
|
||||
// we do not really care about KVO'ing - do nothing
|
||||
return;
|
||||
}
|
||||
- (id) init
|
||||
{
|
||||
self = [super init];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[super dealloc];
|
||||
}
|
||||
@end
|
||||
|
||||
int main (int argc, const char * argv[])
|
||||
{
|
||||
|
||||
|
|
@ -479,7 +543,16 @@ int main (int argc, const char * argv[])
|
|||
HIPoint hi_point = {7,12};
|
||||
HIRect hi_rect = {{3,5},{4,6}};
|
||||
|
||||
Molecule *molecule = [Molecule new];
|
||||
|
||||
// Set break point at this line.
|
||||
|
||||
[molecule addObserver:[My_KVO_Observer new] forKeyPath:@"atoms" options:0 context:NULL];
|
||||
[newMutableDictionary addObserver:[My_KVO_Observer new] forKeyPath:@"weirdKeyToKVO" options:NSKeyValueObservingOptionNew context:NULL];
|
||||
|
||||
[molecule setAtoms:nil];
|
||||
[molecule setAtoms:[NSMutableArray new]];
|
||||
|
||||
[pool drain];
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue