mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-17 16:43:53 +00:00
ios: Enable extra_memory_ranges on iOS.
Port set_extra_memory_ranges support to iOS. Because iOS crashes are processed in two parts, store the memory data itself (not just the range) in the intermediate dump, and on post-crash processing, move the memory to ProcessSnapshot ExtraMemory. Change-Id: I759d32bec5b451417b078dee4f836db6f6778fb1 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/6341431 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Justin Cohen <justincohen@chromium.org>
This commit is contained in:
parent
e09f5ee484
commit
342bd4df0e
@ -81,16 +81,25 @@ struct CrashpadInfo {
|
|||||||
//! this method is called, or they may be added, removed, or modified in \a
|
//! this method is called, or they may be added, removed, or modified in \a
|
||||||
//! address_range_bag after this method is called.
|
//! address_range_bag after this method is called.
|
||||||
//!
|
//!
|
||||||
//! TODO(scottmg) This is currently only supported on Windows.
|
//! TODO(scottmg) This is currently only supported on Windows and iOS.
|
||||||
//!
|
//!
|
||||||
//! \param[in] address_range_bag A bag of address ranges. The CrashpadInfo
|
//! \param[in] address_range_bag A bag of address ranges. The CrashpadInfo
|
||||||
//! object does not take ownership of the SimpleAddressRangeBag object.
|
//! object does not take ownership of the SimpleAddressRangeBag object.
|
||||||
//! It is the caller’s responsibility to ensure that this pointer remains
|
//! It is the caller’s responsibility to ensure that this pointer remains
|
||||||
//! valid while it is in effect for a CrashpadInfo object.
|
//! valid while it is in effect for a CrashpadInfo object.
|
||||||
|
//!
|
||||||
|
//! \sa extra_memory_ranges()
|
||||||
void set_extra_memory_ranges(SimpleAddressRangeBag* address_range_bag) {
|
void set_extra_memory_ranges(SimpleAddressRangeBag* address_range_bag) {
|
||||||
extra_memory_ranges_ = address_range_bag;
|
extra_memory_ranges_ = address_range_bag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! \return The simple extra memory ranges SimpleAddressRangeBag object.
|
||||||
|
//!
|
||||||
|
//! \sa set_extra_memory_ranges()
|
||||||
|
SimpleAddressRangeBag* extra_memory_ranges() const {
|
||||||
|
return extra_memory_ranges_;
|
||||||
|
}
|
||||||
|
|
||||||
//! \brief Sets the simple annotations dictionary.
|
//! \brief Sets the simple annotations dictionary.
|
||||||
//!
|
//!
|
||||||
//! Simple annotations set on a CrashpadInfo structure are interpreted by
|
//! Simple annotations set on a CrashpadInfo structure are interpreted by
|
||||||
|
@ -1144,6 +1144,7 @@ void InProcessIntermediateDumpHandler::WriteDataSegmentAnnotations(
|
|||||||
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());
|
||||||
|
WriteCrashpadExtraMemoryRanges(writer, crashpad_info.get());
|
||||||
}
|
}
|
||||||
} else if (strcmp(section_vm_read_ptr->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;
|
||||||
@ -1257,5 +1258,35 @@ void InProcessIntermediateDumpHandler::WriteCrashpadAnnotationsList(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InProcessIntermediateDumpHandler::WriteCrashpadExtraMemoryRanges(
|
||||||
|
IOSIntermediateDumpWriter* writer,
|
||||||
|
CrashpadInfo* crashpad_info) {
|
||||||
|
if (!crashpad_info->extra_memory_ranges()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopedVMRead<SimpleAddressRangeBag> extra_memory_ranges;
|
||||||
|
if (!extra_memory_ranges.Read(crashpad_info->extra_memory_ranges())) {
|
||||||
|
CRASHPAD_RAW_LOG("Unable to read extra memory ranges object");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IOSIntermediateDumpWriter::ScopedArray module_extra_memory_regions_array(
|
||||||
|
writer, IntermediateDumpKey::kModuleExtraMemoryRegions);
|
||||||
|
|
||||||
|
SimpleAddressRangeBag::Iterator iterator(*(extra_memory_ranges.get()));
|
||||||
|
while (const SimpleAddressRangeBag::Entry* entry = iterator.Next()) {
|
||||||
|
const uint64_t& address = entry->base;
|
||||||
|
const uint64_t& size = entry->size;
|
||||||
|
IOSIntermediateDumpWriter::ScopedArrayMap memory_region_map(writer);
|
||||||
|
WriteProperty(
|
||||||
|
writer, IntermediateDumpKey::kModuleExtraMemoryRegionAddress, &address);
|
||||||
|
WritePropertyBytes(writer,
|
||||||
|
IntermediateDumpKey::kModuleExtraMemoryRegionData,
|
||||||
|
reinterpret_cast<const void*>(address),
|
||||||
|
size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace crashpad
|
} // namespace crashpad
|
||||||
|
@ -152,6 +152,10 @@ class InProcessIntermediateDumpHandler final {
|
|||||||
//! \brief Write Crashpad annotations list.
|
//! \brief Write Crashpad annotations list.
|
||||||
static void WriteCrashpadAnnotationsList(IOSIntermediateDumpWriter* writer,
|
static void WriteCrashpadAnnotationsList(IOSIntermediateDumpWriter* writer,
|
||||||
CrashpadInfo* crashpad_info);
|
CrashpadInfo* crashpad_info);
|
||||||
|
|
||||||
|
//! \brief Write Crashpad extra memory data.
|
||||||
|
static void WriteCrashpadExtraMemoryRanges(IOSIntermediateDumpWriter* writer,
|
||||||
|
CrashpadInfo* crashpad_info);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
@ -38,6 +38,16 @@ namespace {
|
|||||||
|
|
||||||
using internal::InProcessIntermediateDumpHandler;
|
using internal::InProcessIntermediateDumpHandler;
|
||||||
|
|
||||||
|
class ReadToString : public crashpad::MemorySnapshot::Delegate {
|
||||||
|
public:
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
bool MemorySnapshotDelegateRead(void* data, size_t size) override {
|
||||||
|
result = std::string(reinterpret_cast<const char*>(data), size);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class InProcessIntermediateDumpHandlerTest : public testing::Test {
|
class InProcessIntermediateDumpHandlerTest : public testing::Test {
|
||||||
protected:
|
protected:
|
||||||
// testing::Test:
|
// testing::Test:
|
||||||
@ -230,6 +240,37 @@ TEST_F(InProcessIntermediateDumpHandlerTest, TestAnnotations) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(InProcessIntermediateDumpHandlerTest, TestExtraMemoryRanges) {
|
||||||
|
#if TARGET_OS_SIMULATOR
|
||||||
|
// This test will fail on older (<iOS17 simulators) when running on macOS 14.3
|
||||||
|
// or newer due to a bug in Simulator. crbug.com/328282286
|
||||||
|
if (IsMacOSVersion143OrGreaterAndiOS16OrLess()) {
|
||||||
|
// For TearDown.
|
||||||
|
ASSERT_TRUE(LoggingRemoveFile(path()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
constexpr char kSomeExtraMemoryString[] = "extra memory range";
|
||||||
|
crashpad::SimpleAddressRangeBag* ios_extra_ranges =
|
||||||
|
new crashpad::SimpleAddressRangeBag();
|
||||||
|
crashpad::CrashpadInfo::GetCrashpadInfo()->set_extra_memory_ranges(
|
||||||
|
ios_extra_ranges);
|
||||||
|
ios_extra_ranges->Insert((void*)kSomeExtraMemoryString, 18);
|
||||||
|
WriteReportAndCloseWriter();
|
||||||
|
crashpad::CrashpadInfo::GetCrashpadInfo()->set_extra_memory_ranges(nullptr);
|
||||||
|
internal::ProcessSnapshotIOSIntermediateDump process_snapshot;
|
||||||
|
ASSERT_TRUE(process_snapshot.InitializeWithFilePath(path(), {}));
|
||||||
|
ASSERT_EQ(process_snapshot.ExtraMemory().size(), 1LU);
|
||||||
|
auto memory = process_snapshot.ExtraMemory()[0];
|
||||||
|
EXPECT_EQ(memory->Address(),
|
||||||
|
reinterpret_cast<uint64_t>(kSomeExtraMemoryString));
|
||||||
|
EXPECT_EQ(memory->Size(), 18LU);
|
||||||
|
ReadToString delegate;
|
||||||
|
ASSERT_TRUE(memory->Read(&delegate));
|
||||||
|
EXPECT_EQ(delegate.result, kSomeExtraMemoryString);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(InProcessIntermediateDumpHandlerTest, TestThreads) {
|
TEST_F(InProcessIntermediateDumpHandlerTest, TestThreads) {
|
||||||
const ScopedSetThreadName scoped_set_thread_name("TestThreads");
|
const ScopedSetThreadName scoped_set_thread_name("TestThreads");
|
||||||
|
|
||||||
|
@ -127,6 +127,33 @@ bool ModuleSnapshotIOSIntermediateDump::Initialize(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const IOSIntermediateDumpList* extra_memory_regions_array =
|
||||||
|
image_data->GetAsList(IntermediateDumpKey::kModuleExtraMemoryRegions);
|
||||||
|
if (extra_memory_regions_array) {
|
||||||
|
for (auto& region : *extra_memory_regions_array) {
|
||||||
|
vm_address_t address;
|
||||||
|
const IOSIntermediateDumpData* region_data =
|
||||||
|
region->GetAsData(Key::kModuleExtraMemoryRegionData);
|
||||||
|
if (!region_data)
|
||||||
|
continue;
|
||||||
|
if (GetDataValueFromMap(
|
||||||
|
region.get(), Key::kModuleExtraMemoryRegionAddress, &address)) {
|
||||||
|
const std::vector<uint8_t>& bytes = region_data->bytes();
|
||||||
|
vm_size_t data_size = bytes.size();
|
||||||
|
if (data_size == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const vm_address_t data =
|
||||||
|
reinterpret_cast<const vm_address_t>(bytes.data());
|
||||||
|
|
||||||
|
auto memory =
|
||||||
|
std::make_unique<internal::MemorySnapshotIOSIntermediateDump>();
|
||||||
|
memory->Initialize(address, data, data_size);
|
||||||
|
extra_memory_.push_back(std::move(memory));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const IOSIntermediateDumpMap* crash_info_dump =
|
const IOSIntermediateDumpMap* crash_info_dump =
|
||||||
image_data->GetAsMap(IntermediateDumpKey::kAnnotationsCrashInfo);
|
image_data->GetAsMap(IntermediateDumpKey::kAnnotationsCrashInfo);
|
||||||
if (crash_info_dump) {
|
if (crash_info_dump) {
|
||||||
@ -266,6 +293,15 @@ ModuleSnapshotIOSIntermediateDump::ExtraMemoryRanges() const {
|
|||||||
return std::set<CheckedRange<uint64_t>>();
|
return std::set<CheckedRange<uint64_t>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<const MemorySnapshot*>
|
||||||
|
ModuleSnapshotIOSIntermediateDump::ExtraMemory() const {
|
||||||
|
std::vector<const MemorySnapshot*> extra_memory;
|
||||||
|
for (const auto& memory : extra_memory_) {
|
||||||
|
extra_memory.push_back(memory.get());
|
||||||
|
}
|
||||||
|
return extra_memory;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<const UserMinidumpStream*>
|
std::vector<const UserMinidumpStream*>
|
||||||
ModuleSnapshotIOSIntermediateDump::CustomMinidumpStreams() const {
|
ModuleSnapshotIOSIntermediateDump::CustomMinidumpStreams() const {
|
||||||
return std::vector<const UserMinidumpStream*>();
|
return std::vector<const UserMinidumpStream*>();
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "snapshot/crashpad_info_client_options.h"
|
#include "snapshot/crashpad_info_client_options.h"
|
||||||
|
#include "snapshot/ios/memory_snapshot_ios_intermediate_dump.h"
|
||||||
#include "snapshot/module_snapshot.h"
|
#include "snapshot/module_snapshot.h"
|
||||||
#include "util/ios/ios_intermediate_dump_map.h"
|
#include "util/ios/ios_intermediate_dump_map.h"
|
||||||
#include "util/misc/initialization_state_dcheck.h"
|
#include "util/misc/initialization_state_dcheck.h"
|
||||||
@ -75,6 +76,9 @@ class ModuleSnapshotIOSIntermediateDump final : public ModuleSnapshot {
|
|||||||
std::set<CheckedRange<uint64_t>> ExtraMemoryRanges() const override;
|
std::set<CheckedRange<uint64_t>> ExtraMemoryRanges() const override;
|
||||||
std::vector<const UserMinidumpStream*> CustomMinidumpStreams() const override;
|
std::vector<const UserMinidumpStream*> CustomMinidumpStreams() const override;
|
||||||
|
|
||||||
|
// Used by ProcessSnapshot
|
||||||
|
std::vector<const MemorySnapshot*> ExtraMemory() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string name_;
|
std::string name_;
|
||||||
uint64_t address_;
|
uint64_t address_;
|
||||||
@ -87,7 +91,8 @@ class ModuleSnapshotIOSIntermediateDump final : public ModuleSnapshot {
|
|||||||
std::vector<std::string> annotations_vector_;
|
std::vector<std::string> annotations_vector_;
|
||||||
std::map<std::string, std::string> annotations_simple_map_;
|
std::map<std::string, std::string> annotations_simple_map_;
|
||||||
std::vector<AnnotationSnapshot> annotation_objects_;
|
std::vector<AnnotationSnapshot> annotation_objects_;
|
||||||
|
std::vector<std::unique_ptr<internal::MemorySnapshotIOSIntermediateDump>>
|
||||||
|
extra_memory_;
|
||||||
InitializationStateDcheck initialized_;
|
InitializationStateDcheck initialized_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -304,7 +304,13 @@ std::vector<HandleSnapshot> ProcessSnapshotIOSIntermediateDump::Handles()
|
|||||||
std::vector<const MemorySnapshot*>
|
std::vector<const MemorySnapshot*>
|
||||||
ProcessSnapshotIOSIntermediateDump::ExtraMemory() const {
|
ProcessSnapshotIOSIntermediateDump::ExtraMemory() const {
|
||||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||||
return std::vector<const MemorySnapshot*>();
|
std::vector<const MemorySnapshot*> extra_memory;
|
||||||
|
for (const auto& module : modules_) {
|
||||||
|
for (const auto& memory : module->ExtraMemory()) {
|
||||||
|
extra_memory.push_back(memory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return extra_memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ProcessMemory* ProcessSnapshotIOSIntermediateDump::Memory() const {
|
const ProcessMemory* ProcessSnapshotIOSIntermediateDump::Memory() const {
|
||||||
|
@ -121,6 +121,8 @@ class ProcessSnapshotIOSIntermediateDump final : public ProcessSnapshot {
|
|||||||
UUID client_id_;
|
UUID client_id_;
|
||||||
std::map<std::string, std::string> annotations_simple_map_;
|
std::map<std::string, std::string> annotations_simple_map_;
|
||||||
timeval snapshot_time_;
|
timeval snapshot_time_;
|
||||||
|
std::vector<std::unique_ptr<internal::MemorySnapshotIOSIntermediateDump>>
|
||||||
|
extra_memory_;
|
||||||
InitializationStateDcheck initialized_;
|
InitializationStateDcheck initialized_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -242,6 +242,7 @@ uint64_t ThreadSnapshotIOSIntermediateDump::ThreadSpecificDataAddress() const {
|
|||||||
|
|
||||||
std::vector<const MemorySnapshot*>
|
std::vector<const MemorySnapshot*>
|
||||||
ThreadSnapshotIOSIntermediateDump::ExtraMemory() const {
|
ThreadSnapshotIOSIntermediateDump::ExtraMemory() const {
|
||||||
|
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||||
std::vector<const MemorySnapshot*> extra_memory;
|
std::vector<const MemorySnapshot*> extra_memory;
|
||||||
for (const auto& memory : extra_memory_) {
|
for (const auto& memory : extra_memory_) {
|
||||||
extra_memory.push_back(memory.get());
|
extra_memory.push_back(memory.get());
|
||||||
|
@ -56,6 +56,9 @@ namespace internal {
|
|||||||
TD(kAnnotationsCrashInfoMessage1, 3016) \
|
TD(kAnnotationsCrashInfoMessage1, 3016) \
|
||||||
TD(kAnnotationsCrashInfoMessage2, 3017) \
|
TD(kAnnotationsCrashInfoMessage2, 3017) \
|
||||||
TD(kAnnotationsDyldErrorString, 3018) \
|
TD(kAnnotationsDyldErrorString, 3018) \
|
||||||
|
TD(kModuleExtraMemoryRegions, 3019) \
|
||||||
|
TD(kModuleExtraMemoryRegionAddress, 3020) \
|
||||||
|
TD(kModuleExtraMemoryRegionData, 3021) \
|
||||||
TD(kProcessInfo, 4000) \
|
TD(kProcessInfo, 4000) \
|
||||||
TD(kParentPID, 4001) \
|
TD(kParentPID, 4001) \
|
||||||
TD(kPID, 4002) \
|
TD(kPID, 4002) \
|
||||||
|
Loading…
x
Reference in New Issue
Block a user