Создание мини-дампа запущенного процесса - PullRequest
1 голос
/ 08 апреля 2010

Я пытаюсь создать инструмент для моих конечных пользователей, который может создать MiniDump моего приложения, если оно зависает (то есть вне приложения).Я использую тот же код, что и внутренний MiniDumper, но с дескриптором и processid приложения, но я продолжаю получать код ошибки 0xD0000024 при вызове MiniDumpWriteDump.Любые идеи?

void produceDump( const char* exe )
{
    DWORD processId = 0;
    HANDLE process = findProcess(exe, processId);

    if (!process || processId == 0)
    {
        printf("Unable to find exe %s to produce dump.\n", exe);
        return;
    }

    LONG retval = EXCEPTION_CONTINUE_SEARCH;
    HWND hParent = NULL;                        // find a better value for your app

    // firstly see if dbghelp.dll is around and has the function we need
    // look next to the EXE first, as the one in System32 might be old 
    // (e.g. Windows 2000)
    HMODULE hDll = NULL;
    char szDbgHelpPath[_MAX_PATH];

    if (GetModuleFileName( NULL, szDbgHelpPath, _MAX_PATH ))
    {
        char *pSlash = _tcsrchr( szDbgHelpPath, '\\' );
        if (pSlash)
        {
            _tcscpy( pSlash+1, "DBGHELP.DLL" );
            hDll = ::LoadLibrary( szDbgHelpPath );
        }
    }

    if (hDll==NULL)
    {
        // load any version we can
        hDll = ::LoadLibrary( "DBGHELP.DLL" );
    }

    LPCTSTR szResult = NULL;

    int err = 0;

    if (hDll)
    {
        MINIDUMPWRITEDUMP pDump = (MINIDUMPWRITEDUMP)::GetProcAddress( hDll, "MiniDumpWriteDump" );
        if (pDump)
        {
            char szDumpPath[_MAX_PATH];
            char szScratch [_MAX_PATH];

            time_t rawtime;
            struct tm * timeinfo;

            time ( &rawtime );
            timeinfo = localtime ( &rawtime );

            char comAppPath[MAX_PATH];
            SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA , NULL, SHGFP_TYPE_CURRENT, comAppPath );


            //COMMONAPP_PATH
            _snprintf(szDumpPath, _MAX_PATH, "%s\\DN", comAppPath);
            CreateDirectory(szDumpPath, NULL);

            _snprintf(szDumpPath, _MAX_PATH, "%s\\DN\\D", comAppPath);
            CreateDirectory(szDumpPath, NULL);

            _snprintf(szDumpPath, _MAX_PATH, "%s\\DN\\D\\dumps", comAppPath);
            CreateDirectory(szDumpPath, NULL);

            char fileName[_MAX_PATH];
            _snprintf(fileName, _MAX_PATH, "%s_Dump_%04d%02d%02d_%02d%02d%02d.dmp", exe, timeinfo->tm_year+1900, timeinfo->tm_mon, timeinfo->tm_mday,  timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec );
            _snprintf(szDumpPath, _MAX_PATH, "%s\\DN\\D\\dumps\\%s", comAppPath, fileName);

            // create the file
            HANDLE hFile = ::CreateFile( szDumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
            if (hFile!=INVALID_HANDLE_VALUE)
            {
                MINIDUMP_CALLBACK_INFORMATION mci; 

                mci.CallbackRoutine     = (MINIDUMP_CALLBACK_ROUTINE)MyMiniDumpCallback; 
                mci.CallbackParam       = 0; 

                MINIDUMP_TYPE mdt       = (MINIDUMP_TYPE)(MiniDumpWithPrivateReadWriteMemory | 
                                                          MiniDumpWithDataSegs | 
                                                          MiniDumpWithHandleData |
                                                          //MiniDumpWithFullMemoryInfo | 
                                                          //MiniDumpWithThreadInfo | 
                                                          MiniDumpWithProcessThreadData |
                                                          MiniDumpWithUnloadedModules ); 

                // write the dump
                BOOL bOK = pDump( process, processId, hFile, mdt, NULL, NULL, &mci );
                DWORD lastErr = GetLastError();

                if (bOK)
                {
                    printf("Crash dump saved to: %s\n", szDumpPath);
                    return;
                }
                else
                {
                    _snprintf( szScratch, _MAX_PATH, "Failed to save dump file to '%s' (error %u)", szDumpPath, lastErr);
                    szResult = szScratch;
                    err = ERR_CANTSAVEFILE;
                }
                ::CloseHandle(hFile);
            }
            else
            {
                _snprintf( szScratch, _MAX_PATH, "Failed to create dump file '%s' (error %u)", szDumpPath, GetLastError());
                szResult = szScratch;
                err = ERR_CANTMAKEFILE;
            }
        }
        else
        {
            szResult = "DBGHELP.DLL too old";
            err = ERR_DBGHELP_TOOLD;
        }
    }
    else
    {
        szResult = "DBGHELP.DLL not found";
        err = ERR_DBGHELP_NOTFOUND;
    }

    printf("Could not produce a crash dump of %s.\n\n[error: %u %s].\n", exe, err, szResult);
    return;
}

этот код работает на 100%, когда его внутренний для процесса (т.е. с SetUnhandledExceptionFilter)

Ответы [ 2 ]

2 голосов
/ 09 апреля 2010

Вы открываете процесс с необходимыми правами доступа? MiniDumpWriteDump() необходимо открыть дескриптор процесса, используя права доступа PROCESS_QUERY_INFORMATION и PROCESS_VM_READ. Я думаю, что при использовании GetCurrentProcess() они предоставляются автоматически, но при использовании OpenProcess() для открытия другого процесса вы должны запросить эти права.

Для этого может также необходимо включить SeDebugPrivilege, что может вызвать проблемы у пользователей, чьи учетные записи не имеют такой привилегии. Но, похоже, в документации неясно, нужно ли SeDebugPrivilege для прав PROCESS_QUERY_INFORMATION и PROCESS_VM_READ конкретно (в отличие от всех прав доступа к процессу), особенно при открытии процесса, работающего под той же учетной записью пользователя. ,

0 голосов
/ 09 апреля 2010

Я вижу, что вы явно приводите MyMiniDumpCallback к типу PMINIDUMP_CALLBACK_INFORMATION. Это выглядит подозрительно, как если бы у вас была ошибка компилятора, которую вы обошли, потому что типы не совпадали. Это и PMINIDUMP_CALLBACK_INFORMATION является структурой, а не указателем на функцию.

Прямое приведение указателя функции к PMINIDUMP_CALLBACK_INFORMATION может быть допустимым, поскольку первым параметром этой структуры является функция обратного вызова. Но опять же, это выглядит очень подозрительно. Возможно, вы неправильно объявили свою функцию обратного вызова (например, забыли модификатор CALLBACK / __stdcall). Получите ваш код для компиляции без приведения этих формальных параметров, а затем я буду более склонен вам помочь.

Кроме того, вы даже проверяли, что ваша функция обратного вызова вообще вызывается?

...