summaryrefslogtreecommitdiff
path: root/examples/summaries/cocoa/CFString.py
diff options
context:
space:
mode:
Diffstat (limited to 'examples/summaries/cocoa/CFString.py')
-rw-r--r--examples/summaries/cocoa/CFString.py351
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()