static plcrash_error_t pl_async_objc_parse_from_module_info()

in Source/PLCrashAsyncObjCSection.mm [622:714]


static plcrash_error_t pl_async_objc_parse_from_module_info (plcrash_async_macho_t *image, plcrash_async_objc_found_method_cb callback, void *ctx) {
    plcrash_error_t err = PLCRASH_EUNKNOWN;
    struct pl_objc1_module *moduleData;

    /* Map the __module_info section. */
    bool moduleMobjInitialized = false;
    plcrash_async_mobject_t moduleMobj;

    err = plcrash_async_macho_map_section(image, kObjCSegmentName, kObjCModuleInfoSectionName, &moduleMobj);
    if (err != PLCRASH_ESUCCESS) {
        if (err != PLCRASH_ENOTFOUND)
            PLCF_DEBUG("pl_async_macho_map_section(%p, %s, %s, %p) failure %d", image, kObjCSegmentName, kObjCModuleInfoSectionName, &moduleMobj, err);
        goto cleanup;
    }

    /* Successful mapping, so mark the memory object as needing cleanup. */
    moduleMobjInitialized = true;
    
    /* Get a pointer to the module info data. */
    moduleData = (struct pl_objc1_module *) plcrash_async_mobject_remap_address(&moduleMobj, moduleMobj.task_address, 0, sizeof(*moduleData));
    if (moduleData == NULL) {
        PLCF_DEBUG("Failed to obtain pointer from %s memory object", kObjCModuleInfoSectionName);
        err = PLCRASH_ENOTFOUND;
        goto cleanup;
    }
    
    /* Read successive module structs from the section until we run out of data. */
    for (unsigned moduleIndex = 0; moduleIndex < moduleMobj.length / sizeof(*moduleData); moduleIndex++) {
        /* Grab the pointer to the symtab for this module struct. */
        pl_vm_address_t symtabPtr = image->byteorder->swap32(moduleData[moduleIndex].symtab);
        if (symtabPtr == 0)
            continue;
        
        /* Read a symtab struct from that pointer. */
        struct pl_objc1_symtab symtab;
        err = plcrash_async_task_memcpy(image->task, symtabPtr, 0, &symtab, sizeof(symtab));
        if (err != PLCRASH_ESUCCESS) {
            PLCF_DEBUG("plcrash_async_task_memcpy at 0x%llx error %d", (long long)symtabPtr, err);
            goto cleanup;
        }
        
        /* Iterate over the classes in the symtab. */
        uint16_t classCount = image->byteorder->swap16(symtab.cls_def_count);
        for (unsigned i = 0; i < classCount; i++) {
            /* Classes are indicated by pointers laid out sequentially after the
             * symtab structure. */
            uint32_t classPtr;
            pl_vm_address_t cursor = symtabPtr + sizeof(symtab) + i * sizeof(classPtr);
            err = plcrash_async_task_memcpy(image->task, cursor, 0, &classPtr, sizeof(classPtr));
            if (err != PLCRASH_ESUCCESS) {
                PLCF_DEBUG("plcrash_async_task_memcpy at 0x%llx error %d", (long long)cursor, err);
                goto cleanup;
            }
            classPtr = image->byteorder->swap32(classPtr);
            
            /* Read a class structure from the class pointer. */
            struct pl_objc1_class cls;
            err = plcrash_async_task_memcpy(image->task, classPtr, 0, &cls, sizeof(cls));
            if (err != PLCRASH_ESUCCESS) {
                PLCF_DEBUG("plcrash_async_task_memcpy at 0x%llx error %d", (long long)classPtr, err);
                goto cleanup;
            }
            
            err = pl_async_parse_obj1_class(image, &cls, false, callback, ctx);
            if (err != PLCRASH_ESUCCESS) {
                PLCF_DEBUG("pl_async_parse_obj1_class error %d while parsing class", err);
                goto cleanup;
            }
            
            /* Read a class structure for the metaclass. */
            pl_vm_address_t isa = plcrash_async_objc_isa_pointer(image->byteorder->swap(cls.isa));
            struct pl_objc1_class metaclass;
            err = plcrash_async_task_memcpy(image->task, isa, 0, &metaclass, sizeof(metaclass));
            if (err != PLCRASH_ESUCCESS) {
                PLCF_DEBUG("plcrash_async_task_memcpy at 0x%llx error %d", (long long)isa, err);
                goto cleanup;
            }
            
            err = pl_async_parse_obj1_class(image, &metaclass, true, callback, ctx);
            if (err != PLCRASH_ESUCCESS) {
                PLCF_DEBUG("pl_async_parse_obj1_class error %d while parsing metaclass", err);
                goto cleanup;
            }
        }
    }
    
cleanup:
    /* Clean up the memory objects before returning if they're initialized. */
    if (moduleMobjInitialized)
        plcrash_async_mobject_free(&moduleMobj);
    
    return err;
}