1 // Copyright 2015 The Crashpad Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "snapshot/win/thread_snapshot_win.h"
16 
17 #include <iterator>
18 #include <vector>
19 
20 #include "base/check_op.h"
21 #include "snapshot/capture_memory.h"
22 #include "snapshot/win/capture_memory_delegate_win.h"
23 #include "snapshot/win/cpu_context_win.h"
24 #include "snapshot/win/process_reader_win.h"
25 
26 namespace crashpad {
27 namespace internal {
28 
ThreadSnapshotWin()29 ThreadSnapshotWin::ThreadSnapshotWin()
30     : ThreadSnapshot(),
31       context_(),
32       stack_(),
33       teb_(),
34       thread_(),
35       initialized_() {
36 }
37 
~ThreadSnapshotWin()38 ThreadSnapshotWin::~ThreadSnapshotWin() {
39 }
40 
Initialize(ProcessReaderWin * process_reader,const ProcessReaderWin::Thread & process_reader_thread,uint32_t * gather_indirectly_referenced_memory_bytes_remaining)41 bool ThreadSnapshotWin::Initialize(
42     ProcessReaderWin* process_reader,
43     const ProcessReaderWin::Thread& process_reader_thread,
44     uint32_t* gather_indirectly_referenced_memory_bytes_remaining) {
45   INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
46 
47   thread_ = process_reader_thread;
48   if (process_reader->GetProcessInfo().LoggingRangeIsFullyReadable(
49           CheckedRange<WinVMAddress, WinVMSize>(thread_.stack_region_address,
50                                                 thread_.stack_region_size))) {
51     stack_.Initialize(process_reader->Memory(),
52                       thread_.stack_region_address,
53                       thread_.stack_region_size);
54   } else {
55     stack_.Initialize(process_reader->Memory(), 0, 0);
56   }
57 
58   if (process_reader->GetProcessInfo().LoggingRangeIsFullyReadable(
59           CheckedRange<WinVMAddress, WinVMSize>(thread_.teb_address,
60                                                 thread_.teb_size))) {
61     teb_.Initialize(
62         process_reader->Memory(), thread_.teb_address, thread_.teb_size);
63   } else {
64     teb_.Initialize(process_reader->Memory(), 0, 0);
65   }
66 
67 #if defined(ARCH_CPU_X86)
68   context_.architecture = kCPUArchitectureX86;
69   context_.x86 = &context_union_.x86;
70   InitializeX86Context(process_reader_thread.context.native, context_.x86);
71 #elif defined(ARCH_CPU_X86_64)
72   if (process_reader->Is64Bit()) {
73     context_.architecture = kCPUArchitectureX86_64;
74     context_.x86_64 = &context_union_.x86_64;
75     InitializeX64Context(process_reader_thread.context.native, context_.x86_64);
76   } else {
77     context_.architecture = kCPUArchitectureX86;
78     context_.x86 = &context_union_.x86;
79     InitializeX86Context(process_reader_thread.context.wow64, context_.x86);
80   }
81 #elif defined(ARCH_CPU_ARM64)
82   context_.architecture = kCPUArchitectureARM64;
83   context_.arm64 = &context_union_.arm64;
84   InitializeARM64Context(process_reader_thread.context.native, context_.arm64);
85 #else
86 #error Unsupported Windows Arch
87 #endif  // ARCH_CPU_X86
88 
89   CaptureMemoryDelegateWin capture_memory_delegate(
90       process_reader,
91       thread_,
92       &pointed_to_memory_,
93       gather_indirectly_referenced_memory_bytes_remaining);
94   CaptureMemory::PointedToByContext(context_, &capture_memory_delegate);
95   if (gather_indirectly_referenced_memory_bytes_remaining) {
96     CaptureMemory::PointedToByMemoryRange(stack_, &capture_memory_delegate);
97   }
98 
99   INITIALIZATION_STATE_SET_VALID(initialized_);
100   return true;
101 }
102 
Context() const103 const CPUContext* ThreadSnapshotWin::Context() const {
104   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
105   return &context_;
106 }
107 
Stack() const108 const MemorySnapshot* ThreadSnapshotWin::Stack() const {
109   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
110   return &stack_;
111 }
112 
ThreadID() const113 uint64_t ThreadSnapshotWin::ThreadID() const {
114   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
115   return thread_.id;
116 }
117 
SuspendCount() const118 int ThreadSnapshotWin::SuspendCount() const {
119   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
120   return thread_.suspend_count;
121 }
122 
Priority() const123 int ThreadSnapshotWin::Priority() const {
124   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
125   return thread_.priority;
126 }
127 
ThreadSpecificDataAddress() const128 uint64_t ThreadSnapshotWin::ThreadSpecificDataAddress() const {
129   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
130   return thread_.teb_address;
131 }
132 
ExtraMemory() const133 std::vector<const MemorySnapshot*> ThreadSnapshotWin::ExtraMemory() const {
134   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
135   std::vector<const MemorySnapshot*> result;
136   result.reserve(1 + pointed_to_memory_.size());
137   result.push_back(&teb_);
138   for (const auto& pointed_to_memory : pointed_to_memory_) {
139     result.push_back(pointed_to_memory.get());
140   }
141   return result;
142 }
143 
144 }  // namespace internal
145 }  // namespace crashpad
146