OLD | NEW |
| (Empty) |
1 // Copyright 2003-2009 Google Inc. | |
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 // | |
16 // Debug functions | |
17 | |
18 #ifndef OMAHA_BASE_DEBUG_H_ | |
19 #define OMAHA_BASE_DEBUG_H_ | |
20 | |
21 // To create a release build with asserts turned on, uncomment the | |
22 // following line, and uncomment the linking with atls.lib in api. | |
23 // | |
24 // #define ASSERT_IN_RELEASE | |
25 | |
26 #include "omaha/base/atlassert.h" | |
27 #include "omaha/base/synchronized.h" | |
28 #include "omaha/base/time.h" | |
29 | |
30 namespace omaha { | |
31 | |
32 // hash table for counts of the number of times REPORTs occur | |
33 // template<class K, class V> | |
34 // class HashTable; | |
35 // extern HashTable<uint32, uint16> *g_reports; | |
36 | |
37 #define kMaxUniqueReports (20) | |
38 #define kMaxReportCountString (20) | |
39 | |
40 class ReportIds; | |
41 extern ReportIds g_report_ids; | |
42 extern volatile LONG g_debugassertrecursioncheck; | |
43 extern bool g_always_assert; | |
44 | |
45 const int kMaxStackTraceDialogLen = 512; // too long and dialog box fails | |
46 | |
47 // TODO(omaha): consider merging this into DebugObserver. | |
48 // | |
49 // For automated testing, we don't (always) want asserts to fire. So | |
50 // we allow the unit test system to handle asserts instead. | |
51 // | |
52 // Give a function matching the prototype to REPLACE_ASSERT_FUNCTION to | |
53 // have your function called instead of the normal assert function. | |
54 typedef int DebugAssertFunctionType(const char *expression, | |
55 const char *message, const char *file, int line); | |
56 | |
57 enum ReportType; | |
58 enum DebugReportKind; | |
59 class DebugObserver { | |
60 public: | |
61 virtual ~DebugObserver() {} | |
62 virtual int SehSendMinidump(unsigned int code, struct _EXCEPTION_POINTERS *ep, | |
63 time64 time_between_minidumps) = 0; | |
64 | |
65 #if defined(_DEBUG) || defined(ASSERT_IN_RELEASE) | |
66 virtual void OnAssert(const char *expr, const TCHAR *msg, | |
67 const char *filename, int32 linenumber) = 0; | |
68 #endif | |
69 | |
70 #if defined(_DEBUG) | |
71 virtual void SendExceptionReport(const TCHAR *log_file, const TCHAR *filename, | |
72 int line, const TCHAR *type, uint32 id, | |
73 bool offline) = 0; | |
74 virtual CString OnDebugReport(uint32 id, bool is_report, ReportType type, | |
75 const char *expr, const TCHAR *message, | |
76 const char *filename, int32 linenumber, | |
77 DebugReportKind debug_report_kind) = 0; | |
78 #endif | |
79 }; | |
80 | |
81 // replaces the debug observer, returns the previous value. | |
82 DebugObserver* SetDebugObserver(DebugObserver* observer); | |
83 DebugObserver* PeekDebugObserver(); | |
84 | |
85 #ifdef __cplusplus | |
86 extern "C" { | |
87 #endif | |
88 | |
89 int SehSendMinidump(unsigned int code, | |
90 struct _EXCEPTION_POINTERS *ep, | |
91 time64 time_between_minidumps); | |
92 | |
93 #define kMinReportInterval100ns (60 * kSecsTo100ns) | |
94 #define kMinStackReportInterval100ns (60 * kSecsTo100ns) | |
95 #define DEBUG_LOG_SEPARATOR_CHAR "-------------------------------------------\n" | |
96 #define DEBUG_LOG_SEPARATOR L"-------------------------------------------\n" | |
97 #define kExceptionReportHeaders L"Content-Type: binary" | |
98 | |
99 #undef ASSERT | |
100 #undef VERIFY | |
101 #undef TRACE | |
102 | |
103 // Holds information about REPORTS and their frequency | |
104 struct ReportData { | |
105 uint32 report_counts_num; | |
106 uint32 report_ids[kMaxUniqueReports]; | |
107 uint16 report_counts[kMaxUniqueReports]; | |
108 }; | |
109 | |
110 // Used to hold REPORT IDs and to back them to the registry, where they'll be | |
111 // read and sent in a ping. | |
112 class ReportIds : public GLock { | |
113 public: | |
114 ReportIds(); | |
115 ~ReportIds(); | |
116 | |
117 // Call this after a successful ping to clear the report IDs from the registry | |
118 // and from this component (TRS). | |
119 void ResetReportsAfterPing(); | |
120 | |
121 // Adds a report ID to our list, if there's enough space. | |
122 bool ReleaseReport(uint32 id); | |
123 | |
124 // Creates a string with the report IDs and their frequency. | |
125 // Caller deletes string. | |
126 TCHAR *DebugReportString(); | |
127 | |
128 private: | |
129 ReportData data_; | |
130 | |
131 // Merges the report data from data2 with data1. | |
132 void MergeReports(ReportData *data1, const ReportData *data2); | |
133 | |
134 // We have to use RegKey directly, because we can't depend on the global | |
135 // Config object during destruction. | |
136 bool LoadReportData(ReportData **data); | |
137 void SaveReportData(ReportData *data); | |
138 | |
139 DISALLOW_EVIL_CONSTRUCTORS(ReportIds); | |
140 }; | |
141 | |
142 #if defined(_DEBUG) || defined(ASSERT_IN_RELEASE) | |
143 // Replaces the debug assert function; returns the old value. | |
144 DebugAssertFunctionType *ReplaceDebugAssertFunction(DebugAssertFunctionType | |
145 *replacement); | |
146 #define REPLACE_ASSERT_FUNCTION(replacement) \ | |
147 ReplaceDebugAssertFunction(replacement) | |
148 #else | |
149 #define REPLACE_ASSERT_FUNCTION(replacement) NULL | |
150 #endif | |
151 | |
152 #ifdef _DEBUG | |
153 void SendExceptionReport(const TCHAR *log_file, | |
154 const TCHAR *filename, | |
155 int line, | |
156 const TCHAR *type, | |
157 uint32 id, | |
158 bool offline); | |
159 | |
160 void SendStackTrace(const TCHAR *filename, | |
161 int line, | |
162 const TCHAR *type, | |
163 bool all_threads, | |
164 uint32 id); | |
165 | |
166 // DEBUG MODE | |
167 | |
168 extern bool g_LSPMode; | |
169 | |
170 bool DebugReport(unsigned int id, | |
171 ReportType type, | |
172 const char *expr, | |
173 const TCHAR *message, | |
174 const char *filename, | |
175 int linenumber, | |
176 DebugReportKind debug_report_kind); | |
177 | |
178 #define VERIFY(expr, msg) ASSERT(expr, msg) // VERIFY is ASSERT | |
179 | |
180 #define ASSERT(expr, msg) \ | |
181 do { \ | |
182 ((expr) ? 0 : omaha::DebugReport(0, omaha::R_FATAL, #expr, \ | |
183 omaha::SPRINTF msg, __FILE__, __LINE__, omaha::DEBUGREPORT_ASSERT)); \ | |
184 } while (0) | |
185 | |
186 #define REPORT(expr, type, msg, id) \ | |
187 ((expr) ? 0 : omaha::DebugReport(id, \ | |
188 type, \ | |
189 #expr, \ | |
190 omaha::SPRINTF msg, \ | |
191 __FILE__, \ | |
192 __LINE__, \ | |
193 omaha::DEBUGREPORT_REPORT)) | |
194 void DebugAbort(const TCHAR* msg, | |
195 const char* filename, | |
196 int32 linenumber, | |
197 bool do_abort); | |
198 #define ABORT(msg) \ | |
199 omaha::DebugAbort(omaha::SPRINTF msg, __FILE__, __LINE__, true) | |
200 | |
201 void TraceError(DWORD error); | |
202 inline void TraceLastError() { TraceError(GetLastError()); } | |
203 | |
204 /** | |
205 * Iterates through HKEY_CLASSES_ROOT\Interface and calls QI for | |
206 * all the interfaces there. Useful for finding out what type of | |
207 * object you're dealing with :-) | |
208 */ | |
209 void DumpInterface(IUnknown* unknown); | |
210 | |
211 #else // #ifdef _DEBUG | |
212 | |
213 #ifdef ASSERT_IN_RELEASE | |
214 bool ReleaseAssert(const char *expr, | |
215 const TCHAR *msg, | |
216 const char *filename, | |
217 int32 linenumber); | |
218 #define ASSERT(expr, msg) \ | |
219 ((expr) ? 0 : ReleaseAssert(#expr, SPRINTF msg, __FILE__, __LINE__)) | |
220 #else | |
221 #define ASSERT(expr, msg) 0 | |
222 #endif | |
223 | |
224 // VERIFY executes but does not check expression | |
225 #define VERIFY(expr, msg) \ | |
226 do { \ | |
227 (expr); \ | |
228 } while (0) | |
229 #define REPORT(expr, type, msg, id) \ | |
230 ((expr) ? 0 : g_report_ids.ReleaseReport(id)) | |
231 void ReleaseAbort(const TCHAR* msg, | |
232 const char* filename, | |
233 int32 linenumber, | |
234 bool do_abort); | |
235 #define ABORT(msg) ReleaseAbort(SPRINTF msg, __FILE__, __LINE__, true) | |
236 | |
237 #endif // #ifdef _DEBUG | |
238 | |
239 #define ASSERT1(expr) ASSERT(expr, (_T(""))) | |
240 #define VERIFY1(expr) VERIFY(expr, (_T(""))) | |
241 | |
242 #ifdef __cplusplus | |
243 } // extern "C"{ | |
244 #endif | |
245 | |
246 #ifdef _DEBUG | |
247 void ShowAssertDialog(const TCHAR *message, const TCHAR *title); | |
248 | |
249 // used to automatically dump the global summary of reports when the | |
250 // program exits | |
251 class ReportSummaryGenerator { | |
252 public: | |
253 ReportSummaryGenerator() {} | |
254 // calls DumpReportSummary() | |
255 ~ReportSummaryGenerator(); | |
256 // some programs exit without calling destructors, they can use this function | |
257 // to dump the report summary | |
258 void DumpReportSummary(); | |
259 // get text summary of reports | |
260 // caller is responsible for deleting the string returned | |
261 TCHAR *GetReportSummary(); | |
262 DISALLOW_EVIL_CONSTRUCTORS(ReportSummaryGenerator); | |
263 }; | |
264 | |
265 extern ReportSummaryGenerator g_report_summary_generator; | |
266 #endif | |
267 | |
268 // return string from format+arglist; for debugging; not thread-safe | |
269 TCHAR * __cdecl SPRINTF(const TCHAR * format, ...); | |
270 bool DebugError(const char * expr, | |
271 const TCHAR * message, | |
272 const char * filename, | |
273 INT linenumber, | |
274 BOOL report_only); | |
275 | |
276 // shows an error dialog in DEBUG and when g_release_debug is true | |
277 // | |
278 // example usage: | |
279 // | |
280 // __try { | |
281 // do something that sometimes causes a known exception (e.g., | |
282 // calling third party code) | |
283 // } __except(SehNoMinidump(GetExceptionCode(), GetExceptionInformation(), | |
284 // __FILE__, __LINE__)) { | |
285 // REPORT(false, R_ERROR, (L"exception doing something"), 103178920); | |
286 // } | |
287 // show_message - show an error dialog in DEBUG and when g_release_debug is true | |
288 int SehNoMinidump(unsigned int code, struct _EXCEPTION_POINTERS *ep, | |
289 const char *filename, int32 linenumber, bool show_message); | |
290 | |
291 /** | |
292 * @return Always returns an error value. If GetLastError is not ERROR_SUCCESS | |
293 * the function returns an HRESULT value derived from GetLastError() | |
294 */ | |
295 inline HRESULT GetCurError() { | |
296 return ::GetLastError() == ERROR_SUCCESS ? | |
297 E_FAIL : HRESULT_FROM_WIN32(::GetLastError()); | |
298 } | |
299 | |
300 // Returns the directory where the debugging module stores debug-related files. | |
301 CString GetDebugDirectory(); | |
302 | |
303 } // namespace omaha | |
304 | |
305 #endif // OMAHA_BASE_DEBUG_H_ | |
OLD | NEW |