1ea6c96105f3830441fbad6404280c12561733a03Enrico Granata# This implements the "diagnose-nsstring" command, usually installed in the debug session like 2ea6c96105f3830441fbad6404280c12561733a03Enrico Granata# command script import lldb.diagnose 3ea6c96105f3830441fbad6404280c12561733a03Enrico Granata# it is used when NSString summary formatter fails to replicate the logic that went into LLDB making the 4ea6c96105f3830441fbad6404280c12561733a03Enrico Granata# decisions it did and providing some useful context information that can be used for improving the formatter 5ea6c96105f3830441fbad6404280c12561733a03Enrico Granata 6ea6c96105f3830441fbad6404280c12561733a03Enrico Granataimport lldb 7ea6c96105f3830441fbad6404280c12561733a03Enrico Granata 8ea6c96105f3830441fbad6404280c12561733a03Enrico Granatadef read_memory(process,location,size): 9ea6c96105f3830441fbad6404280c12561733a03Enrico Granata data = "" 10ea6c96105f3830441fbad6404280c12561733a03Enrico Granata error = lldb.SBError() 11ea6c96105f3830441fbad6404280c12561733a03Enrico Granata for x in range(0,size-1): 12ea6c96105f3830441fbad6404280c12561733a03Enrico Granata byte = process.ReadUnsignedFromMemory(x+location,1,error) 13ea6c96105f3830441fbad6404280c12561733a03Enrico Granata if error.fail: 14ea6c96105f3830441fbad6404280c12561733a03Enrico Granata data = data + "err%s" % "" if x == size-2 else ":" 15ea6c96105f3830441fbad6404280c12561733a03Enrico Granata else: 16ea6c96105f3830441fbad6404280c12561733a03Enrico Granata try: 17ea6c96105f3830441fbad6404280c12561733a03Enrico Granata data = data + "0x%x" % byte 18ea6c96105f3830441fbad6404280c12561733a03Enrico Granata if byte == 0: 19ea6c96105f3830441fbad6404280c12561733a03Enrico Granata data = data + "(\\0)" 20ea6c96105f3830441fbad6404280c12561733a03Enrico Granata elif byte == 0xa: 21ea6c96105f3830441fbad6404280c12561733a03Enrico Granata data = data + "(\\a)" 22ea6c96105f3830441fbad6404280c12561733a03Enrico Granata elif byte == 0xb: 23ea6c96105f3830441fbad6404280c12561733a03Enrico Granata data = data + "(\\b)" 24ea6c96105f3830441fbad6404280c12561733a03Enrico Granata elif byte == 0xc: 25ea6c96105f3830441fbad6404280c12561733a03Enrico Granata data = data + "(\\c)" 26ea6c96105f3830441fbad6404280c12561733a03Enrico Granata elif byte == '\n': 27ea6c96105f3830441fbad6404280c12561733a03Enrico Granata data = data + "(\\n)" 28ea6c96105f3830441fbad6404280c12561733a03Enrico Granata else: 29ea6c96105f3830441fbad6404280c12561733a03Enrico Granata data = data + "(%s)" % chr(byte) 30ea6c96105f3830441fbad6404280c12561733a03Enrico Granata if x < size-2: 31ea6c96105f3830441fbad6404280c12561733a03Enrico Granata data = data + ":" 32ea6c96105f3830441fbad6404280c12561733a03Enrico Granata except Exception as e: 33ea6c96105f3830441fbad6404280c12561733a03Enrico Granata print e 34ea6c96105f3830441fbad6404280c12561733a03Enrico Granata return data 35ea6c96105f3830441fbad6404280c12561733a03Enrico Granata 36ea6c96105f3830441fbad6404280c12561733a03Enrico Granatadef diagnose_nsstring_Command_Impl(debugger,command,result,internal_dict): 37ea6c96105f3830441fbad6404280c12561733a03Enrico Granata """ 38ea6c96105f3830441fbad6404280c12561733a03Enrico Granata A command to diagnose the LLDB NSString data formatter 39ea6c96105f3830441fbad6404280c12561733a03Enrico Granata invoke as 40ea6c96105f3830441fbad6404280c12561733a03Enrico Granata (lldb) diagnose-nsstring <expr returning NSString> 41ea6c96105f3830441fbad6404280c12561733a03Enrico Granata e.g. 42ea6c96105f3830441fbad6404280c12561733a03Enrico Granata (lldb) diagnose-nsstring @"Hello world" 43ea6c96105f3830441fbad6404280c12561733a03Enrico Granata """ 44ea6c96105f3830441fbad6404280c12561733a03Enrico Granata target = debugger.GetSelectedTarget() 45ea6c96105f3830441fbad6404280c12561733a03Enrico Granata process = target.GetProcess() 46ea6c96105f3830441fbad6404280c12561733a03Enrico Granata thread = process.GetSelectedThread() 47ea6c96105f3830441fbad6404280c12561733a03Enrico Granata frame = thread.GetSelectedFrame() 48ea6c96105f3830441fbad6404280c12561733a03Enrico Granata if not target.IsValid() or not process.IsValid(): 49ea6c96105f3830441fbad6404280c12561733a03Enrico Granata return "unable to get target/process - cannot proceed" 50ea6c96105f3830441fbad6404280c12561733a03Enrico Granata options = lldb.SBExpressionOptions() 51ea6c96105f3830441fbad6404280c12561733a03Enrico Granata options.SetFetchDynamicValue() 52ea6c96105f3830441fbad6404280c12561733a03Enrico Granata error = lldb.SBError() 53ea6c96105f3830441fbad6404280c12561733a03Enrico Granata if frame.IsValid(): 54ea6c96105f3830441fbad6404280c12561733a03Enrico Granata nsstring = frame.EvaluateExpression(command,options) 55ea6c96105f3830441fbad6404280c12561733a03Enrico Granata else: 56ea6c96105f3830441fbad6404280c12561733a03Enrico Granata nsstring = target.EvaluateExpression(command,options) 57ea6c96105f3830441fbad6404280c12561733a03Enrico Granata print >>result,str(nsstring) 58ea6c96105f3830441fbad6404280c12561733a03Enrico Granata nsstring_address = nsstring.GetValueAsUnsigned(0) 59ea6c96105f3830441fbad6404280c12561733a03Enrico Granata if nsstring_address == 0: 60ea6c96105f3830441fbad6404280c12561733a03Enrico Granata return "unable to obtain the string - cannot proceed" 61ea6c96105f3830441fbad6404280c12561733a03Enrico Granata expression = "\ 62ea6c96105f3830441fbad6404280c12561733a03Enrico Granatastruct $__lldb__notInlineMutable {\ 63ea6c96105f3830441fbad6404280c12561733a03Enrico Granata char* buffer;\ 64ea6c96105f3830441fbad6404280c12561733a03Enrico Granata signed long length;\ 65ea6c96105f3830441fbad6404280c12561733a03Enrico Granata signed long capacity;\ 66ea6c96105f3830441fbad6404280c12561733a03Enrico Granata unsigned int hasGap:1;\ 67ea6c96105f3830441fbad6404280c12561733a03Enrico Granata unsigned int isFixedCapacity:1;\ 68ea6c96105f3830441fbad6404280c12561733a03Enrico Granata unsigned int isExternalMutable:1;\ 69ea6c96105f3830441fbad6404280c12561733a03Enrico Granata unsigned int capacityProvidedExternally:1;\n\ 70ea6c96105f3830441fbad6404280c12561733a03Enrico Granata#if __LP64__\n\ 71ea6c96105f3830441fbad6404280c12561733a03Enrico Granata unsigned long desiredCapacity:60;\n\ 72ea6c96105f3830441fbad6404280c12561733a03Enrico Granata#else\n\ 73ea6c96105f3830441fbad6404280c12561733a03Enrico Granata unsigned long desiredCapacity:28;\n\ 74ea6c96105f3830441fbad6404280c12561733a03Enrico Granata#endif\n\ 75ea6c96105f3830441fbad6404280c12561733a03Enrico Granata void* contentsAllocator;\ 76ea6c96105f3830441fbad6404280c12561733a03Enrico Granata};\ 77ea6c96105f3830441fbad6404280c12561733a03Enrico Granata\ 78ea6c96105f3830441fbad6404280c12561733a03Enrico Granatastruct $__lldb__CFString {\ 79ea6c96105f3830441fbad6404280c12561733a03Enrico Granata void* _cfisa;\ 80ea6c96105f3830441fbad6404280c12561733a03Enrico Granata uint8_t _cfinfo[4];\ 81ea6c96105f3830441fbad6404280c12561733a03Enrico Granata uint32_t _rc;\ 82ea6c96105f3830441fbad6404280c12561733a03Enrico Granata union {\ 83ea6c96105f3830441fbad6404280c12561733a03Enrico Granata struct __inline1 {\ 84ea6c96105f3830441fbad6404280c12561733a03Enrico Granata signed long length;\ 85ea6c96105f3830441fbad6404280c12561733a03Enrico Granata } inline1;\ 86ea6c96105f3830441fbad6404280c12561733a03Enrico Granata struct __notInlineImmutable1 {\ 87ea6c96105f3830441fbad6404280c12561733a03Enrico Granata char* buffer;\ 88ea6c96105f3830441fbad6404280c12561733a03Enrico Granata signed long length;\ 89ea6c96105f3830441fbad6404280c12561733a03Enrico Granata void* contentsDeallocator;\ 90ea6c96105f3830441fbad6404280c12561733a03Enrico Granata } notInlineImmutable1;\ 91ea6c96105f3830441fbad6404280c12561733a03Enrico Granata struct __notInlineImmutable2 {\ 92ea6c96105f3830441fbad6404280c12561733a03Enrico Granata char* buffer;\ 93ea6c96105f3830441fbad6404280c12561733a03Enrico Granata void* contentsDeallocator;\ 94ea6c96105f3830441fbad6404280c12561733a03Enrico Granata } notInlineImmutable2;\ 95ea6c96105f3830441fbad6404280c12561733a03Enrico Granata struct $__lldb__notInlineMutable notInlineMutable;\ 96ea6c96105f3830441fbad6404280c12561733a03Enrico Granata } variants;\ 97ea6c96105f3830441fbad6404280c12561733a03Enrico Granata};\ 98ea6c96105f3830441fbad6404280c12561733a03Enrico Granata" 99ea6c96105f3830441fbad6404280c12561733a03Enrico Granata 100ea6c96105f3830441fbad6404280c12561733a03Enrico Granata expression = expression + "*(($__lldb__CFString*) %d)" % nsstring_address 101ea6c96105f3830441fbad6404280c12561733a03Enrico Granata # print expression 102ea6c96105f3830441fbad6404280c12561733a03Enrico Granata dumped = target.EvaluateExpression(expression,options) 103ea6c96105f3830441fbad6404280c12561733a03Enrico Granata print >>result, str(dumped) 104ea6c96105f3830441fbad6404280c12561733a03Enrico Granata 105ea6c96105f3830441fbad6404280c12561733a03Enrico Granata little_endian = (target.byte_order == lldb.eByteOrderLittle) 106ea6c96105f3830441fbad6404280c12561733a03Enrico Granata ptr_size = target.addr_size 107ea6c96105f3830441fbad6404280c12561733a03Enrico Granata 108ea6c96105f3830441fbad6404280c12561733a03Enrico Granata info_bits = dumped.GetChildMemberWithName("_cfinfo").GetChildAtIndex(0 if little_endian else 3).GetValueAsUnsigned(0) 109ea6c96105f3830441fbad6404280c12561733a03Enrico Granata is_mutable = (info_bits & 1) == 1 110ea6c96105f3830441fbad6404280c12561733a03Enrico Granata is_inline = (info_bits & 0x60) == 0 111ea6c96105f3830441fbad6404280c12561733a03Enrico Granata has_explicit_length = (info_bits & (1 | 4)) != 4 112ea6c96105f3830441fbad6404280c12561733a03Enrico Granata is_unicode = (info_bits & 0x10) == 0x10 113ea6c96105f3830441fbad6404280c12561733a03Enrico Granata is_special = (nsstring.GetDynamicValue(lldb.eDynamicCanRunTarget).GetTypeName() == "NSPathStore2") 114ea6c96105f3830441fbad6404280c12561733a03Enrico Granata has_null = (info_bits & 8) == 8 115ea6c96105f3830441fbad6404280c12561733a03Enrico Granata 116ea6c96105f3830441fbad6404280c12561733a03Enrico Granata print >>result,"\nInfo=%d\nMutable=%s\nInline=%s\nExplicit=%s\nUnicode=%s\nSpecial=%s\nNull=%s\n" % \ 117ea6c96105f3830441fbad6404280c12561733a03Enrico Granata (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") 118ea6c96105f3830441fbad6404280c12561733a03Enrico Granata 119ea6c96105f3830441fbad6404280c12561733a03Enrico Granata 120ea6c96105f3830441fbad6404280c12561733a03Enrico Granata explicit_length_offset = 0 121ea6c96105f3830441fbad6404280c12561733a03Enrico Granata if not has_null and has_explicit_length and not is_special: 122ea6c96105f3830441fbad6404280c12561733a03Enrico Granata explicit_length_offset = 2*ptr_size 123ea6c96105f3830441fbad6404280c12561733a03Enrico Granata if is_mutable and not is_inline: 124ea6c96105f3830441fbad6404280c12561733a03Enrico Granata explicit_length_offset = explicit_length_offset + ptr_size 125ea6c96105f3830441fbad6404280c12561733a03Enrico Granata elif is_inline: 126ea6c96105f3830441fbad6404280c12561733a03Enrico Granata pass 127ea6c96105f3830441fbad6404280c12561733a03Enrico Granata elif not is_inline and not is_mutable: 128ea6c96105f3830441fbad6404280c12561733a03Enrico Granata explicit_length_offset = explicit_length_offset + ptr_size 129ea6c96105f3830441fbad6404280c12561733a03Enrico Granata else: 130ea6c96105f3830441fbad6404280c12561733a03Enrico Granata explicit_length_offset = 0 131ea6c96105f3830441fbad6404280c12561733a03Enrico Granata 132ea6c96105f3830441fbad6404280c12561733a03Enrico Granata if explicit_length_offset == 0: 133ea6c96105f3830441fbad6404280c12561733a03Enrico Granata print >>result,"There is no explicit length marker - skipping this step\n" 134ea6c96105f3830441fbad6404280c12561733a03Enrico Granata else: 135ea6c96105f3830441fbad6404280c12561733a03Enrico Granata explicit_length_offset = nsstring_address + explicit_length_offset 136ea6c96105f3830441fbad6404280c12561733a03Enrico Granata explicit_length = process.ReadUnsignedFromMemory(explicit_length_offset, 4, error) 137ea6c96105f3830441fbad6404280c12561733a03Enrico Granata print >>result,"Explicit length location is at 0x%x - read value is %d\n" % (explicit_length_offset,explicit_length) 138ea6c96105f3830441fbad6404280c12561733a03Enrico Granata 139ea6c96105f3830441fbad6404280c12561733a03Enrico Granata if is_mutable: 140ea6c96105f3830441fbad6404280c12561733a03Enrico Granata location = 2 * ptr_size + nsstring_address 141ea6c96105f3830441fbad6404280c12561733a03Enrico Granata location = process.ReadPointerFromMemory(location,error) 142ea6c96105f3830441fbad6404280c12561733a03Enrico Granata elif is_inline and has_explicit_length and not is_unicode and not is_special and not is_mutable: 143ea6c96105f3830441fbad6404280c12561733a03Enrico Granata location = 3 * ptr_size + nsstring_address 144ea6c96105f3830441fbad6404280c12561733a03Enrico Granata elif is_unicode: 145ea6c96105f3830441fbad6404280c12561733a03Enrico Granata location = 2 * ptr_size + nsstring_address 146ea6c96105f3830441fbad6404280c12561733a03Enrico Granata if is_inline: 147ea6c96105f3830441fbad6404280c12561733a03Enrico Granata if not has_explicit_length: 148ea6c96105f3830441fbad6404280c12561733a03Enrico Granata print >>result,"Unicode & Inline & !Explicit is a new combo - no formula for it" 149ea6c96105f3830441fbad6404280c12561733a03Enrico Granata else: 150ea6c96105f3830441fbad6404280c12561733a03Enrico Granata location += ptr_size 151ea6c96105f3830441fbad6404280c12561733a03Enrico Granata else: 152ea6c96105f3830441fbad6404280c12561733a03Enrico Granata location = process.ReadPointerFromMemory(location,error) 153ea6c96105f3830441fbad6404280c12561733a03Enrico Granata elif is_special: 154ea6c96105f3830441fbad6404280c12561733a03Enrico Granata location = nsstring_address + ptr_size + 4 155ea6c96105f3830441fbad6404280c12561733a03Enrico Granata elif is_inline: 156ea6c96105f3830441fbad6404280c12561733a03Enrico Granata location = 2 * ptr_size + nsstring_address 157ea6c96105f3830441fbad6404280c12561733a03Enrico Granata if not has_explicit_length: 158ea6c96105f3830441fbad6404280c12561733a03Enrico Granata location += 1 159ea6c96105f3830441fbad6404280c12561733a03Enrico Granata else: 160ea6c96105f3830441fbad6404280c12561733a03Enrico Granata location = 2 * ptr_size + nsstring_address 161ea6c96105f3830441fbad6404280c12561733a03Enrico Granata location = process.ReadPointerFromMemory(location,error) 162ea6c96105f3830441fbad6404280c12561733a03Enrico Granata print >>result,"Expected data location: 0x%x\n" % (location) 163ea6c96105f3830441fbad6404280c12561733a03Enrico Granata print >>result,"1K of data around location: %s\n" % read_memory(process,location,1024) 164ea6c96105f3830441fbad6404280c12561733a03Enrico Granata print >>result,"5K of data around string pointer: %s\n" % read_memory(process,nsstring_address,1024*5) 165ea6c96105f3830441fbad6404280c12561733a03Enrico Granata 166ea6c96105f3830441fbad6404280c12561733a03Enrico Granatadef __lldb_init_module(debugger, internal_dict): 167ea6c96105f3830441fbad6404280c12561733a03Enrico Granata debugger.HandleCommand("command script add -f %s.diagnose_nsstring_Command_Impl diagnose-nsstring" % __name__) 168ea6c96105f3830441fbad6404280c12561733a03Enrico Granata print 'The "diagnose-nsstring" command has been installed, type "help diagnose-nsstring" for detailed help.' 169ea6c96105f3830441fbad6404280c12561733a03Enrico Granata 170ea6c96105f3830441fbad6404280c12561733a03Enrico Granata__lldb_init_module(lldb.debugger,None) 171ea6c96105f3830441fbad6404280c12561733a03Enrico Granata__lldb_init_module = None