Logging function name, line, file...

Robert Fraser fraserofthenight at gmail.com
Mon Mar 17 17:31:03 PDT 2008


Jaro wrote:
> Is it possible to log file name, line, and function name in D like it was in C++ when we could hide __FILE__, __LINE__, __FUNCTION__ in a new logging macro? That way this information was printed in log file, and was extremely useful.

If you have debug symbols on, you could get it at runtime:

* Get the return address of the logging function - this is the address 
it was called from.

* Load up an image of the current process and enumerate debug symbols, 
including line information (just do this once, either in the module 
static constructor or on the first call to the logging function).

* Get the file/line from the address of the function that called the 
logging function at runtime. In Windows, this would be done by calling 
SymGetLineFromAddr in imagehlp.dll .

* Sip peppermint tea with scotch in it and feel very cultured.

Here's a copy of the Windows-specific line-getting code from Flute, 
you'll probably need to adjust this to your needs:

version(Windows)
{
   /// Can we lookup debug info?
   private bool debugInfo = false;

   import std.c.windows.windows;

   private enum
   {
     MAX_MODULE_NAME32 = 255,
     TH32CS_SNAPMODULE = 0x00000008,
     SYMOPT_LOAD_LINES = 0x10,
   }

   private extern(Windows) struct MODULEENTRY32
   {
     DWORD  dwSize;
     DWORD  th32ModuleID;
     DWORD  th32ProcessID;
     DWORD  GlblcntUsage;
     DWORD  ProccntUsage;
     BYTE  *modBaseAddr;
     DWORD  modBaseSize;
     HMODULE hModule;
     char   szModule[MAX_MODULE_NAME32 + 1];
     char   szExePath[MAX_PATH];
   }

   private extern(Windows) struct IMAGEHLP_LINE
   {
     DWORD SizeOfStruct;
       PVOID Key;
       DWORD LineNumber;
       PTSTR FileName;
       DWORD Address;
   }
   alias IMAGEHLP_LINE* PIMAGEHLP_LINE;

   private extern(Windows) BOOL Module32First(HANDLE, MODULEENTRY32*);
   private extern(Windows) BOOL Module32Next(HANDLE, MODULEENTRY32*);
   private extern(Windows) HANDLE CreateToolhelp32Snapshot(DWORD,DWORD);

   private HMODULE imagehlp;
   private HANDLE proc;
   private extern(Windows) DWORD function(DWORD) SymSetOptions;
   private extern(Windows) BOOL function(HANDLE, PCSTR, BOOL) SymInitialize;
   private extern(Windows) BOOL function(HANDLE) SymCleanup;
   private extern(Windows) DWORD function(HANDLE, HANDLE, PCSTR, PCSTR, 
DWORD, DWORD) SymLoadModule;
   private extern(Windows) BOOL function(HANDLE, DWORD, PDWORD, 
PIMAGEHLP_LINE) SymGetLineFromAddr;

   private void initDebugInfo()
   {
     MODULEENTRY32 moduleEntry;
     moduleEntry.dwSize = moduleEntry.sizeof;
     char buffer[4096];

     try
     {
       scope(failure)
       {
         if(imagehlp)
           FreeLibrary(imagehlp);

         SymSetOptions = null;
         SymInitialize = null;
         SymCleanup = null;
         SymLoadModule = null;
         SymGetLineFromAddr = null;
       }

       proc = GetCurrentProcess();
       if(!proc)
         throw new Exception("GetCurrentProcess() returned null");

       HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0);
       if(!snapshot)
         throw new Exception("CreateToolHelp32Snapshot failed");

       imagehlp = LoadLibraryA("imagehlp.dll");
       if(!imagehlp)
         throw new Exception("Failed to load imagehlp.dll");

       SymSetOptions = cast(typeof(SymSetOptions)) 
GetProcAddress(imagehlp, "SymSetOptions");
       if(!SymSetOptions)
         throw new Exception("Failed to load SymSetOptions");

       SymInitialize = cast(typeof(SymInitialize)) 
GetProcAddress(imagehlp, "SymInitialize");
       if(!SymInitialize)
         throw new Exception("Failed to load SymInitialize");

       SymCleanup = cast(typeof(SymCleanup)) GetProcAddress(imagehlp, 
"SymCleanup");
       if(!SymCleanup)
         throw new Exception("Failed to load SymCleanup");

       SymLoadModule = cast(typeof(SymLoadModule)) 
GetProcAddress(imagehlp, "SymLoadModule");
       if(!SymLoadModule)
         throw new Exception("Failed to load SymLoadModule");

       SymGetLineFromAddr = cast(typeof(SymGetLineFromAddr)) 
GetProcAddress(imagehlp, "SymGetLineFromAddr");
       if(!SymGetLineFromAddr)
         throw new Exception("Failed to load SymGetLineFromAddr");

       if(!SymCleanup(proc))
         throw new Exception("SymCleanup failed");
       SymSetOptions(SYMOPT_LOAD_LINES);
       if(!SymInitialize(proc, null, FALSE))
         throw new Exception("SymInitialize failed");

       // We have to enumerate through the modules individually so that each
       // module finds its search path
       if(!Module32First(snapshot, &moduleEntry))
         throw new Exception("Module32First Failed");
       do
       {
         if(GetModuleFileNameA(moduleEntry.hModule, buffer.ptr, 
buffer.length))
           SymLoadModule(proc, HANDLE.init, buffer.ptr, null, 0, 0);
       }
       while(Module32Next(snapshot, &moduleEntry));

       debugInfo = true;
     }
     catch(Exception e)
     {
       //write(e.toString() ~ "\n");
     }
   }

   private void closeDebugInfo()
   {
     if(debugInfo)
     {
       SymCleanup(proc);
       FreeLibrary(imagehlp);

       SymSetOptions = null;
       SymInitialize = null;
       SymCleanup = null;
       SymLoadModule = null;
       SymGetLineFromAddr = null;
     }
   }

   private bool getDebugInfo(void* addr, out int line, out char[] file)
   {
     if(!debugInfo || !addr)
       goto Lunknown;

     IMAGEHLP_LINE lineInfo;
     DWORD displacement;
     lineInfo.SizeOfStruct = lineInfo.sizeof;

     if(!SymGetLineFromAddr(proc, cast(DWORD) addr, &displacement, 
&lineInfo))
       goto Lunknown;

     line = lineInfo.LineNumber;
     file = lineInfo.FileName[0 .. strlen(lineInfo.FileName)];
     return true;

     Lunknown:
       return false;
   }
}



More information about the Digitalmars-d mailing list