dmd0xf - Tango dmd package from team0xf

Robert Fraser fraserofthenight at gmail.com
Sun Jan 20 15:54:40 PST 2008


I was working on this for Flute last night and it might be sort of 
relevant. Basically, it uses the Windows debug info to look up the file 
and line information of the actual line that was being executed from the 
execution address. For long functions, this is often more valuable than 
just the name of the function. It'll take a little coercing to compile 
since it's been taken out of context, but may prove useful. Only for 
D1/Phobos/Windows, though porting to D2 or Tango will take very little 
effort.

version(Windows)
{
	/// Can we lookup debug info?
	private bool debugInfo = false;
	
	version(inPhobos)
	{
	    import std.c.windows.windows;
	    import std.c.string : strlen;
	}
	else
	    { } //TANGO
	
	private enum
	{
		MAX_MODULE_NAME32 = 255,
		TH32CS_SNAPMODULE = 0x08,
		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;
	
	
	/**
      * Initalize libraries needed to lookup file/line information in 
exception stack
      * traces.
      */
	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");
			
			// Since Flectioned doesn't load the line inforamtion when loading
			// symbols, we have little choice but to load all the symbols again, this
			// time with SYMOPT_LOAD_LINES on.
			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");
		}
	}
	
	
     /**
      * Close librries needed to lookup file/line information in 
exception stack traces.
      */
	private void closeDebugInfo()
	{
		if(debugInfo)
		{
			SymCleanup(proc);
			FreeLibrary(imagehlp);
			
			SymSetOptions = null;
			SymInitialize = null;
			SymCleanup = null;
			SymLoadModule = null;
			SymGetLineFromAddr = null;
		}
	}
	
	/**
      * Attempts to look up the file/line in the debug info given an 
execution
      * address.
      *
      * Params:
      *     addr = the execution address to look up
      * Returns: If the lookup is succesful, returns "[file]:[line]", 
where [file]
      *     is the filename where the code is located and [line] is th 
line of code
      *     the address refers to. On failure returns "0x[address]", 
where [address]
      *     is the hexadecimal representation of addr.
      */
	private char[] getDebugInfo(void* addr)
	{
		char[] toHex(size_t val)
		{
			const int percision = (void*).sizeof * 2;
			
			version(inPhobos)
				return format("%#0.*x", percision, val);
			else
				{ } // TANGO
		}
		
		if(!debugInfo || !addr)
			goto Lunknown;
		
		IMAGEHLP_LINE lineInfo;
		DWORD displacement;
		lineInfo.SizeOfStruct = lineInfo.sizeof;
		
		if(!SymGetLineFromAddr(proc, cast(DWORD) addr, &displacement, &lineInfo))
			goto Lunknown;
		
		return lineInfo.FileName[0 .. strlen(lineInfo.FileName)] ~ ":" ~
		        itoa(lineInfo.LineNumber);
		
		Lunknown:
			return toHex(cast(size_t) addr);
	}
}


More information about the Digitalmars-d-announce mailing list