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;
}