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

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: fixes 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 = std::wstring();
Mark Mentovai 2015/03/05 21:53:36 result->clear()
scottmg 2015/03/06 00:42:52 Done.
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__;
Mark Mentovai 2015/03/05 21:53:36 Tiny nit: colons on these messages but not on the
scottmg 2015/03/06 00:42:52 Done.
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. Add that here.
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.
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 union {
115 LIST_ENTRY HashLinks;
116 struct {
117 PVOID SectionPointer;
118 ULONG CheckSum;
119 };
120 };
121 union {
122 ULONG TimeDateStamp;
123 PVOID LoadedImports;
124 };
125 _ACTIVATION_CONTEXT* EntryPointActivationContext;
126 PVOID PatchInformation;
127 LIST_ENTRY ForwarderLinks;
128 LIST_ENTRY ServiceTagLinks;
129 LIST_ENTRY StaticLinks;
130 };
131
132 } // namespace
133
134 ProcessInfo::ProcessInfo()
135 : process_basic_information_(),
136 command_line_(),
Mark Mentovai 2015/03/05 21:53:36 Let’s be explicit about everything: modules_ and i
scottmg 2015/03/06 00:42:52 Done.
137 is_64_bit_(false),
138 is_wow64_(false) {
139 }
140
141 ProcessInfo::~ProcessInfo() {
142 }
143
144 bool ProcessInfo::Initialize(HANDLE process) {
145 INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
146
147 is_wow64_ = IsProcessWow64(process);
148
149 if (is_wow64_) {
150 // If it's WoW64, then it's 32-on-64.
151 is_64_bit_ = false;
152 } else {
153 // Otherwise, it's either 32 on 32, or 64 on 64. Use GetSystemInfo() to
154 // distinguish between these two cases.
155 SYSTEM_INFO system_info;
156 GetSystemInfo(&system_info);
157 is_64_bit_ =
158 system_info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64;
159 }
160
161 #if ARCH_CPU_64_BITS
162 if (!is_64_bit_) {
163 LOG(ERROR) << "Reading different bitness not yet supported";
164 return false;
165 }
166 #else
167 if (is_64_bit_) {
168 LOG(ERROR) << "Reading x64 process from x86 process not supported";
Mark Mentovai 2015/03/05 21:53:36 The “escape WoW64 and call the native function” is
scottmg 2015/03/06 00:42:52 In this case, the Wow64 ntdll contains the necessa
169 return false;
170 }
171 #endif
172
173 ULONG bytes_returned;
174 NTSTATUS status =
175 crashpad::NtQueryInformationProcess(process,
176 ProcessBasicInformation,
177 &process_basic_information_,
178 sizeof(process_basic_information_),
179 &bytes_returned);
180 if (status < 0) {
181 LOG(ERROR) << "NtQueryInformationProcess: status=" << status;
182 return false;
183 }
184 if (bytes_returned != sizeof(process_basic_information_)) {
185 LOG(ERROR) << "NtQueryInformationProcess incorrect size";
186 return false;
187 }
188
189 // Try to read the process environment block.
190 PEB peb;
191 if (!ReadStruct(process,
192 reinterpret_cast<uintptr_t>(
193 process_basic_information_.PebBaseAddress),
194 &peb))
195 return false;
Mark Mentovai 2015/03/05 21:53:36 {} on these raggedy ifs. The next one too.
scottmg 2015/03/06 00:42:52 Oops, done.
196
197 RTL_USER_PROCESS_PARAMETERS process_parameters;
198 if (!ReadStruct(process,
199 reinterpret_cast<uintptr_t>(peb.ProcessParameters),
200 &process_parameters))
201 return false;
202
203 if (!ReadUnicodeString(
204 process, process_parameters.CommandLine, &command_line_)) {
205 return false;
206 }
207
208 FULL_PEB_LDR_DATA peb_ldr_data;
209 if (!ReadStruct(process, reinterpret_cast<uintptr_t>(peb.Ldr), &peb_ldr_data))
210 return false;
211
212 // Walk the PEB LDR structure (doubly-linked list) to get the list of loaded
213 // modules. We use this method rather than EnumProcessModules to get the
214 // modules in initialization order rather than memory order.
215 LIST_ENTRY* last = peb_ldr_data.InInitializationOrderModuleList.Blink;
Mark Mentovai 2015/03/05 21:53:36 Can last and cur can be pointers to const data? If
scottmg 2015/03/06 00:42:52 Done.
216 FULL_LDR_DATA_TABLE_ENTRY ldr_data_table_entry;
Mark Mentovai 2015/03/05 21:53:36 Pull this into the loop body.
scottmg 2015/03/06 00:42:52 Can't, it's used in the loop-expression.
217 for (LIST_ENTRY* cur = peb_ldr_data.InInitializationOrderModuleList.Flink;;
218 cur = ldr_data_table_entry.InInitializationOrderLinks.Flink) {
219 // |cur| is the pointer to the LIST_ENTRY embedded in the
220 // FULL_LDR_DATA_TABLE_ENTRY, in the target process's address space. So we
221 // need to read from the target, and also offset back to the beginning of
222 // the structure.
223 if (!ReadStruct(
224 process,
225 reinterpret_cast<uintptr_t>(reinterpret_cast<char*>(cur) -
226 offsetof(FULL_LDR_DATA_TABLE_ENTRY,
227 InInitializationOrderLinks)),
228 &ldr_data_table_entry)) {
229 break;
230 }
231 // TODO(scottmg): Capture TimeDateStamp, Checksum, etc. too?
232 std::wstring module;
233 if (!ReadUnicodeString(process, ldr_data_table_entry.FullDllName, &module))
234 break;
235 modules_.push_back(module);
236 if (cur == last)
Mark Mentovai 2015/03/05 21:53:36 Oh right, I see, yeah, this has to be in the loop.
237 break;
238 }
239
240 INITIALIZATION_STATE_SET_VALID(initialized_);
241 return true;
242 }
243
244 bool ProcessInfo::Is64Bit() const {
245 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
246 return is_64_bit_;
247 }
248
249 bool ProcessInfo::IsWow64() const {
250 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
251 return is_wow64_;
252 }
253
254 pid_t ProcessInfo::ProcessID() const {
255 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
256 return process_basic_information_.UniqueProcessId;
257 }
258
259 pid_t ProcessInfo::ParentProcessID() const {
260 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
261 return process_basic_information_.InheritedFromUniqueProcessId;
262 }
263
264 bool ProcessInfo::CommandLine(std::wstring* command_line) const {
265 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
266 *command_line = command_line_;
267 return true;
268 }
269
270 bool ProcessInfo::Modules(std::vector<std::wstring>* modules) const {
271 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
272 *modules = modules_;
273 return true;
274 }
275
276 } // namespace crashpad
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698