mirror of
https://github.com/chromium/crashpad.git
synced 2024-12-27 15:32:10 +08:00
fuchsia: Include address space information in process snapshot
This plumbs some of the ZX_INFO_PROCESS_MAPS information out into MINIDUMP_MEMORY_INFO. The mapping loses some information that Zircon provides, and some of the data that Windows would provide isn't available (for example, AllocationProtect). But this gives a general idea of the memory layout of the process to check for bad pointers, etc. when inspecting crashes. Bug: fuchsia:DX-615 Change-Id: I2d7c02be0996672253cf0b1eb6a60b0a55e6033b Reviewed-on: https://chromium-review.googlesource.com/c/1377089 Commit-Queue: Scott Graham <scottmg@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org>
This commit is contained in:
parent
067f7ddebf
commit
8b6f158d20
@ -200,6 +200,8 @@ static_library("snapshot") {
|
||||
"fuchsia/exception_snapshot_fuchsia.h",
|
||||
"fuchsia/memory_map_fuchsia.cc",
|
||||
"fuchsia/memory_map_fuchsia.h",
|
||||
"fuchsia/memory_map_region_snapshot_fuchsia.cc",
|
||||
"fuchsia/memory_map_region_snapshot_fuchsia.h",
|
||||
"fuchsia/process_reader_fuchsia.cc",
|
||||
"fuchsia/process_reader_fuchsia.h",
|
||||
"fuchsia/process_snapshot_fuchsia.cc",
|
||||
@ -384,7 +386,10 @@ source_set("snapshot_test") {
|
||||
}
|
||||
|
||||
if (crashpad_is_fuchsia) {
|
||||
sources += [ "fuchsia/process_reader_fuchsia_test.cc" ]
|
||||
sources += [
|
||||
"fuchsia/process_reader_fuchsia_test.cc",
|
||||
"fuchsia/process_snapshot_fuchsia_test.cc",
|
||||
]
|
||||
}
|
||||
|
||||
# public_configs isn’t quite right. snapshot_test_link sets ldflags, and
|
||||
|
@ -46,6 +46,10 @@ class MemoryMapFuchsia {
|
||||
//! will be filled out, otherwise `false` and \a map will be unchanged.
|
||||
bool FindMappingForAddress(zx_vaddr_t address, zx_info_maps_t* map) const;
|
||||
|
||||
//! \brief Get a vector of `zx_info_maps_t` representing the memory map for
|
||||
//! this process.
|
||||
const std::vector<zx_info_maps_t>& Entries() const { return map_entries_; }
|
||||
|
||||
private:
|
||||
std::vector<zx_info_maps_t> map_entries_;
|
||||
InitializationStateDcheck initialized_;
|
||||
|
83
snapshot/fuchsia/memory_map_region_snapshot_fuchsia.cc
Normal file
83
snapshot/fuchsia/memory_map_region_snapshot_fuchsia.cc
Normal file
@ -0,0 +1,83 @@
|
||||
// Copyright 2018 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "snapshot/fuchsia/memory_map_region_snapshot_fuchsia.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
|
||||
namespace crashpad {
|
||||
namespace internal {
|
||||
|
||||
namespace {
|
||||
|
||||
// Maps from bitwise OR of Zircon's flags to enumerated Windows version.
|
||||
uint32_t MmuFlagsToProtectFlags(zx_vm_option_t flags) {
|
||||
// These bits are currently the lowest 3 of zx_vm_option_t. They're used to
|
||||
// index into a mapping array, so make sure that we notice if they change
|
||||
// values.
|
||||
static_assert(
|
||||
ZX_VM_PERM_READ == 1 && ZX_VM_PERM_WRITE == 2 && ZX_VM_PERM_EXECUTE == 4,
|
||||
"table below will need fixing");
|
||||
|
||||
// The entries set to zero don't have good corresponding Windows minidump
|
||||
// names. They also aren't currently supported by the mapping syscall on
|
||||
// Zircon, so DCHECK that they don't happen in practice. EXECUTE-only also
|
||||
// cannot currently happen, but as that has a good mapping to the Windows
|
||||
// value, leave it in place in case it's supported by the syscall in the
|
||||
// future.
|
||||
static constexpr uint32_t mapping[] = {
|
||||
/* --- */ PAGE_NOACCESS,
|
||||
/* --r */ PAGE_READONLY,
|
||||
/* -w- */ 0,
|
||||
/* -wr */ PAGE_READWRITE,
|
||||
/* x-- */ PAGE_EXECUTE,
|
||||
/* x-r */ PAGE_EXECUTE_READ,
|
||||
/* xw- */ 0,
|
||||
/* xwr */ PAGE_EXECUTE_READWRITE,
|
||||
};
|
||||
|
||||
const uint32_t index =
|
||||
flags & (ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_PERM_EXECUTE);
|
||||
DCHECK_LT(index, arraysize(mapping));
|
||||
|
||||
const uint32_t protect_flags = mapping[index];
|
||||
DCHECK_NE(protect_flags, 0u);
|
||||
return protect_flags;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
MemoryMapRegionSnapshotFuchsia::MemoryMapRegionSnapshotFuchsia(
|
||||
const zx_info_maps_t& info_map)
|
||||
: memory_info_() {
|
||||
DCHECK_EQ(info_map.type, ZX_INFO_MAPS_TYPE_MAPPING);
|
||||
|
||||
memory_info_.BaseAddress = info_map.base;
|
||||
memory_info_.AllocationBase = info_map.base;
|
||||
memory_info_.RegionSize = info_map.size;
|
||||
memory_info_.State = MEM_COMMIT;
|
||||
memory_info_.Protect = memory_info_.AllocationProtect =
|
||||
MmuFlagsToProtectFlags(info_map.u.mapping.mmu_flags);
|
||||
memory_info_.Type = MEM_MAPPED;
|
||||
}
|
||||
|
||||
MemoryMapRegionSnapshotFuchsia::~MemoryMapRegionSnapshotFuchsia() {}
|
||||
|
||||
const MINIDUMP_MEMORY_INFO&
|
||||
MemoryMapRegionSnapshotFuchsia::AsMinidumpMemoryInfo() const {
|
||||
return memory_info_;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace crashpad
|
39
snapshot/fuchsia/memory_map_region_snapshot_fuchsia.h
Normal file
39
snapshot/fuchsia/memory_map_region_snapshot_fuchsia.h
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright 2018 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef CRASHPAD_SNAPSHOT_FUCHSIA_MEMORY_MAP_REGION_SNAPSHOT_FUCHSIA_H_
|
||||
#define CRASHPAD_SNAPSHOT_FUCHSIA_MEMORY_MAP_REGION_SNAPSHOT_FUCHSIA_H_
|
||||
|
||||
#include "snapshot/memory_map_region_snapshot.h"
|
||||
|
||||
#include <zircon/syscalls/object.h>
|
||||
|
||||
namespace crashpad {
|
||||
namespace internal {
|
||||
|
||||
class MemoryMapRegionSnapshotFuchsia : public MemoryMapRegionSnapshot {
|
||||
public:
|
||||
explicit MemoryMapRegionSnapshotFuchsia(const zx_info_maps_t& info_map);
|
||||
~MemoryMapRegionSnapshotFuchsia() override;
|
||||
|
||||
virtual const MINIDUMP_MEMORY_INFO& AsMinidumpMemoryInfo() const override;
|
||||
|
||||
private:
|
||||
MINIDUMP_MEMORY_INFO memory_info_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_SNAPSHOT_FUCHSIA_MEMORY_MAP_REGION_SNAPSHOT_FUCHSIA_H_
|
@ -111,6 +111,9 @@ class ProcessReaderFuchsia {
|
||||
//! \brief Return a memory reader for the target process.
|
||||
const ProcessMemory* Memory() const { return process_memory_.get(); }
|
||||
|
||||
//! \brief Return a memory map for the target process.
|
||||
const MemoryMapFuchsia* MemoryMap() const { return &memory_map_; }
|
||||
|
||||
private:
|
||||
//! Performs lazy initialization of the \a modules_ vector on behalf of
|
||||
//! Modules().
|
||||
|
@ -41,6 +41,13 @@ bool ProcessSnapshotFuchsia::Initialize(const zx::process& process) {
|
||||
InitializeThreads();
|
||||
InitializeModules();
|
||||
|
||||
for (const auto& entry : process_reader_.MemoryMap()->Entries()) {
|
||||
if (entry.type == ZX_INFO_MAPS_TYPE_MAPPING) {
|
||||
memory_map_.push_back(
|
||||
std::make_unique<internal::MemoryMapRegionSnapshotFuchsia>(entry));
|
||||
}
|
||||
}
|
||||
|
||||
INITIALIZATION_STATE_SET_VALID(initialized_);
|
||||
return true;
|
||||
}
|
||||
@ -175,7 +182,11 @@ const ExceptionSnapshot* ProcessSnapshotFuchsia::Exception() const {
|
||||
std::vector<const MemoryMapRegionSnapshot*> ProcessSnapshotFuchsia::MemoryMap()
|
||||
const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
return std::vector<const MemoryMapRegionSnapshot*>();
|
||||
std::vector<const MemoryMapRegionSnapshot*> memory_map;
|
||||
for (const auto& item : memory_map_) {
|
||||
memory_map.push_back(item.get());
|
||||
}
|
||||
return memory_map;
|
||||
}
|
||||
|
||||
std::vector<HandleSnapshot> ProcessSnapshotFuchsia::Handles() const {
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "snapshot/elf/elf_image_reader.h"
|
||||
#include "snapshot/elf/module_snapshot_elf.h"
|
||||
#include "snapshot/fuchsia/exception_snapshot_fuchsia.h"
|
||||
#include "snapshot/fuchsia/memory_map_region_snapshot_fuchsia.h"
|
||||
#include "snapshot/fuchsia/process_reader_fuchsia.h"
|
||||
#include "snapshot/fuchsia/system_snapshot_fuchsia.h"
|
||||
#include "snapshot/fuchsia/thread_snapshot_fuchsia.h"
|
||||
@ -137,6 +138,8 @@ class ProcessSnapshotFuchsia : public ProcessSnapshot {
|
||||
ProcessReaderFuchsia process_reader_;
|
||||
ProcessMemoryRange memory_range_;
|
||||
std::map<std::string, std::string> annotations_simple_map_;
|
||||
std::vector<std::unique_ptr<internal::MemoryMapRegionSnapshotFuchsia>>
|
||||
memory_map_;
|
||||
UUID report_id_;
|
||||
UUID client_id_;
|
||||
timeval snapshot_time_;
|
||||
|
141
snapshot/fuchsia/process_snapshot_fuchsia_test.cc
Normal file
141
snapshot/fuchsia/process_snapshot_fuchsia_test.cc
Normal file
@ -0,0 +1,141 @@
|
||||
// Copyright 2018 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "snapshot/fuchsia/memory_map_region_snapshot_fuchsia.h"
|
||||
|
||||
#include <dbghelp.h>
|
||||
#include <zircon/syscalls.h>
|
||||
|
||||
#include "base/fuchsia/fuchsia_logging.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "snapshot/fuchsia/process_snapshot_fuchsia.h"
|
||||
#include "test/multiprocess_exec.h"
|
||||
#include "util/fuchsia/scoped_task_suspend.h"
|
||||
|
||||
namespace crashpad {
|
||||
namespace test {
|
||||
namespace {
|
||||
|
||||
constexpr struct {
|
||||
uint32_t zircon_perm;
|
||||
size_t pages;
|
||||
uint32_t minidump_perm;
|
||||
} kTestMappingPermAndSizes[] = {
|
||||
// Zircon doesn't currently allow write-only, execute-only, or
|
||||
// write-execute-only, returning ZX_ERR_INVALID_ARGS on map.
|
||||
{0, 5, PAGE_NOACCESS},
|
||||
{ZX_VM_PERM_READ, 6, PAGE_READONLY},
|
||||
// {ZX_VM_PERM_WRITE, 7, PAGE_WRITECOPY},
|
||||
// {ZX_VM_PERM_EXECUTE, 8, PAGE_EXECUTE},
|
||||
{ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 9, PAGE_READWRITE},
|
||||
{ZX_VM_PERM_READ | ZX_VM_PERM_EXECUTE, 10, PAGE_EXECUTE_READ},
|
||||
// {ZX_VM_PERM_WRITE | ZX_VM_PERM_EXECUTE, 11, PAGE_EXECUTE_WRITECOPY},
|
||||
{ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_PERM_EXECUTE,
|
||||
12,
|
||||
PAGE_EXECUTE_READWRITE},
|
||||
};
|
||||
|
||||
CRASHPAD_CHILD_TEST_MAIN(AddressSpaceChildTestMain) {
|
||||
// Create specifically sized mappings/permissions and write the address in
|
||||
// our address space to the parent so that the reader can check they're read
|
||||
// correctly.
|
||||
for (const auto& t : kTestMappingPermAndSizes) {
|
||||
zx_handle_t vmo = ZX_HANDLE_INVALID;
|
||||
const size_t size = t.pages * PAGE_SIZE;
|
||||
zx_status_t status = zx_vmo_create(size, 0, &vmo);
|
||||
ZX_CHECK(status == ZX_OK, status) << "zx_vmo_create";
|
||||
uintptr_t mapping_addr = 0;
|
||||
status = zx_vmar_map(
|
||||
zx_vmar_root_self(), t.zircon_perm, 0, vmo, 0, size, &mapping_addr);
|
||||
ZX_CHECK(status == ZX_OK, status) << "zx_vmar_map";
|
||||
CheckedWriteFile(StdioFileHandle(StdioStream::kStandardOutput),
|
||||
&mapping_addr,
|
||||
sizeof(mapping_addr));
|
||||
}
|
||||
|
||||
CheckedReadFileAtEOF(StdioFileHandle(StdioStream::kStandardInput));
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool HasSingleMatchingMapping(
|
||||
const std::vector<const MemoryMapRegionSnapshot*>& memory_map,
|
||||
uintptr_t address,
|
||||
size_t size,
|
||||
uint32_t perm) {
|
||||
const MemoryMapRegionSnapshot* matching = nullptr;
|
||||
for (const auto* region : memory_map) {
|
||||
const MINIDUMP_MEMORY_INFO& mmi = region->AsMinidumpMemoryInfo();
|
||||
if (mmi.BaseAddress == address) {
|
||||
if (matching) {
|
||||
LOG(ERROR) << "multiple mappings matching address";
|
||||
return false;
|
||||
}
|
||||
matching = region;
|
||||
}
|
||||
}
|
||||
|
||||
if (!matching)
|
||||
return false;
|
||||
|
||||
const MINIDUMP_MEMORY_INFO& matching_mmi = matching->AsMinidumpMemoryInfo();
|
||||
return matching_mmi.Protect == perm && matching_mmi.RegionSize == size;
|
||||
}
|
||||
|
||||
class AddressSpaceTest : public MultiprocessExec {
|
||||
public:
|
||||
AddressSpaceTest() : MultiprocessExec() {
|
||||
SetChildTestMainFunction("AddressSpaceChildTestMain");
|
||||
}
|
||||
~AddressSpaceTest() {}
|
||||
|
||||
private:
|
||||
void MultiprocessParent() override {
|
||||
uintptr_t test_addresses[arraysize(kTestMappingPermAndSizes)];
|
||||
for (size_t i = 0; i < arraysize(test_addresses); ++i) {
|
||||
ASSERT_TRUE(ReadFileExactly(
|
||||
ReadPipeHandle(), &test_addresses[i], sizeof(test_addresses[i])));
|
||||
}
|
||||
|
||||
ScopedTaskSuspend suspend(*ChildProcess());
|
||||
|
||||
ProcessSnapshotFuchsia process_snapshot;
|
||||
ASSERT_TRUE(process_snapshot.Initialize(*ChildProcess()));
|
||||
|
||||
for (size_t i = 0; i < arraysize(test_addresses); ++i) {
|
||||
const auto& t = kTestMappingPermAndSizes[i];
|
||||
EXPECT_TRUE(HasSingleMatchingMapping(process_snapshot.MemoryMap(),
|
||||
test_addresses[i],
|
||||
t.pages * PAGE_SIZE,
|
||||
t.minidump_perm))
|
||||
<< base::StringPrintf(
|
||||
"index %zu, zircon_perm 0x%x, minidump_perm 0x%x",
|
||||
i,
|
||||
t.zircon_perm,
|
||||
t.minidump_perm);
|
||||
}
|
||||
}
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AddressSpaceTest);
|
||||
};
|
||||
|
||||
TEST(ProcessSnapshotFuchsiaTest, AddressSpaceMapping) {
|
||||
AddressSpaceTest test;
|
||||
test.Run();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace test
|
||||
} // namespace crashpad
|
Loading…
x
Reference in New Issue
Block a user