Chromium Code Reviews| Index: snapshot/win/exception_snapshot_win.cc |
| diff --git a/snapshot/win/exception_snapshot_win.cc b/snapshot/win/exception_snapshot_win.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..4f8001fb7ddcfe337a0d5ba60e7d26792b774ae7 |
| --- /dev/null |
| +++ b/snapshot/win/exception_snapshot_win.cc |
| @@ -0,0 +1,170 @@ |
| +// 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/win/exception_snapshot_win.h" |
| + |
| +#include "snapshot/win/cpu_context_win.h" |
| +#include "snapshot/win/process_reader_win.h" |
| +#include "util/win/nt_internals.h" |
| +#include "util/win/process_structs.h" |
| + |
| +namespace crashpad { |
| +namespace internal { |
| + |
| +namespace { |
| + |
| +// ::GetThreadId is not available on XP, so get the thread id via |
| +// NtQueryInformationThread. |
| +template <class Traits> |
| +uint64_t GetThreadId(HANDLE handle) { |
|
Mark Mentovai
2015/08/18 16:17:19
Can you add a test for this that makes sure that i
scottmg
2015/08/18 16:56:00
Removed.
|
| + process_types::THREAD_BASIC_INFORMATION<Traits> basic_information; |
| + if (!NT_SUCCESS(crashpad::NtQueryInformationThread( |
| + handle, |
| + static_cast<THREADINFOCLASS>(ThreadBasicInformation), |
| + &basic_information, |
| + sizeof(basic_information), |
| + nullptr))) { |
| + LOG(ERROR) << "could not retrieve ThreadBasicInformation"; |
|
Mark Mentovai
2015/08/18 16:17:19
This and a couple of other things we have would be
scottmg
2015/08/18 16:56:00
Removed.
|
| + return 0; |
| + } |
| + return basic_information.ClientId.UniqueThread; |
|
Mark Mentovai
2015/08/18 16:17:19
This is declared in our structs as a Pointer, but
scottmg
2015/08/18 16:56:00
Removed.
|
| +} |
| + |
| +uint64_t GetThreadId(ProcessReaderWin* process_reader, HANDLE handle) { |
|
Mark Mentovai
2015/08/18 16:17:19
Now I feel duped. This doesn’t seem to be called b
scottmg
2015/08/18 16:56:00
Oops, sorry. I previously had the thread HANDLE be
|
| + if (process_reader->Is64Bit()) |
| + return GetThreadId<process_types::internal::Traits64>(handle); |
| + else |
| + return GetThreadId<process_types::internal::Traits32>(handle); |
| +} |
| + |
| +} // namespace |
| + |
| +ExceptionSnapshotWin::ExceptionSnapshotWin() |
| + : ExceptionSnapshot(), |
| + context_union_(), |
| + context_(), |
| + codes_(), |
| + thread_id_(0), |
| + exception_address_(0), |
| + exception_flags_(0), |
| + exception_code_(0), |
| + initialized_() { |
| +} |
| + |
| +ExceptionSnapshotWin::~ExceptionSnapshotWin() { |
| +} |
| + |
| +bool ExceptionSnapshotWin::Initialize(ProcessReaderWin* process_reader, |
| + DWORD thread_id, |
| + WinVMAddress exception_pointers_address) { |
| + INITIALIZATION_STATE_SET_INITIALIZING(initialized_); |
| + |
| + bool found_thread = false; |
| + for (const auto& loop_thread : process_reader->Threads()) { |
| + if (thread_id == loop_thread.id) { |
| + found_thread = true; |
| + break; |
| + } |
| + } |
| + |
| + if (!found_thread) { |
| + LOG(ERROR) << "thread id not found in process"; |
|
Mark Mentovai
2015/08/18 16:17:19
Spew out the problem ID here?
scottmg
2015/08/18 16:56:00
Done.
|
| + return false; |
| + } else { |
| + thread_id_ = thread_id; |
| + } |
| + |
| + EXCEPTION_POINTERS exception_pointers; |
| + if (!process_reader->ReadMemory(exception_pointers_address, |
| + sizeof(EXCEPTION_POINTERS), |
| + &exception_pointers)) { |
| + LOG(ERROR) << "EXCEPTION_POINTERS read failed"; |
| + return false; |
| + } |
| + if (!exception_pointers.ExceptionRecord) { |
| + LOG(ERROR) << "null ExceptionRecord"; |
| + return false; |
| + } |
| + |
| + if (process_reader->Is64Bit()) { |
| + EXCEPTION_RECORD64 first_record; |
| + if (!process_reader->ReadMemory( |
| + reinterpret_cast<WinVMAddress>(exception_pointers.ExceptionRecord), |
| + sizeof(first_record), |
| + &first_record)) { |
| + LOG(ERROR) << "ExceptionRecord"; |
| + return false; |
| + } |
| + exception_code_ = first_record.ExceptionCode; |
| + exception_flags_ = first_record.ExceptionFlags; |
| + exception_address_ = first_record.ExceptionAddress; |
| + for (DWORD i = 0; i < first_record.NumberParameters; ++i) |
| + codes_.push_back(first_record.ExceptionInformation[i]); |
| + if (first_record.ExceptionRecord) |
| + LOG(WARNING) << "dropping chained ExceptionRecord"; |
| + |
| + context_.architecture = kCPUArchitectureX86_64; |
| + context_.x86_64 = &context_union_.x86_64; |
| + // We assume 64-on-64 here in that we're relying on the CONTEXT definition |
| + // to be the x64 one. |
| + CONTEXT context_record; |
| + if (!process_reader->ReadMemory( |
| + reinterpret_cast<WinVMAddress>(exception_pointers.ContextRecord), |
| + sizeof(context_record), |
| + &context_record)) { |
| + LOG(ERROR) << "ContextRecord"; |
| + return false; |
| + } |
| + InitializeX64Context(context_record, context_.x86_64); |
| + } else { |
| + CHECK(false) << "TODO(scottmg) x86"; |
| + return false; |
| + } |
| + |
| + INITIALIZATION_STATE_SET_VALID(initialized_); |
| + return true; |
| +} |
| + |
| +const CPUContext* ExceptionSnapshotWin::Context() const { |
| + INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| + return &context_; |
| +} |
| + |
| +uint64_t ExceptionSnapshotWin::ThreadID() const { |
| + INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| + return thread_id_; |
| +} |
| + |
| +uint32_t ExceptionSnapshotWin::Exception() const { |
| + INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| + return exception_code_; |
| +} |
| + |
| +uint32_t ExceptionSnapshotWin::ExceptionInfo() const { |
| + INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| + return exception_flags_; |
| +} |
| + |
| +uint64_t ExceptionSnapshotWin::ExceptionAddress() const { |
| + INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| + return exception_address_; |
| +} |
| + |
| +const std::vector<uint64_t>& ExceptionSnapshotWin::Codes() const { |
| + INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| + return codes_; |
| +} |
| + |
| +} // namespace internal |
| +} // namespace crashpad |