Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(258)

Side by Side Diff: util/win/process_info.cc

Issue 977003003: win: Add implementation of ProcessInfo (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: fixes2 Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 "util/win/process_info.h"
16
17 #include "base/logging.h"
18
19 namespace crashpad {
20
21 namespace {
22
23 NTSTATUS NtQueryInformationProcess(HANDLE process_handle,
24 PROCESSINFOCLASS process_information_class,
25 PVOID process_information,
26 ULONG process_information_length,
27 PULONG return_length) {
28 static decltype(::NtQueryInformationProcess)* nt_query_information_process =
29 reinterpret_cast<decltype(::NtQueryInformationProcess)*>(GetProcAddress(
30 LoadLibrary(L"ntdll.dll"), "NtQueryInformationProcess"));
31 DCHECK(nt_query_information_process);
32 return nt_query_information_process(process_handle,
33 process_information_class,
34 process_information,
35 process_information_length,
36 return_length);
37 }
38
39 bool IsProcessWow64(HANDLE process_handle) {
40 static decltype(IsWow64Process)* is_wow64_process =
41 reinterpret_cast<decltype(IsWow64Process)*>(
42 GetProcAddress(LoadLibrary(L"kernel32.dll"), "IsWow64Process"));
43 if (!is_wow64_process)
44 return false;
45 BOOL is_wow64;
46 if (!is_wow64_process(process_handle, &is_wow64)) {
47 PLOG(ERROR) << "IsWow64Process";
48 return false;
49 }
50 return is_wow64;
51 }
52
53 bool ReadUnicodeString(HANDLE process,
54 const UNICODE_STRING& us,
55 std::wstring* result) {
56 if (us.Length == 0) {
57 result->clear();
58 return true;
59 }
60 DCHECK_EQ(us.Length % sizeof(wchar_t), 0u);
61 result->resize(us.Length / sizeof(wchar_t));
62 SIZE_T bytes_read;
63 if (!ReadProcessMemory(
64 process, us.Buffer, &result->operator[](0), us.Length, &bytes_read)) {
65 PLOG(ERROR) << "ReadProcessMemory UNICODE_STRING";
66 return false;
67 }
68 if (bytes_read != us.Length) {
69 LOG(ERROR) << "ReadProcessMemory UNICODE_STRING incorrect size";
70 return false;
71 }
72 return true;
73 }
74
75 template <class T> bool ReadStruct(HANDLE process, uintptr_t at, T* into) {
76 SIZE_T bytes_read;
77 if (!ReadProcessMemory(process,
78 reinterpret_cast<const void*>(at),
79 into,
80 sizeof(T),
81 &bytes_read)) {
82 // We don't have a name for the type we're reading, so include the signature
83 // to get the type of T.
84 PLOG(ERROR) << "ReadProcessMemory " << __FUNCSIG__;
85 return false;
86 }
87 if (bytes_read != sizeof(T)) {
88 LOG(ERROR) << "ReadProcessMemory " << __FUNCSIG__ << " incorrect size";
89 return false;
90 }
91 return true;
92 }
93
94 // PEB_LDR_DATA in winternl.h doesn't document the trailing
95 // InInitializationOrderModuleList field. See `dt ntdll!PEB_LDR_DATA`.
96 struct FULL_PEB_LDR_DATA : public PEB_LDR_DATA {
97 LIST_ENTRY InInitializationOrderModuleList;
98 };
99
100 // LDR_DATA_TABLE_ENTRY doesn't include InInitializationOrderLinks, define a
101 // complete version here. See `dt ntdll!_LDR_DATA_TABLE_ENTRY`.
102 struct FULL_LDR_DATA_TABLE_ENTRY {
103 LIST_ENTRY InLoadOrderLinks;
104 LIST_ENTRY InMemoryOrderLinks;
105 LIST_ENTRY InInitializationOrderLinks;
106 PVOID DllBase;
107 PVOID EntryPoint;
108 ULONG SizeOfImage;
109 UNICODE_STRING FullDllName;
110 UNICODE_STRING BaseDllName;
111 ULONG Flags;
112 WORD LoadCount;
113 WORD TlsIndex;
114 LIST_ENTRY HashLinks;
115 ULONG TimeDateStamp;
116 _ACTIVATION_CONTEXT* EntryPointActivationContext;
117 };
118
119 } // namespace
120
121 ProcessInfo::ProcessInfo()
122 : process_basic_information_(),
123 command_line_(),
124 modules_(),
125 is_64_bit_(false),
126 is_wow64_(false),
127 initialized_() {
128 }
129
130 ProcessInfo::~ProcessInfo() {
131 }
132
133 bool ProcessInfo::Initialize(HANDLE process) {
134 INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
135
136 is_wow64_ = IsProcessWow64(process);
137
138 if (is_wow64_) {
139 // If it's WoW64, then it's 32-on-64.
140 is_64_bit_ = false;
141 } else {
142 // Otherwise, it's either 32 on 32, or 64 on 64. Use GetSystemInfo() to
143 // distinguish between these two cases.
144 SYSTEM_INFO system_info;
145 GetSystemInfo(&system_info);
146 is_64_bit_ =
147 system_info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64;
148 }
149
150 #if ARCH_CPU_64_BITS
151 if (!is_64_bit_) {
152 LOG(ERROR) << "Reading different bitness not yet supported";
153 return false;
154 }
155 #else
156 if (is_64_bit_) {
157 LOG(ERROR) << "Reading x64 process from x86 process not supported";
158 return false;
159 }
160 #endif
161
162 ULONG bytes_returned;
163 NTSTATUS status =
164 crashpad::NtQueryInformationProcess(process,
165 ProcessBasicInformation,
166 &process_basic_information_,
167 sizeof(process_basic_information_),
168 &bytes_returned);
169 if (status < 0) {
170 LOG(ERROR) << "NtQueryInformationProcess: status=" << status;
171 return false;
172 }
173 if (bytes_returned != sizeof(process_basic_information_)) {
174 LOG(ERROR) << "NtQueryInformationProcess incorrect size";
175 return false;
176 }
177
178 // Try to read the process environment block.
179 PEB peb;
180 if (!ReadStruct(process,
181 reinterpret_cast<uintptr_t>(
182 process_basic_information_.PebBaseAddress),
183 &peb)) {
184 return false;
185 }
186
187 RTL_USER_PROCESS_PARAMETERS process_parameters;
188 if (!ReadStruct(process,
189 reinterpret_cast<uintptr_t>(peb.ProcessParameters),
190 &process_parameters)) {
191 return false;
192 }
193
194 if (!ReadUnicodeString(
195 process, process_parameters.CommandLine, &command_line_)) {
196 return false;
197 }
198
199 FULL_PEB_LDR_DATA peb_ldr_data;
200 if (!ReadStruct(process, reinterpret_cast<uintptr_t>(peb.Ldr), &peb_ldr_data))
201 return false;
202
203 // Include the first module in the memory order list to get our own name as
Mark Mentovai 2015/03/06 03:40:23 Is this true even if you build an executable with
scottmg 2015/03/06 06:04:07 Good question! Experimentally, yes, on Win81 at le
204 // it's not included in initialization order below.
205 std::wstring self_module;
206 FULL_LDR_DATA_TABLE_ENTRY self_ldr_data_table_entry;
207 if (!ReadStruct(process,
208 reinterpret_cast<uintptr_t>(
209 reinterpret_cast<const char*>(
210 peb_ldr_data.InMemoryOrderModuleList.Flink) -
211 offsetof(FULL_LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks)),
212 &self_ldr_data_table_entry)) {
213 return false;
214 }
215 if (!ReadUnicodeString(
216 process, self_ldr_data_table_entry.FullDllName, &self_module)) {
217 return false;
218 }
219 modules_.push_back(self_module);
220
221 // Walk the PEB LDR structure (doubly-linked list) to get the list of loaded
222 // modules. We use this method rather than EnumProcessModules to get the
223 // modules in initialization order rather than memory order.
224 const LIST_ENTRY* last = peb_ldr_data.InInitializationOrderModuleList.Blink;
225 FULL_LDR_DATA_TABLE_ENTRY ldr_data_table_entry;
226 for (const LIST_ENTRY* cur =
227 peb_ldr_data.InInitializationOrderModuleList.Flink;
228 ;
229 cur = ldr_data_table_entry.InInitializationOrderLinks.Flink) {
230 // |cur| is the pointer to the LIST_ENTRY embedded in the
231 // FULL_LDR_DATA_TABLE_ENTRY, in the target process's address space. So we
232 // need to read from the target, and also offset back to the beginning of
233 // the structure.
234 if (!ReadStruct(
235 process,
236 reinterpret_cast<uintptr_t>(reinterpret_cast<const char*>(cur) -
237 offsetof(FULL_LDR_DATA_TABLE_ENTRY,
238 InInitializationOrderLinks)),
239 &ldr_data_table_entry)) {
240 break;
241 }
242 // TODO(scottmg): Capture TimeDateStamp, Checksum, etc. too?
243 std::wstring module;
244 if (!ReadUnicodeString(process, ldr_data_table_entry.FullDllName, &module))
245 break;
246 modules_.push_back(module);
247 if (cur == last)
248 break;
249 }
250
251 INITIALIZATION_STATE_SET_VALID(initialized_);
252 return true;
253 }
254
255 bool ProcessInfo::Is64Bit() const {
256 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
257 return is_64_bit_;
258 }
259
260 bool ProcessInfo::IsWow64() const {
261 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
262 return is_wow64_;
263 }
264
265 pid_t ProcessInfo::ProcessID() const {
266 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
267 return process_basic_information_.UniqueProcessId;
268 }
269
270 pid_t ProcessInfo::ParentProcessID() const {
271 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
272 return process_basic_information_.InheritedFromUniqueProcessId;
273 }
274
275 bool ProcessInfo::CommandLine(std::wstring* command_line) const {
276 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
277 *command_line = command_line_;
278 return true;
279 }
280
281 bool ProcessInfo::Modules(std::vector<std::wstring>* modules) const {
282 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
283 *modules = modules_;
284 return true;
285 }
286
287 } // namespace crashpad
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698