in Source/PLCrashAsyncObjCSection.mm [1033:1136]
static plcrash_error_t pl_async_objc_parse_from_data_section (plcrash_async_macho_t *image, plcrash_async_objc_cache_t *objcContext, plcrash_async_objc_found_method_cb callback, void *ctx) {
plcrash_error_t err;
/* Map memory objects. */
err = map_sections(image, objcContext);
if (err != PLCRASH_ESUCCESS) {
/* Don't log an error if ObjC data was simply not found */
if (err != PLCRASH_ENOTFOUND)
PLCF_DEBUG("Unable to map relevant sections in %s for ObjC2 class parsing, error %d", PLCF_DEBUG_IMAGE_NAME(image), err);
return err;
}
/* Get a pointer out of the mapped class list. */
machine_ptr_t *classPtrs = (machine_ptr_t *) plcrash_async_mobject_remap_address(&objcContext->classMobj, objcContext->classMobj.task_address, 0, objcContext->classMobj.length);
if (classPtrs == NULL) {
PLCF_DEBUG("plcrash_async_mobject_remap_address in __objc_classlist for pointer 0x%llx returned NULL", (long long)objcContext->classMobj.address);
return PLCRASH_EINVALID_DATA;
}
/* Figure out how many classes are in the class list based on its length and
* the size of a pointer in the image. */
pl_vm_size_t classCount = objcContext->classMobj.length / sizeof(machine_ptr_t);
/* Iterate over all classes. */
for(unsigned i = 0; i < classCount; i++) {
/* Read the class structure */
pl_vm_address_t ptr = (pl_vm_address_t) classPtrs[i];
class_t *classPtr = (class_t *) plcrash_async_mobject_remap_address(&objcContext->objcDataMobj, ptr, 0, sizeof(*classPtr));
if (classPtr == NULL) {
classPtr = (class_t *) plcrash_async_mobject_remap_address(&objcContext->dataMobj, ptr, 0, sizeof(*classPtr));
}
if (classPtr == NULL) {
PLCF_DEBUG("plcrash_async_mobject_remap_address in __objc_data and __data for pointer 0x%llx returned NULL", (long long)ptr);
return PLCRASH_EINVALID_DATA;
}
/* Parse the class. */
err = pl_async_objc_parse_objc2_class_methods<class_t, class_ro_t, class_rw_t, machine_ptr_t>(image, objcContext, classPtr, false, callback, ctx);
if (err != PLCRASH_ESUCCESS) {
/* Skip unrealized classes; they'll never appear in a live backtrace. */
if (err == PLCRASH_ENOTFOUND) {
/* We should reset the error variable to avoid return it from the function. */
err = PLCRASH_ESUCCESS;
continue;
}
PLCF_DEBUG("pl_async_objc_parse_objc2_class error %d while parsing class", err);
return err;
}
/* Read an architecture-appropriate class structure for the metaclass. */
pl_vm_address_t isa = plcrash_async_objc_isa_pointer((pl_vm_address_t) image->byteorder->swap(classPtr->isa));
class_t *metaclass = (class_t *) plcrash_async_mobject_remap_address(&objcContext->objcDataMobj, isa, 0, sizeof(*metaclass));
if (metaclass == NULL) {
metaclass = (class_t *) plcrash_async_mobject_remap_address(&objcContext->dataMobj, isa, 0, sizeof(*metaclass));
}
if (metaclass == NULL) {
PLCF_DEBUG("plcrash_async_mobject_remap_address in __objc_data and __data for pointer 0x%llx returned NULL", (long long)isa);
return PLCRASH_EINVALID_DATA;
}
/* Parse the metaclass. */
err = pl_async_objc_parse_objc2_class_methods<class_t, class_ro_t, class_rw_t, machine_ptr_t>(image, objcContext, metaclass, true, callback, ctx);
if (err != PLCRASH_ESUCCESS) {
PLCF_DEBUG("pl_async_objc_parse_objc2_class_methods error %d while parsing metaclass", err);
return err;
}
}
/* Get a pointer out of the mapped category list. */
machine_ptr_t *catPtrs = (machine_ptr_t *) plcrash_async_mobject_remap_address(&objcContext->catMobj, objcContext->catMobj.task_address, 0, objcContext->catMobj.length);
if (catPtrs == NULL) {
PLCF_DEBUG("plcrash_async_mobject_remap_address in __objc_catlist for pointer 0x%llx returned NULL", (long long)objcContext->catMobj.address);
return PLCRASH_EINVALID_DATA;
}
/* Figure out how many categories are in the category list based on its length and the size of a pointer in the image. */
pl_vm_size_t catCount = objcContext->catMobj.length / sizeof(*catPtrs);
/* Iterate over all classes. */
for(unsigned i = 0; i < catCount; i++) {
/* Read a category pointer at the current index from the appropriate pointer. */
pl_vm_address_t ptr = (pl_vm_address_t) image->byteorder->swap(catPtrs[i]);
/* Read the category structure. */
category_t *category = (category_t *) plcrash_async_mobject_remap_address(&objcContext->objcConstMobj, ptr, 0, sizeof(*category));
if (category == NULL) {
PLCF_DEBUG("plcrash_async_mobject_remap_address in __objc_const for pointer 0x%llx returned NULL", (long long)ptr);
return PLCRASH_EINVALID_DATA;
}
/* Parse the category. */
err = pl_async_objc_parse_objc2_category_methods<category_t, class_t, class_ro_t, class_rw_t, machine_ptr_t>(image, objcContext, category, callback, ctx);
if (err != PLCRASH_ESUCCESS) {
/* Skip unrealized classes; they'll never appear in a live backtrace. */
if (err == PLCRASH_ENOTFOUND)
continue;
PLCF_DEBUG("pl_async_objc_parse_objc2_class error %d while parsing class", err);
return err;
}
}
return err;
}