int CMiniDumpReader::StackWalk(DWORD dwThreadId)
{ 
    int nThreadIndex = GetThreadRowIdByThreadId(dwThreadId);
    if(m_DumpData.m_Threads[nThreadIndex].m_bStackWalk == TRUE)
        return 0; // Already done

    CONTEXT* pThreadContext = NULL;

    if(m_DumpData.m_Threads[nThreadIndex].m_dwThreadId==m_DumpData.m_uExceptionThreadId)
        pThreadContext = m_DumpData.m_pExceptionThreadContext;
    else
        pThreadContext = m_DumpData.m_Threads[nThreadIndex].m_pThreadContext;  

    if(pThreadContext==NULL)
        return 1;

    // Make modifiable context
    CONTEXT Context;
    memcpy(&Context, pThreadContext, sizeof(CONTEXT));

    g_pMiniDumpReader = this;

    // Init stack frame with correct initial values
    // See this:
    // http://www.codeproject.com/KB/threads/StackWalker.aspx
    //
    // Given a current dbghelp, your code should:
    //  1. Always use StackWalk64
    //  2. Always set AddrPC to the current instruction pointer (Eip on x86, Rip on x64 and StIIP on IA64)
    //  3. Always set AddrStack to the current stack pointer (Esp on x86, Rsp on x64 and IntSp on IA64)
    //  4. Set AddrFrame to the current frame pointer when meaningful. On x86 this is Ebp, on x64 you 
    //     can use Rbp (but is not used by VC2005B2; instead it uses Rdi!) and on IA64 you can use RsBSP. 
    //     StackWalk64 will ignore the value when it isn't needed for unwinding.
    //  5. Set AddrBStore to RsBSP for IA64. 

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

    sf.AddrPC.Mode = AddrModeFlat;  
    sf.AddrFrame.Mode = AddrModeFlat;  
    sf.AddrStack.Mode = AddrModeFlat;  
    sf.AddrBStore.Mode = AddrModeFlat;  

    DWORD dwMachineType = 0;
    switch(m_DumpData.m_uProcessorArchitecture)
    {
#ifdef _X86_
  case PROCESSOR_ARCHITECTURE_INTEL: 
      dwMachineType = IMAGE_FILE_MACHINE_I386;
      sf.AddrPC.Offset = pThreadContext->Eip;    
      sf.AddrStack.Offset = pThreadContext->Esp;
      sf.AddrFrame.Offset = pThreadContext->Ebp;
      break;
#endif
#ifdef _AMD64_
  case PROCESSOR_ARCHITECTURE_AMD64:
      dwMachineType = IMAGE_FILE_MACHINE_AMD64;
      sf.AddrPC.Offset = pThreadContext->Rip;    
      sf.AddrStack.Offset = pThreadContext->Rsp;
      sf.AddrFrame.Offset = pThreadContext->Rbp;
      break;
#endif
#ifdef _IA64_
  case PROCESSOR_ARCHITECTURE_AMD64:
      dwMachineType = IMAGE_FILE_MACHINE_IA64;
      sf.AddrPC.Offset = pThreadContext->StIIP;
      sf.AddrStack.Offset = pThreadContext->IntSp;
      sf.AddrFrame.Offset = pThreadContext->RsBSP;    
      sf.AddrBStore.Offset = pThreadContext->RsBSP;
      break;
#endif 
  default:
      {
          assert(0);
          return 1; // Unsupported architecture
      }
    }

    for(;;)
    {    
        BOOL bWalk = ::StackWalk64(
            dwMachineType,               // machine type
            m_DumpData.m_hProcess,       // our process handle
            (HANDLE)dwThreadId,          // thread ID
            &sf,                         // stack frame
            dwMachineType==IMAGE_FILE_MACHINE_I386?NULL:(&Context), // used for non-I386 machines 
            ReadProcessMemoryProc64,     // our routine
            FunctionTableAccessProc64,   // our routine
            GetModuleBaseProc64,         // our routine
            NULL                         // safe to be NULL
            );

        if(!bWalk)
            break;      

        MdmpStackFrame stack_frame;
        stack_frame.m_dwAddrPCOffset = sf.AddrPC.Offset;

        // Get module info
        IMAGEHLP_MODULE64 mi;
        memset(&mi, 0, sizeof(IMAGEHLP_MODULE64));
        mi.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
        BOOL bGetModuleInfo = SymGetModuleInfo64(m_DumpData.m_hProcess, sf.AddrPC.Offset, &mi);     
        if(bGetModuleInfo)
        {
            stack_frame.m_nModuleRowID = GetModuleRowIdByBaseAddr(mi.BaseOfImage);      
        }

        // Get symbol info
        DWORD64 dwDisp64;
        BYTE buffer[4096];
        SYMBOL_INFO* sym_info = (SYMBOL_INFO*)buffer;
        sym_info->SizeOfStruct = sizeof(SYMBOL_INFO);
        sym_info->MaxNameLen = 4096-sizeof(SYMBOL_INFO)-1;
        BOOL bGetSym = SymFromAddr(
            m_DumpData.m_hProcess, 
            sf.AddrPC.Offset, 
            &dwDisp64, 
            sym_info);

        if(bGetSym)
        {
            stack_frame.m_sSymbolName = CString(sym_info->Name, sym_info->NameLen);
            stack_frame.m_dw64OffsInSymbol = dwDisp64;
        }

        // Get source filename and line
        DWORD dwDisplacement;
        IMAGEHLP_LINE64 line;
        BOOL bGetLine = SymGetLineFromAddr64(
            m_DumpData.m_hProcess, 
            sf.AddrPC.Offset,
            &dwDisplacement,
            &line);

        if(bGetLine)
        {
            stack_frame.m_sSrcFileName = line.FileName;
            stack_frame.m_nSrcLineNumber = line.LineNumber;
        }

        m_DumpData.m_Threads[nThreadIndex].m_StackTrace.push_back(stack_frame);
    }


    CString sStackTrace;
    UINT i;
    for(i=0; i<m_DumpData.m_Threads[nThreadIndex].m_StackTrace.size(); i++)
    {
        MdmpStackFrame& frame = m_DumpData.m_Threads[nThreadIndex].m_StackTrace[i];

        if(frame.m_sSymbolName.IsEmpty())
            continue;

        CString sModuleName;
        CString sAddrPCOffset;
        CString sSymbolName;            
        CString sOffsInSymbol;
        CString sSourceFile;
        CString sSourceLine;

        if(frame.m_nModuleRowID>=0)
        {
            sModuleName = m_DumpData.m_Modules[frame.m_nModuleRowID].m_sModuleName;
        }           

        sSymbolName = frame.m_sSymbolName;
        sAddrPCOffset.Format(_T("0x%I64x"), frame.m_dwAddrPCOffset);
        sSourceFile = frame.m_sSrcFileName;
        sSourceLine.Format(_T("%d"), frame.m_nSrcLineNumber);
        sOffsInSymbol.Format(_T("0x%I64x"), frame.m_dw64OffsInSymbol);

        CString str;
        str = sModuleName;
        if(!str.IsEmpty())
            str += _T("!");

        if(sSymbolName.IsEmpty())
            str += sAddrPCOffset;  
        else
        {
            str += sSymbolName;
            str += _T("+");
            str += sOffsInSymbol;
        }

        if(!sSourceFile.IsEmpty())
        {
            int pos = sSourceFile.ReverseFind('\\');
            if(pos>=0)
                sSourceFile = sSourceFile.Mid(pos+1);
            str += _T(" [ ");
            str += sSourceFile;
            str += _T(": ");
            str += sSourceLine;
            str += _T(" ] ");
        } 

        sStackTrace += str; 
        sStackTrace += _T("\n");
    }

    if(!sStackTrace.IsEmpty())
    {
        strconv_t strconv;
        LPCSTR szStackTrace = strconv.t2utf8(sStackTrace);
        MD5 md5;
        MD5_CTX md5_ctx;
        unsigned char md5_hash[16];
        md5.MD5Init(&md5_ctx);  
        md5.MD5Update(&md5_ctx, (unsigned char*)szStackTrace, (unsigned int)strlen(szStackTrace));  
        md5.MD5Final(md5_hash, &md5_ctx);

        for(i=0; i<16; i++)
        {
            CString number;
            number.Format(_T("%02x"), md5_hash[i]);
            m_DumpData.m_Threads[nThreadIndex].m_sStackTraceMD5 += number;
        }
    }

    m_DumpData.m_Threads[nThreadIndex].m_bStackWalk = TRUE;


    return 0;
}
Exemple #2
0
/**
 * Logs the stack back trace leading up to this function call.
 * @param ex Pointer to stack context (PCONTEXT on Windows), NULL to use current context.
 */
void stackTrace(void *ctx)
{
#ifdef _WIN32
	const int MAX_SYMBOL_LENGTH = 1024;
	CONTEXT context;
	if (ctx != 0)
	{
		context = *((PCONTEXT)ctx);
	}
	else
	{
#ifdef _MSC_VER
		memset(&context, 0, sizeof(CONTEXT));
		context.ContextFlags = CONTEXT_FULL;
		RtlCaptureContext(&context);
#else
		// TODO: Doesn't work on MinGW
		return;
#endif
	}
	HANDLE thread = GetCurrentThread();
	HANDLE process = GetCurrentProcess();
	STACKFRAME64 frame;
	memset(&frame, 0, sizeof(STACKFRAME64));
	DWORD image;
#ifdef _M_IX86
	image = IMAGE_FILE_MACHINE_I386;
	frame.AddrPC.Offset = context.Eip;
	frame.AddrPC.Mode = AddrModeFlat;
	frame.AddrFrame.Offset = context.Ebp;
	frame.AddrFrame.Mode = AddrModeFlat;
	frame.AddrStack.Offset = context.Esp;
	frame.AddrStack.Mode = AddrModeFlat;
#elif _M_X64
	image = IMAGE_FILE_MACHINE_AMD64;
	frame.AddrPC.Offset = context.Rip;
	frame.AddrPC.Mode = AddrModeFlat;
	frame.AddrFrame.Offset = context.Rbp;
	frame.AddrFrame.Mode = AddrModeFlat;
	frame.AddrStack.Offset = context.Rsp;
	frame.AddrStack.Mode = AddrModeFlat;
#elif _M_IA64
	image = IMAGE_FILE_MACHINE_IA64;
	frame.AddrPC.Offset = context.StIIP;
	frame.AddrPC.Mode = AddrModeFlat;
	frame.AddrFrame.Offset = context.IntSp;
	frame.AddrFrame.Mode = AddrModeFlat;
	frame.AddrBStore.Offset = context.RsBSP;
	frame.AddrBStore.Mode = AddrModeFlat;
	frame.AddrStack.Offset = context.IntSp;
	frame.AddrStack.Mode = AddrModeFlat;
#else
	// TODO: Stack trace not supported on this architecture
	Log(LOG_FATAL) << "Unfortunately, no stack trace information is available";
	return;
#endif
	SYMBOL_INFO *symbol = (SYMBOL_INFO *)malloc(sizeof(SYMBOL_INFO) + (MAX_SYMBOL_LENGTH - 1) * sizeof(TCHAR));
	symbol->MaxNameLen = MAX_SYMBOL_LENGTH;
	symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
	IMAGEHLP_LINE64 *line = (IMAGEHLP_LINE64 *)malloc(sizeof(IMAGEHLP_LINE64));
	line->SizeOfStruct = sizeof(IMAGEHLP_LINE64);
	DWORD displacement;
	SymInitialize(process, NULL, TRUE);
	while (StackWalk64(image, process, thread, &frame, &context, NULL, NULL, NULL, NULL))
	{
		if (SymFromAddr(process, frame.AddrPC.Offset, NULL, symbol))
		{
			if (SymGetLineFromAddr64(process, frame.AddrPC.Offset, &displacement, line))
			{
				std::string filename = line->FileName;
				size_t n = filename.find_last_of(PATH_SEPARATOR);
				if (n != std::string::npos)
				{
					filename = filename.substr(n + 1);
				}
				Log(LOG_FATAL) << "0x" << std::hex << symbol->Address << std::dec << " " << symbol->Name << " (" << filename << ":" << line->LineNumber << ")";
			}
			else
			{
				Log(LOG_FATAL) << "0x" << std::hex << symbol->Address << std::dec << " " << symbol->Name << " (??: " << GetLastError() << ")";
			}
		}
		else
		{
			Log(LOG_FATAL) << "??: " << GetLastError();
		}
	}
	DWORD err = GetLastError();
	if (err)
	{
		Log(LOG_FATAL) << "No stack trace generated: " << err;
	}
	SymCleanup(process);
#else
	const int MAX_STACK_FRAMES = 16;
	void *array[MAX_STACK_FRAMES];
	size_t size = backtrace(array, MAX_STACK_FRAMES);
	char **strings = backtrace_symbols(array, size);

	for (size_t i = 0; i < size; ++i)
	{
		Log(LOG_FATAL) << strings[i];
	}

	free(strings);
#endif
}
Exemple #3
0
void printStackTrace(MemoryAllocationRecord* rec)
{
    const unsigned int bufferSize = 512;

    // Resolve the program counter to the corresponding function names.
    unsigned int pc;
    for (int i = 0; i < MAX_STACK_FRAMES; i++)
    {
        // Check to see if we are at the end of the stack trace.
        pc = rec->pc[i];
        if (pc == 0)
            break;

        // Get the function name.
        unsigned char buffer[sizeof(IMAGEHLP_SYMBOL64) + bufferSize];
        IMAGEHLP_SYMBOL64* symbol = (IMAGEHLP_SYMBOL64*)buffer;
        DWORD64 displacement;
        memset(symbol, 0, sizeof(IMAGEHLP_SYMBOL64) + bufferSize);
        symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
        symbol->MaxNameLength = bufferSize;
        if (!SymGetSymFromAddr64(GetCurrentProcess(), pc, &displacement, symbol))
        {
            gameplay::print("[memory] STACK TRACE: <unknown location>\n");
        }
        else
        {
            symbol->Name[bufferSize - 1] = '\0';

            // Check if we need to go further up the stack.
            if (strncmp(symbol->Name, "operator new", 12) == 0)
            {
                // In operator new or new[], keep going...
            }
            else
            {
                // Get the file and line number.
                if (pc != 0)
                {
                    IMAGEHLP_LINE64 line;
                    DWORD displacement;
                    memset(&line, 0, sizeof(line));
                    line.SizeOfStruct = sizeof(line);
                    if (!SymGetLineFromAddr64(GetCurrentProcess(), pc, &displacement, &line))
                    {
                        gameplay::print("[memory] STACK TRACE: %s - <unknown file>:<unknown line number>\n", symbol->Name);
                    }
                    else
                    {
                        const char* file = strrchr(line.FileName, '\\');
                        if(!file) 
                            file = line.FileName;
                        else
                            file++;
                        
                        gameplay::print("[memory] STACK TRACE: %s - %s:%d\n", symbol->Name, file, line.LineNumber);
                    }
                }
            }
        }
    }
}
Exemple #4
0
void PrintBacktrace(PCONTEXT context)
{
	HANDLE hProcess = GetCurrentProcess();
	HANDLE hThread = GetCurrentThread();

	char appDir[MAX_PATH + 1];
	GetModuleFileName(nullptr, appDir, sizeof(appDir));
	char* end = strrchr(appDir, PATH_SEPARATOR);
	if (end) *end = '\0';

	SymSetOptions(SymGetOptions() | SYMOPT_LOAD_LINES | SYMOPT_FAIL_CRITICAL_ERRORS);

	if (!SymInitialize(hProcess, appDir, TRUE))
	{
		warn("Could not obtain detailed exception information: SymInitialize failed");
		return;
	}

	const int MAX_NAMELEN = 1024;
	IMAGEHLP_SYMBOL64* sym = (IMAGEHLP_SYMBOL64 *) malloc(sizeof(IMAGEHLP_SYMBOL64) + MAX_NAMELEN);
	memset(sym, 0, sizeof(IMAGEHLP_SYMBOL64) + MAX_NAMELEN);
	sym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
	sym->MaxNameLength = MAX_NAMELEN;

	IMAGEHLP_LINE64 ilLine;
	memset(&ilLine, 0, sizeof(ilLine));
	ilLine.SizeOfStruct = sizeof(ilLine);

	STACKFRAME64 sfStackFrame;
	memset(&sfStackFrame, 0, sizeof(sfStackFrame));
	DWORD imageType;
#ifdef _M_IX86
	imageType = IMAGE_FILE_MACHINE_I386;
	sfStackFrame.AddrPC.Offset = context->Eip;
	sfStackFrame.AddrPC.Mode = AddrModeFlat;
	sfStackFrame.AddrFrame.Offset = context->Ebp;
	sfStackFrame.AddrFrame.Mode = AddrModeFlat;
	sfStackFrame.AddrStack.Offset = context->Esp;
	sfStackFrame.AddrStack.Mode = AddrModeFlat;
#elif _M_X64
	imageType = IMAGE_FILE_MACHINE_AMD64;
	sfStackFrame.AddrPC.Offset = context->Rip;
	sfStackFrame.AddrPC.Mode = AddrModeFlat;
	sfStackFrame.AddrFrame.Offset = context->Rsp;
	sfStackFrame.AddrFrame.Mode = AddrModeFlat;
	sfStackFrame.AddrStack.Offset = context->Rsp;
	sfStackFrame.AddrStack.Mode = AddrModeFlat;
#else
	warn("Could not obtain detailed exception information: platform not supported");
	return;
#endif

	for (int frameNum = 0; ; frameNum++)
	{
		if (frameNum > 1000)
		{
			warn("Endless stack, abort tracing");
			return;
		}

		if (!StackWalk64(imageType, hProcess, hThread, &sfStackFrame, context, nullptr, SymFunctionTableAccess64, SymGetModuleBase64, nullptr))
		{
			warn("Could not obtain detailed exception information: StackWalk64 failed");
			return;
		}

		DWORD64 dwAddr = sfStackFrame.AddrPC.Offset;
		BString<1024> symName;
		BString<1024> srcFileName;
		int lineNumber = 0;

		DWORD64 dwSymbolDisplacement;
		if (SymGetSymFromAddr64(hProcess, dwAddr, &dwSymbolDisplacement, sym))
		{
			UnDecorateSymbolName(sym->Name, symName, symName.Capacity(), UNDNAME_COMPLETE);
			symName[sizeof(symName) - 1] = '\0';
		}
		else
		{
			symName = "<symbol not available>";
		}

		DWORD dwLineDisplacement;
		if (SymGetLineFromAddr64(hProcess, dwAddr, &dwLineDisplacement, &ilLine))
		{
			lineNumber = ilLine.LineNumber;
			char* useFileName = ilLine.FileName;
			char* root = strstr(useFileName, "\\daemon\\");
			if (root)
			{
				useFileName = root;
			}
			srcFileName = useFileName;
		}
		else
		{
			srcFileName = "<filename not available>";
		}

		info("%s (%i) : %s", *srcFileName, lineNumber, *symName);

		if (sfStackFrame.AddrReturn.Offset == 0)
		{
			break;
		}
	}
}
Exemple #5
0
/***********************************************************************
 *           symbol_get_lvalue
 *
 * Get the address of a named symbol.
 * Return values:
 *      sglv_found:   if the symbol is found
 *      sglv_unknown: if the symbol isn't found
 *      sglv_aborted: some error occurred (likely, many symbols of same name exist,
 *          and user didn't pick one of them)
 */
enum sym_get_lval symbol_get_lvalue(const char* name, const int lineno,
                                    struct dbg_lvalue* rtn, BOOL bp_disp)
{
    struct sgv_data             sgv;
    int		                i;
    char                        buffer[512];
    DWORD                       opt;
    IMAGEHLP_STACK_FRAME        ihsf;

    if (strlen(name) + 4 > sizeof(buffer))
    {
        WINE_WARN("Too long symbol (%s)\n", name);
        return sglv_unknown;
    }

    sgv.num        = 0;
    sgv.num_thunks = 0;
    sgv.name       = &buffer[2];
    sgv.do_thunks  = DBG_IVAR(AlwaysShowThunks);

    if (strchr(name, '!'))
    {
        strcpy(buffer, name);
    }
    else
    {
        buffer[0] = '*';
        buffer[1] = '!';
        strcpy(&buffer[2], name);
    }

    /* this is a wine specific options to return also ELF modules in the
     * enumeration
     */
    SymSetOptions((opt = SymGetOptions()) | 0x40000000);
    SymEnumSymbols(dbg_curr_process->handle, 0, buffer, sgv_cb, (void*)&sgv);

    if (!sgv.num)
    {
        const char*   ptr = strchr(name, '!');
        if ((ptr && ptr[1] != '_') || (!ptr && *name != '_'))
        {
            if (ptr)
            {
                int offset = ptr - name;
                memcpy(buffer, name, offset + 1);
                buffer[offset + 1] = '_';
                strcpy(&buffer[offset + 2], ptr + 1);
            }
            else
            {
                buffer[0] = '*';
                buffer[1] = '!';
                buffer[2] = '_';
                strcpy(&buffer[3], name);
            }
            SymEnumSymbols(dbg_curr_process->handle, 0, buffer, sgv_cb, (void*)&sgv);
        }
    }
    SymSetOptions(opt);

    /* now grab local symbols */
    if (stack_get_current_frame(&ihsf) && sgv.num < NUMDBGV)
    {
        sgv.frame_offset = ihsf.FrameOffset;
        SymEnumSymbols(dbg_curr_process->handle, 0, name, sgv_cb, (void*)&sgv);
    }

    if (!sgv.num)
    {
        dbg_printf("No symbols found for %s\n", name);
        return sglv_unknown;
    }

    /* recompute potential offsets for functions (linenumber, skip prolog) */
    for (i = 0; i < sgv.num; i++)
    {
        if (sgv.syms[i].flags & (SYMFLAG_REGISTER|SYMFLAG_REGREL|SYMFLAG_LOCAL|SYMFLAG_THUNK))
            continue;

        if (lineno == -1)
        {
            struct dbg_type     type;
            ULONG64             addr;

            type.module = sgv.syms[i].lvalue.type.module;
            type.id     = sgv.syms[i].sym_info;
            if (bp_disp && symbol_get_debug_start(&type, &addr))
                sgv.syms[i].lvalue.addr.Offset = addr;
        }
        else
        {
            DWORD               disp;
            IMAGEHLP_LINE64     il;
            BOOL                found = FALSE;

            il.SizeOfStruct = sizeof(il);
            SymGetLineFromAddr64(dbg_curr_process->handle,
                                 (DWORD_PTR)memory_to_linear_addr(&sgv.syms[i].lvalue.addr),
				 &disp, &il);
            do
            {
                if (lineno == il.LineNumber)
                {
                    sgv.syms[i].lvalue.addr.Offset = il.Address;
                    found = TRUE;
                    break;
                }
            } while (SymGetLineNext64(dbg_curr_process->handle, &il));
            if (!found)
                WINE_FIXME("No line (%d) found for %s (setting to symbol start)\n",
                           lineno, name);
        }
    }

    if (sgv.num - sgv.num_thunks > 1 || /* many symbols non thunks (and showing only non thunks) */
        (sgv.num > 1 && DBG_IVAR(AlwaysShowThunks)) || /* many symbols (showing symbols & thunks) */
        (sgv.num == sgv.num_thunks && sgv.num_thunks > 1))
    {
        return symbol_current_picker(name, &sgv, rtn);
    }
    /* first symbol is the one we want:
     * - only one symbol found,
     * - or many symbols but only one non thunk when AlwaysShowThunks is FALSE
     */
    *rtn = sgv.syms[0].lvalue;
    return sglv_found;
}
Exemple #6
0
/***********************************************************************
 *           symbol_get_line
 *
 * Find the symbol nearest to a given address.
 * Returns sourcefile name and line number in a format that the listing
 * handler can deal with.
 */
BOOL symbol_get_line(const char* filename, const char* name,
		     IMAGEHLP_LINE64* line)
{
    struct sgv_data     sgv;
    char                buffer[512];
    DWORD               opt, disp;
    unsigned            i, found = FALSE;
    IMAGEHLP_LINE64     il;

    sgv.num        = 0;
    sgv.num_thunks = 0;
    sgv.name       = &buffer[2];
    sgv.do_thunks  = FALSE;

    buffer[0] = '*';
    buffer[1] = '!';
    strcpy(&buffer[2], name);

    /* this is a wine specific options to return also ELF modules in the
     * enumeration
     */
    SymSetOptions((opt = SymGetOptions()) | 0x40000000);
    if (!SymEnumSymbols(dbg_curr_process->handle, 0, buffer, sgv_cb, (void*)&sgv))
    {
        SymSetOptions(opt);
        return FALSE;
    }

    if (!sgv.num && (name[0] != '_'))
    {
        buffer[2] = '_';
        strcpy(&buffer[3], name);
        if (!SymEnumSymbols(dbg_curr_process->handle, 0, buffer, sgv_cb, (void*)&sgv))
        {
            SymSetOptions(opt);
            return FALSE;
        }
    }
    SymSetOptions(opt);

    for (i = 0; i < sgv.num; i++)
    {
        DWORD_PTR linear = (DWORD_PTR)memory_to_linear_addr(&sgv.syms[i].lvalue.addr);

        il.SizeOfStruct = sizeof(il);
        if (!SymGetLineFromAddr64(dbg_curr_process->handle, linear, &disp, &il))
            continue;
        if (filename && strcmp(il.FileName, filename)) continue;
        if (found)
        {
            WINE_FIXME("Several found, returning first (may not be what you want)...\n");
            break;
        }
        found = TRUE;
        *line = il;
    }
    if (!found)
    {
        if (filename)   dbg_printf("No such function %s in %s\n", name, filename);
	else            dbg_printf("No such function %s\n", name);
        return FALSE;
    }
    return TRUE;
}
bool CATDbgHelper::AddressToLine( CATMemoryAddress* result )
{
	LOG_FUNC_ENTRY("CATDbgHelper::AddressToLine");
	
	// Set state out of range
	result->SetAddressToLineState( CATMemoryAddress::OUT_OF_RANGE );

	// check that dbghelper has been initialized successfully.
	if ( ! CDBGHELPER_OPEN )
		return false;

	// Check has binary been moved, if so unload and load to new base address.
	if ( result->GetModuleStartAddress() + AT_VIRTUAL_OFFSET_DBGHELPER != m_BaseAddress )
	{
		// Unload.
		if ( SymUnloadModule64( GetCurrentProcess(), m_BaseAddress ) )
		{
			// Set new base address.
			m_BaseAddress = result->GetModuleStartAddress() + AT_VIRTUAL_OFFSET_DBGHELPER;
			// (Re)load.
			DWORD64 loading = SymLoadModule64( GetCurrentProcess(), NULL, m_pBinaryFile, NULL, m_BaseAddress, NULL );
			if ( loading != m_BaseAddress  && loading != 0)	
			{
				LOG_STRING("Dbghelp:Module load failed " << (int) GetLastError());
				return false;
			}
		}
		else
			LOG_STRING("Dbghelp:Module unload failed " << (int) GetLastError() );
	}
	// Address to find (offset+given address).
	unsigned long iAddressToFind = result->GetAddress() + AT_VIRTUAL_OFFSET_DBGHELPER;
	// Displacements of line/symbol information.
	DWORD64 displacementSymbol;
	DWORD displacementLine;
	// Structure to get symbol information.
	CSymbolInfo symbol;
	// Structure to get line information.
	CLineInfo line;
	// Find Symbol for given address 
	if( ! SymFromAddr( GetCurrentProcess(), iAddressToFind , &displacementSymbol, &symbol.si ) )
	{
		LOG_STRING("Failed to find symbol information for given line.");
		return AddressToFunction( result );
	}
	// Find line information
	if( ! SymGetLineFromAddr64( GetCurrentProcess(), iAddressToFind, &displacementLine, &line ) )
	{
		// If it fails get symbol line information
		LOG_STRING("Dbghelp:Failed to find line information for address, trying for symbol of address.");
		if( ! SymGetLineFromAddr64( GetCurrentProcess(), symbol.si.Address, &displacementLine, &line ) )
		{
			LOG_STRING("Dbghelp:Failed to find line information for symbol address.");
			return AddressToFunction( result );
		}
	}
	// Set the results.
	result->SetFileName( string( line.FileName ) );
	result->SetFunctionName( string( symbol.si.Name ) );
	result->SetExactLineNumber( (int) line.LineNumber );
	result->SetAddressToLineState( CATMemoryAddress::EXACT );
	// Return.
	return true;
}
static void dlgPrint(
    uint64_t addr,const char *filename,int lineno,const char *funcname,
    void *context,int columnno )
{
  struct dialog_info *di = context;
#ifndef NO_DBGHELP
  char buffer[sizeof(SYMBOL_INFO)+MAX_SYM_NAME];
  SYMBOL_INFO *si = (SYMBOL_INFO*)&buffer;
  if( lineno==DWST_NO_DBG_SYM )
  {
    IMAGEHLP_LINE64 ihl;
    memset( &ihl,0,sizeof(IMAGEHLP_LINE64) );
    ihl.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
    DWORD displ;
    if( SymGetLineFromAddr64(GetCurrentProcess(),addr,&displ,&ihl) )
    {
      filename = ihl.FileName;
      lineno = ihl.LineNumber;
    }

    DWORD64 displ2;
    si->SizeOfStruct = sizeof(SYMBOL_INFO);
    si->MaxNameLen = MAX_SYM_NAME;
    if( SymFromAddr(GetCurrentProcess(),addr,&displ2,si) )
    {
      char *fn = si->Name;
      fn[MAX_SYM_NAME] = 0;
      funcname = fn;
    }
  }
#endif

  const char *delim = strrchr( filename,'/' );
  if( delim ) filename = delim + 1;
  delim = strrchr( filename,'\\' );
  if( delim ) filename = delim + 1;

  void *ptr = (void*)(uintptr_t)addr;
  switch( lineno )
  {
    case DWST_BASE_ADDR:
      if( ptr==di->lastBase ) break;
      di->lastBase = ptr;

      printAddr( di->hwnd,TEXT("base address"),-1,
          ptr,filename,0,NULL,0 );
      break;

    case DWST_NOT_FOUND:
    case DWST_NO_DBG_SYM:
    case DWST_NO_SRC_FILE:
      printAddr( di->hwnd,TEXT("    stack "),di->count++,
          ptr,NULL,0,funcname,0 );
      break;

    default:
      printAddr( di->hwnd,TEXT("    stack "),di->count,
          ptr,filename,lineno,funcname,columnno );
      if( ptr ) di->count++;
      break;
  }
}
void printBacktrace(std::ostream * os) {
  if(os == 0)
    os = &std::cout;

  const int SIZE = 100;
  const int NAME_SIZE = 256;
#if defined(_WIN32)
  HANDLE process = GetCurrentProcess();
  SymSetOptions(SYMOPT_LOAD_LINES);
  SymInitialize(process, NULL, TRUE);

  void * stack[SIZE];
  unsigned short frames = CaptureStackBackTrace(0, SIZE, stack, NULL);
  SYMBOL_INFO * symbol = (SYMBOL_INFO * )calloc(sizeof(SYMBOL_INFO) + NAME_SIZE * sizeof(char), 1);
  symbol->MaxNameLen = NAME_SIZE;
  symbol->SizeOfStruct = sizeof(SYMBOL_INFO);

  for(unsigned short i = 0; i < frames; i++ ) {
    SymFromAddr(process, (DWORD64)(stack[i]), 0, symbol);
    IMAGEHLP_LINE64 line;
    line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
    DWORD  dwDisplacement;
    if(!strstr(symbol->Name, __FUNCTION__) && !strstr(symbol->Name,"pgr::debugCallback") && SymGetLineFromAddr64(process, (DWORD64)(stack[i]), &dwDisplacement, &line)) {
      *os << symbol->Name << "():" << line.LineNumber << std::endl;
    }
    if(strcmp(symbol->Name, "main") == 0)
      break;
  }

  free(symbol);
#elif defined(__linux__)
  int j;
  void *buffer[SIZE];
  char **strings;

  int nptrs = backtrace(buffer, SIZE);
  strings = backtrace_symbols(buffer, nptrs);
  if(strings == NULL) {
    *os << "error in backtrace_symbols" << std::endl;
    return;
  }
  for (j = 0; j < nptrs; j++)
    *os << strings[j] << std::endl;
  free(strings);
#else
  *os << "backtrace not supported on this platform" << std::endl;
#endif
}
Exemple #10
0
std::vector<std::string> backtrace_get(int skip) {
     unsigned int   i;
     void         * stack[ 100 ];
     unsigned short frames;
     SYMBOL_INFO  * symbol;
     HANDLE         process;
	 IMAGEHLP_LINE *line = (IMAGEHLP_LINE *)malloc(sizeof(IMAGEHLP_LINE));
	 line->SizeOfStruct = sizeof(IMAGEHLP_LINE);
	 IMAGEHLP_LINE64 *line64 = (IMAGEHLP_LINE64 *)malloc(sizeof(IMAGEHLP_LINE64));
	 line64->SizeOfStruct = sizeof(IMAGEHLP_LINE64);

	 IMAGEHLP_MODULE *mod = (IMAGEHLP_MODULE *)malloc(sizeof(IMAGEHLP_MODULE));
	 mod->SizeOfStruct = sizeof(IMAGEHLP_MODULE);
	 IMAGEHLP_MODULE64 *mod64 = (IMAGEHLP_MODULE64 *)malloc(sizeof(IMAGEHLP_MODULE64));
	 mod->SizeOfStruct = sizeof(IMAGEHLP_MODULE64);

     process = GetCurrentProcess();

     SymSetOptions(SYMOPT_LOAD_LINES);
     SymInitialize( process, NULL, TRUE );

     frames               = CaptureStackBackTrace( 0, 100, stack, NULL );
     symbol               = ( SYMBOL_INFO * )calloc( sizeof( SYMBOL_INFO ) + 256 * sizeof( char ), 1 );
     symbol->MaxNameLen   = 255;
     symbol->SizeOfStruct = sizeof( SYMBOL_INFO );

     char *buf = (char *)malloc(1024);
     std::vector<std::string> vs;

     for( i = skip; i < frames; i++ ){
         SymFromAddr( process, ( DWORD64 )( stack[ i ] ), 0, symbol );

		 bool m64 = false;
		 BOOL mod_status = SymGetModuleInfo(process, symbol->Address, mod);
		 if (!mod_status) {
			 mod_status = SymGetModuleInfo64(process, symbol->Address, mod64);
			 m64 = true;
		 }

		 DWORD dwDisplacement;
		 bool l64 = false;

		 BOOL line_status = SymGetLineFromAddr(process, (ULONG64)stack[i], &dwDisplacement, line);
		 if (!line_status) {
			 line_status = SymGetLineFromAddr64(process, (ULONG64)stack[i], &dwDisplacement, line64);
			 l64 = true;
		 }

		 sprintf(buf, "%-3d %*p %s(%s +  0x%I64x)",
			 frames - i - 1, 
			 int(2 + sizeof(void*) * 2), stack[i],
			 mod_status ? (m64 ? mod64->ModuleName : mod->ModuleName) : "<unknown dll>",
			 symbol->Name,
			 symbol->Address);

		 vs.push_back(std::string(buf));

		 if (line_status) {
			 sprintf(buf, "\t\t%s:%d", l64 ? line64->FileName : line->FileName, l64 ? line64->LineNumber : line->LineNumber);
			 vs.push_back(std::string(buf));
		 }

     }

     free(buf);
     free(symbol);
	 SymCleanup(process);
     return vs;
}
Exemple #11
0
PXR_NAMESPACE_OPEN_SCOPE

bool
ArchGetAddressInfo(
    void* address,
    std::string* objectPath, void** baseAddress,
    std::string* symbolName, void** symbolAddress)
{
#if defined(_GNU_SOURCE) || defined(ARCH_OS_DARWIN)

    Dl_info info;
    if (dladdr(address, &info)) {
        if (objectPath) {
            // The object filename may be a relative path if, for instance,
            // the given address comes from an executable that was invoked
            // with a relative path, or from a shared library that was 
            // dlopen'd with a relative path. We want to always return 
            // absolute paths, so do the resolution here.
            //
            // This may be incorrect if the current working directory was 
            // changed after the source object was loaded.
            *objectPath = ArchAbsPath(info.dli_fname);
        }
        if (baseAddress) {
            *baseAddress = info.dli_fbase;
        }
        if (symbolName) {
            *symbolName = info.dli_sname ? info.dli_sname : "";
        }
        if (symbolAddress) {
            *symbolAddress = info.dli_saddr;
        }
        return true;
    }
    return false;

#elif defined(ARCH_OS_WINDOWS)

    if (!address) {
        return false;
    }

    HMODULE module = nullptr;
    if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
                             GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
                             reinterpret_cast<LPCSTR>(address),
                             &module)) {
        return false;
    }

    if (objectPath) {
        char modName[MAX_PATH] = {0};
        if (GetModuleFileName(module, modName, MAX_PATH)) {
            objectPath->assign(modName);
        }
    }

    if (baseAddress || symbolName || symbolAddress) {
        DWORD displacement;
        HANDLE process = GetCurrentProcess();
        SymInitialize(process, NULL, TRUE);

        // Symbol
        ULONG64 symBuffer[(sizeof(SYMBOL_INFO) +
                          MAX_SYM_NAME * sizeof(TCHAR) +
                          sizeof(ULONG64) - 1) / sizeof(ULONG64)];
        SYMBOL_INFO *symbol = (SYMBOL_INFO*)symBuffer;
        symbol->MaxNameLen = MAX_SYM_NAME;
        symbol->SizeOfStruct = sizeof(SYMBOL_INFO);

        // Line
        IMAGEHLP_LINE64 line = {0};
        line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);

        DWORD64 dwAddress = (DWORD64)address;
        SymFromAddr(process, dwAddress, NULL, symbol);
        if (!SymGetLineFromAddr64(process, dwAddress,
                                  &displacement, &line)) {
            return false;
        }

        if (baseAddress) {
            MODULEINFO moduleInfo = {0};
            if (!GetModuleInformation(process, module,
                                      &moduleInfo, sizeof(moduleInfo))) {
                return false;
            }
            *baseAddress = moduleInfo.lpBaseOfDll;
        }

        if (symbolName) {
            *symbolName = symbol->Name ? symbol->Name : "";
        }

        if (symbolAddress) {
            *symbolAddress = (void*)symbol->Address;
        }
    }
    return true;

#else

    return false;

#endif
}
const char* MemoryManager::GetCallerForAllocation(AllocHeader* pAllocation)
{
#ifdef USE_STACKTRACE
	const size_t cnBufferSize=512;
	char szFile[cnBufferSize];
	char szFunc[cnBufferSize];
	unsigned int nLine;
	static char szBuff[cnBufferSize*3];

	strcpy(szFile,"??");
	nLine=0;

	DWORD64 nPC;
	for(int i=0;i<AllocHeader::cnMaxStackFrames;++i) {
		nPC=pAllocation->nPC[i];
		if(nPC==0)
			break;

		unsigned char byBuffer[sizeof(IMAGEHLP_SYMBOL64)+cnBufferSize];
		IMAGEHLP_SYMBOL64* pSymbol=(IMAGEHLP_SYMBOL64*)byBuffer;
		DWORD64 dwDisplacement;
		memset(pSymbol,0,sizeof(IMAGEHLP_SYMBOL64)+cnBufferSize);
		pSymbol->SizeOfStruct=sizeof(IMAGEHLP_SYMBOL64);
		pSymbol->MaxNameLength=cnBufferSize;
		if(!SymGetSymFromAddr64(GetCurrentProcess(),nPC,&dwDisplacement,pSymbol))
			strcpy(szFunc,"??");
		else {
			pSymbol->Name[cnBufferSize-1]='\0';
			if(strncmp(pSymbol->Name,"MemMgr::",8)==0) {
				// In MemMgr,keep going...
			} else if(strncmp(pSymbol->Name,"operator new",12)==0) {
				// In operator new or new[],keep going...
			} else if(strncmp(pSymbol->Name,"std::",5)==0) {
				// In STL code,keep going...
			} else {
				// Found the allocator (Or near to it)
				strcpy(szFunc,pSymbol->Name);
				break;
			}
		}
	}

	if(nPC!=0) {
		IMAGEHLP_LINE64 theLine;
		DWORD dwDisplacement;
		memset(&theLine,0,sizeof(theLine));
		theLine.SizeOfStruct=sizeof(theLine);
		if(!SymGetLineFromAddr64(GetCurrentProcess(),nPC,&dwDisplacement,&theLine)) {
			strcpy(szFile,"??");
			nLine=0;
		} else {
			const char* pszFile=strrchr(theLine.FileName,'\\');
			if(!pszFile) pszFile=theLine.FileName;
			else ++pszFile;
			strncpy(szFile,pszFile,cnBufferSize);
			nLine=theLine.LineNumber;
		}
	}

	sprintf(szBuff,"%s:%d (%s)",szFile,nLine,szFunc);
	return szBuff;
#else
	UNREFERENCED_PARAMETER(pAllocation);
	return "Stack trace unavailable";
#endif
}
Exemple #13
0
int main(int argc, char *argv[]) {
  DWORD  error;
  HANDLE process;
  ULONG64 module_base;
  int i;
  char* search;
  char buf[256];   /* Enough to hold one hex address, I trust! */
  int rv = 0;
  /* We may add SYMOPT_UNDNAME if --demangle is specified: */
  DWORD symopts = SYMOPT_DEFERRED_LOADS | SYMOPT_DEBUG | SYMOPT_LOAD_LINES;
  char* filename = "a.out";         /* The default if -e isn't specified */
  int print_function_name = 0;      /* Set to 1 if -f is specified */

  for (i = 1; i < argc; i++) {
    if (strcmp(argv[i], "--functions") == 0 || strcmp(argv[i], "-f") == 0) {
      print_function_name = 1;
    } else if (strcmp(argv[i], "--demangle") == 0 ||
               strcmp(argv[i], "-C") == 0) {
      symopts |= SYMOPT_UNDNAME;
    } else if (strcmp(argv[i], "--exe") == 0 ||
               strcmp(argv[i], "-e") == 0) {
      if (i + 1 >= argc) {
        fprintf(stderr, "FATAL ERROR: -e must be followed by a filename\n");
        return 1;
      }
      filename = argv[i+1];
      i++;     /* to skip over filename too */
    } else if (strcmp(argv[i], "--help") == 0) {
      usage();
      exit(0);
    } else {
      usage();
      exit(1);
    }
  }

  process = GetCurrentProcess();

  if (!SymInitialize(process, NULL, FALSE)) {
    error = GetLastError();
    fprintf(stderr, "SymInitialize returned error : %lu\n", error);
    return 1;
  }

  search = malloc(SEARCH_CAP);
  if (SymGetSearchPath(process, search, SEARCH_CAP)) {
    if (strlen(search) + sizeof(";" WEBSYM) > SEARCH_CAP) {
      fprintf(stderr, "Search path too long\n");
      SymCleanup(process);
      return 1;
    }
    strcat(search, ";" WEBSYM);
  } else {
    error = GetLastError();
    fprintf(stderr, "SymGetSearchPath returned error : %lu\n", error);
    rv = 1;                   /* An error, but not a fatal one */
    strcpy(search, WEBSYM);   /* Use a default value */
  }
  if (!SymSetSearchPath(process, search)) {
    error = GetLastError();
    fprintf(stderr, "SymSetSearchPath returned error : %lu\n", error);
    rv = 1;                   /* An error, but not a fatal one */
  }

  SymSetOptions(symopts);
  module_base = SymLoadModuleEx(process, NULL, filename, NULL, 0, 0, NULL, 0);
  if (!module_base) {
    /* SymLoadModuleEx failed */
    error = GetLastError();
    fprintf(stderr, "SymLoadModuleEx returned error : %lu for %s\n",
            error, filename);
    SymCleanup(process);
    return 1;
  }

  buf[sizeof(buf)-1] = '\0';  /* Just to be safe */
  while (fgets(buf, sizeof(buf)-1, stdin)) {
    /* GNU addr2line seems to just do a strtol and ignore any
     * weird characters it gets, so we will too.
     */
    unsigned __int64 reladdr = _strtoui64(buf, NULL, 16);
    ULONG64 buffer[(sizeof(SYMBOL_INFO) +
                    MAX_SYM_NAME*sizeof(TCHAR) +
                    sizeof(ULONG64) - 1)
                   / sizeof(ULONG64)];
    memset(buffer, 0, sizeof(buffer));
    PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
    IMAGEHLP_LINE64 line;
    DWORD dummy;

    // Just ignore overflow. In an overflow scenario, the resulting address
    // will be lower than module_base which hasn't been mapped by any prior
    // SymLoadModuleEx() command. This will cause SymFromAddr() and
    // SymGetLineFromAddr64() both to return failures and print the correct
    // ?? and ??:0 message variant.
    ULONG64 absaddr = reladdr + module_base;

    pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
    // The length of the name is not including the null-terminating character.
    pSymbol->MaxNameLen = MAX_SYM_NAME - 1;
    if (print_function_name) {
      if (SymFromAddr(process, (DWORD64)absaddr, NULL, pSymbol)) {
        printf("%s\n", pSymbol->Name);
      } else {
        printf("??\n");
      }
    }
    line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
    if (SymGetLineFromAddr64(process, (DWORD64)absaddr, &dummy, &line)) {
      printf("%s:%d\n", line.FileName, (int)line.LineNumber);
    } else {
      printf("??:0\n");
    }
  }
  SymUnloadModule64(process, module_base);
  SymCleanup(process);
  return rv;
}