From 4600643a78e8080713bfef6b12b7ab7b6956c6bf Mon Sep 17 00:00:00 2001 From: Scott Graham Date: Fri, 16 Oct 2015 15:58:40 -0700 Subject: [PATCH] Some plumbing for the beginning of getting handles into snapshot/minidump Follows https://codereview.chromium.org/1400413002/. R=mark@chromium.org BUG=crashpad:21, crashpad:46, crashpad:52 Review URL: https://codereview.chromium.org/1407643004 . --- compat/non_win/dbghelp.h | 65 +++++++++++++++++++ snapshot/handle_snapshot.cc | 31 +++++++++ snapshot/handle_snapshot.h | 56 ++++++++++++++++ .../minidump/process_snapshot_minidump.cc | 6 ++ snapshot/minidump/process_snapshot_minidump.h | 1 + snapshot/process_snapshot.h | 7 ++ snapshot/snapshot.gyp | 2 + snapshot/test/test_process_snapshot.cc | 5 ++ snapshot/test/test_process_snapshot.h | 9 +++ snapshot/win/process_snapshot_win.cc | 15 +++++ snapshot/win/process_snapshot_win.h | 1 + util/win/process_info.cc | 2 +- util/win/process_info.h | 8 ++- 13 files changed, 205 insertions(+), 3 deletions(-) create mode 100644 snapshot/handle_snapshot.cc create mode 100644 snapshot/handle_snapshot.h diff --git a/compat/non_win/dbghelp.h b/compat/non_win/dbghelp.h index 6fed86bd..baf088ba 100644 --- a/compat/non_win/dbghelp.h +++ b/compat/non_win/dbghelp.h @@ -621,6 +621,71 @@ struct __attribute__((packed, aligned(4))) MINIDUMP_MEMORY_LIST { MINIDUMP_MEMORY_DESCRIPTOR MemoryRanges[0]; }; +//! \brief Contains the state of an individual system handle at the time the +//! snapshot was taken. This structure is Windows-specific. +//! +//! \sa MINIDUMP_HANDLE_DESCRIPTOR_2 +struct __attribute__((packed, aligned(4))) MINIDUMP_HANDLE_DESCRIPTOR { + //! \brief The Windows `HANDLE` value. + uint64_t Handle; + + //! \brief An RVA to a MINIDUMP_STRING structure that specifies the object + //! type of the handle. This member can be zero. + RVA TypeNameRva; + + //! \brief An RVA to a MINIDUMP_STRING structure that specifies the object + //! name of the handle. This member can be zero. + RVA ObjectNameRva; + + //! \brief The attributes for the handle, this corresponds to `OBJ_INHERIT`, + //! `OBJ_CASE_INSENSITIVE`, etc. + uint32_t Attributes; + + //! \brief The `ACCESS_MASK` for the handle. + uint32_t GrantedAccess; + + //! \brief This is the number of open handles to the object that this handle + //! refers to. + uint32_t HandleCount; + + //! \brief This is the number kernel references to the object that this + //! handle refers to. + uint32_t PointerCount; +}; + +//! \brief Contains the state of an individual system handle at the time the +//! snapshot was taken. This structure is Windows-specific. +//! +//! \sa MINIDUMP_HANDLE_DESCRIPTOR +struct __attribute__((packed, aligned(4))) MINIDUMP_HANDLE_DESCRIPTOR_2 + : public MINIDUMP_HANDLE_DESCRIPTOR { + //! \brief An RVA to a MINIDUMP_HANDLE_OBJECT_INFORMATION structure that + //! specifies object-specific information. This member can be zero if + //! there is no extra information. + RVA ObjectInfoRva; + + //! \brief Must be zero. + uint32_t Reserved0; +}; + +//! \brief Represents the header for a handle data stream. +struct __attribute((packed, aligned(4))) MINIDUMP_HANDLE_DATA_STREAM { + //! \brief The size of the header information for the stream, in bytes. This + //! value is `sizeof(MINIDUMP_HANDLE_DATA_STREAM)`. + uint32_t SizeOfHeader; + + //! \brief The size of a descriptor in the stream, in bytes. This value is + //! `sizeof(MINIDUMP_HANDLE_DESCRIPTOR)` or + //! `sizeof(MINIDUMP_HANDLE_DESCRIPTOR_2)`. + uint32_t SizeOfDescriptor; + + //! \brief The number of descriptors in the stream. + uint32_t NumberOfDescriptors; + + //! \brief Must be zero. + uint32_t Reserved; +}; + //! \anchor MINIDUMP_MISCx //! \name MINIDUMP_MISC* //! diff --git a/snapshot/handle_snapshot.cc b/snapshot/handle_snapshot.cc new file mode 100644 index 00000000..331b6b35 --- /dev/null +++ b/snapshot/handle_snapshot.cc @@ -0,0 +1,31 @@ +// Copyright 2015 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/handle_snapshot.h" + +namespace crashpad { + +HandleSnapshot::HandleSnapshot() + : type_name(), + handle(0), + attributes(0), + granted_access(0), + pointer_count(0), + handle_count(0) { +} + +HandleSnapshot::~HandleSnapshot() { +} + +} // namespace crashpad diff --git a/snapshot/handle_snapshot.h b/snapshot/handle_snapshot.h new file mode 100644 index 00000000..b86706e7 --- /dev/null +++ b/snapshot/handle_snapshot.h @@ -0,0 +1,56 @@ +// Copyright 2015 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_HANDLE_SNAPSHOT_H_ +#define CRASHPAD_SNAPSHOT_HANDLE_SNAPSHOT_H_ + +#include + +#include + +namespace crashpad { + +struct HandleSnapshot { + HandleSnapshot(); + ~HandleSnapshot(); + + //! \brief A string representation of the handle's type. + std::wstring type_name; + + //! \brief The handle's value. + uint32_t handle; + + //! \brief The attributes for the handle, e.g. `OBJ_INHERIT`, + //! `OBJ_CASE_INSENSITIVE`, etc. + uint32_t attributes; + + //! \brief The ACCESS_MASK for the handle in this process. + //! + //! See + //! http://blogs.msdn.com/b/openspecification/archive/2010/04/01/about-the-access-mask-structure.aspx + //! for more information. + uint32_t granted_access; + + //! \brief The number of kernel references to the object that this handle + //! refers to. + uint32_t pointer_count; + + //! \brief The number of open handles to the object that this handle refers + //! to. + uint32_t handle_count; +}; + +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_HANDLE_SNAPSHOT_H_ diff --git a/snapshot/minidump/process_snapshot_minidump.cc b/snapshot/minidump/process_snapshot_minidump.cc index d07274f3..2d6c6dbf 100644 --- a/snapshot/minidump/process_snapshot_minidump.cc +++ b/snapshot/minidump/process_snapshot_minidump.cc @@ -184,6 +184,12 @@ std::vector ProcessSnapshotMinidump::MemoryMap() return std::vector(); } +std::vector ProcessSnapshotMinidump::Handles() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); // https://code.google.com/p/crashpad/issues/detail?id=10 + return std::vector(); +} + std::vector ProcessSnapshotMinidump::ExtraMemory() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); diff --git a/snapshot/minidump/process_snapshot_minidump.h b/snapshot/minidump/process_snapshot_minidump.h index c02fcc9b..9384eaff 100644 --- a/snapshot/minidump/process_snapshot_minidump.h +++ b/snapshot/minidump/process_snapshot_minidump.h @@ -70,6 +70,7 @@ class ProcessSnapshotMinidump final : public ProcessSnapshot { std::vector Modules() const override; const ExceptionSnapshot* Exception() const override; std::vector MemoryMap() const override; + std::vector Handles() const override; std::vector ExtraMemory() const override; private: diff --git a/snapshot/process_snapshot.h b/snapshot/process_snapshot.h index 0a2f4f9f..19d34607 100644 --- a/snapshot/process_snapshot.h +++ b/snapshot/process_snapshot.h @@ -22,6 +22,7 @@ #include #include +#include "snapshot/handle_snapshot.h" #include "util/misc/uuid.h" namespace crashpad { @@ -171,6 +172,12 @@ class ProcessSnapshot { //! the ProcessSnapshot object that they were obtained from. virtual std::vector MemoryMap() const = 0; + //! \brief Returns HandleSnapshot objects reflecting the open handles in the + //! snapshot process at the time of the snapshot. + //! + //! \return A vector of HandleSnapshot objects. + virtual std::vector Handles() const = 0; + //! \brief Returns a vector of additional memory blocks that should be //! included in a minidump. //! diff --git a/snapshot/snapshot.gyp b/snapshot/snapshot.gyp index 76d07aa6..0a78e90c 100644 --- a/snapshot/snapshot.gyp +++ b/snapshot/snapshot.gyp @@ -36,6 +36,8 @@ 'crashpad_info_client_options.cc', 'crashpad_info_client_options.h', 'exception_snapshot.h', + 'handle_snapshot.cc', + 'handle_snapshot.h', 'mac/cpu_context_mac.cc', 'mac/cpu_context_mac.h', 'mac/exception_snapshot_mac.cc', diff --git a/snapshot/test/test_process_snapshot.cc b/snapshot/test/test_process_snapshot.cc index d388c601..c022dc41 100644 --- a/snapshot/test/test_process_snapshot.cc +++ b/snapshot/test/test_process_snapshot.cc @@ -34,6 +34,7 @@ TestProcessSnapshot::TestProcessSnapshot() modules_(), exception_(), memory_map_(), + handles_(), extra_memory_() { } @@ -107,6 +108,10 @@ std::vector TestProcessSnapshot::MemoryMap() return memory_map; } +std::vector TestProcessSnapshot::Handles() const { + return handles_; +} + std::vector TestProcessSnapshot::ExtraMemory() const { std::vector extra_memory; for (const auto& em : extra_memory_) diff --git a/snapshot/test/test_process_snapshot.h b/snapshot/test/test_process_snapshot.h index 2f5cd45a..ec124481 100644 --- a/snapshot/test/test_process_snapshot.h +++ b/snapshot/test/test_process_snapshot.h @@ -106,6 +106,13 @@ class TestProcessSnapshot final : public ProcessSnapshot { memory_map_.push_back(region.release()); } + //! \brief Adds a handle snapshot to be returned by Handles(). + //! + //! \param[in] region The handle snapshot that will be included in Handles(). + void AddHandle(const HandleSnapshot& handle) { + handles_.push_back(handle); + } + //! \brief Add a memory snapshot to be returned by ExtraMemory(). //! //! \param[in] extra_memory The memory snapshot that will be included in @@ -131,6 +138,7 @@ class TestProcessSnapshot final : public ProcessSnapshot { std::vector Modules() const override; const ExceptionSnapshot* Exception() const override; std::vector MemoryMap() const override; + std::vector Handles() const override; std::vector ExtraMemory() const override; private: @@ -148,6 +156,7 @@ class TestProcessSnapshot final : public ProcessSnapshot { PointerVector modules_; scoped_ptr exception_; PointerVector memory_map_; + std::vector handles_; PointerVector extra_memory_; DISALLOW_COPY_AND_ASSIGN(TestProcessSnapshot); diff --git a/snapshot/win/process_snapshot_win.cc b/snapshot/win/process_snapshot_win.cc index e3f4baad..ca26d4b8 100644 --- a/snapshot/win/process_snapshot_win.cc +++ b/snapshot/win/process_snapshot_win.cc @@ -207,6 +207,21 @@ std::vector ProcessSnapshotWin::MemoryMap() return memory_map; } +std::vector ProcessSnapshotWin::Handles() const { + std::vector result; + for (const auto& handle : process_reader_.GetProcessInfo().Handles()) { + HandleSnapshot snapshot; + snapshot.type_name = handle.type_name; + snapshot.handle = handle.handle; + snapshot.attributes = handle.attributes; + snapshot.granted_access = handle.granted_access; + snapshot.pointer_count = handle.pointer_count; + snapshot.handle_count = handle.handle_count; + result.push_back(snapshot); + } + return result; +} + std::vector ProcessSnapshotWin::ExtraMemory() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); std::vector extra_memory; diff --git a/snapshot/win/process_snapshot_win.h b/snapshot/win/process_snapshot_win.h index c9edfac3..a7238fd7 100644 --- a/snapshot/win/process_snapshot_win.h +++ b/snapshot/win/process_snapshot_win.h @@ -135,6 +135,7 @@ class ProcessSnapshotWin final : public ProcessSnapshot { std::vector Modules() const override; const ExceptionSnapshot* Exception() const override; std::vector MemoryMap() const override; + std::vector Handles() const override; std::vector ExtraMemory() const override; private: diff --git a/util/win/process_info.cc b/util/win/process_info.cc index 01748ff4..ee5668b4 100644 --- a/util/win/process_info.cc +++ b/util/win/process_info.cc @@ -602,7 +602,7 @@ ProcessInfo::GetReadableRanges( return GetReadableRangesOfMemoryMap(range, MemoryInfo()); } -const std::vector& ProcessInfo::Handles() { +const std::vector& ProcessInfo::Handles() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); if (handles_.empty()) handles_ = BuildHandleVector(process_); diff --git a/util/win/process_info.h b/util/win/process_info.h index 019e945c..41b92598 100644 --- a/util/win/process_info.h +++ b/util/win/process_info.h @@ -140,7 +140,7 @@ class ProcessInfo { const CheckedRange& range) const; //! \brief Retrieves information about open handles in the target process. - const std::vector& Handles(); + const std::vector& Handles() const; private: template @@ -168,7 +168,11 @@ class ProcessInfo { WinVMSize peb_size_; std::vector modules_; std::vector memory_info_; - std::vector handles_; + + // Handles() is logically const, but updates this member on first retrieval. + // See https://code.google.com/p/crashpad/issues/detail?id=9. + mutable std::vector handles_; + bool is_64_bit_; bool is_wow64_; InitializationStateDcheck initialized_;