ios: Use fewer vm_reads when iterating modules.

Rather than vm_reading each individual module load_command, load all of
the commands at once. This saves nearly 200ms on an iPhone 12 Pro.

Change-Id: I06f56c3ecbdf74f78759648ea62bcccd027f304c
Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3764242
Reviewed-by: Mark Mentovai <mark@chromium.org>
Commit-Queue: Justin Cohen <justincohen@chromium.org>
This commit is contained in:
Justin Cohen 2022-07-15 14:36:38 -04:00 committed by Crashpad LUCI CQ
parent df86075acc
commit ae7d8a9ba4
2 changed files with 60 additions and 71 deletions

View File

@ -1053,68 +1053,63 @@ void InProcessIntermediateDumpHandler::WriteModuleInfoAtAddress(
return; return;
} }
const load_command* command_ptr = reinterpret_cast<const load_command*>( const load_command* unsafe_command_ptr =
reinterpret_cast<const mach_header_64*>(address) + 1); reinterpret_cast<const load_command*>(
reinterpret_cast<const mach_header_64*>(address) + 1);
ScopedVMRead<load_command> command; // Rather than using an individual ScopedVMRead for each load_command, load
if (!command.Read(command_ptr)) { // the entire block of commands at once.
CRASHPAD_RAW_LOG("Invalid module command"); ScopedVMRead<char> all_commands;
if (!all_commands.Read(unsafe_command_ptr, header->sizeofcmds)) {
CRASHPAD_RAW_LOG("Unable to read module load_commands.");
return; return;
} }
// All the *_vm_read_ptr variables in the load_command loop below have been
// vm_read in `all_commands` above, and may be dereferenced without additional
// ScopedVMReads.
const load_command* command_vm_read_ptr =
reinterpret_cast<const load_command*>(all_commands.get());
// Make sure that the basic load command structure doesnt overflow the // Make sure that the basic load command structure doesnt overflow the
// space allotted for load commands, as well as iterating through ncmds. // space allotted for load commands, as well as iterating through ncmds.
vm_size_t slide = 0; vm_size_t slide = 0;
for (uint32_t cmd_index = 0, cumulative_cmd_size = 0; for (uint32_t cmd_index = 0, cumulative_cmd_size = 0;
cmd_index <= header->ncmds && cumulative_cmd_size < header->sizeofcmds; cmd_index < header->ncmds && cumulative_cmd_size < header->sizeofcmds;
++cmd_index, cumulative_cmd_size += command->cmdsize) { ++cmd_index) {
if (command->cmd == LC_SEGMENT_64) { if (command_vm_read_ptr->cmd == LC_SEGMENT_64) {
ScopedVMRead<segment_command_64> segment; const segment_command_64* segment_vm_read_ptr =
if (!segment.Read(command_ptr)) { reinterpret_cast<const segment_command_64*>(command_vm_read_ptr);
CRASHPAD_RAW_LOG("Invalid LC_SEGMENT_64 segment"); if (strcmp(segment_vm_read_ptr->segname, SEG_TEXT) == 0) {
return; WriteProperty(
} writer, IntermediateDumpKey::kSize, &segment_vm_read_ptr->vmsize);
const segment_command_64* segment_ptr = slide = address - segment_vm_read_ptr->vmaddr;
reinterpret_cast<const segment_command_64*>(command_ptr); } else if (strcmp(segment_vm_read_ptr->segname, SEG_DATA) == 0) {
if (strcmp(segment->segname, SEG_TEXT) == 0) { WriteDataSegmentAnnotations(writer, segment_vm_read_ptr, slide);
WriteProperty(writer, IntermediateDumpKey::kSize, &segment->vmsize);
slide = address - segment->vmaddr;
} else if (strcmp(segment->segname, SEG_DATA) == 0) {
WriteDataSegmentAnnotations(writer, segment_ptr, slide);
}
} else if (command->cmd == LC_ID_DYLIB) {
ScopedVMRead<dylib_command> dylib;
if (!dylib.Read(command_ptr)) {
CRASHPAD_RAW_LOG("Invalid LC_ID_DYLIB segment");
return;
} }
} else if (command_vm_read_ptr->cmd == LC_ID_DYLIB) {
const dylib_command* dylib_vm_read_ptr =
reinterpret_cast<const dylib_command*>(command_vm_read_ptr);
WriteProperty(writer, WriteProperty(writer,
IntermediateDumpKey::kDylibCurrentVersion, IntermediateDumpKey::kDylibCurrentVersion,
&dylib->dylib.current_version); &dylib_vm_read_ptr->dylib.current_version);
} else if (command->cmd == LC_SOURCE_VERSION) { } else if (command_vm_read_ptr->cmd == LC_SOURCE_VERSION) {
ScopedVMRead<source_version_command> source_version; const source_version_command* source_version_vm_read_ptr =
if (!source_version.Read(command_ptr)) { reinterpret_cast<const source_version_command*>(command_vm_read_ptr);
CRASHPAD_RAW_LOG("Invalid LC_SOURCE_VERSION segment");
return;
}
WriteProperty(writer, WriteProperty(writer,
IntermediateDumpKey::kSourceVersion, IntermediateDumpKey::kSourceVersion,
&source_version->version); &source_version_vm_read_ptr->version);
} else if (command->cmd == LC_UUID) { } else if (command_vm_read_ptr->cmd == LC_UUID) {
ScopedVMRead<uuid_command> uuid; const uuid_command* uuid_vm_read_ptr =
if (!uuid.Read(command_ptr)) { reinterpret_cast<const uuid_command*>(command_vm_read_ptr);
CRASHPAD_RAW_LOG("Invalid LC_UUID segment"); WriteProperty(
return; writer, IntermediateDumpKey::kUUID, &uuid_vm_read_ptr->uuid);
}
WriteProperty(writer, IntermediateDumpKey::kUUID, &uuid->uuid);
} }
command_ptr = reinterpret_cast<const load_command*>( cumulative_cmd_size += command_vm_read_ptr->cmdsize;
reinterpret_cast<const uint8_t*>(command_ptr) + command->cmdsize); command_vm_read_ptr = reinterpret_cast<const load_command*>(
if (!command.Read(command_ptr)) { reinterpret_cast<const uint8_t*>(command_vm_read_ptr) +
CRASHPAD_RAW_LOG("Invalid module command"); command_vm_read_ptr->cmdsize);
return;
}
} }
WriteProperty(writer, IntermediateDumpKey::kFileType, &header->filetype); WriteProperty(writer, IntermediateDumpKey::kFileType, &header->filetype);
@ -1122,40 +1117,32 @@ void InProcessIntermediateDumpHandler::WriteModuleInfoAtAddress(
void InProcessIntermediateDumpHandler::WriteDataSegmentAnnotations( void InProcessIntermediateDumpHandler::WriteDataSegmentAnnotations(
IOSIntermediateDumpWriter* writer, IOSIntermediateDumpWriter* writer,
const segment_command_64* segment_ptr, const segment_command_64* segment_vm_read_ptr,
vm_size_t slide) { vm_size_t slide) {
ScopedVMRead<segment_command_64> segment; const section_64* section_vm_read_ptr = reinterpret_cast<const section_64*>(
if (!segment.Read(segment_ptr)) { reinterpret_cast<uint64_t>(segment_vm_read_ptr) +
CRASHPAD_RAW_LOG("Unable to read SEG_DATA."); sizeof(segment_command_64));
return; for (uint32_t sect_index = 0; sect_index <= segment_vm_read_ptr->nsects;
} ++sect_index) {
const section_64* section_ptr = reinterpret_cast<const section_64*>( if (strcmp(section_vm_read_ptr->sectname, "crashpad_info") == 0) {
reinterpret_cast<uint64_t>(segment_ptr) + sizeof(segment_command_64));
for (uint32_t sect_index = 0; sect_index <= segment->nsects; ++sect_index) {
ScopedVMRead<section_64> section;
if (!section.Read(section_ptr)) {
CRASHPAD_RAW_LOG("Unable to read SEG_DATA section.");
return;
}
if (strcmp(section->sectname, "crashpad_info") == 0) {
ScopedVMRead<CrashpadInfo> crashpad_info; ScopedVMRead<CrashpadInfo> crashpad_info;
if (crashpad_info.Read(section->addr + slide) && if (crashpad_info.Read(section_vm_read_ptr->addr + slide) &&
crashpad_info->size() == sizeof(CrashpadInfo) && crashpad_info->size() == sizeof(CrashpadInfo) &&
crashpad_info->signature() == CrashpadInfo::kSignature && crashpad_info->signature() == CrashpadInfo::kSignature &&
crashpad_info->version() == 1) { crashpad_info->version() == 1) {
WriteCrashpadAnnotationsList(writer, crashpad_info.get()); WriteCrashpadAnnotationsList(writer, crashpad_info.get());
WriteCrashpadSimpleAnnotationsDictionary(writer, crashpad_info.get()); WriteCrashpadSimpleAnnotationsDictionary(writer, crashpad_info.get());
} }
} else if (strcmp(section->sectname, "__crash_info") == 0) { } else if (strcmp(section_vm_read_ptr->sectname, "__crash_info") == 0) {
ScopedVMRead<crashreporter_annotations_t> crash_info; ScopedVMRead<crashreporter_annotations_t> crash_info;
if (!crash_info.Read(section->addr + slide) || if (!crash_info.Read(section_vm_read_ptr->addr + slide) ||
(crash_info->version != 4 && crash_info->version != 5)) { (crash_info->version != 4 && crash_info->version != 5)) {
continue; continue;
} }
WriteAppleCrashReporterAnnotations(writer, crash_info.get()); WriteAppleCrashReporterAnnotations(writer, crash_info.get());
} }
section_ptr = reinterpret_cast<const section_64*>( section_vm_read_ptr = reinterpret_cast<const section_64*>(
reinterpret_cast<uint64_t>(section_ptr) + sizeof(section_64)); reinterpret_cast<uint64_t>(section_vm_read_ptr) + sizeof(section_64));
} }
} }

View File

@ -139,10 +139,12 @@ class InProcessIntermediateDumpHandler final {
bool is_dyld); bool is_dyld);
//! \brief Extract and write Apple crashreporter_annotations_t data and //! \brief Extract and write Apple crashreporter_annotations_t data and
//! Crashpad annotations. //! Crashpad annotations. Note that \a segment_vm_read_ptr has already
static void WriteDataSegmentAnnotations(IOSIntermediateDumpWriter* writer, //! been read via vm_read and may be dereferenced without a ScopedVMRead.
const segment_command_64* segment_ptr, static void WriteDataSegmentAnnotations(
vm_size_t slide); IOSIntermediateDumpWriter* writer,
const segment_command_64* segment_vm_read_ptr,
vm_size_t slide);
//! \brief Write Crashpad annotations list. //! \brief Write Crashpad annotations list.
static void WriteCrashpadAnnotationsList(IOSIntermediateDumpWriter* writer, static void WriteCrashpadAnnotationsList(IOSIntermediateDumpWriter* writer,