| 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 |