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

Side by Side Diff: tools/memory_watcher/call_stack.cc

Issue 366031: Support running memory watch under vista, plus other tweaks... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 1 month 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 | Annotate | Revision Log
« no previous file with comments | « tools/memory_watcher/call_stack.h ('k') | tools/memory_watcher/dllmain.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "call_stack.h" 5 #include "call_stack.h"
6 #include <shlwapi.h> 6 #include <shlwapi.h>
7 #include <tlhelp32.h> 7 #include <tlhelp32.h>
8 8
9 #include "memory_hook.h" 9 #include "memory_hook.h"
10 #include "base/string_util.h" 10 #include "base/string_util.h"
(...skipping 15 matching lines...) Expand all
26 PIMAGEHLP_LINE64); 26 PIMAGEHLP_LINE64);
27 typedef BOOL (__stdcall *t_SymInitialize)(HANDLE, PCTSTR, BOOL); 27 typedef BOOL (__stdcall *t_SymInitialize)(HANDLE, PCTSTR, BOOL);
28 typedef DWORD (__stdcall *t_SymGetOptions)(void); 28 typedef DWORD (__stdcall *t_SymGetOptions)(void);
29 typedef DWORD (__stdcall *t_SymSetOptions)(DWORD); 29 typedef DWORD (__stdcall *t_SymSetOptions)(DWORD);
30 typedef BOOL (__stdcall *t_SymGetSearchPath)(HANDLE, PTSTR, DWORD); 30 typedef BOOL (__stdcall *t_SymGetSearchPath)(HANDLE, PTSTR, DWORD);
31 typedef DWORD64 (__stdcall *t_SymLoadModule64)(HANDLE, HANDLE, PCSTR, 31 typedef DWORD64 (__stdcall *t_SymLoadModule64)(HANDLE, HANDLE, PCSTR,
32 PCSTR, DWORD64, DWORD); 32 PCSTR, DWORD64, DWORD);
33 typedef BOOL (__stdcall *t_SymGetModuleInfo64)(HANDLE, DWORD64, 33 typedef BOOL (__stdcall *t_SymGetModuleInfo64)(HANDLE, DWORD64,
34 PIMAGEHLP_MODULE64); 34 PIMAGEHLP_MODULE64);
35 35
36 // According to http://msdn2.microsoft.com/en-us/library/ms680650(VS.85).aspx 36 // static
37 // "All DbgHelp functions, such as this one, are single threaded. Therefore, 37 Lock CallStack::dbghelp_lock_;
38 // calls from more than one thread to this function will likely result in 38 // static
39 // unexpected behavior or memory corruption. To avoid this, you must 39 bool CallStack::dbghelp_loaded_ = false;
40 // synchromize all concurrent calls from one thread to this function." 40 // static
41 // 41 DWORD CallStack::active_thread_id_ = 0;
42 // dbghelp_lock_ is used to serialize access across all calls to the DbgHelp 42
43 // library. This may be overly conservative (serializing them all together),
44 // but does guarantee correctness.
45 static Lock dbghelp_lock_;
46 43
47 static t_StackWalk64 pStackWalk64 = NULL; 44 static t_StackWalk64 pStackWalk64 = NULL;
48 static t_SymCleanup pSymCleanup = NULL; 45 static t_SymCleanup pSymCleanup = NULL;
49 static t_SymGetSymFromAddr64 pSymGetSymFromAddr64 = NULL; 46 static t_SymGetSymFromAddr64 pSymGetSymFromAddr64 = NULL;
50 static t_SymFunctionTableAccess64 pSymFunctionTableAccess64 = NULL; 47 static t_SymFunctionTableAccess64 pSymFunctionTableAccess64 = NULL;
51 static t_SymGetModuleBase64 pSymGetModuleBase64 = NULL; 48 static t_SymGetModuleBase64 pSymGetModuleBase64 = NULL;
52 static t_SymGetLineFromAddr64 pSymGetLineFromAddr64 = NULL; 49 static t_SymGetLineFromAddr64 pSymGetLineFromAddr64 = NULL;
53 static t_SymInitialize pSymInitialize = NULL; 50 static t_SymInitialize pSymInitialize = NULL;
54 static t_SymGetOptions pSymGetOptions = NULL; 51 static t_SymGetOptions pSymGetOptions = NULL;
55 static t_SymSetOptions pSymSetOptions = NULL; 52 static t_SymSetOptions pSymSetOptions = NULL;
56 static t_SymGetModuleInfo64 pSymGetModuleInfo64 = NULL; 53 static t_SymGetModuleInfo64 pSymGetModuleInfo64 = NULL;
57 static t_SymGetSearchPath pSymGetSearchPath = NULL; 54 static t_SymGetSearchPath pSymGetSearchPath = NULL;
58 static t_SymLoadModule64 pSymLoadModule64 = NULL; 55 static t_SymLoadModule64 pSymLoadModule64 = NULL;
59 56
60 #define LOADPROC(module, name) do { \ 57 #define LOADPROC(module, name) do { \
61 p##name = reinterpret_cast<t_##name>(GetProcAddress(module, #name)); \ 58 p##name = reinterpret_cast<t_##name>(GetProcAddress(module, #name)); \
62 if (p##name == NULL) return false; \ 59 if (p##name == NULL) return false; \
63 } while (0) 60 } while (0)
64 61
65 // Dynamically load the DbgHelp library and supporting routines that we 62 // This code has to be VERY careful to not induce any allocations, as memory
66 // will use. 63 // watching code may cause recursion, which may obscure the stack for the truly
67 static bool LoadDbgHelp() { 64 // offensive issue. We use this function to break into a debugger, and it
68 static bool loaded = false; 65 // is guaranteed to not do any allocations (in fact, not do anything).
69 if (!loaded) { 66 static void UltraSafeDebugBreak() {
67 _asm int(3);
68 }
69
70 // static
71 bool CallStack::LoadDbgHelp() {
72 if (!dbghelp_loaded_) {
70 AutoLock Lock(dbghelp_lock_); 73 AutoLock Lock(dbghelp_lock_);
71 74
72 // Re-check if we've loaded successfully now that we have the lock. 75 // Re-check if we've loaded successfully now that we have the lock.
73 if (loaded) 76 if (dbghelp_loaded_)
74 return true; 77 return true;
75 78
76 // Load dbghelp.dll, and obtain pointers to the exported functions that we 79 // Load dbghelp.dll, and obtain pointers to the exported functions that we
77 // will be using. 80 // will be using.
78 HMODULE dbghelp_module = LoadLibrary(L"dbghelp.dll"); 81 HMODULE dbghelp_module = LoadLibrary(L"dbghelp.dll");
79 if (dbghelp_module) { 82 if (dbghelp_module) {
80 LOADPROC(dbghelp_module, StackWalk64); 83 LOADPROC(dbghelp_module, StackWalk64);
81 LOADPROC(dbghelp_module, SymFunctionTableAccess64); 84 LOADPROC(dbghelp_module, SymFunctionTableAccess64);
82 LOADPROC(dbghelp_module, SymGetModuleBase64); 85 LOADPROC(dbghelp_module, SymGetModuleBase64);
83 LOADPROC(dbghelp_module, SymCleanup); 86 LOADPROC(dbghelp_module, SymCleanup);
84 LOADPROC(dbghelp_module, SymGetSymFromAddr64); 87 LOADPROC(dbghelp_module, SymGetSymFromAddr64);
85 LOADPROC(dbghelp_module, SymGetLineFromAddr64); 88 LOADPROC(dbghelp_module, SymGetLineFromAddr64);
86 LOADPROC(dbghelp_module, SymInitialize); 89 LOADPROC(dbghelp_module, SymInitialize);
87 LOADPROC(dbghelp_module, SymGetOptions); 90 LOADPROC(dbghelp_module, SymGetOptions);
88 LOADPROC(dbghelp_module, SymSetOptions); 91 LOADPROC(dbghelp_module, SymSetOptions);
89 LOADPROC(dbghelp_module, SymGetModuleInfo64); 92 LOADPROC(dbghelp_module, SymGetModuleInfo64);
90 LOADPROC(dbghelp_module, SymGetSearchPath); 93 LOADPROC(dbghelp_module, SymGetSearchPath);
91 LOADPROC(dbghelp_module, SymLoadModule64); 94 LOADPROC(dbghelp_module, SymLoadModule64);
92 loaded = true; 95 dbghelp_loaded_ = true;
93 } else { 96 } else {
97 UltraSafeDebugBreak();
94 return false; 98 return false;
95 } 99 }
96 } 100 }
97 return loaded; 101 return dbghelp_loaded_;
98 } 102 }
99 103
100 // Load the symbols for generating stack traces. 104 // Load the symbols for generating stack traces.
101 static bool LoadSymbols(HANDLE process_handle) { 105 static bool LoadSymbols(HANDLE process_handle) {
102 static bool symbols_loaded = false; 106 static bool symbols_loaded = false;
103 if (symbols_loaded) return true; 107 if (symbols_loaded) return true;
104 108
105 BOOL ok; 109 BOOL ok;
106 110
107 // Initialize the symbol engine. 111 // Initialize the symbol engine.
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
161 // the MemoryHook heap is alive. 165 // the MemoryHook heap is alive.
162 symbol_cache_ = new SymbolCache(); 166 symbol_cache_ = new SymbolCache();
163 return LoadDbgHelp(); 167 return LoadDbgHelp();
164 } 168 }
165 169
166 CallStack::CallStack() { 170 CallStack::CallStack() {
167 static LONG callstack_id = 0; 171 static LONG callstack_id = 0;
168 frame_count_ = 0; 172 frame_count_ = 0;
169 hash_ = 0; 173 hash_ = 0;
170 id_ = InterlockedIncrement(&callstack_id); 174 id_ = InterlockedIncrement(&callstack_id);
175 valid_ = false;
171 176
172 LoadDbgHelp(); 177 if (!dbghelp_loaded_) {
173 CHECK(GetStackTrace()); 178 UltraSafeDebugBreak(); // Initialize should have been called.
179 return;
180 }
181
182 GetStackTrace();
174 } 183 }
175 184
176 bool CallStack::IsEqual(const CallStack &target) { 185 bool CallStack::IsEqual(const CallStack &target) {
177 if (frame_count_ != target.frame_count_) 186 if (frame_count_ != target.frame_count_)
178 return false; // They can't be equal if the sizes are different. 187 return false; // They can't be equal if the sizes are different.
179 188
180 // Walk the frames array until we 189 // Walk the frames array until we
181 // either find a mismatch, or until we reach the end of the call stacks. 190 // either find a mismatch, or until we reach the end of the call stacks.
182 for (int index = 0; index < frame_count_; index++) { 191 for (int index = 0; index < frame_count_; index++) {
183 if (frames_[index] != target.frames_[index]) 192 if (frames_[index] != target.frames_[index])
(...skipping 11 matching lines...) Expand all
195 // Create a unique id for this CallStack. 204 // Create a unique id for this CallStack.
196 pc = pc + (frame_count_ * 13); // Alter the PC based on position in stack. 205 pc = pc + (frame_count_ * 13); // Alter the PC based on position in stack.
197 hash_ = ~hash_ + (pc << 15); 206 hash_ = ~hash_ + (pc << 15);
198 hash_ = hash_ ^ (pc >> 12); 207 hash_ = hash_ ^ (pc >> 12);
199 hash_ = hash_ + (pc << 2); 208 hash_ = hash_ + (pc << 2);
200 hash_ = hash_ ^ (pc >> 4); 209 hash_ = hash_ ^ (pc >> 4);
201 hash_ = hash_ * 2057; 210 hash_ = hash_ * 2057;
202 hash_ = hash_ ^ (pc >> 16); 211 hash_ = hash_ ^ (pc >> 16);
203 } 212 }
204 213
214 bool CallStack::LockedRecursionDetected() const {
215 if (!active_thread_id_) return false;
216 DWORD thread_id = GetCurrentThreadId();
217 // TODO(jar): Perchance we should use atomic access to member.
218 return thread_id == active_thread_id_;
219 }
220
205 bool CallStack::GetStackTrace() { 221 bool CallStack::GetStackTrace() {
222 if (LockedRecursionDetected())
223 return false;
224
206 // Initialize the context record. 225 // Initialize the context record.
207 CONTEXT context; 226 CONTEXT context;
208 memset(&context, 0, sizeof(context)); 227 memset(&context, 0, sizeof(context));
209 context.ContextFlags = CONTEXT_FULL; 228 context.ContextFlags = CONTEXT_FULL;
210 __asm call x 229 __asm call x
211 __asm x: pop eax 230 __asm x: pop eax
212 __asm mov context.Eip, eax 231 __asm mov context.Eip, eax
213 __asm mov context.Ebp, ebp 232 __asm mov context.Ebp, ebp
214 __asm mov context.Esp, esp 233 __asm mov context.Esp, esp
215 234
(...skipping 11 matching lines...) Expand all
227 #elif 246 #elif
228 NOT IMPLEMENTED! 247 NOT IMPLEMENTED!
229 #endif 248 #endif
230 249
231 HANDLE current_process = GetCurrentProcess(); 250 HANDLE current_process = GetCurrentProcess();
232 HANDLE current_thread = GetCurrentThread(); 251 HANDLE current_thread = GetCurrentThread();
233 252
234 // Walk the stack. 253 // Walk the stack.
235 unsigned int count = 0; 254 unsigned int count = 0;
236 { 255 {
237 AutoLock lock(dbghelp_lock_); 256 AutoDbgHelpLock thread_monitoring_lock;
238 257
239 while (count < kMaxTraceFrames) { 258 while (count < kMaxTraceFrames) {
240 count++; 259 count++;
241 if (!pStackWalk64(image_type, 260 if (!pStackWalk64(image_type,
242 current_process, 261 current_process,
243 current_thread, 262 current_thread,
244 &frame, 263 &frame,
245 &context, 264 &context,
246 0, 265 0,
247 pSymFunctionTableAccess64, 266 pSymFunctionTableAccess64,
248 pSymGetModuleBase64, 267 pSymGetModuleBase64,
249 NULL)) 268 NULL))
250 break; // Couldn't trace back through any more frames. 269 break; // Couldn't trace back through any more frames.
251 270
252 if (frame.AddrFrame.Offset == 0) 271 if (frame.AddrFrame.Offset == 0)
253 continue; // End of stack. 272 continue; // End of stack.
254 273
255 // Push this frame's program counter onto the provided CallStack. 274 // Push this frame's program counter onto the provided CallStack.
256 AddFrame((DWORD_PTR)frame.AddrPC.Offset); 275 AddFrame((DWORD_PTR)frame.AddrPC.Offset);
257 } 276 }
277 valid_ = true;
258 } 278 }
259 return true; 279 return true;
260 } 280 }
261 281
262 void CallStack::ToString(std::string* output) { 282 void CallStack::ToString(PrivateAllocatorString* output) {
263 static const int kStackWalkMaxNameLen = MAX_SYM_NAME; 283 static const int kStackWalkMaxNameLen = MAX_SYM_NAME;
264 HANDLE current_process = GetCurrentProcess(); 284 HANDLE current_process = GetCurrentProcess();
265 285
266 if (!LoadSymbols(current_process)) { 286 if (!LoadSymbols(current_process)) {
267 *output = "Error"; 287 *output = "Error";
268 return; 288 return;
269 } 289 }
270 290
271 AutoLock lock(dbghelp_lock_); 291 AutoLock lock(dbghelp_lock_);
272 292
273 // Iterate through each frame in the call stack. 293 // Iterate through each frame in the call stack.
274 for (int32 index = 0; index < frame_count_; index++) { 294 for (int32 index = 0; index < frame_count_; index++) {
275 std::string line; 295 PrivateAllocatorString line;
276 296
277 DWORD_PTR intruction_pointer = frame(index); 297 DWORD_PTR intruction_pointer = frame(index);
278 298
279 SymbolCache::iterator it; 299 SymbolCache::iterator it;
280 it = symbol_cache_->find( intruction_pointer ); 300 it = symbol_cache_->find(intruction_pointer);
281 if (it != symbol_cache_->end()) { 301 if (it != symbol_cache_->end()) {
282 line = it->second; 302 line = it->second;
283 } else { 303 } else {
284 // Try to locate a symbol for this frame. 304 // Try to locate a symbol for this frame.
285 DWORD64 symbol_displacement = 0; 305 DWORD64 symbol_displacement = 0;
286 ULONG64 buffer[(sizeof(IMAGEHLP_SYMBOL64) + 306 ULONG64 buffer[(sizeof(IMAGEHLP_SYMBOL64) +
287 sizeof(TCHAR)*kStackWalkMaxNameLen + 307 sizeof(TCHAR)*kStackWalkMaxNameLen +
288 sizeof(ULONG64) - 1) / sizeof(ULONG64)]; 308 sizeof(ULONG64) - 1) / sizeof(ULONG64)];
289 IMAGEHLP_SYMBOL64* symbol = reinterpret_cast<IMAGEHLP_SYMBOL64*>(buffer); 309 IMAGEHLP_SYMBOL64* symbol = reinterpret_cast<IMAGEHLP_SYMBOL64*>(buffer);
290 memset(buffer, 0, sizeof(buffer)); 310 memset(buffer, 0, sizeof(buffer));
(...skipping 13 matching lines...) Expand all
304 intruction_pointer, 324 intruction_pointer,
305 &line_displacement, 325 &line_displacement,
306 &Line); 326 &Line);
307 if (ok) { 327 if (ok) {
308 // Skip junk symbols from our internal stuff. 328 // Skip junk symbols from our internal stuff.
309 if (strstr(symbol->Name, "CallStack::") || 329 if (strstr(symbol->Name, "CallStack::") ||
310 strstr(symbol->Name, "MemoryWatcher::") || 330 strstr(symbol->Name, "MemoryWatcher::") ||
311 strstr(symbol->Name, "Perftools_") || 331 strstr(symbol->Name, "Perftools_") ||
312 strstr(symbol->Name, "MemoryHook::") ) { 332 strstr(symbol->Name, "MemoryHook::") ) {
313 // Just record a blank string. 333 // Just record a blank string.
314 (*symbol_cache_)[intruction_pointer] = std::string(""); 334 (*symbol_cache_)[intruction_pointer] = "";
315 continue; 335 continue;
316 } 336 }
317 337
318 line += " "; 338 line += " ";
319 line += static_cast<char*>(Line.FileName); 339 line += static_cast<char*>(Line.FileName);
320 line += " ("; 340 line += " (";
321 line += IntToString(Line.LineNumber); 341 // TODO(jar): get something like this template to work :-/
342 // line += IntToCustomString<PrivateAllocatorString>(Line.LineNumber);
343 // ...and then delete this line, which uses std::string.
344 line += IntToString(Line.LineNumber).c_str();
322 line += "): "; 345 line += "): ";
323 line += symbol->Name; 346 line += symbol->Name;
324 line += "\n"; 347 line += "\n";
325 } else { 348 } else {
326 line += " unknown (0):"; 349 line += " unknown (0):";
327 line += symbol->Name; 350 line += symbol->Name;
328 line += "\n"; 351 line += "\n";
329 } 352 }
330 } else { 353 } else {
331 // OK - couldn't get any info. Try for the module. 354 // OK - couldn't get any info. Try for the module.
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
366 return MemoryHook::Alloc(size); 389 return MemoryHook::Alloc(size);
367 } 390 }
368 391
369 void AllocationStack::operator delete(void* ptr) { 392 void AllocationStack::operator delete(void* ptr) {
370 AllocationStack *stack = reinterpret_cast<AllocationStack*>(ptr); 393 AllocationStack *stack = reinterpret_cast<AllocationStack*>(ptr);
371 AutoLock lock(freelist_lock_); 394 AutoLock lock(freelist_lock_);
372 DCHECK(stack->next_ == NULL); 395 DCHECK(stack->next_ == NULL);
373 stack->next_ = freelist_; 396 stack->next_ = freelist_;
374 freelist_ = stack; 397 freelist_ = stack;
375 } 398 }
OLDNEW
« no previous file with comments | « tools/memory_watcher/call_stack.h ('k') | tools/memory_watcher/dllmain.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698