Home   Notes   Contact Me

Windows Debugging

--> Gotcha's <--

Local

External


Exporting a debug variable to other modules

// In the defining module namespace { extern "C" { __declspec(dllexport) int jbpSkipFlag = 0; } } // In the using module namespace { extern "C" { __declspec(dllimport) int jbpSkipFlag; } }

High Resolution Timer

Time one event

LARGE_INTEGER jstart; QueryPerformanceCounter(&jstart); // Do stuff that needs timing LARGE_INTEGER jend; QueryPerformanceCounter(&jend); LARGE_INTEGER span; span.QuadPart = jend.QuadPart - jstart.QuadPart;

Timer Frequency

LARGE_INTEGER freq; QueryPerformanceFrequency(&freq); std::cout << "Frequency=0x" << std::hex << freq.u.HighPart << std::hex << freq.u.LowPart << std::endl;

Average Time of event

LARGE_INTEGER jstart; QueryPerformanceCounter(&jstart); // Do stuff to time here // Do stuff to time here // Do stuff to time here // Do stuff to time here // Do stuff to time here LARGE_INTEGER jend; QueryPerformanceCounter(&jend); static int count = 0; static LONGLONG total = 0; LONGLONG span = jend.QuadPart - jstart.QuadPart; HANDLE mutex2 = CreateMutex( 0, false, "uniqueName"); WaitForSingleObject( mutex2, INFINITE); count++; total += span; if (count == 1543) { std::cout << "Per=" << total / count << std::endl; } ReleaseMutex( mutex2);

Save Raw RGB to .bmp

void SaveRawToBmpLayerInterleaved(bool* pInitialized, const char* zDirNamePrefix, unsigned char* pData, unsigned long wide, unsigned long tall) //void SaveRawToBmpPixelInterleaved( // const char* zDirNamePrefix, // unsigned char* pData, // unsigned long wide, unsigned long tall) { static HANDLE mutex = CreateMutex(0, false, L"blocksavergb"); WaitForSingleObject(mutex, INFINITE); static int blockNum = 0; static int timestamp = ::GetTickCount(); char zName[1000]; if (!(*pInitialized)) { sprintf(zName, "c:\\delme\\blocks-%08x-%s", timestamp, zDirNamePrefix); CreateDirectoryA(zName, NULL); (*pInitialized) = true; } sprintf(zName, "c:\\delme\\blocks-%08x-%s\\block-%08d.bmp", timestamp, zDirNamePrefix, blockNum); blockNum++; FILE* fout = fopen(zName, "wb"); if (fout) { char bmpHeader[0x36]; char* pMagic0 = bmpHeader + 0x00; char* pMagic1 = bmpHeader + 0x01; DWORD* pFileSize = (DWORD*)(bmpHeader + 0x02); DWORD* pStartOfData = (DWORD*)(bmpHeader + 0x0a); DWORD* pSizeOfHeader = (DWORD*)(bmpHeader + 0x0e); DWORD* pWidth = (DWORD*)(bmpHeader + 0x12); DWORD* pHeight = (DWORD*)(bmpHeader + 0x16); WORD* pPlanes = (WORD*)(bmpHeader + 0x1a); WORD* pBitsPerPixel = (WORD*)(bmpHeader + 0x1c); DWORD* pImageDataSize = (DWORD*)(bmpHeader + 0x22); // size of file - headersize // headersize is 0x36 memset(bmpHeader, 0, sizeof(bmpHeader)); *pMagic0 = 'B'; *pMagic1 = 'M'; *pFileSize = 0x36 + wide * tall * 3; *pStartOfData = 0x36; *pSizeOfHeader = 0x28; *pWidth = wide; *pHeight = tall; *pPlanes = 1; *pBitsPerPixel = 24; *pImageDataSize = *pFileSize - 0x36; size_t written; written = fwrite(bmpHeader, sizeof(bmpHeader), 1, fout); //unsigned char* pLine = new unsigned char[bh * bw * 3]; unsigned char* pOut = new unsigned char[tall * wide * 3]; unsigned char* pTo = pOut; int span = wide; unsigned char* pFromR = pData + tall * wide * 3 * 1; unsigned char* pFromG = pData + tall * wide * 3 * 2; unsigned char* pFromB = pData + tall * wide * 3 * 3; for (int y = tall - 1; y >= 0; y--) { pFromR -= span; pFromG -= span; pFromB -= span; //pTo = pLine; for (int x = 0; x < wide; x++) { *pTo++ = pFromR[x]; *pTo++ = pFromG[x]; *pTo++ = pFromB[x]; } } fwrite(pOut, tall * wide * 3, 1, fout); delete[] pOut; fclose(fout); } ReleaseMutex(mutex); } void SaveRawToBmpPixelInterleaved(bool* pInitialized, const char* zDirNamePrefix, unsigned char* pData, unsigned long wide, unsigned long tall) //void SaveRawToBmpPixelInterleaved( // const char* zDirNamePrefix, // unsigned char* pData, // unsigned long wide, unsigned long tall) { static HANDLE mutex = CreateMutex(0, false, L"blocksavergb"); WaitForSingleObject(mutex, INFINITE); static int blockNum = 0; static int timestamp = ::GetTickCount(); char zName[1000]; if (!(*pInitialized)) { sprintf(zName, "c:\\delme\\blocks-%08x-%s", timestamp, zDirNamePrefix); CreateDirectoryA(zName, NULL); (*pInitialized) = true; } sprintf(zName, "c:\\delme\\blocks-%08x-%s\\block-%08d.bmp", timestamp, zDirNamePrefix, blockNum); blockNum++; FILE* fout = fopen(zName, "wb"); if (fout) { char bmpHeader[0x36]; char* pMagic0 = bmpHeader + 0x00; char* pMagic1 = bmpHeader + 0x01; DWORD* pFileSize = (DWORD*)(bmpHeader + 0x02); DWORD* pStartOfData = (DWORD*)(bmpHeader + 0x0a); DWORD* pSizeOfHeader = (DWORD*)(bmpHeader + 0x0e); DWORD* pWidth = (DWORD*)(bmpHeader + 0x12); DWORD* pHeight = (DWORD*)(bmpHeader + 0x16); WORD* pPlanes = (WORD*)(bmpHeader + 0x1a); WORD* pBitsPerPixel = (WORD*)(bmpHeader + 0x1c); DWORD* pImageDataSize = (DWORD*)(bmpHeader + 0x22); // size of file - headersize // headersize is 0x36 memset(bmpHeader, 0, sizeof(bmpHeader)); *pMagic0 = 'B'; *pMagic1 = 'M'; *pFileSize = 0x36 + wide * tall * 3; *pStartOfData = 0x36; *pSizeOfHeader = 0x28; *pWidth = wide; *pHeight = tall; *pPlanes = 1; *pBitsPerPixel = 24; *pImageDataSize = *pFileSize - 0x36; size_t written; written = fwrite(bmpHeader, sizeof(bmpHeader), 1, fout); //unsigned char* pLine = new unsigned char[bh * bw * 3]; unsigned char* pOut = new unsigned char[tall * wide * 3]; unsigned char* pTo = pOut; int span = wide * 3; unsigned char* pFromR = pData + tall * wide * 3; unsigned char* pFromG = pFromR + 1; unsigned char* pFromB = pFromR + 2; for (int y = tall - 1; y >= 0; y--) { pFromR -= span; pFromG -= span; pFromB -= span; //pTo = pLine; for (int x = 0; x < wide; x++) { *pTo++ = pFromR[x]; *pTo++ = pFromG[x]; *pTo++ = pFromB[x]; } } fwrite(pOut, tall * wide * 3, 1, fout); delete[] pOut; fclose(fout); } ReleaseMutex(mutex); } void SaveRawToBmp(bool* pInitialized, const char* zDirNamePrefix, unsigned char* pDataR, unsigned char* pDataG, unsigned char* pDataB, unsigned long wide, unsigned long tall) { static HANDLE mutex = CreateMutex(0, false, L"blocksavergb"); WaitForSingleObject(mutex, INFINITE); static int blockNum = 0; static int timestamp = ::GetTickCount(); char zName[1000]; if (!(*pInitialized)) { sprintf(zName, "c:\\delme\\blocks-%08x-%s", timestamp, zDirNamePrefix); CreateDirectoryA(zName, NULL); (*pInitialized) = true; } sprintf(zName, "c:\\delme\\blocks-%08x-%s\\block-%08d.bmp", timestamp, zDirNamePrefix, blockNum); blockNum++; FILE* fout = fopen(zName, "wb"); if (fout) { char bmpHeader[0x36]; char* pMagic0 = bmpHeader + 0x00; char* pMagic1 = bmpHeader + 0x01; DWORD* pFileSize = (DWORD*)(bmpHeader + 0x02); DWORD* pStartOfData = (DWORD*)(bmpHeader + 0x0a); DWORD* pSizeOfHeader = (DWORD*)(bmpHeader + 0x0e); DWORD* pWidth = (DWORD*)(bmpHeader + 0x12); DWORD* pHeight = (DWORD*)(bmpHeader + 0x16); WORD* pPlanes = (WORD*)(bmpHeader + 0x1a); WORD* pBitsPerPixel = (WORD*)(bmpHeader + 0x1c); DWORD* pImageDataSize = (DWORD*)(bmpHeader + 0x22); // size of file - headersize // headersize is 0x36 memset(bmpHeader, 0, sizeof(bmpHeader)); *pMagic0 = 'B'; *pMagic1 = 'M'; *pFileSize = 0x36 + wide * tall * 3; *pStartOfData = 0x36; *pSizeOfHeader = 0x28; *pWidth = wide; *pHeight = tall; *pPlanes = 1; *pBitsPerPixel = 24; *pImageDataSize = *pFileSize - 0x36; size_t written; written = fwrite(bmpHeader, sizeof(bmpHeader), 1, fout); //unsigned char* pLine = new unsigned char[bh * bw * 3]; unsigned char* pOut = new unsigned char[tall * wide * 3]; unsigned char* pTo = pOut; int span = wide; unsigned char* pFromR = pDataR + tall * wide; unsigned char* pFromG = pDataG + tall * wide; unsigned char* pFromB = pDataB + tall * wide; for (int y = tall - 1; y >= 0; y--) { pFromR -= span; pFromG -= span; pFromB -= span; //pTo = pLine; for (int x = 0; x < wide; x++) { *pTo++ = pFromR[x]; *pTo++ = pFromG[x]; *pTo++ = pFromB[x]; } } fwrite(pOut, tall * wide * 3, 1, fout); delete[] pOut; fclose(fout); } ReleaseMutex(mutex); }

Memory change detector (Debug)

In a low level library put this

#include <memory.h> #include <vector> #define WIN32_LEAN_AND_MEAN #include <windows.h> struct WatchTarget { public: void* m_pWhere; int m_nLen; unsigned char* m_pData; WatchTarget(void* pWhere, int nLen) { m_pWhere = pWhere; m_nLen = nLen; m_pData = new unsigned char[m_nLen]; memcpy(m_pData, m_pWhere, m_nLen); } }; std::vector<WatchTarget*> g_watches; HANDLE mutex = CreateMutex( 0, false, "jbpdebug"); extern "C" { __declspec(dllexport) void addWatch(void *pWhere, int nLen); __declspec(dllexport) void removeWatch(void *pWhere); __declspec(dllexport) void verifyWatchesUnchanged(); } void addWatch(void *pWhere, int nLen) { WaitForSingleObject(mutex, INFINITE); WatchTarget* pWatch = new WatchTarget(pWhere, nLen); g_watches.push_back(pWatch); ReleaseMutex(mutex); } void removeWatch(void *pWhere) { WaitForSingleObject(mutex, INFINITE); std::vector<WatchTarget*>::iterator it; for (it = g_watches.begin(); it != g_watches.end(); it++) { WatchTarget* pWatch = *it; if (pWatch->m_pWhere == pWhere) { g_watches.erase(it); break; } } ReleaseMutex(mutex); } void verifyWatchesUnchanged() { WaitForSingleObject(mutex, INFINITE); std::vector<WatchTarget*>::iterator it; for (it = g_watches.begin(); it != g_watches.end(); it++) { WatchTarget* pWatch = *it; if (memcmp(pWatch->m_pWhere, pWatch->m_pData, pWatch->m_nLen)) { _asm int 3; } } ReleaseMutex(mutex); }

Put this where it will be used

__declspec(dllimport) void addWatch(void *pWhere, int nLen); __declspec(dllimport) void removeWatch(void *pWhere); __declspec(dllimport) void verifyWatchesUnchanged();

Example Use

static Thing* pThing = 0; if (0 == pThing) { pThing = new Thing(); // do once addWatch(pThing, sizeof(*pThing)); } // do alot: verifyWatchesUnchanged(); if (deleting it for some reason) { removeWatch(pThing); delete pThing; }

Heap Debugging in Windows

To use:
#include <crtdbg.h>

Functions

Function Description
_CrtCheckMemory() Checks heap integrity
_CrtSetDbgFlag Sets or gets debug heap flags
int debugHeapFlags = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); debugHeapFlags |= _CRTDBG_CHECK_EVERY_1024_DF; _CrtSetDbgFlag(debugHeapFlags);

Internet Access, disabling

To temporarily disable your access to the internet, you can open a command prompt and type: route ADD 0.0.0.0 MASK 0.0.0.0 [your IP address] This will redirect all traffic destined outside the LAN back to your machine. Bye bye internet. . . example: route delete 0.0.0.0 mask 0.0.0.0 10.44.8.133 To restore your internet access: route DELETE 0.0.0.0 MASK 0.0.0.0 [your IP address]

Library Loading problems, diagnose with via "Loader Snaps"

See http://blogs.msdn.com/junfeng/archive/2006/11/20/debugging-loadlibrary-failures.aspx

Get "Debugging Tools for Windows" here http://www.microsoft.com/whdc/devtools/debugging/default.mspx


RtlAllocateHeapSlowly

To find info about what happened, in the debugger look at the output pane, there is usually text about what caused this.


GetLastError not returning a reasonable code, How to deal with it

Debugging 'Last Error' problems

On a few occasions I have run into problems where some Windows API was returning a 'strange' error code. Here is a technique that works with some APIs:

   1. Go get public symbols for your operating system – add http://msdl.microsoft.com/download/symbols to your symbol path and define a symbol cache directory
   2. Set a breakpoint on SetLastError: to be on the safe side, set the breakpoint on both {,,kernel32}_SetLastError@4 and {,,ntdll}_RtlSetLastWin32Error@4
   3. Assuming that you get a million calls, figure out where the last error is being passed to the set last error functions. For me, this is *(unsigned*)(@esp+4), but your mileage may vary. Once you know where the error code is passed, you can either set a tracepoint, or turn the breakpoint into a conditional breakpoint (see more information bellow).
   4. Run your scenario and find your bug

To set a tracepoint:

   1. Right click on the breakpoint, and click 'When Hit...'
   2. Check 'print a message'
   3. Set the message to '{*(unsigned*)(@esp+4)} -- $CALLSTACK', or whatever information you want
   4. Click 'okay'

To set a conditional breakpoint:

   1. Right click on the breakpoint, and click 'Condition...'
   2. Set your condition to be '*(unsigned*)(@esp+4)==1234' where 1234 is the strange error code that you are seeing

Article on Debugging, with info about tools

Here are links to the article


Heap Messes

Excellent Quote

From http://www.codeguru.com/forum/archive/index.php/t-229394.html

Paul McKenzie
02-06-2003, 11:03 PM
Sorry RobAnd, galathaea is correct.

You never mentioned what version of the run-time library you were using. This is the deciding factor, not the source code.
If you are using the DLL version of the C runtime library, you won't get an error, since your app and DLL are using the same heap.

Change your project settings to use the non-DLL version of the runtime library. You will be using two different heap managers -- you can't create a pointer from one heap manager and delete it with another heap manager. Your program will crash, if not now, eventually it will.

This is a well-known problem for years, and has been written about in various articles, most notably in the C/C++ User's Journal a couple of years ago when discussing VC++ and STL (Sorry, I can't find the article).

Also note the many posters on CodeGuru that have come across this problem (there must be at least 50 or so threads dealing with this topic). The remedy is to either use the DLL version of the CRT, or restructure the code so that only one module is responsible for memory allocation / deletion.

Regards,

Paul McKenzie

Sorry RobAnd, galathaea is correct.

You never mentioned what version of the run-time library you were using. This is the deciding factor, not the source code.
If you are using the DLL version of the C runtime library, you won't get an error, since your app and DLL are using the same heap.

Change your project settings to use the non-DLL version of the runtime library. You will be using two different heap managers -- you can't create a pointer from one heap manager and delete it with another heap manager. Your program will crash, if not now, eventually it will.

This is a well-known problem for years, and has been written about in various articles, most notably in the C/C++ User's Journal a couple of years ago when discussing VC++ and STL (Sorry, I can't find the article).

Also note the many posters on CodeGuru that have come across this problem (there must be at least 50 or so threads dealing with this topic). The remedy is to either use the DLL version of the CRT, or restructure the code so that only one module is responsible for memory allocation / deletion.

Regards,

Paul McKenzie

Symbols, how to provide them to the debugger

What does this mean? If you debug something and look at the stack, you will often see some criptic call levels. If you provide the debugger with the right symbols, it will show you reasonable names for call levels that are associated with the provided symbols.

Setting them up in Visual Studio .NET 2003 (VS7.1)

Microsoft "HOW TO: Use a Symbol Server with the Visual Studio .NET Debugger" http://support.microsoft.com/default.aspx?scid=kb;en-us;319037

  1. Get the symchk utility to get the Microsoft symbols. The utility can be found with the "Debugging Tools for Windows" at http://www.microsoft.com/ddk/debugging
  2. [why??] You should add the "Debugging Tools for Windows" directory to your system PATH
  3. Run symchk from the command line to get the symbols you want. [see below]
  4. Copy the symsrv.dll file from the "Debugging Tools for Windows" directory to the C:\Program Files\Microsoft Visual Studio .NET\Common7\IDE directory. {yes this looks like it is for VS7.0, but I tested that it works with VS7.1)
  5. Specify the location of the local symbol cache in your SOLUTIONS properties
    Select the Solution | Context Menu | Properties | Debug Symbol Files | {New Folder Icon} And put a value like this there srv*c:\symbols
# substitute your windows path for winnt where appropriate

#symbols for kernel32.dll
symchk /r c:\winnt\system32\kernel32.dll /s srv*c:\symbols*http://msdl.microsoft.com/download/symbols

# ntdll.dll
symchk /r c:\winnt\system32\ntdll.dll /s srv*c:\symbols*http://msdl.microsoft.com/download/symbols

symchk /r c:\winnt\system32\msvcr71.dll /s srv*c:\symbols*http://msdl.microsoft.com/download/symbols

symchk /r c:\winnt\system32\kernel32.dll /s srv*c:\symbols*http://msdl.microsoft.com/download/symbols

# everything at once !!!
symchk /r c:\winnt\system32 /s srv*c:\symbols*http://msdl.microsoft.com/download/symbols

More useful info

Base info for this was found at "greggm's WebLog" "Bad Native Callstacks" http://blogs.msdn.com/greggm/archive/2004/02/10/71125.aspx