brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.2 KiB · 5197993 Raw
221 lines · python
1# This implements the "diagnose-nsstring" command, usually installed in the debug session like2#   command script import lldb.diagnose3# it is used when NSString summary formatter fails to replicate the logic that went into LLDB making the4# decisions it did and  providing some useful context information that can5# be used for improving the formatter6 7import lldb8 9 10def read_memory(process, location, size):11    data = ""12    error = lldb.SBError()13    for x in range(0, size - 1):14        byte = process.ReadUnsignedFromMemory(x + location, 1, error)15        if error.fail:16            data = data + "err%s" % "" if x == size - 2 else ":"17        else:18            try:19                data = data + "0x%x" % byte20                if byte == 0:21                    data = data + "(\\0)"22                elif byte == 0xA:23                    data = data + "(\\a)"24                elif byte == 0xB:25                    data = data + "(\\b)"26                elif byte == 0xC:27                    data = data + "(\\c)"28                elif byte == "\n":29                    data = data + "(\\n)"30                else:31                    data = data + "(%s)" % chr(byte)32                if x < size - 2:33                    data = data + ":"34            except Exception as e:35                print(e)36    return data37 38 39def diagnose_nsstring_Command_Impl(debugger, command, result, internal_dict):40    """41    A command to diagnose the LLDB NSString data formatter42    invoke as43    (lldb) diagnose-nsstring <expr returning NSString>44    e.g.45    (lldb) diagnose-nsstring @"Hello world"46    """47    target = debugger.GetSelectedTarget()48    process = target.GetProcess()49    thread = process.GetSelectedThread()50    frame = thread.GetSelectedFrame()51    if not target.IsValid() or not process.IsValid():52        return "unable to get target/process - cannot proceed"53    options = lldb.SBExpressionOptions()54    options.SetFetchDynamicValue()55    error = lldb.SBError()56    if frame.IsValid():57        nsstring = frame.EvaluateExpression(command, options)58    else:59        nsstring = target.EvaluateExpression(command, options)60    print(str(nsstring), file=result)61    nsstring_address = nsstring.GetValueAsUnsigned(0)62    if nsstring_address == 0:63        return "unable to obtain the string - cannot proceed"64    expression = "\65struct $__lldb__notInlineMutable {\66    char* buffer;\67    signed long length;\68    signed long capacity;\69    unsigned int hasGap:1;\70    unsigned int isFixedCapacity:1;\71    unsigned int isExternalMutable:1;\72    unsigned int capacityProvidedExternally:1;\n\73#if __LP64__\n\74    unsigned long desiredCapacity:60;\n\75#else\n\76    unsigned long desiredCapacity:28;\n\77#endif\n\78    void* contentsAllocator;\79};\80\81struct $__lldb__CFString {\82    void* _cfisa;\83    uint8_t _cfinfo[4];\84    uint32_t _rc;\85    union {\86        struct __inline1 {\87            signed long length;\88        } inline1;\89        struct __notInlineImmutable1 {\90            char* buffer;\91            signed long length;\92            void* contentsDeallocator;\93        } notInlineImmutable1;\94        struct __notInlineImmutable2 {\95            char* buffer;\96            void* contentsDeallocator;\97        } notInlineImmutable2;\98        struct $__lldb__notInlineMutable notInlineMutable;\99    } variants;\100};\101"102 103    expression = expression + "*(($__lldb__CFString*) %d)" % nsstring_address104    # print expression105    dumped = target.EvaluateExpression(expression, options)106    print(str(dumped), file=result)107 108    little_endian = target.byte_order == lldb.eByteOrderLittle109    ptr_size = target.addr_size110 111    info_bits = (112        dumped.GetChildMemberWithName("_cfinfo")113        .GetChildAtIndex(0 if little_endian else 3)114        .GetValueAsUnsigned(0)115    )116    is_mutable = (info_bits & 1) == 1117    is_inline = (info_bits & 0x60) == 0118    has_explicit_length = (info_bits & (1 | 4)) != 4119    is_unicode = (info_bits & 0x10) == 0x10120    is_special = (121        nsstring.GetDynamicValue(lldb.eDynamicCanRunTarget).GetTypeName()122        == "NSPathStore2"123    )124    has_null = (info_bits & 8) == 8125 126    print(127        "\nInfo=%d\nMutable=%s\nInline=%s\nExplicit=%s\nUnicode=%s\nSpecial=%s\nNull=%s\n"128        % (129            info_bits,130            "yes" if is_mutable else "no",131            "yes" if is_inline else "no",132            "yes" if has_explicit_length else "no",133            "yes" if is_unicode else "no",134            "yes" if is_special else "no",135            "yes" if has_null else "no",136        ),137        file=result,138    )139 140    explicit_length_offset = 0141    if not has_null and has_explicit_length and not is_special:142        explicit_length_offset = 2 * ptr_size143        if is_mutable and not is_inline:144            explicit_length_offset = explicit_length_offset + ptr_size145        elif is_inline:146            pass147        elif not is_inline and not is_mutable:148            explicit_length_offset = explicit_length_offset + ptr_size149        else:150            explicit_length_offset = 0151 152    if explicit_length_offset == 0:153        print("There is no explicit length marker - skipping this step\n", file=result)154    else:155        explicit_length_offset = nsstring_address + explicit_length_offset156        explicit_length = process.ReadUnsignedFromMemory(157            explicit_length_offset, 4, error158        )159        print(160            "Explicit length location is at 0x%x - read value is %d\n"161            % (explicit_length_offset, explicit_length),162            file=result,163        )164 165    if is_mutable:166        location = 2 * ptr_size + nsstring_address167        location = process.ReadPointerFromMemory(location, error)168    elif (169        is_inline170        and has_explicit_length171        and not is_unicode172        and not is_special173        and not is_mutable174    ):175        location = 3 * ptr_size + nsstring_address176    elif is_unicode:177        location = 2 * ptr_size + nsstring_address178        if is_inline:179            if not has_explicit_length:180                print(181                    "Unicode & Inline & !Explicit is a new combo - no formula for it",182                    file=result,183                )184            else:185                location += ptr_size186        else:187            location = process.ReadPointerFromMemory(location, error)188    elif is_special:189        location = nsstring_address + ptr_size + 4190    elif is_inline:191        location = 2 * ptr_size + nsstring_address192        if not has_explicit_length:193            location += 1194    else:195        location = 2 * ptr_size + nsstring_address196        location = process.ReadPointerFromMemory(location, error)197    print("Expected data location: 0x%x\n" % (location), file=result)198    print(199        "1K of data around location: %s\n" % read_memory(process, location, 1024),200        file=result,201    )202    print(203        "5K of data around string pointer: %s\n"204        % read_memory(process, nsstring_address, 1024 * 5),205        file=result,206    )207 208 209def __lldb_init_module(debugger, internal_dict):210    debugger.HandleCommand(211        "command script add -o -f %s.diagnose_nsstring_Command_Impl diagnose-nsstring"212        % __name__213    )214    print(215        'The "diagnose-nsstring" command has been installed, type "help diagnose-nsstring" for detailed help.'216    )217 218 219__lldb_init_module(lldb.debugger, None)220__lldb_init_module = None221