00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #ifdef HAVE_NELCONFIG_H
00027 # include "nelconfig.h"
00028 #endif // HAVE_NELCONFIG_H
00029
00030 #include "stdmisc.h"
00031 #include "nel/misc/log.h"
00032 #include "nel/misc/displayer.h"
00033 #include "nel/misc/mem_displayer.h"
00034 #include "nel/misc/command.h"
00035 #include "nel/misc/report.h"
00036 #include "nel/misc/path.h"
00037
00038 #ifdef NL_OS_WINDOWS
00039 # define _WIN32_WINDOWS 0x0410
00040 # define WINVER 0x0400
00041 # include <windows.h>
00042 # include <direct.h>
00043 # include <imagehlp.h>
00044 # pragma comment(lib, "imagehlp.lib")
00045 # define getcwd(_a, _b) (_getcwd(_a,_b))
00046 #elif defined NL_OS_UNIX
00047 # include <unistd.h>
00048 # include <stdio.h>
00049 # include <stdlib.h>
00050 # define IsDebuggerPresent() false
00051 #endif
00052
00053 #include <stdarg.h>
00054 #include <iostream>
00055
00056 using namespace std;
00057
00058
00059
00060
00061
00062 #ifndef NEL_DEFAULT_DISPLAYER
00063 #define NEL_DEFAULT_DISPLAYER 1
00064 #endif // NEL_DEFAULT_DISPLAYER
00065
00066
00067
00068
00069 #ifndef NEL_LOG_IN_FILE
00070 #define NEL_LOG_IN_FILE 1
00071 #endif // NEL_LOG_IN_FILE
00072
00073 #define DEFAULT_DISPLAYER NEL_DEFAULT_DISPLAYER
00074
00075 #define LOG_IN_FILE NEL_LOG_IN_FILE
00076
00077
00078 static const bool TrapCrashInDebugger = false;
00079
00080 namespace NLMISC
00081 {
00082
00083
00084 bool DebugNeedAssert = false;
00085
00086 CLog *ErrorLog = NULL;
00087 CLog *WarningLog = NULL;
00088 CLog *InfoLog = NULL;
00089 CLog *DebugLog = NULL;
00090 CLog *AssertLog = NULL;
00091
00092 CMemDisplayer *DefaultMemDisplayer = NULL;
00093 CMsgBoxDisplayer *DefaultMsgBoxDisplayer = NULL;
00094
00095 static CStdDisplayer *sd = NULL;
00096 static CFileDisplayer *fd = NULL;
00097
00098 void nlFatalError (const char *format, ...)
00099 {
00100 char *str;
00101 NLMISC_CONVERT_VARGS (str, format, 256);
00102
00103 NLMISC::DebugNeedAssert = NLMISC::DefaultMsgBoxDisplayer==0;
00104
00105 NLMISC::ErrorLog->displayNL (str);
00106
00107 if (NLMISC::DebugNeedAssert)
00108 NLMISC_BREAKPOINT;
00109
00110 #ifndef NL_OS_WINDOWS
00111 exit(EXIT_FAILURE);
00112 #endif
00113
00114 }
00115
00116 void nlError (const char *format, ...)
00117 {
00118 char *str;
00119 NLMISC_CONVERT_VARGS (str, format, 256);
00120
00121 NLMISC::DebugNeedAssert = NLMISC::DefaultMsgBoxDisplayer==0;
00122
00123 NLMISC::ErrorLog->displayNL (str);
00124
00125 if (NLMISC::DebugNeedAssert)
00126 NLMISC_BREAKPOINT;
00127
00128 #ifndef NL_OS_WINDOWS
00129 exit(EXIT_FAILURE);
00130 #endif
00131 }
00132
00133
00134
00135 void initDebug2 (bool logInFile)
00136 {
00137 static bool alreadyInit = false;
00138
00139 if (!alreadyInit)
00140 {
00141 #if DEFAULT_DISPLAYER
00142
00143
00144
00145 #ifdef NL_DEBUG
00146 DebugLog->addDisplayer (sd);
00147 #endif // NL_DEBUG
00148 InfoLog->addDisplayer (sd);
00149 WarningLog->addDisplayer (sd);
00150 AssertLog->addDisplayer (sd);
00151 ErrorLog->addDisplayer (sd);
00152
00153
00154
00155
00156 DebugLog->addDisplayer (DefaultMemDisplayer, true);
00157 InfoLog->addDisplayer (DefaultMemDisplayer, true);
00158 WarningLog->addDisplayer (DefaultMemDisplayer, true);
00159 AssertLog->addDisplayer (DefaultMemDisplayer, true);
00160 ErrorLog->addDisplayer (DefaultMemDisplayer, true);
00161
00162
00163
00164 #if LOG_IN_FILE
00165 if (logInFile)
00166 {
00167 #ifdef NL_DEBUG
00168 DebugLog->addDisplayer (fd);
00169 #endif // NL_DEBUG
00170 InfoLog->addDisplayer (fd);
00171 WarningLog->addDisplayer (fd);
00172 AssertLog->addDisplayer (fd);
00173 ErrorLog->addDisplayer (fd);
00174 }
00175 #endif // LOG_IN_FILE
00176
00177
00178
00179 if (TrapCrashInDebugger || !IsDebuggerPresent ())
00180 {
00181 AssertLog->addDisplayer (DefaultMsgBoxDisplayer);
00182 ErrorLog->addDisplayer (DefaultMsgBoxDisplayer);
00183 }
00184
00185 #endif // DEFAULT_DISPLAYER
00186 alreadyInit = true;
00187 }
00188 else
00189 {
00190 nlwarning ("NLMISC::initDebug2() already called");
00191 }
00192 }
00193
00194
00195 #ifdef NL_OS_WINDOWS
00196
00197
00198
00199
00200
00201 static DWORD __stdcall GetModuleBase(HANDLE hProcess, DWORD dwReturnAddress)
00202 {
00203 IMAGEHLP_MODULE moduleInfo;
00204
00205 if (SymGetModuleInfo(hProcess, dwReturnAddress, &moduleInfo))
00206 return moduleInfo.BaseOfImage;
00207 else
00208 {
00209 MEMORY_BASIC_INFORMATION memoryBasicInfo;
00210
00211 if (::VirtualQueryEx(hProcess, (LPVOID) dwReturnAddress,
00212 &memoryBasicInfo, sizeof(memoryBasicInfo)))
00213 {
00214 DWORD cch = 0;
00215 char szFile[MAX_PATH] = { 0 };
00216
00217 cch = GetModuleFileNameA((HINSTANCE)memoryBasicInfo.AllocationBase,
00218 szFile, MAX_PATH);
00219
00220 if (cch && (lstrcmp(szFile, "DBFN")== 0))
00221 {
00222 if (!SymLoadModule(hProcess,
00223 NULL, "MN",
00224 NULL, (DWORD) memoryBasicInfo.AllocationBase, 0))
00225 {
00226 DWORD dwError = GetLastError();
00227
00228 }
00229 }
00230 else
00231 {
00232 if (!SymLoadModule(hProcess,
00233 NULL, ((cch) ? szFile : NULL),
00234 NULL, (DWORD) memoryBasicInfo.AllocationBase, 0))
00235 {
00236 DWORD dwError = GetLastError();
00237
00238 }
00239
00240 }
00241
00242 return (DWORD) memoryBasicInfo.AllocationBase;
00243 }
00244
00245
00246 }
00247
00248 return 0;
00249 }
00250
00251 LPVOID __stdcall FunctionTableAccess (HANDLE hProcess, DWORD AddrBase)
00252 {
00253 AddrBase = 0x40291f;
00254 DWORD addr = SymGetModuleBase (hProcess, AddrBase);
00255 HRESULT hr = GetLastError ();
00256
00257 IMAGEHLP_MODULE moduleInfo;
00258 moduleInfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE);
00259 SymGetModuleInfo(hProcess, addr, &moduleInfo);
00260 hr = GetLastError ();
00261 SymLoadModule(hProcess, NULL, NULL, NULL, 0, 0);
00262 hr = GetLastError ();
00263
00264 LPVOID temp = SymFunctionTableAccess (hProcess, AddrBase);
00265 hr = GetLastError ();
00266 return temp;
00267 }
00268
00269 class EDebug : public ETrapDebug
00270 {
00271 public:
00272
00273 EDebug() { _Reason = "Nothing about EDebug"; }
00274
00275 ~EDebug () { }
00276
00277 EDebug(EXCEPTION_POINTERS * pexp) : m_pexp(pexp) { nlassert(pexp != 0); createWhat(); }
00278 EDebug(const EDebug& se) : m_pexp(se.m_pexp) { createWhat(); }
00279
00280 void createWhat ()
00281 {
00282 string shortExc, longExc, subject;
00283 string addr, ext;
00284 sint skipNFirst = 0;
00285 _Reason = "";
00286
00287 if (m_pexp == NULL)
00288 {
00289 _Reason = "Unknown exception, don't have context.";
00290 }
00291 else
00292 {
00293 switch (m_pexp->ExceptionRecord->ExceptionCode)
00294 {
00295 case EXCEPTION_ACCESS_VIOLATION : shortExc="Access Violation"; longExc="The thread attempted to read from or write to a virtual address for which it does not have the appropriate access";
00296 ext = ", thread attempts to ";
00297 ext += m_pexp->ExceptionRecord->ExceptionInformation[0]?"write":"read";
00298 if (m_pexp->ExceptionRecord->ExceptionInformation[1])
00299 ext += toString(" at 0x%X",m_pexp->ExceptionRecord->ExceptionInformation[1]);
00300 else
00301 ext += " at <NULL>";
00302 break;
00303 case EXCEPTION_DATATYPE_MISALIGNMENT : shortExc="Datatype Misalignment"; longExc="The thread attempted to read or write data that is misaligned on hardware that does not provide alignment. For example, 16-bit values must be aligned on 2-byte boundaries, 32-bit values on 4-byte boundaries, and so on"; break;
00304 case EXCEPTION_BREAKPOINT : shortExc="Breakpoint"; longExc="A breakpoint was encountered"; break;
00305 case EXCEPTION_SINGLE_STEP : shortExc="Single Step"; longExc="A trace trap or other single-instruction mechanism signaled that one instruction has been executed"; break;
00306 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED : shortExc="Array Bounds Exceeded"; longExc="The thread attempted to access an array element that is out of bounds, and the underlying hardware supports bounds checking"; break;
00307 case EXCEPTION_FLT_DENORMAL_OPERAND : shortExc="Float Denormal Operand"; longExc="One of the operands in a floating-point operation is denormal. A denormal value is one that is too small to represent as a standard floating-point value"; break;
00308 case EXCEPTION_FLT_DIVIDE_BY_ZERO : shortExc="Float Divide By Zero"; longExc="The thread attempted to divide a floating-point value by a floating-point divisor of zero"; break;
00309 case EXCEPTION_FLT_INEXACT_RESULT : shortExc="Float Inexact Result"; longExc="The result of a floating-point operation cannot be represented exactly as a decimal fraction"; break;
00310 case EXCEPTION_FLT_INVALID_OPERATION : shortExc="Float Invalid Operation"; longExc="This exception represents any floating-point exception not included in this list"; break;
00311 case EXCEPTION_FLT_OVERFLOW : shortExc="Float Overflow"; longExc="The exponent of a floating-point operation is greater than the magnitude allowed by the corresponding type"; break;
00312 case EXCEPTION_FLT_STACK_CHECK : shortExc="Float Stack Check"; longExc="The stack overflowed or underflowed as the result of a floating-point operation"; break;
00313 case EXCEPTION_FLT_UNDERFLOW : shortExc="Float Underflow"; longExc="The exponent of a floating-point operation is less than the magnitude allowed by the corresponding type"; break;
00314 case EXCEPTION_INT_DIVIDE_BY_ZERO : shortExc="Integer Divide By Zero"; longExc="The thread attempted to divide an integer value by an integer divisor of zero"; break;
00315 case EXCEPTION_INT_OVERFLOW : shortExc="Integer Overflow"; longExc="The result of an integer operation caused a carry out of the most significant bit of the result"; break;
00316 case EXCEPTION_PRIV_INSTRUCTION : shortExc="Privileged Instruction"; longExc="The thread attempted to execute an instruction whose operation is not allowed in the current machine mode"; break;
00317 case EXCEPTION_IN_PAGE_ERROR : shortExc="In Page Error"; longExc="The thread tried to access a page that was not present, and the system was unable to load the page. -ie. the program or memory mapped file couldn't be paged in because it isn't accessable any more. Device drivers can return this exception if something went wrong with the read (i.e hardware problems)"; break;
00318 case EXCEPTION_ILLEGAL_INSTRUCTION : shortExc="Illegal Instruction"; longExc="The thread tried to execute an invalid instruction -such as MMX opcodes on a non MMX system. Branching to an invalid location can cause this -something stack corruption often causes"; break;
00319 case EXCEPTION_NONCONTINUABLE_EXCEPTION : shortExc="Noncontinuable Exception"; longExc="The thread attempted to continue execution after a noncontinuable exception occurred"; break;
00320 case EXCEPTION_STACK_OVERFLOW : shortExc="Stack Overflow"; longExc="Stack overflow. Can occur during errant recursion, or when a function creates a particularly large array on the stack"; break;
00321 case EXCEPTION_INVALID_DISPOSITION : shortExc="Invalid Disposition"; longExc="Whatever number the exception filter returned, it wasn't a value the OS knows about"; break;
00322 case EXCEPTION_GUARD_PAGE : shortExc="Guard Page"; longExc="Memory Allocated as PAGE_GUARD by VirtualAlloc() has been accessed"; break;
00323 case EXCEPTION_INVALID_HANDLE : shortExc="Invalid Handle"; longExc=""; break;
00324 case CONTROL_C_EXIT : shortExc="Control-C"; longExc="Lets the debugger know the user hit Ctrl-C. Seemingly for console apps only"; break;
00325 case STATUS_NO_MEMORY : shortExc="No Memory"; longExc="Called by HeapAlloc() if you specify HEAP_GENERATE_EXCEPTIONS and there is no memory or heap corruption";
00326 ext = ", unable to allocate ";
00327 ext += toString ("%d bytes", m_pexp->ExceptionRecord->ExceptionInformation [0]);
00328 break;
00329 case STATUS_WAIT_0 : shortExc="Wait 0"; longExc=""; break;
00330 case STATUS_ABANDONED_WAIT_0 : shortExc="Abandoned Wait 0"; longExc=""; break;
00331 case STATUS_USER_APC : shortExc="User APC"; longExc="A user APC was delivered to the current thread before the specified Timeout interval expired"; break;
00332 case STATUS_TIMEOUT : shortExc="Timeout"; longExc=""; break;
00333 case STATUS_PENDING : shortExc="Pending"; longExc=""; break;
00334 case STATUS_SEGMENT_NOTIFICATION : shortExc="Segment Notification"; longExc=""; break;
00335 case STATUS_FLOAT_MULTIPLE_FAULTS : shortExc="Float Multiple Faults"; longExc=""; break;
00336 case STATUS_FLOAT_MULTIPLE_TRAPS : shortExc="Float Multiple Traps"; longExc=""; break;
00337 case STATUS_ILLEGAL_VLM_REFERENCE : shortExc="Illegal VLM Reference"; longExc=""; break;
00338 case 0xE06D7363 : shortExc="Microsoft C++ Exception"; longExc="Microsoft C++ Exception"; break;
00339 case 0xACE0ACE : shortExc=""; longExc="";
00340 if (m_pexp->ExceptionRecord->NumberParameters == 1)
00341 skipNFirst = m_pexp->ExceptionRecord->ExceptionInformation [0];
00342 break;
00343 default : shortExc="Unknown Exception"; longExc="Unknown Exception "+toString("0x%X", m_pexp->ExceptionRecord->ExceptionCode); break;
00344 };
00345
00346 if(m_pexp->ExceptionRecord != NULL)
00347 {
00348 if (m_pexp->ExceptionRecord->ExceptionAddress)
00349 addr = toString(" at 0x%X", m_pexp->ExceptionRecord->ExceptionAddress);
00350 else
00351 addr = " at <NULL>";
00352 }
00353
00354 string progname;
00355 if(!shortExc.empty() || !longExc.empty())
00356 {
00357 char name[1024];
00358 GetModuleFileName (NULL, name, 1023);
00359 progname = CFile::getFilename(name);
00360 progname += " ";
00361 }
00362
00363 subject = progname + shortExc + addr;
00364
00365 if (_Reason.empty())
00366 {
00367 if (!shortExc.empty()) _Reason += shortExc + " exception generated" + addr + ext + ".\n";
00368 if (!longExc.empty()) _Reason += longExc + ".\n";
00369 }
00370
00371
00372 addStackAndLogToReason (skipNFirst);
00373
00374 if(!shortExc.empty() || !longExc.empty())
00375 {
00376 bool i = false;
00377 report (progname+shortExc, "", subject, _Reason, true, 1, true, 1, true, i);
00378 }
00379 }
00380 }
00381
00382
00383 void addStackAndLogToReason (sint skipNFirst = 0)
00384 {
00385
00386 skipNFirst = 0;
00387
00388 DWORD symOptions = SymGetOptions();
00389 symOptions |= SYMOPT_LOAD_LINES;
00390 symOptions &= ~SYMOPT_UNDNAME;
00391 SymSetOptions (symOptions);
00392
00393 nlverify (SymInitialize(getProcessHandle(), NULL, FALSE) == TRUE);
00394
00395 STACKFRAME callStack;
00396 ::ZeroMemory (&callStack, sizeof(callStack));
00397 callStack.AddrPC.Mode = AddrModeFlat;
00398 callStack.AddrPC.Offset = m_pexp->ContextRecord->Eip;
00399 callStack.AddrStack.Mode = AddrModeFlat;
00400 callStack.AddrStack.Offset = m_pexp->ContextRecord->Esp;
00401 callStack.AddrFrame.Mode = AddrModeFlat;
00402 callStack.AddrFrame.Offset = m_pexp->ContextRecord->Ebp;
00403
00404 _Reason += "\nCallstack:\n";
00405 _Reason += "-------------------------------\n";
00406 for (sint32 i = 0; ; i++)
00407 {
00408 SetLastError(0);
00409 BOOL res = StackWalk (IMAGE_FILE_MACHINE_I386, getProcessHandle(), GetCurrentThread(), &callStack,
00410 m_pexp->ContextRecord, NULL, FunctionTableAccess, GetModuleBase, NULL);
00411
00412 if (res == FALSE || callStack.AddrFrame.Offset == 0)
00413 break;
00414
00415 string symInfo, srcInfo;
00416
00417 if (i >= skipNFirst)
00418 {
00419 srcInfo = getSourceInfo (callStack.AddrPC.Offset);
00420 symInfo = getFuncInfo (callStack.AddrPC.Offset, callStack.AddrFrame.Offset);
00421 _Reason += srcInfo + ": " + symInfo + "\n";
00422 }
00423 }
00424 _Reason += "-------------------------------\n";
00425 _Reason += "\n";
00426 if(DefaultMemDisplayer)
00427 {
00428 _Reason += "Log with no filter:\n";
00429 _Reason += "-------------------------------\n";
00430 DefaultMemDisplayer->write (_Reason);
00431 }
00432 else
00433 {
00434 _Reason += "No log\n";
00435 }
00436 _Reason += "-------------------------------\n";
00437
00438 nlverify (SymCleanup(getProcessHandle()) == TRUE);
00439 }
00440
00441 string getSourceInfo (DWORD addr)
00442 {
00443 string str;
00444
00445 IMAGEHLP_LINE line;
00446 ::ZeroMemory (&line, sizeof (line));
00447 line.SizeOfStruct = sizeof(line);
00448
00449
00450
00451
00452
00453
00454 bool ok = true;
00455 DWORD displacement = 0 ;
00456 DWORD resdisp;
00457 while (!SymGetLineFromAddr (getProcessHandle(), addr - displacement, (DWORD*)&resdisp, &line))
00458 {
00459 if (100 == ++displacement)
00460 {
00461 ok = false;
00462 break;
00463 }
00464 }
00465
00466
00467
00468
00469 if (displacement)
00470 resdisp = displacement;
00471
00472 if (ok)
00473 {
00474 str = line.FileName;
00475 str += "(" + toString (line.LineNumber) + ")";
00476 str += toString(": 0x%X", addr);
00477 }
00478 else
00479 {
00480 HRESULT hr = GetLastError();
00481 IMAGEHLP_MODULE module;
00482 ::ZeroMemory (&module, sizeof(module));
00483 module.SizeOfStruct = sizeof(module);
00484
00485 if (SymGetModuleInfo (getProcessHandle(), addr, &module))
00486 {
00487 str = module.ModuleName;
00488 }
00489 else
00490 {
00491 HRESULT hr = GetLastError ();
00492 str = "<NoModule>";
00493 }
00494 str += toString("!0x%X", addr);
00495 }
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526 return str;
00527 }
00528
00529 HANDLE getProcessHandle()
00530 {
00531 return CSystemInfo::isNT()?GetCurrentProcess():(HANDLE)GetCurrentProcessId();
00532 }
00533
00534
00535 bool findAndErase(string &str, const char *token, const char *replace = NULL)
00536 {
00537 int pos;
00538 if ((pos = str.find(token)) != string::npos)
00539 {
00540 str.erase (pos,strlen(token));
00541 if (replace != NULL)
00542 str.insert (pos, replace);
00543 return true;
00544 }
00545 else
00546 return false;
00547 }
00548
00549
00550
00551
00552 void cleanType(string &rawType, string &displayType)
00553 {
00554 while (findAndErase(rawType, "std::")) ;
00555 while (findAndErase(displayType, "std::")) ;
00556
00557 while (findAndErase(rawType, "const")) ;
00558
00559 while (findAndErase(rawType, " ")) ;
00560
00561 while (findAndErase(rawType, "&")) ;
00562
00563
00564
00565 while (findAndErase(rawType, "classbasic_string<char,classchar_traits<char>,classallocator<char>>", "string")) ;
00566 while (findAndErase(displayType, "class basic_string<char,class char_traits<char>,class allocator<char> >", "string")) ;
00567 while (findAndErase(rawType, "classvector<char,class char_traits<char>,class allocator<char> >", "string")) ;
00568 }
00569
00570 string getFuncInfo (DWORD funcAddr, DWORD stackAddr)
00571 {
00572 string str ("NoSymbol");
00573
00574 DWORD symSize = 10000;
00575 PIMAGEHLP_SYMBOL sym = (PIMAGEHLP_SYMBOL) GlobalAlloc (GMEM_FIXED, symSize);
00576 ::ZeroMemory (sym, symSize);
00577 sym->SizeOfStruct = symSize;
00578 sym->MaxNameLength = symSize - sizeof(IMAGEHLP_SYMBOL);
00579
00580 DWORD disp = 0;
00581 if (SymGetSymFromAddr (getProcessHandle(), funcAddr, &disp, sym) == FALSE)
00582 {
00583 return str;
00584 }
00585
00586 CHAR undecSymbol[1024];
00587 if (UnDecorateSymbolName (sym->Name, undecSymbol, 1024, UNDNAME_COMPLETE | UNDNAME_NO_THISTYPE | UNDNAME_NO_SPECIAL_SYMS | UNDNAME_NO_MEMBER_TYPE | UNDNAME_NO_MS_KEYWORDS | UNDNAME_NO_ACCESS_SPECIFIERS ) > 0)
00588 {
00589 str = undecSymbol;
00590 }
00591 else if (SymUnDName (sym, undecSymbol, 1024) == TRUE)
00592 {
00593 str = undecSymbol;
00594 }
00595
00596
00597
00598 string parse = str;
00599 str = "";
00600 uint pos = 0;
00601 sint stop = 0;
00602
00603 string type;
00604
00605 uint i = parse.find ("(");
00606
00607
00608 str = parse.substr(0, i);
00609
00610
00611
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720 return str;
00721 }
00722
00723 private:
00724 EXCEPTION_POINTERS * m_pexp;
00725 };
00726
00727
00728 bool global_force_exception_flag = false;
00729 #define WORKAROUND_VCPP_SYNCHRONOUS_EXCEPTION if (global_force_exception_flag) force_exception_frame();
00730 void force_exception_frame(...) {std::cout.flush();}
00731
00732 static void exceptionTranslator(unsigned, EXCEPTION_POINTERS *pexp)
00733 {
00734
00735
00736 {
00737 if (pexp->ExceptionRecord->ExceptionCode == 0xACE0ACE)
00738 throw EDebug (pexp);
00739 else
00740 return;
00741 }
00742
00743
00744
00745
00746
00747
00748
00749 }
00750
00751 #endif // NL_OS_WINDOWS
00752
00753 void getCallStackAndLog (string &result, sint skipNFirst)
00754 {
00755 #ifdef NL_OS_WINDOWS
00756 try
00757 {
00758 WORKAROUND_VCPP_SYNCHRONOUS_EXCEPTION
00759
00760 DWORD array[1];
00761 array[0] = skipNFirst;
00762 RaiseException (0xACE0ACE, 0, 1, array);
00763 }
00764 catch (EDebug &e)
00765 {
00766 result += e.what();
00767 }
00768 #else
00769 result += "No callstack available";
00770 #endif
00771 }
00772
00773
00774 void createDebug (const char *logPath, bool logInFile)
00775 {
00776 NL_ALLOC_CONTEXT (_Debug)
00777
00778 static bool alreadyCreate = false;
00779 if (!alreadyCreate)
00780 {
00781
00782 #ifdef MUTEX_DEBUG
00783 initAcquireTimeMap();
00784 #endif
00785
00786 #ifdef NL_OS_WINDOWS
00787
00788 {
00789 _set_se_translator(exceptionTranslator);
00790 }
00791 #endif // NL_OS_WINDOWS
00792
00793
00794 ErrorLog = new CLog (CLog::LOG_ERROR);
00795 WarningLog = new CLog (CLog::LOG_WARNING);
00796 InfoLog = new CLog (CLog::LOG_INFO);
00797 DebugLog = new CLog (CLog::LOG_DEBUG);
00798 AssertLog = new CLog (CLog::LOG_ASSERT);
00799
00800 sd = new CStdDisplayer ("DEFAULT_SD");
00801 if (TrapCrashInDebugger || !IsDebuggerPresent ())
00802 {
00803 DefaultMsgBoxDisplayer = new CMsgBoxDisplayer ("DEFAULT_MBD");
00804 }
00805 #if LOG_IN_FILE
00806 if (logInFile)
00807 {
00808 string fn;
00809 if (logPath != NULL)
00810 {
00811 fn += logPath;
00812 }
00813 else
00814 {
00815
00816 char tmpPath[1024];
00817 fn += getcwd(tmpPath, 1024);
00818 fn += "/";
00819 }
00820 fn += "log.log";
00821 fd = new CFileDisplayer (fn, false, "DEFAULT_FD");
00822 }
00823 #endif // LOG_IN_FILE
00824 DefaultMemDisplayer = new CMemDisplayer ("DEFAULT_MD");
00825
00826 initDebug2(logInFile);
00827
00828 alreadyCreate = true;
00829 }
00830 }
00831
00832
00833
00834
00835
00836
00837
00838
00839 NLMISC_COMMAND (displayMemlog, "displays the last N line of the log in memory", "[<NbLines>]")
00840 {
00841 uint nbLines;
00842
00843 if (args.size() == 0) nbLines = 100;
00844 else if (args.size() == 1) nbLines = atoi(args[0].c_str());
00845 else return false;
00846
00847 if (DefaultMemDisplayer == NULL) return false;
00848
00849 deque<string>::const_iterator it;
00850
00851 const deque<string> &str = DefaultMemDisplayer->lockStrings ();
00852
00853 if (nbLines >= str.size())
00854 it = str.begin();
00855 else
00856 it = str.end() - nbLines;
00857
00858 DefaultMemDisplayer->write (&log);
00859
00860 DefaultMemDisplayer->unlockStrings ();
00861
00862 return true;
00863 }
00864
00865
00866 NLMISC_COMMAND(resetFilters, "disable all filters on Nel loggers", "[debug|info|warning|error|assert]")
00867 {
00868 if(args.size() == 0)
00869 {
00870 DebugLog->resetFilters();
00871 InfoLog->resetFilters();
00872 WarningLog->resetFilters();
00873 ErrorLog->resetFilters();
00874 AssertLog->resetFilters();
00875 }
00876 else if (args.size() == 1)
00877 {
00878 if (args[0] == "debug") DebugLog->resetFilters();
00879 else if (args[0] == "info") InfoLog->resetFilters();
00880 else if (args[0] == "warning") WarningLog->resetFilters();
00881 else if (args[0] == "error") ErrorLog->resetFilters();
00882 else if (args[0] == "assert") AssertLog->resetFilters();
00883 }
00884 else
00885 {
00886 return false;
00887 }
00888
00889 return true;
00890 }
00891
00892 NLMISC_COMMAND(addPositiveFilterDebug, "add a positive filter on DebugLog", "<filterstr>")
00893 {
00894 if(args.size() != 1) return false;
00895 DebugLog->addPositiveFilter( args[0].c_str() );
00896 return true;
00897 }
00898
00899 NLMISC_COMMAND(addNegativeFilterDebug, "add a negative filter on DebugLog", "<filterstr>")
00900 {
00901 if(args.size() != 1) return false;
00902 DebugLog->addNegativeFilter( args[0].c_str() );
00903 return true;
00904 }
00905
00906 NLMISC_COMMAND(removeFilterDebug, "remove a filter on DebugLog", "[<filterstr>]")
00907 {
00908 if(args.size() == 0)
00909 DebugLog->removeFilter();
00910 else if(args.size() == 1)
00911 DebugLog->removeFilter( args[0].c_str() );
00912 else return false;
00913 return true;
00914 }
00915
00916 NLMISC_COMMAND(displayFilterDebug, "display filter on DebugLog", "")
00917 {
00918 if(args.size() != 0) return false;
00919 DebugLog->displayFilter(log);
00920 return true;
00921 }
00922
00923 NLMISC_COMMAND(addPositiveFilterInfo, "add a positive filter on InfoLog", "<filterstr>")
00924 {
00925 if(args.size() != 1) return false;
00926 InfoLog->addPositiveFilter( args[0].c_str() );
00927 return true;
00928 }
00929
00930 NLMISC_COMMAND(addNegativeFilterInfo, "add a negative filter on InfoLog", "<filterstr>")
00931 {
00932 if(args.size() != 1) return false;
00933 InfoLog->addNegativeFilter( args[0].c_str() );
00934 return true;
00935 }
00936
00937 NLMISC_COMMAND(removeFilterInfo, "remove a filter on InfoLog", "[<filterstr>]")
00938 {
00939 if(args.size() == 0)
00940 InfoLog->removeFilter();
00941 else if(args.size() == 1)
00942 InfoLog->removeFilter( args[0].c_str() );
00943 else return false;
00944 return true;
00945 }
00946
00947 NLMISC_COMMAND(displayFilterInfo, "display filter on InfoLog", "[d|i|w|e]")
00948 {
00949 if(args.size() > 1) return false;
00950 if ( args.size() == 1 )
00951 {
00952 if ( strcmp( args[0].c_str(), "d" ) == 0 )
00953 InfoLog->displayFilter(*DebugLog);
00954 else if ( strcmp( args[0].c_str(), "i" ) == 0 )
00955 InfoLog->displayFilter(*InfoLog);
00956 else if ( strcmp( args[0].c_str(), "w" ) == 0 )
00957 InfoLog->displayFilter(*WarningLog);
00958 else if ( strcmp( args[0].c_str(), "e" ) == 0 )
00959 InfoLog->displayFilter(*ErrorLog);
00960 else
00961 return false;
00962 }
00963 else
00964 {
00965 InfoLog->displayFilter(log);
00966 }
00967 return true;
00968 }
00969
00970 NLMISC_COMMAND(addPositiveFilterWarning, "add a positive filter on WarningLog", "<filterstr>")
00971 {
00972 if(args.size() != 1) return false;
00973 WarningLog->addPositiveFilter( args[0].c_str() );
00974 return true;
00975 }
00976
00977 NLMISC_COMMAND(addNegativeFilterWarning, "add a negative filter on WarningLog", "<filterstr>")
00978 {
00979 if(args.size() != 1) return false;
00980 WarningLog->addNegativeFilter( args[0].c_str() );
00981 return true;
00982 }
00983
00984 NLMISC_COMMAND(removeFilterWarning, "remove a filter on WarningLog", "[<filterstr>]")
00985 {
00986 if(args.size() == 0)
00987 WarningLog->removeFilter();
00988 else if(args.size() == 1)
00989 WarningLog->removeFilter( args[0].c_str() );
00990 else return false;
00991 return true;
00992 }
00993
00994 NLMISC_COMMAND(displayFilterWarning, "display filter on WarningLog", "")
00995 {
00996 if(args.size() != 0) return false;
00997 WarningLog->displayFilter(log);
00998 return true;
00999 }
01000
01001 NLMISC_COMMAND(assert, "generate a failed assert", "")
01002 {
01003 if(args.size() != 0) return false;
01004 nlassertex (false, ("Assert generated by the assert command"));
01005 return true;
01006 }
01007
01008 NLMISC_COMMAND(stop, "generate a stop", "")
01009 {
01010 if(args.size() != 0) return false;
01011 nlstopex (("Stop generated by the stop command"));
01012 return true;
01013 }
01014
01015 }