303 lines
9 KiB
Plaintext
303 lines
9 KiB
Plaintext
|
Title:
|
||
|
C++ Debug Library
|
||
|
|
||
|
Author:
|
||
|
Steve Kiraly (SteveKi)
|
||
|
6-17-1998
|
||
|
1-31-1999
|
||
|
3-03-1999
|
||
|
|
||
|
Purpose:
|
||
|
The purpose of this document is to describe the design and
|
||
|
document features of this debug library. It will in addition outline some
|
||
|
of the basic design premises and include direction on how to extend or
|
||
|
add features to this library.
|
||
|
|
||
|
Description:
|
||
|
Everyone has at one time or another developed there own mini debug messging
|
||
|
class, function or library which usually includes a set of macros that
|
||
|
expand to calls to output strings to the debugger or console in the checked
|
||
|
builds and nothing in the free builds. This debug library offers a similar
|
||
|
feature however grows on this idea to permit sending the output string to one
|
||
|
or many debug devices simultaniously.
|
||
|
|
||
|
Extensions:
|
||
|
All file names have a dbg prefix because I wanted to ensure that it's
|
||
|
obvious these files are debug files and can be ignored in the free
|
||
|
version. If any files are added please stick to the dbg prefix for new
|
||
|
file names. Do not add dependencies to dlls in this library that you would
|
||
|
not normally have clients of this library link to. For example the back
|
||
|
tracing code uses imagehlp.dll it does not implicity link to imagehlp.dll
|
||
|
because this would require the client to link to imagehlp.dll. Sources
|
||
|
files do not have an easy way to conditionally link to certain libraries
|
||
|
in either the checked of free version. As a result clients are then equired to
|
||
|
link to imagehlp.dll in both the checked and free version. If there is a
|
||
|
library that you only need in this library and is not used in the
|
||
|
checked version then lazy load the library, using LoadLibrary().
|
||
|
|
||
|
To Do List:
|
||
|
1. Add memory leak detection code, both C and C++ allocations.
|
||
|
|
||
|
2. Add memory debug output device type that is compatible with splx
|
||
|
debug extension.
|
||
|
|
||
|
3. Add counter to critical section, that will be used to determine if we
|
||
|
are in the critical when the TUnLock class is used.
|
||
|
|
||
|
4. Add global variable that can be set to indicate that the backtrace
|
||
|
code should reload symbols using a new symbol path specified in the
|
||
|
registry.
|
||
|
|
||
|
5. Add code for random failed allocations. Requirements include introducing
|
||
|
random program memory allocations using backtraces to preventing duplicate
|
||
|
allocation failures.
|
||
|
|
||
|
6. Implement the Debug serial terminal. This debug device will allow you to
|
||
|
send output to a remote via a dumb serial terminal.
|
||
|
|
||
|
7. Create a method to track generic resources for leak detection. The current
|
||
|
thinking is to create a set of macros for tracking and releasing a generic
|
||
|
resource handle. The way this could work is the when a resouce is allocated
|
||
|
it is entered into a mini database along with a backtrace. When the resource
|
||
|
is release it is removed from the mini database. At the end of the program or
|
||
|
in a stratigic checkpoint the resouces that are left in the mini database can
|
||
|
be dump, these are potential resource leaks.
|
||
|
|
||
|
8. Look at the environment for the symbol path when capturing backtraces.
|
||
|
|
||
|
Example Usage:
|
||
|
|
||
|
-------------------------------------------------------------------------------
|
||
|
|
||
|
1. Display basic debug messages to the default device, debugger.
|
||
|
|
||
|
//
|
||
|
// Initialize the debug library, this is optional.
|
||
|
//
|
||
|
DBG_INIT();
|
||
|
|
||
|
//
|
||
|
// Open the debug message class, this function does the following.
|
||
|
//
|
||
|
// 1. Seting the module prefix to "DEBUG".
|
||
|
// 2. The default output device will be enabled, i.e. Debugger.
|
||
|
// 3. Trace, warning and error messages will be displayed.
|
||
|
// 4. Error messages will break to the debugger.
|
||
|
//
|
||
|
DBG_OPEN(_T("DEBUG"), DBG_DEFAULT, DBG_TRACE|DBG_WARN|DBG_ERROR, DBG_ERROR);
|
||
|
|
||
|
//
|
||
|
// Call to display a unicode debug message string.
|
||
|
//
|
||
|
DBG_MSG(DBG_TRACE, (_T("Trace testing Param %d String %s\n"), 1, _T("Test")));
|
||
|
|
||
|
//
|
||
|
// Call to display a ansi debug message string.
|
||
|
//
|
||
|
DBG_MSG(DBG_TRACE, ("Trace testing Param %d String %s\n", 1, "Test"));
|
||
|
|
||
|
//
|
||
|
// Close the debug message class, this is optional if you use DBG_RELEASE().
|
||
|
//
|
||
|
DBG_CLOSE();
|
||
|
|
||
|
//
|
||
|
// Release the debug library.
|
||
|
//
|
||
|
DBG_RELEASE();
|
||
|
|
||
|
-------------------------------------------------------------------------------
|
||
|
|
||
|
2. Dumping trace messages the debugger.
|
||
|
|
||
|
//
|
||
|
// Initialize the debug library, this is optional.
|
||
|
//
|
||
|
DBG_INIT();
|
||
|
|
||
|
//
|
||
|
// Open the message class.
|
||
|
//
|
||
|
DBG_OPEN(_T("TRACE"), DBG_DEFAULT, DBG_TRACE, DBG_NONE);
|
||
|
|
||
|
//
|
||
|
// Display a entry and exit trace message after each scope.
|
||
|
//
|
||
|
//
|
||
|
DBG_TRACE(_T("Test Scope 1"))
|
||
|
{
|
||
|
DBG_TRACE(_T("Test Scope 2"))
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Release the debug library.
|
||
|
//
|
||
|
DBG_RELEASE();
|
||
|
|
||
|
-------------------------------------------------------------------------------
|
||
|
|
||
|
3. Log messages to multiple devices, file, debugger.
|
||
|
|
||
|
//
|
||
|
// Initialize the debug library, this is optional.
|
||
|
//
|
||
|
DBG_INIT();
|
||
|
|
||
|
//
|
||
|
// Open the message class.
|
||
|
//
|
||
|
DBG_OPEN(_T("DEBUG"), DBG_DEBUGGER, DBG_TRACE, DBG_NONE);
|
||
|
|
||
|
//
|
||
|
// Declare the debug file device handle.
|
||
|
//
|
||
|
DBG_HANDLE_(hDebugFile);
|
||
|
|
||
|
//
|
||
|
// Attach the messages to file output device.
|
||
|
//
|
||
|
DBG_ATTACH_(hDebugFile, DBG_FILE, _T("output.log"));
|
||
|
|
||
|
//
|
||
|
// Display a message, this message will be sent to both the debugger and the
|
||
|
// output.log file.
|
||
|
//
|
||
|
DBG_MSG(DBG_TRACE, (_T( "Trace testing Param %d String %s\n"), 1, _T("Test")));
|
||
|
|
||
|
//
|
||
|
// Detach the file device from the output stream, this step is optional if you
|
||
|
// use either the DBG_CLOSE or the DBG_RELEASE functions they will release the
|
||
|
// the attached devices.
|
||
|
//
|
||
|
DBG_DETACH_(hDebugFile);
|
||
|
|
||
|
//
|
||
|
// Close the debug message class, this is optional if you use DBG_RELEASE().
|
||
|
//
|
||
|
DBG_CLOSE();
|
||
|
|
||
|
//
|
||
|
// Release the debug library.
|
||
|
//
|
||
|
DBG_RELEASE();
|
||
|
|
||
|
-------------------------------------------------------------------------------
|
||
|
|
||
|
4. Display message with time stamp and thread id.
|
||
|
|
||
|
//
|
||
|
// Initialize the debug library, this is optional.
|
||
|
//
|
||
|
DBG_INIT();
|
||
|
|
||
|
//
|
||
|
// Open the message class, displaying a thread id and time stamp.
|
||
|
//
|
||
|
DBG_OPEN(_T("DEBUG"), DBG_TRHEADID|DBG_TIMESTAMP|DBG_DEBUGGER, DBG_TRACE, DBG_NONE);
|
||
|
|
||
|
//
|
||
|
// Display trace message.
|
||
|
//
|
||
|
DBG_MSG(DBG_TRACE, (_T("Trace testing Param %d String %s\n"), 1, _T("Test")));
|
||
|
|
||
|
//
|
||
|
// Close the debug message class, this is optional if you use DBG_RELEASE().
|
||
|
//
|
||
|
DBG_CLOSE();
|
||
|
|
||
|
//
|
||
|
// Release the debug library.
|
||
|
//
|
||
|
DBG_RELEASE();
|
||
|
|
||
|
-------------------------------------------------------------------------------
|
||
|
|
||
|
5. Display message with custom time stamp and thread id formats.
|
||
|
|
||
|
DBG_OPEN(_T("DBG_TIME"), DBG_DEFAULT, DBG_TRACE|DBG_TIMESTAMP|DBG_THREADID, DBG_NONE);
|
||
|
|
||
|
DBG_SET_FIELD_FORMAT(DBG_TIMESTAMP, _T(" Tick Count (%x)"));
|
||
|
|
||
|
DBG_SET_FIELD_FORMAT(DBG_THREADID, _T(" Thread Id = [%d]"));
|
||
|
|
||
|
DBG_MSG(DBG_TRACE, ("Test Message\n"));
|
||
|
|
||
|
DBG_CLOSE();
|
||
|
|
||
|
-------------------------------------------------------------------------------
|
||
|
|
||
|
6. Capture macros used for capturing stack backtraces.
|
||
|
|
||
|
The symbol path by default will look in .;%_NT_SYMBOL_PATH%;_ALT_SYMBOL_PATH;
|
||
|
if you need to specify an alternate symbol path the debug library will look in
|
||
|
the following registry key for an alternate symbol path.
|
||
|
|
||
|
HKLM\Software\Microsoft\Windows NT\CurrentVersion\PrintSysDebugLibrary
|
||
|
Sympath REG_SZ ="Your own symbol path"
|
||
|
|
||
|
//
|
||
|
// Initialize the debug library, this is optional.
|
||
|
//
|
||
|
DBG_INIT();
|
||
|
|
||
|
DBG_CAPTURE_HANDLE(Capture);
|
||
|
DBG_CAPTURE_OPEN(Capture, _T("nosymbols"), DBG_DEBUGGER, NULL);
|
||
|
DBG_CAPTURE(Capture, 0, ("Ansi %d Multi Thread Test.\n", dwThread));
|
||
|
DBG_CAPTURE_CLOSE(Capture);
|
||
|
|
||
|
//
|
||
|
// Capture stack back traces with symbols and output to debugger.
|
||
|
//
|
||
|
DBG_CAPTURE_HANDLE(Capture);
|
||
|
DBG_CAPTURE_OPEN(Capture, _T("symbols"), DBG_DEBUGGER, NULL);
|
||
|
DBG_CAPTURE(Capture, 0, (_T("Unicode %d Multi Thread Test.\n"), dwThread));
|
||
|
DBG_CAPTURE_CLOSE(Capture);
|
||
|
|
||
|
//
|
||
|
// Capture stack back traces with symbols and output to file "backtrace.log"
|
||
|
//
|
||
|
DBG_CAPTURE_HANDLE(Capture);
|
||
|
DBG_CAPTURE_OPEN(Capture, _T("symbols"), DBG_FILE, _T("backtrace.log"));
|
||
|
DBG_CAPTURE(Capture, 0, (_T("Unicode %d Multi Thread Test.\n"), dwThread));
|
||
|
DBG_CAPTURE_CLOSE(Capture);
|
||
|
|
||
|
//
|
||
|
// Release the debug library.
|
||
|
//
|
||
|
DBG_RELEASE();
|
||
|
|
||
|
-------------------------------------------------------------------------------
|
||
|
|
||
|
7. Misc assert and macro usage examples.
|
||
|
|
||
|
//
|
||
|
// Some other useful macros.
|
||
|
//
|
||
|
// Call to output a string to the debugger with no formatting.
|
||
|
// The passed string must use the _T() or TEXT() macros and
|
||
|
// have a trailing semicolan;
|
||
|
//
|
||
|
DBG_RAW(_T("Trace message"));
|
||
|
|
||
|
//
|
||
|
// Break to the debugger.
|
||
|
//
|
||
|
DBG_BREAK();
|
||
|
|
||
|
//
|
||
|
// Normal assert message
|
||
|
//
|
||
|
DBG_ASSERT(FALSE);
|
||
|
|
||
|
//
|
||
|
// Assert message with ansi description string
|
||
|
//
|
||
|
DBG_ASSERT_MSG(i==0, ("Null pointer found %s.\n", "Here"));
|
||
|
|
||
|
//
|
||
|
// Assert message with unicode description string
|
||
|
//
|
||
|
DBG_ASSERT_MSG(i==0, (_T("Null pointer found %s.\n"), _T("Here")));
|
||
|
|
||
|
|