接手一个软件,前辈们把一些核心功能封装进了几个DLL,所以没有源代码,你懂的现在软件在运行时会不定时(注意是不定时)产生异常,异常信息为:"0x004c5032"指令引用的"0x00000000"内存,该内存不能为"Read"。参考了网上一些方法,如《仅通过崩溃地址找出源代码的出错行》等但都没能找到问题点,后来偶然发现这个0x004c5032地址可能是在某一个DLL中,问题是DLL没有源代码,有没有办法像计算主程序代码行一样,计算出DLL中的异常代码行??急求各位大哥及高人的指点,不胜感激!异常DLL定位

解决方案 »

  1.   


    有用的,因为那前辈认为没问题所以不理睬,如果能证明是DLL问题,就可以通过老总找他们
      

  2.   


    可我没有DLL的源代码,跟不进去,而且由于是偶发性的,我在debug下也没有截获到异常,怀疑是不是只有release下才有问题
      

  3.   

    搞个DMP输出呗,这样就算DLL崩溃也会指到崩溃点。也就是你调用的DLL函数处。这就是证据SetUnhandledExceptionFilter(回调函数);
    在回调函数中写MiniDumpWriteDump即可
      

  4.   


    可我没有DLL的源代码,跟不进去,而且由于是偶发性的,我在debug下也没有截获到异常,怀疑是不是只有release下才有问题
    crash有,dump中有call stack就可以看到是否由DLL中引起。
      

  5.   


    感谢两位版主的解答,有没有办法也能直接定位到DLL的代码行,就像通过分析map文件能定位主程序代码行一样??
      

  6.   

    dmp文件如果用VS打开的话会直接定位到代码行的
      

  7.   

    记得只要点击 debug with new instance 就可以了一下子跳转了。该方法对于内存不足的问题定位无效,因为没有内存去写dmp了
      

  8.   


    虎哥 有例子吗,实在没做过SetUnhandledExceptionFilter + Minidump,
      

  9.   

    SetUnhandledExceptionFilter(回调函数);放在InitInstance里面
    回调函数函数例子:LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *pExceptionPointers)
    { SetErrorMode( SEM_NOGPFAULTERRORBOX ); //收集信息
    CString strBuild;
    strBuild.Format(_T("Build: %s %s"), __DATE__, __TIME__);
    CString strError;
    HMODULE hModule;
    TCHAR szModuleName[MAX_PATH] = _T("");
    GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)pExceptionPointers->ExceptionRecord->ExceptionAddress, &hModule);
    GetModuleFileName(hModule, szModuleName, ARRAYSIZE(szModuleName));
    strError.AppendFormat(_T("%s %d , %d ,%d."), szModuleName,pExceptionPointers->ExceptionRecord->ExceptionCode, pExceptionPointers->ExceptionRecord->ExceptionFlags, pExceptionPointers->ExceptionRecord->ExceptionAddress); //生成 mini crash dump
    BOOL bMiniDumpSuccessful;
    // TCHAR szPath[MAX_PATH]; 
    TCHAR szFileName[MAX_PATH]; 
    TCHAR* szAppName = _T("OCTOPUS");
    TCHAR* szVersion = _T("v1.0");
    DWORD dwBufferSize = MAX_PATH;
    HANDLE hDumpFile;
    SYSTEMTIME stLocalTime;
    MINIDUMP_EXCEPTION_INFORMATION ExpParam;
    GetLocalTime( &stLocalTime );
    CString cstrName = GetAppPath(); memset(szFileName,0,MAX_PATH); TCHAR abPath[MAX_PATH]; 
    memset(abPath,0,MAX_PATH);
    memcpy(abPath,cstrName.GetBuffer(),cstrName.GetLength()); //  StringCchPrintfA( szFileName, MAX_PATH, _T("%s%s"), cstrName.GetBuffer(), szAppName );
    //  CreateDirectory( szFileName, NULL );
    StringCchPrintfA( szFileName, MAX_PATH, _T("%04d%02d%02d-%02d%02d%02d-%ld-%ld_%s.dmp"),  
    stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay, 
    stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond, 
    GetCurrentProcessId(), GetCurrentThreadId(),OCTOPUS_VERSION_NUM); strcat(abPath,szFileName); hDumpFile = CreateFile(abPath, GENERIC_READ|GENERIC_WRITE, 
    FILE_SHARE_WRITE|FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);//  MINIDUMP_USER_STREAM UserStream[2];
    //  MINIDUMP_USER_STREAM_INFORMATION UserInfo;
    //  UserInfo.UserStreamCount = 1;
    //  UserInfo.UserStreamArray = UserStream;
    //  UserStream[0].Type = CommentStreamA;
    //  UserStream[0].BufferSize = strBuild.GetLength()*sizeof(TCHAR);
    //  UserStream[0].Buffer = strBuild.GetBuffer();
    //  UserStream[1].Type = CommentStreamA;
    //  UserStream[1].BufferSize = strError.GetLength()*sizeof(TCHAR);
    //  UserStream[1].Buffer = strError.GetBuffer(); ExpParam.ThreadId = GetCurrentThreadId();
    ExpParam.ExceptionPointers = pExceptionPointers;
    ExpParam.ClientPointers = TRUE; //  MINIDUMP_TYPE MiniDumpWithDataSegs = MiniDumpNormal 
    //  | MiniDumpWithUnloadedModules 
    //  | MiniDumpWithIndirectlyReferencedMemory 
    //  | MiniDumpScanMemory 
    //  | MiniDumpWithProcessThreadData 
    //  | MiniDumpWithThreadInfo; bMiniDumpSuccessful = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), 
    hDumpFile, MiniDumpNormal/*MiniDumpWithPrivateReadWriteMemory*/, &ExpParam, NULL, NULL); if(TRUE == bMiniDumpSuccessful)
    {
    //AfxMessageBox(_T("Please send dmp file to the developers!\n They will deal with the trouble!"));
    if(IDOK==MessageBox(NULL,_T("Confirm to send the crash information to the developer for improvement?"),_T("Er...,Octopus crashed!"),MB_OKCANCEL))
    {
    char cUserName[255];
    char errInfo[256];
    memset(cUserName,0,sizeof(cUserName));
    memset(errInfo,0,sizeof(errInfo)); DWORD dwcbBuffer = 255;
    GetUserName(cUserName,&dwcbBuffer);
    sprintf_s(errInfo,"%s%s","this dmp file is sent off by user:",cUserName); char* attachFiles[2];
    attachFiles[0]=(char*)malloc(sizeof(char)*256);
    attachFiles[1]=(char*)malloc(sizeof(char)*256); memset(attachFiles[0],0,256);
    memset(attachFiles[1],0,256); strcpy(attachFiles[0],abPath); int res=sendmail(errInfo,attachFiles,1);
    if(0 == res)
    {
    AfxMessageBox(_T("Send dmp File Successfully!"));
    }
    else
    {
    AfxMessageBox(_T("Send dmp File Failed!"));
    }
    }
    }
    else
    {
    int id;
    id = GetLastError();
    CString cstrId;
    cstrId.Format(_T("dmp File Create Failed!Please check your memory!ID:%d"),id);
    AfxMessageBox(cstrId);
    } exit(0); return EXCEPTION_EXECUTE_HANDLER/*EXCEPTION_CONTINUE_SEARCH*/; //或者 EXCEPTION_EXECUTE_HANDLER 关闭程序
    }
      

  10.   

    或者直接用工具跑也行,depends -> profile -> start profile,直接运行,一般情况会显示你call的dll函数及地址,运行到对应崩溃的地方给他看就成了
      

  11.   


    感谢两位版主的解答,有没有办法也能直接定位到DLL的代码行,就像通过分析map文件能定位主程序代码行一样??
    结合DLL对应的PDB文件,windbg可以帮你找到代码行数
      

  12.   

    crash了用windbg拿crash dump文件给他看。
      

  13.   


    正好要问老大这个问题,这几个DLL人家连源代码都不给,更不可能有PDB文件了,只有一个DLL还能定位吗?
      

  14.   


    另外,按虎哥的方法生成了DMP文件,但我觉得有个问题,这个dmp文件是针对整个软件的,而DLL部分只有头文件没有源代码,还能通过dmp文件实现定位吗?
      

  15.   


    正好要问老大这个问题,这几个DLL人家连源代码都不给,更不可能有PDB文件了,只有一个DLL还能定位吗?
    看12L
      

  16.   


    谢谢,可没明白您的意思怎么做另外,虽然我也想运行给那人看,让他低头认错,但我更想找出实际出错的地方,以解决问题为主
    profile一般情况下能直接定位错误,相当于你od载入
      

  17.   


    正好要问老大这个问题,这几个DLL人家连源代码都不给,更不可能有PDB文件了,只有一个DLL还能定位吗?
    直接把dump crash的call stack打印给别人看