OLD | NEW |
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 // Parts of this module come from: | 5 // Parts of this module come from: |
6 // http://www.codeproject.com/KB/applications/visualleakdetector.aspx | 6 // http://www.codeproject.com/KB/applications/visualleakdetector.aspx |
7 // by Dan Moulding. | 7 // by Dan Moulding. |
8 // http://www.codeproject.com/KB/threads/StackWalker.aspx | 8 // http://www.codeproject.com/KB/threads/StackWalker.aspx |
9 // by Jochen Kalmbach | 9 // by Jochen Kalmbach |
10 | 10 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
44 DWORD_PTR frame(int32 index) { | 44 DWORD_PTR frame(int32 index) { |
45 DCHECK(index < frame_count_ && index >= 0); | 45 DCHECK(index < frame_count_ && index >= 0); |
46 return frames_[index]; | 46 return frames_[index]; |
47 } | 47 } |
48 | 48 |
49 // Compares the CallStack to another CallStack | 49 // Compares the CallStack to another CallStack |
50 // for equality. Two CallStacks are equal if they are the same size and if | 50 // for equality. Two CallStacks are equal if they are the same size and if |
51 // every frame in each is identical to the corresponding frame in the other. | 51 // every frame in each is identical to the corresponding frame in the other. |
52 bool IsEqual(const CallStack &target); | 52 bool IsEqual(const CallStack &target); |
53 | 53 |
| 54 typedef std::basic_string<char, std::char_traits<char>, |
| 55 PrivateHookAllocator<char> > PrivateAllocatorString; |
| 56 |
54 // Convert the callstack to a string stored in output. | 57 // Convert the callstack to a string stored in output. |
55 void CallStack::ToString(std::string* output); | 58 void CallStack::ToString(PrivateAllocatorString* output); |
| 59 |
| 60 // |
| 61 bool Valid() const { return valid_; } |
56 | 62 |
57 private: | 63 private: |
58 // The maximum number of frames to trace. | 64 // The maximum number of frames to trace. |
59 static const int kMaxTraceFrames = 32; | 65 static const int kMaxTraceFrames = 32; |
60 | 66 |
61 // Pushes a frame's program counter onto the CallStack. | 67 // Pushes a frame's program counter onto the CallStack. |
62 void AddFrame(DWORD_PTR programcounter); | 68 void AddFrame(DWORD_PTR programcounter); |
63 | 69 |
64 // Traces the stack, starting from this function, up to kMaxTraceFrames | 70 // Traces the stack, starting from this function, up to kMaxTraceFrames |
65 // frames. | 71 // frames. |
66 bool GetStackTrace(); | 72 bool GetStackTrace(); |
67 | 73 |
68 // Functions for manipulating the frame list. | 74 // Functions for manipulating the frame list. |
69 void ClearFrames(); | 75 void ClearFrames(); |
70 | 76 |
| 77 // Dynamically load the DbgHelp library and supporting routines that we |
| 78 // will use. |
| 79 static bool LoadDbgHelp(); |
| 80 |
| 81 static void LockDbgHelp() { |
| 82 dbghelp_lock_.Acquire(); |
| 83 active_thread_id_ = GetCurrentThreadId(); |
| 84 } |
| 85 |
| 86 static void UnlockDbgHelp() { |
| 87 active_thread_id_ = GetCurrentThreadId(); |
| 88 dbghelp_lock_.Release(); |
| 89 } |
| 90 |
| 91 class AutoDbgHelpLock { |
| 92 public: |
| 93 AutoDbgHelpLock() { |
| 94 CallStack::LockDbgHelp(); |
| 95 } |
| 96 ~AutoDbgHelpLock() { |
| 97 CallStack::UnlockDbgHelp(); |
| 98 } |
| 99 }; |
| 100 |
| 101 // Check to see if this thread is already processing a stack. |
| 102 bool LockedRecursionDetected() const; |
| 103 |
| 104 // According to http://msdn2.microsoft.com/en-us/library/ms680650(VS.85).aspx |
| 105 // "All DbgHelp functions, such as this one, are single threaded. Therefore, |
| 106 // calls from more than one thread to this function will likely result in |
| 107 // unexpected behavior or memory corruption. To avoid this, you must |
| 108 // synchromize all concurrent calls from one thread to this function." |
| 109 // |
| 110 // dbghelp_lock_ is used to serialize access across all calls to the DbgHelp |
| 111 // library. This may be overly conservative (serializing them all together), |
| 112 // but does guarantee correctness. |
| 113 static Lock dbghelp_lock_; |
| 114 |
| 115 // Record the fact that dbghelp has been loaded. |
| 116 // Changes to this variable are protected by dbghelp_lock_. |
| 117 // It will only changes once... from false to true. |
| 118 static bool dbghelp_loaded_; |
| 119 |
| 120 // To prevent infinite recursion due to unexpected side effects in libraries, |
| 121 // we track the thread_id of the thread currently holding the dbghelp_lock_. |
| 122 // We avoid re-aquiring said lock and return an !valid_ instance when we |
| 123 // detect recursion. |
| 124 static DWORD active_thread_id_; |
| 125 |
71 int frame_count_; // Current size (in frames) | 126 int frame_count_; // Current size (in frames) |
72 DWORD_PTR frames_[kMaxTraceFrames]; | 127 DWORD_PTR frames_[kMaxTraceFrames]; |
73 int32 hash_; | 128 int32 hash_; |
74 int32 id_; | 129 int32 id_; |
75 | 130 |
| 131 // Indicate is this is a valid stack. |
| 132 // This is false if recursion precluded a real stack generation. |
| 133 bool valid_; |
| 134 |
76 // Cache ProgramCounter -> Symbol lookups. | 135 // Cache ProgramCounter -> Symbol lookups. |
77 // This cache is not thread safe. | 136 // This cache is not thread safe. |
78 typedef std::map<int32, std::string, std::less<int32>, | 137 typedef std::map<int32, PrivateAllocatorString, std::less<int32>, |
79 PrivateHookAllocator<int32> > SymbolCache; | 138 PrivateHookAllocator<int32> > SymbolCache; |
80 static SymbolCache* symbol_cache_; | 139 static SymbolCache* symbol_cache_; |
81 | 140 |
82 DISALLOW_EVIL_CONSTRUCTORS(CallStack); | 141 DISALLOW_EVIL_CONSTRUCTORS(CallStack); |
83 }; | 142 }; |
84 | 143 |
85 // An AllocationStack is a type of CallStack which represents a CallStack where | 144 // An AllocationStack is a type of CallStack which represents a CallStack where |
86 // memory has been allocated. This class is also a list item, so that it can | 145 // memory has been allocated. This class is also a list item, so that it can |
87 // be easilly allocated and deallocated from its static singly-linked-list of | 146 // be easilly allocated and deallocated from its static singly-linked-list of |
88 // free instances. | 147 // free instances. |
89 class AllocationStack : public CallStack { | 148 class AllocationStack : public CallStack { |
90 public: | 149 public: |
91 AllocationStack() : next_(NULL), CallStack() {} | 150 explicit AllocationStack(int32 size) |
| 151 : next_(NULL), size_(size), CallStack() {} |
92 | 152 |
93 // We maintain a freelist of the AllocationStacks. | 153 // We maintain a freelist of the AllocationStacks. |
94 void* operator new(size_t s); | 154 void* operator new(size_t s); |
95 void operator delete(void*p); | 155 void operator delete(void*p); |
96 | 156 |
| 157 int32 size() const { return size_; } |
| 158 |
97 private: | 159 private: |
98 AllocationStack* next_; // Pointer used when on the freelist. | 160 AllocationStack* next_; // Pointer used when on the freelist. |
| 161 int32 size_; // Size of block allocated. |
99 static AllocationStack* freelist_; | 162 static AllocationStack* freelist_; |
100 static Lock freelist_lock_; | 163 static Lock freelist_lock_; |
101 | 164 |
102 DISALLOW_EVIL_CONSTRUCTORS(AllocationStack); | 165 DISALLOW_EVIL_CONSTRUCTORS(AllocationStack); |
103 }; | 166 }; |
104 | 167 |
105 #endif // MEMORY_WATCHER_CALL_STACK_H_ | 168 #endif // MEMORY_WATCHER_CALL_STACK_H_ |
OLD | NEW |