summaryrefslogtreecommitdiffstats
path: root/gnu/llvm/lldb/examples/python/diagnose_nsstring.py
diff options
context:
space:
mode:
authorpatrick <patrick@openbsd.org>2020-08-03 14:33:06 +0000
committerpatrick <patrick@openbsd.org>2020-08-03 14:33:06 +0000
commit061da546b983eb767bad15e67af1174fb0bcf31c (patch)
tree83c78b820819d70aa40c36d90447978b300078c5 /gnu/llvm/lldb/examples/python/diagnose_nsstring.py
parentImport LLVM 10.0.0 release including clang, lld and lldb. (diff)
downloadwireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.tar.xz
wireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.zip
Import LLVM 10.0.0 release including clang, lld and lldb.
ok hackroom tested by plenty
Diffstat (limited to 'gnu/llvm/lldb/examples/python/diagnose_nsstring.py')
-rw-r--r--gnu/llvm/lldb/examples/python/diagnose_nsstring.py185
1 files changed, 185 insertions, 0 deletions
diff --git a/gnu/llvm/lldb/examples/python/diagnose_nsstring.py b/gnu/llvm/lldb/examples/python/diagnose_nsstring.py
new file mode 100644
index 00000000000..4a8eee3c2dd
--- /dev/null
+++ b/gnu/llvm/lldb/examples/python/diagnose_nsstring.py
@@ -0,0 +1,185 @@
+# This implements the "diagnose-nsstring" command, usually installed in the debug session like
+# command script import lldb.diagnose
+# it is used when NSString summary formatter fails to replicate the logic that went into LLDB making the
+# decisions it did and providing some useful context information that can
+# be used for improving the formatter
+
+from __future__ import print_function
+
+import lldb
+
+
+def read_memory(process, location, size):
+ data = ""
+ error = lldb.SBError()
+ for x in range(0, size - 1):
+ byte = process.ReadUnsignedFromMemory(x + location, 1, error)
+ if error.fail:
+ data = data + "err%s" % "" if x == size - 2 else ":"
+ else:
+ try:
+ data = data + "0x%x" % byte
+ if byte == 0:
+ data = data + "(\\0)"
+ elif byte == 0xa:
+ data = data + "(\\a)"
+ elif byte == 0xb:
+ data = data + "(\\b)"
+ elif byte == 0xc:
+ data = data + "(\\c)"
+ elif byte == '\n':
+ data = data + "(\\n)"
+ else:
+ data = data + "(%s)" % chr(byte)
+ if x < size - 2:
+ data = data + ":"
+ except Exception as e:
+ print(e)
+ return data
+
+
+def diagnose_nsstring_Command_Impl(debugger, command, result, internal_dict):
+ """
+ A command to diagnose the LLDB NSString data formatter
+ invoke as
+ (lldb) diagnose-nsstring <expr returning NSString>
+ e.g.
+ (lldb) diagnose-nsstring @"Hello world"
+ """
+ target = debugger.GetSelectedTarget()
+ process = target.GetProcess()
+ thread = process.GetSelectedThread()
+ frame = thread.GetSelectedFrame()
+ if not target.IsValid() or not process.IsValid():
+ return "unable to get target/process - cannot proceed"
+ options = lldb.SBExpressionOptions()
+ options.SetFetchDynamicValue()
+ error = lldb.SBError()
+ if frame.IsValid():
+ nsstring = frame.EvaluateExpression(command, options)
+ else:
+ nsstring = target.EvaluateExpression(command, options)
+ print(str(nsstring), file=result)
+ nsstring_address = nsstring.GetValueAsUnsigned(0)
+ if nsstring_address == 0:
+ return "unable to obtain the string - cannot proceed"
+ expression = "\
+struct $__lldb__notInlineMutable {\
+ char* buffer;\
+ signed long length;\
+ signed long capacity;\
+ unsigned int hasGap:1;\
+ unsigned int isFixedCapacity:1;\
+ unsigned int isExternalMutable:1;\
+ unsigned int capacityProvidedExternally:1;\n\
+#if __LP64__\n\
+ unsigned long desiredCapacity:60;\n\
+#else\n\
+ unsigned long desiredCapacity:28;\n\
+#endif\n\
+ void* contentsAllocator;\
+};\
+\
+struct $__lldb__CFString {\
+ void* _cfisa;\
+ uint8_t _cfinfo[4];\
+ uint32_t _rc;\
+ union {\
+ struct __inline1 {\
+ signed long length;\
+ } inline1;\
+ struct __notInlineImmutable1 {\
+ char* buffer;\
+ signed long length;\
+ void* contentsDeallocator;\
+ } notInlineImmutable1;\
+ struct __notInlineImmutable2 {\
+ char* buffer;\
+ void* contentsDeallocator;\
+ } notInlineImmutable2;\
+ struct $__lldb__notInlineMutable notInlineMutable;\
+ } variants;\
+};\
+"
+
+ expression = expression + "*(($__lldb__CFString*) %d)" % nsstring_address
+ # print expression
+ dumped = target.EvaluateExpression(expression, options)
+ print(str(dumped), file=result)
+
+ little_endian = (target.byte_order == lldb.eByteOrderLittle)
+ ptr_size = target.addr_size
+
+ info_bits = dumped.GetChildMemberWithName("_cfinfo").GetChildAtIndex(
+ 0 if little_endian else 3).GetValueAsUnsigned(0)
+ is_mutable = (info_bits & 1) == 1
+ is_inline = (info_bits & 0x60) == 0
+ has_explicit_length = (info_bits & (1 | 4)) != 4
+ is_unicode = (info_bits & 0x10) == 0x10
+ is_special = (
+ nsstring.GetDynamicValue(
+ lldb.eDynamicCanRunTarget).GetTypeName() == "NSPathStore2")
+ has_null = (info_bits & 8) == 8
+
+ print("\nInfo=%d\nMutable=%s\nInline=%s\nExplicit=%s\nUnicode=%s\nSpecial=%s\nNull=%s\n" % \
+ (info_bits, "yes" if is_mutable else "no", "yes" if is_inline else "no", "yes" if has_explicit_length else "no", "yes" if is_unicode else "no", "yes" if is_special else "no", "yes" if has_null else "no"), file=result)
+
+ explicit_length_offset = 0
+ if not has_null and has_explicit_length and not is_special:
+ explicit_length_offset = 2 * ptr_size
+ if is_mutable and not is_inline:
+ explicit_length_offset = explicit_length_offset + ptr_size
+ elif is_inline:
+ pass
+ elif not is_inline and not is_mutable:
+ explicit_length_offset = explicit_length_offset + ptr_size
+ else:
+ explicit_length_offset = 0
+
+ if explicit_length_offset == 0:
+ print("There is no explicit length marker - skipping this step\n", file=result)
+ else:
+ explicit_length_offset = nsstring_address + explicit_length_offset
+ explicit_length = process.ReadUnsignedFromMemory(
+ explicit_length_offset, 4, error)
+ print("Explicit length location is at 0x%x - read value is %d\n" % (
+ explicit_length_offset, explicit_length), file=result)
+
+ if is_mutable:
+ location = 2 * ptr_size + nsstring_address
+ location = process.ReadPointerFromMemory(location, error)
+ elif is_inline and has_explicit_length and not is_unicode and not is_special and not is_mutable:
+ location = 3 * ptr_size + nsstring_address
+ elif is_unicode:
+ location = 2 * ptr_size + nsstring_address
+ if is_inline:
+ if not has_explicit_length:
+ print("Unicode & Inline & !Explicit is a new combo - no formula for it", file=result)
+ else:
+ location += ptr_size
+ else:
+ location = process.ReadPointerFromMemory(location, error)
+ elif is_special:
+ location = nsstring_address + ptr_size + 4
+ elif is_inline:
+ location = 2 * ptr_size + nsstring_address
+ if not has_explicit_length:
+ location += 1
+ else:
+ location = 2 * ptr_size + nsstring_address
+ location = process.ReadPointerFromMemory(location, error)
+ print("Expected data location: 0x%x\n" % (location), file=result)
+ print("1K of data around location: %s\n" % read_memory(
+ process, location, 1024), file=result)
+ print("5K of data around string pointer: %s\n" % read_memory(
+ process, nsstring_address, 1024 * 5), file=result)
+
+
+def __lldb_init_module(debugger, internal_dict):
+ debugger.HandleCommand(
+ "command script add -f %s.diagnose_nsstring_Command_Impl diagnose-nsstring" %
+ __name__)
+ print('The "diagnose-nsstring" command has been installed, type "help diagnose-nsstring" for detailed help.')
+
+__lldb_init_module(lldb.debugger, None)
+__lldb_init_module = None