Symbol Dumper (using dbghelp & imagehlp)

#include "windows.h"

#include "tchar.h"

#include "stdio.h"

 

#define DBGHELP_TRANSLATE_TCHAR

#include "dbghelp.h"

#pragma comment(lib, "dbghelp.lib")

 

extern "C"

PLOADED_IMAGE

IMAGEAPI

ImageLoad(

                     __in PCSTR DllName,

                     __in_opt PCSTR DllPath

                     );

 

extern "C"

BOOL

IMAGEAPI

ImageUnload(

                             __inout PLOADED_IMAGE LoadedImage

                             );

 

#pragma comment(lib, "imagehlp.lib")

 

BOOL EnumerateSymbols(PCSTR);

BOOL CALLBACK EnumerateSymbolsProc(PSYMBOL_INFO, ULONG, PVOID);

 

int _tmain(int argc, _TCHAR* argv[], _TCHAR* env[])

{

          if (argc != 2)

          {

                   return 0;

          }

#if defined(UNICODE) && defined(_UNICODE)

          size_t i;

          char pbuffer[MAX_PATH];

          wcstombs_s(&i, pbuffer, MAX_PATH, argv[1], MAX_PATH);

          EnumerateSymbols(pbuffer);

#else

          EnumerateSymbols(argv[1]);

#endif

          return 0;

}

 

BOOL EnumerateSymbols(PCSTR DllName)

{

          HANDLE hProcess;

 

          SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS);

 

          hProcess = GetCurrentProcess();

 

          if (!SymInitialize(hProcess,

                   _T("symsrv*symsrv.dll*C:\\sc\\ms*http://msdl.microsoft.com/download/symbols"),

                   FALSE))

          {

                   _tprintf(_T("SymInitialize. Error: 0x%x.\n"), GetLastError());

                   return FALSE;

          }

 

          PLOADED_IMAGE pli = ImageLoad(DllName, NULL);

          if (pli == NULL)

          {

                   _tprintf(_T("ImageLoad. Error: 0x%x.\n"), GetLastError());

                   return FALSE;

          }

 

          DWORD64 dw64Ret = SymLoadModule64(hProcess,

                   pli->hFile, NULL,

                   pli->ModuleName,

                   (DWORD64)pli->MappedAddress,

                   pli->SizeOfImage);

          if (dw64Ret == 0 || ERROR_SUCCESS != GetLastError())

          {

                   _tprintf(_T("SymLoadModule64. Error: 0x%x.\n"), GetLastError());

                   return FALSE;

          }

 

          dw64Ret = (DWORD64)pli->MappedAddress;

 

          if (!SymEnumSymbols(hProcess,

                   (ULONG64)dw64Ret,

                   NULL,

                   (PSYM_ENUMERATESYMBOLS_CALLBACK)EnumerateSymbolsProc,

                   NULL))

          {

                   _tprintf(_T("SymEnumSymbols. Error: 0x%x.\n"), GetLastError());

                   return FALSE;

          }

 

          if (!SymUnloadModule64(hProcess, (DWORD64)pli->MappedAddress))

          {

                   _tprintf(_T("SymUnloadModule64. Error: 0x%x.\n"), GetLastError());

                   return FALSE;

          }

 

          if (!ImageUnload(pli))

          {

                   _tprintf(_T("ImageUnload. Error: 0x%x.\n"), GetLastError());

                   return FALSE;

          }

 

          if (!SymCleanup(hProcess))

          {

                   _tprintf(_T("SymCleanup. Error: 0x%x.\n"), GetLastError());

                   return FALSE;

          }

          return TRUE;

}

 

BOOL CALLBACK EnumerateSymbolsProc(PSYMBOL_INFO pSymInfo, ULONG SymbolSize, PVOID UserContext)

{

          _tprintf(_T("SymName: %s\n"), pSymInfo->Name);

          _tprintf(_T("SymType: 0x%08x\tSymAddr: 0x%08x\tSymSize: %d\n"),

                   pSymInfo->Flags, pSymInfo->Address, SymbolSize);

 

          return TRUE;

}

Plan to write a User-Mode Debugger

Writting a basic user mode debugger is much easier than I have expected. Note, two key adjectives here: basic and user mode. For basic, it is for the point of view of requirements. A basic debugger only needs to take over two things: (1) Attach to/CreateProcess a debugee (process being debugged) and (2) use WaitForDebugEvent/ContinueDebugEvent pair to deal with relevant debug events. For user mode, it is from the perspective of the target application, which is to be debugged. I will focus on user mode only. For kernel mode, it is still a mystery topic from my mind. As you may know, kernel debugger stands between CPU and Operating System. So if it were not a old-timer or experienced debugger writer, it should be a really hard task.
 
Exactly, a good debugger is much more than this two. Take a look at your already familiar debuggers, Visual Studio and Windbg, they provide many advanced functionalities to ease developers routine work. For example, walking stacks with debugging information, inquiring local variable and parameters on the callstacks, array and structure expansion, stepping into/over/out, setting break point on both source level and assembly level, providing different kinds of break point (data, location), disassembler machine code, if a managed application, IL level disassembler, accessing symbol server, accessing source server, debugger extensions (son of strike), debugging dump files … I can list much more than here…
 
After reading some articles online (in particular, several articles written 10 year ago in Under the Hood column from Microsoft System Journal, and a little from John Robbins’ Debugging Applications for Microsoft .NET and Microsoft Windows), I found most of these advanced features of debugger has already been exposed by Microsoft through dynamic link libraries: Win32 Debugging APIs, in kernel32.dll, dbghelp.dll provided as part of Operating System and debugging Tools of Windows, DIA (Debug Interface Access SDK)… if you read through their documentations, most of you should feel writting a debugger is just a ass work.
 
But, as we alway pointed out, theory and practice are different. How can you prove your understanding without implementing/practising manually? That’s why I schedule my spare time on that. So, in the future’s posts, if no accidental, I will only concentrate on debugging techniques. Walk Native Callstack with Symbolic Info  is the 1st one.
 
Some tips on Walk Native callstack with Symbolic Info
  • APIs in dbghelp.dll suffixed with "64" are all 64-bit widen. During dump eip and ebp, I forcely cast them to 32-bit DWORD.
  • A bug? The 2nd parameter of SymInitilize should be PCTSTR, but it is unexpectedly PCSTR. I forcely use its Unicode version with "W" suffixed. [Update: not a bug, I should have read through the MSDN more carefully. To call the Unicode version of this function, define DBGHELP_TRANSLATE_TCHAR.]
  • The 2nd parameter of SymInitilize provides symbol search path, I use symsrv.dll as symbol server. So you have to put symsrv.dll under the same folder of the executable, otherwise, the result of stack walking will not be correct. In most of cases, you will see export symbols instead of those from PDB.

Walk Native Callstack with Symbolic Info

#include "windows.h"

#include "tchar.h"

#include "dbghelp.h"

 

#pragma comment(lib, "Dbghelp.lib")

 

class StackWalker

{

public:

      StackWalker();

      ~StackWalker();

 

private:

      static void StackWalk(const CONTEXT* ctx);

 

      static LPTOP_LEVEL_EXCEPTION_FILTER m_previousFilter;

      static LONG WINAPI MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo);

};

 

// define static member..

LPTOP_LEVEL_EXCEPTION_FILTER StackWalker::m_previousFilter = NULL;

 

StackWalker::StackWalker()

{

      m_previousFilter = SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);

}

 

StackWalker::~StackWalker()

{

      SetUnhandledExceptionFilter(m_previousFilter);

}

 

LONG WINAPI StackWalker::MyUnhandledExceptionFilter( PEXCEPTION_POINTERS pExceptionInfo )

{

      PCONTEXT pCtx = pExceptionInfo->ContextRecord;

      // stack walking and print it…

      StackWalk(pCtx);

 

      // passing exception processing…

      if (m_previousFilter != NULL)

           return m_previousFilter(pExceptionInfo);

      else

           return EXCEPTION_CONTINUE_SEARCH;

}

 

void StackWalker::StackWalk( const CONTEXT* ctx )

{

      // in debugger, set the first param to process id!

      if (!SymInitializeW(GetCurrentProcess(),

           /*NULL,*/_T("symsrv*symsrv.dll*C:\\sc\\ms*http://msdl.microsoft.com/download/symbols"),

           TRUE))

      {

           _tprintf(_T("SymInitialize Error: 0x%x\n"), GetLastError());

           return;

      }

 

      _tprintf(_T("Callstack:\n"));

      STACKFRAME64 sf64;

      memset(&sf64, 0, sizeof(STACKFRAME64));

 

      // should be initialized first..

      sf64.AddrPC.Offset        = ctx->Eip;

      sf64.AddrPC.Mode         = AddrModeFlat;

      sf64.AddrStack.Offset    = ctx->Esp;

      sf64.AddrStack.Mode     = AddrModeFlat;

      sf64.AddrFrame.Offset   = ctx->Ebp;

      sf64.AddrFrame.Mode    = AddrModeFlat;

 

      while (true)

      {

           if (!StackWalk64(

                      IMAGE_FILE_MACHINE_I386, // CPU architecture

                      GetCurrentProcess(),                 // process that is to undergo stack walking

                      GetCurrentThread(),

                      &sf64,

                      (PVOID)ctx,

                      NULL,

                      SymFunctionTableAccess64,

                      SymGetModuleBase64,

                      NULL

                 ))

           {

                 //_tprintf(_T("StackWalk64 Error: 0x%x\n"), GetLastError());

                 break;

           }

 

           if (sf64.AddrStack.Offset == 0)

                 break;

 

            _tprintf(_T("%08x %08x "), (DWORD)sf64.AddrPC.Offset, (DWORD)sf64.AddrFrame.Offset);

 

           ULONG64 buffer[(sizeof(SYMBOL_INFO) +

                 MAX_SYM_NAME*sizeof(TCHAR) +

                 sizeof(ULONG64) – 1) /

                 sizeof(ULONG64)];

           PSYMBOL_INFO _psymbol = (PSYMBOL_INFO)buffer;

 

           _psymbol->SizeOfStruct = sizeof(SYMBOL_INFO);

           _psymbol->MaxNameLen = MAX_SYM_NAME;

 

           DWORD64 dwDisplacement = 0;

           if (SymFromAddr(GetCurrentProcess(), sf64.AddrPC.Offset,

                 &dwDisplacement, _psymbol))

           {

                 // seems like Name is in single byte even in Unicode

                 _tprintf(_T("%hs+0x%x\n"), _psymbol->Name, dwDisplacement);

           }

           else

           {

                 _tprintf(_T("SymFromAddr Error: 0x%x\n"), GetLastError());

           }

      }

 

      if (!SymCleanup(GetCurrentProcess()))

      {

           _tprintf(_T("SymCleanup Error: 0x%x\n"), GetLastError());

           return;

      }

}

 

StackWalker g_stackWalker;

 

int _tmain(int argc, TCHAR* argv[], TCHAR* env[])

{

      int a = 0;

      int b = 1 / a;

 

      return 0;

}

Mr Children – HANABI (Code Blue)

どれくらいの値打ちがあるだろう?
  僕が今生きてるこの世界に
  全てが無意味だって思える
  ちょっと疲れてんのかな?
  
  手に入れたもんと引き換えにして
  切り捨てた いくつもの輝き
  いちいち憂いでいれるほど
  平和な世の中じゃないし
  
  いったいどんな理想を描いたらいい?
  どんな希望を抱き進んだらいい?
  答えようもないその問い掛けは
  日常に葬られていく
  
  君がいたらなんて言うかな?
  「暗い」と茶化して笑うのかな?
  そのやわらかな笑顔に触れて
  僕の憂鬱が吹き飛んだらいいのに
  
  決して捕まえることの出来ない
  花火のような光だとしたって
  もう一回 もう一回 もう一回 もう一回
  僕はこの手を伸ばしたい
  
  誰も皆 悲しみを抱いている
  だけど素敵な明日を願っている
  臆病風に吹かれて 波風が立った世界を
  どれだけ愛することができるだろう
  
  考えすぎで言葉に詰まる
  自分の不器用さが嫌い
  でも妙に器用に立ち振る舞う
  自分がそれ以上に嫌い
  
  笑っていても 泣いて過ごしても
  平等に時は流れる
  未来が僕らを呼んでいる
  その声は今君にも聞こえていますか?
  
  さよならが迎えに来ること
  最初から分かっていたとしたって
  もう一回 もう一回 もう一回 もう一回
  何度でも君に会いたい
  
  巡り逢えたことでこんなに
  世界が美しく見えるなんて
  想像さえもしていない
  単純だって笑うかい
  君に心から「ありがとう」を言うよ
  
  滞らないように 揺れて流れて
  透き通っていく水のような心であれたら
  
  会いたくなった時の分まで
  寂しくなった時の分まで
  もう一回 もう一回 もう一回 もう一回
  君を強く焼き付けたい
  
  誰も皆 問題を抱えている
  だけど素敵な明日を願っている
  臆病風に吹かれて 波風が立った世界を
  どれだけ愛することができるだろう
  
  もう一回 もう一回
  もう一回 もう一回…

Unit Test Tips

Target Audience

This article is for those of you who are using Visual Studio built-in functionality of Unit Test project, and have some problem when it is necessary for you to access external resources as test data, e.g., files on the disk.

Background

You may be confused and ask why I need to attach an article here, just to explain how to access a file in Unit Test project. It seems trivial.

Of course, you can hardcode a full path to the location of a file, but it will introduce some problem. When this Unit Test is going to run on another machine, at that time of which this full path will be totally wrong. Thus, how about relative path?

As you know (if you have experience with Visual Studio’s built-in Unit Test project), Visual Studio will create a separate folder for each execution of Unit Test. This folder name is created randomly, .NET assemblies of the Unit Test project and its dependency projects will be put in it. Furthermore, Unit Test will be run with setting this folder as the current working space. The folder name constructed is as the following format:

<User Name>_<Machine Name>_<Timestamp>

So, as the folder is changed or dynamically created everytime the Unit Test runs, it’s hardly for us to use current directory and code something like this:

File.Open("test.txt", FileMode.Open);

Or, if in an instance of a Test class, where it sets the path of the file being accessed:

[TestMethod]
public void TestReadAndWrite()
{
    TextFileOp op = new TextFileOp();
    op.SourceFile = "source.txt";
    op.TargetFile = "target.txt";
    op.Handle();
}

where should source.txt and target.txt be put?

Solution

In this case, we can put all these external files in a foler under the solution of project. In Visual Studio IDE, doulbe click ".testrunconfig" file, then you will see a dialog as below prompt:

UnitTest01

In the left panel of dialog, navigate to Deployment, click "Add Directory…" button, select the folder that contains external files and add it. From then on, everytime the Unit Test runs, all the content in this specified folder will be copied to the test result folder (As we said, created dynamically, set as current directory of Unit Test), and then we can easily program the code as below:

[TestMethod]
public void TestReadAndWrite()
{
    string filePath = Directory.GetCurrentDirectory() + "\\";
    TextFileOp op = new TextFileOp();
    op.SourceFile = filePath + "source.txt";
    op.TargetFile = filePath + "target.txt";
    op.Handle();
}

Note: now we are able to access the files, since they are already in the currect directory.

More Information

please refer to http://www.cnblogs.com/wayfarer/archive/2007/03/07/666844.html