diff options
Diffstat (limited to 'examples/summaries/cocoa/CFString.py')
| -rw-r--r-- | examples/summaries/cocoa/CFString.py | 351 |
1 files changed, 0 insertions, 351 deletions
diff --git a/examples/summaries/cocoa/CFString.py b/examples/summaries/cocoa/CFString.py deleted file mode 100644 index 109d918a9de23..0000000000000 --- a/examples/summaries/cocoa/CFString.py +++ /dev/null @@ -1,351 +0,0 @@ -""" -LLDB AppKit formatters - -part of The LLVM Compiler Infrastructure -This file is distributed under the University of Illinois Open Source -License. See LICENSE.TXT for details. -""" -# example synthetic children and summary provider for CFString (and related NSString class) -# the real code is part of the LLDB core -import lldb -import lldb.runtime.objc.objc_runtime -import lldb.formatters.Logger - - -def CFString_SummaryProvider(valobj, dict): - logger = lldb.formatters.Logger.Logger() - provider = CFStringSynthProvider(valobj, dict) - if not provider.invalid: - try: - summary = provider.get_child_at_index( - provider.get_child_index("content")) - if isinstance(summary, lldb.SBValue): - summary = summary.GetSummary() - else: - summary = '"' + summary + '"' - except: - summary = None - if summary is None: - summary = '<variable is not NSString>' - return '@' + summary - return '' - - -def CFAttributedString_SummaryProvider(valobj, dict): - logger = lldb.formatters.Logger.Logger() - offset = valobj.GetTarget().GetProcess().GetAddressByteSize() - pointee = valobj.GetValueAsUnsigned(0) - summary = '<variable is not NSAttributedString>' - if pointee is not None and pointee != 0: - pointee = pointee + offset - child_ptr = valobj.CreateValueFromAddress( - "string_ptr", pointee, valobj.GetType()) - child = child_ptr.CreateValueFromAddress( - "string_data", - child_ptr.GetValueAsUnsigned(), - valobj.GetType()).AddressOf() - provider = CFStringSynthProvider(child, dict) - if not provider.invalid: - try: - summary = provider.get_child_at_index( - provider.get_child_index("content")).GetSummary() - except: - summary = '<variable is not NSAttributedString>' - if summary is None: - summary = '<variable is not NSAttributedString>' - return '@' + summary - - -def __lldb_init_module(debugger, dict): - debugger.HandleCommand( - "type summary add -F CFString.CFString_SummaryProvider NSString CFStringRef CFMutableStringRef") - debugger.HandleCommand( - "type summary add -F CFString.CFAttributedString_SummaryProvider NSAttributedString") - - -class CFStringSynthProvider: - - def __init__(self, valobj, dict): - logger = lldb.formatters.Logger.Logger() - self.valobj = valobj - self.update() - - # children other than "content" are for debugging only and must not be - # used in production code - def num_children(self): - logger = lldb.formatters.Logger.Logger() - if self.invalid: - return 0 - return 6 - - def read_unicode(self, pointer, max_len=2048): - logger = lldb.formatters.Logger.Logger() - process = self.valobj.GetTarget().GetProcess() - error = lldb.SBError() - pystr = u'' - # cannot do the read at once because the length value has - # a weird encoding. better play it safe here - while max_len > 0: - content = process.ReadMemory(pointer, 2, error) - new_bytes = bytearray(content) - b0 = new_bytes[0] - b1 = new_bytes[1] - pointer = pointer + 2 - if b0 == 0 and b1 == 0: - break - # rearrange bytes depending on endianness - # (do we really need this or is Cocoa going to - # use Windows-compatible little-endian even - # if the target is big endian?) - if self.is_little: - value = b1 * 256 + b0 - else: - value = b0 * 256 + b1 - pystr = pystr + unichr(value) - # read max_len unicode values, not max_len bytes - max_len = max_len - 1 - return pystr - - # handle the special case strings - # only use the custom code for the tested LP64 case - def handle_special(self): - logger = lldb.formatters.Logger.Logger() - if not self.is_64_bit: - # for 32bit targets, use safe ObjC code - return self.handle_unicode_string_safe() - offset = 12 - pointer = self.valobj.GetValueAsUnsigned(0) + offset - pystr = self.read_unicode(pointer) - return self.valobj.CreateValueFromExpression( - "content", "(char*)\"" + pystr.encode('utf-8') + "\"") - - # last resort call, use ObjC code to read; the final aim is to - # be able to strip this call away entirely and only do the read - # ourselves - def handle_unicode_string_safe(self): - return self.valobj.CreateValueFromExpression( - "content", "(char*)\"" + self.valobj.GetObjectDescription() + "\"") - - def handle_unicode_string(self): - logger = lldb.formatters.Logger.Logger() - # step 1: find offset - if self.inline: - pointer = self.valobj.GetValueAsUnsigned( - 0) + self.size_of_cfruntime_base() - if not self.explicit: - # untested, use the safe code path - return self.handle_unicode_string_safe() - else: - # a full pointer is skipped here before getting to the live - # data - pointer = pointer + self.pointer_size - else: - pointer = self.valobj.GetValueAsUnsigned( - 0) + self.size_of_cfruntime_base() - # read 8 bytes here and make an address out of them - try: - char_type = self.valobj.GetType().GetBasicType( - lldb.eBasicTypeChar).GetPointerType() - vopointer = self.valobj.CreateValueFromAddress( - "dummy", pointer, char_type) - pointer = vopointer.GetValueAsUnsigned(0) - except: - return self.valobj.CreateValueFromExpression( - "content", '(char*)"@\"invalid NSString\""') - # step 2: read Unicode data at pointer - pystr = self.read_unicode(pointer) - # step 3: return it - return pystr.encode('utf-8') - - def handle_inline_explicit(self): - logger = lldb.formatters.Logger.Logger() - offset = 3 * self.pointer_size - offset = offset + self.valobj.GetValueAsUnsigned(0) - return self.valobj.CreateValueFromExpression( - "content", "(char*)(" + str(offset) + ")") - - def handle_mutable_string(self): - logger = lldb.formatters.Logger.Logger() - offset = 2 * self.pointer_size - data = self.valobj.CreateChildAtOffset( - "content", offset, self.valobj.GetType().GetBasicType( - lldb.eBasicTypeChar).GetPointerType()) - data_value = data.GetValueAsUnsigned(0) - if self.explicit and self.unicode: - return self.read_unicode(data_value).encode('utf-8') - else: - data_value = data_value + 1 - return self.valobj.CreateValueFromExpression( - "content", "(char*)(" + str(data_value) + ")") - - def handle_UTF8_inline(self): - logger = lldb.formatters.Logger.Logger() - offset = self.valobj.GetValueAsUnsigned( - 0) + self.size_of_cfruntime_base() - if not self.explicit: - offset = offset + 1 - return self.valobj.CreateValueFromAddress( - "content", offset, self.valobj.GetType().GetBasicType( - lldb.eBasicTypeChar)).AddressOf() - - def handle_UTF8_not_inline(self): - logger = lldb.formatters.Logger.Logger() - offset = self.size_of_cfruntime_base() - return self.valobj.CreateChildAtOffset( - "content", offset, self.valobj.GetType().GetBasicType( - lldb.eBasicTypeChar).GetPointerType()) - - def get_child_at_index(self, index): - logger = lldb.formatters.Logger.Logger() - logger >> "Querying for child [" + str(index) + "]" - if index == 0: - return self.valobj.CreateValueFromExpression( - "mutable", str(int(self.mutable))) - if index == 1: - return self.valobj.CreateValueFromExpression("inline", - str(int(self.inline))) - if index == 2: - return self.valobj.CreateValueFromExpression( - "explicit", str(int(self.explicit))) - if index == 3: - return self.valobj.CreateValueFromExpression( - "unicode", str(int(self.unicode))) - if index == 4: - return self.valobj.CreateValueFromExpression( - "special", str(int(self.special))) - if index == 5: - # we are handling the several possible combinations of flags. - # for each known combination we have a function that knows how to - # go fetch the data from memory instead of running code. if a string is not - # correctly displayed, one should start by finding a combination of flags that - # makes it different from these known cases, and provide a new reader function - # if this is not possible, a new flag might have to be made up (like the "special" flag - # below, which is not a real flag in CFString), or alternatively one might need to use - # the ObjC runtime helper to detect the new class and deal with it accordingly - # print 'mutable = ' + str(self.mutable) - # print 'inline = ' + str(self.inline) - # print 'explicit = ' + str(self.explicit) - # print 'unicode = ' + str(self.unicode) - # print 'special = ' + str(self.special) - if self.mutable: - return self.handle_mutable_string() - elif self.inline and self.explicit and \ - self.unicode == False and self.special == False and \ - self.mutable == False: - return self.handle_inline_explicit() - elif self.unicode: - return self.handle_unicode_string() - elif self.special: - return self.handle_special() - elif self.inline: - return self.handle_UTF8_inline() - else: - return self.handle_UTF8_not_inline() - - def get_child_index(self, name): - logger = lldb.formatters.Logger.Logger() - logger >> "Querying for child ['" + str(name) + "']" - if name == "content": - return self.num_children() - 1 - if name == "mutable": - return 0 - if name == "inline": - return 1 - if name == "explicit": - return 2 - if name == "unicode": - return 3 - if name == "special": - return 4 - - # CFRuntimeBase is defined as having an additional - # 4 bytes (padding?) on LP64 architectures - # 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): - logger = lldb.formatters.Logger.Logger() - return self.pointer_size + 4 + (4 if self.is_64_bit else 0) - - # the info bits are part of the CFRuntimeBase structure - # to get at them we have to skip a uintptr_t and then get - # at the least-significant byte of a 4 byte array. If we are - # 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): - logger = lldb.formatters.Logger.Logger() - offset = self.pointer_size - if not self.is_little: - offset = offset + 3 - return offset - - def read_info_bits(self): - logger = lldb.formatters.Logger.Logger() - cfinfo = self.valobj.CreateChildAtOffset( - "cfinfo", - self.offset_of_info_bits(), - self.valobj.GetType().GetBasicType( - lldb.eBasicTypeChar)) - cfinfo.SetFormat(11) - info = cfinfo.GetValue() - if info is not None: - self.invalid = False - return int(info, 0) - else: - self.invalid = True - return None - - # calculating internal flag bits of the CFString object - # this stuff is defined and discussed in CFString.c - def is_mutable(self): - logger = lldb.formatters.Logger.Logger() - return (self.info_bits & 1) == 1 - - def is_inline(self): - logger = lldb.formatters.Logger.Logger() - return (self.info_bits & 0x60) == 0 - - # this flag's name is ambiguous, it turns out - # we must skip a length byte to get at the data - # when this flag is False - def has_explicit_length(self): - logger = lldb.formatters.Logger.Logger() - return (self.info_bits & (1 | 4)) != 4 - - # probably a subclass of NSString. obtained this from [str pathExtension] - # here info_bits = 0 and Unicode data at the start of the padding word - # in the long run using the isa value might be safer as a way to identify this - # instead of reading the info_bits - def is_special_case(self): - logger = lldb.formatters.Logger.Logger() - return self.info_bits == 0 - - def is_unicode(self): - logger = lldb.formatters.Logger.Logger() - return (self.info_bits & 0x10) == 0x10 - - # preparing ourselves to read into memory - # by adjusting architecture-specific info - def adjust_for_architecture(self): - logger = lldb.formatters.Logger.Logger() - self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() - self.is_64_bit = self.pointer_size == 8 - self.is_little = self.valobj.GetTarget().GetProcess( - ).GetByteOrder() == lldb.eByteOrderLittle - - # reading info bits out of the CFString and computing - # useful values to get at the real data - def compute_flags(self): - logger = lldb.formatters.Logger.Logger() - self.info_bits = self.read_info_bits() - if self.info_bits is None: - return - self.mutable = self.is_mutable() - self.inline = self.is_inline() - self.explicit = self.has_explicit_length() - self.unicode = self.is_unicode() - self.special = self.is_special_case() - - def update(self): - logger = lldb.formatters.Logger.Logger() - self.adjust_for_architecture() - self.compute_flags() |
