From: Mike McLaughlin Date: Tue, 18 Apr 2017 23:54:53 +0000 (-0700) Subject: Implement the createdump policy options and env variables (dotnet/coreclr#11032) X-Git-Tag: submit/tizen/20210909.063632~11030^2~7207 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1c65850be0be912e54e3636bf1806a72f6de024b;p=platform%2Fupstream%2Fdotnet%2Fruntime.git Implement the createdump policy options and env variables (dotnet/coreclr#11032) Added these command line options: -f, --name - dump path and file name. The pid can be placed in the name with %d. The default is "/tmp/coredump.%d" -n, --normal - create minidump (default). -h, --withheap - create minidump with heap. -m, --micro - create triage minidump. -d, --diag - enable diagnostic messages. Added these environment variables: COMPlus_DbgMiniDumpType - if set to "1" generate MiniDumpNormal, "2" MiniDumpWithPrivateReadWriteMemory, "3" MiniDumpFilterTriage. Default is MiniDumpNormal. COMPlus_DbgMiniDumpName - if set, use as the template to create the dump path and file name. The pid can be placed in the name with %d. The default is "/tmp/coredump.%d". Commit migrated from https://github.com/dotnet/coreclr/commit/29e59e81de5489a3c0515b5d1d50baeb06269bd1 --- diff --git a/src/coreclr/src/debug/createdump/crashinfo.cpp b/src/coreclr/src/debug/createdump/crashinfo.cpp index 8f72542..f92630b 100644 --- a/src/coreclr/src/debug/createdump/crashinfo.cpp +++ b/src/coreclr/src/debug/createdump/crashinfo.cpp @@ -120,6 +120,8 @@ CrashInfo::EnumerateAndSuspendThreads() else { fprintf(stderr, "ptrace(ATTACH, %d) FAILED %s\n", tid, strerror(errno)); + closedir(taskDir); + return false; } } } @@ -129,7 +131,7 @@ CrashInfo::EnumerateAndSuspendThreads() } bool -CrashInfo::GatherCrashInfo(const char* pszExePath, MINIDUMP_TYPE minidumpType) +CrashInfo::GatherCrashInfo(const char* programPath, MINIDUMP_TYPE minidumpType) { // Get the process info if (!GetStatus(m_pid, &m_ppid, &m_tgid, &m_name)) @@ -160,7 +162,7 @@ CrashInfo::GatherCrashInfo(const char* pszExePath, MINIDUMP_TYPE minidumpType) return false; } // Gather all the useful memory regions from the DAC - if (!EnumerateMemoryRegionsWithDAC(pszExePath, minidumpType)) + if (!EnumerateMemoryRegionsWithDAC(programPath, minidumpType)) { return false; } @@ -326,7 +328,7 @@ CrashInfo::EnumerateModuleMappings() } bool -CrashInfo::EnumerateMemoryRegionsWithDAC(const char *pszExePath, MINIDUMP_TYPE minidumpType) +CrashInfo::EnumerateMemoryRegionsWithDAC(const char* programPath, MINIDUMP_TYPE minidumpType) { PFN_CLRDataCreateInstance pfnCLRDataCreateInstance = nullptr; ICLRDataEnumMemoryRegions *clrDataEnumRegions = nullptr; @@ -336,7 +338,7 @@ CrashInfo::EnumerateMemoryRegionsWithDAC(const char *pszExePath, MINIDUMP_TYPE m // We assume that the DAC is in the same location as this createdump exe ArrayHolder dacPath = new char[MAX_LONGPATH]; - strcpy_s(dacPath, MAX_LONGPATH, pszExePath); + strcpy_s(dacPath, MAX_LONGPATH, programPath); char *last = strrchr(dacPath, '/'); if (last != nullptr) { @@ -572,13 +574,10 @@ CrashInfo::CombineMemoryRegions() if (g_diagnostics) { TRACE("Memory Regions:\n"); - uint64_t total = 0; for (const MemoryRegion& region : m_memoryRegions) { region.Print(); - total += region.Size(); } - TRACE("Total %ld bytes (%ld pages) to write\n", total, total >> PAGE_SHIFT); } } diff --git a/src/coreclr/src/debug/createdump/crashinfo.h b/src/coreclr/src/debug/createdump/crashinfo.h index a03ebe3..bdd19cf 100644 --- a/src/coreclr/src/debug/createdump/crashinfo.h +++ b/src/coreclr/src/debug/createdump/crashinfo.h @@ -34,7 +34,7 @@ public: CrashInfo(pid_t pid, DataTarget& dataTarget); virtual ~CrashInfo(); bool EnumerateAndSuspendThreads(); - bool GatherCrashInfo(const char* pszExePath, MINIDUMP_TYPE minidumpType); + bool GatherCrashInfo(const char* programPath, MINIDUMP_TYPE minidumpType); void ResumeThreads(); static bool GetStatus(pid_t pid, pid_t* ppid, pid_t* tgid, char** name); @@ -63,7 +63,7 @@ public: private: bool GetAuxvEntries(); bool EnumerateModuleMappings(); - bool EnumerateMemoryRegionsWithDAC(const char* pszExePath, MINIDUMP_TYPE minidumpType); + bool EnumerateMemoryRegionsWithDAC(const char* programPath, MINIDUMP_TYPE minidumpType); bool GetDSOInfo(); bool ReadMemory(void* address, void* buffer, size_t size); void InsertMemoryRegion(uint64_t address, size_t size); diff --git a/src/coreclr/src/debug/createdump/createdump.cpp b/src/coreclr/src/debug/createdump/createdump.cpp index 4f43d11..ccc284b 100644 --- a/src/coreclr/src/debug/createdump/createdump.cpp +++ b/src/coreclr/src/debug/createdump/createdump.cpp @@ -4,18 +4,26 @@ #include "createdump.h" +const char* g_help = "createdump [options] pid\n" +"-f, --name - dump path and file name. The pid can be placed in the name with %d. The default is '/tmp/coredump.%d'\n" +"-n, --normal - create minidump (default).\n" +"-h, --withheap - create minidump with heap.\n" +"-m, --micro - create triage minidump.\n" +"-d, --diag - enable diagnostic messages.\n"; + bool g_diagnostics = true; // // Create a minidump using the DAC's enum memory regions interface // static bool -CreateDump(const char* pszExePath, const char* dumpPathTemplate, pid_t pid, MINIDUMP_TYPE minidumpType) +CreateDump(const char* programPath, const char* dumpPathTemplate, pid_t pid, MINIDUMP_TYPE minidumpType) { DataTarget* dataTarget = new DataTarget(pid); CrashInfo* crashInfo = new CrashInfo(pid, *dataTarget); DumpWriter* dumpWriter = new DumpWriter(*dataTarget, *crashInfo); ArrayHolder dumpPath = new char[MAX_LONGPATH]; + const char* dumpType = "minidump"; bool result = false; // Suspend all the threads in the target process and build the list of threads @@ -29,7 +37,7 @@ CreateDump(const char* pszExePath, const char* dumpPathTemplate, pid_t pid, MINI goto exit; } // Gather all the info about the process, threads (registers, etc.) and memory regions - if (!crashInfo->GatherCrashInfo(pszExePath, minidumpType)) + if (!crashInfo->GatherCrashInfo(programPath, minidumpType)) { goto exit; } @@ -38,6 +46,20 @@ CreateDump(const char* pszExePath, const char* dumpPathTemplate, pid_t pid, MINI { goto exit; } + switch (minidumpType) + { + case MiniDumpWithPrivateReadWriteMemory: + dumpType = "minidump with heap"; + break; + + case MiniDumpFilterTriage: + dumpType = "triage minidump"; + break; + + default: + break; + } + printf("Writing %s to file %s\n", dumpType, (char*)dumpPath); if (!dumpWriter->WriteDump()) { goto exit; @@ -56,7 +78,10 @@ exit: // int __cdecl main(const int argc, const char* argv[]) { + MINIDUMP_TYPE minidumpType = MiniDumpNormal; const char* dumpPathTemplate = "/tmp/coredump.%d"; + const char* programPath = nullptr; + pid_t pid = 0; char* diagnostics = getenv("COMPlus_CreateDumpDiagnostics"); g_diagnostics = diagnostics != nullptr && strcmp(diagnostics, "1") == 0; @@ -64,24 +89,52 @@ int __cdecl main(const int argc, const char* argv[]) int exitCode = PAL_InitializeDLL(); if (exitCode != 0) { - fprintf(stderr, "PAL_Initialize FAILED %d\n", exitCode); + fprintf(stderr, "PAL initialization FAILED %d\n", exitCode); return exitCode; } - pid_t pid; - if (argc < 2) + programPath = *argv; + argv++; + + for (int i = 1; i < argc; i++) + { + if (*argv != nullptr) + { + if ((strcmp(*argv, "-f") == 0) || (strcmp(*argv, "--name") == 0)) + { + dumpPathTemplate = *++argv; + } + else if ((strcmp(*argv, "-n") == 0) || (strcmp(*argv, "--normal") == 0)) + { + minidumpType = MiniDumpNormal; + } + else if ((strcmp(*argv, "-h") == 0) || (strcmp(*argv, "--withheap") == 0)) + { + minidumpType = MiniDumpWithPrivateReadWriteMemory; + } + else if ((strcmp(*argv, "-m") == 0) || (strcmp(*argv, "--micro") == 0)) + { + minidumpType = MiniDumpFilterTriage; + } + else if ((strcmp(*argv, "-d") == 0) || (strcmp(*argv, "--diag") == 0)) + { + g_diagnostics = true; + } + else { + pid = atoll(*argv); + } + argv++; + } + } + // if no pid or invalid command line option + if (pid == 0) { - fprintf(stderr, "Not enough arguments\n"); + fprintf(stderr, "%s", g_help); exitCode = -1; - goto exit; } - pid = _atoi64(argv[1]); - - if (!CreateDump(argv[0], dumpPathTemplate, pid, MiniDumpNormal)) + else if (!CreateDump(programPath, dumpPathTemplate, pid, minidumpType)) { exitCode = -1; - goto exit; } -exit: PAL_TerminateEx(exitCode); return exitCode; } diff --git a/src/coreclr/src/debug/createdump/dumpwriter.cpp b/src/coreclr/src/debug/createdump/dumpwriter.cpp index ef3adac..cec19e8 100644 --- a/src/coreclr/src/debug/createdump/dumpwriter.cpp +++ b/src/coreclr/src/debug/createdump/dumpwriter.cpp @@ -70,7 +70,6 @@ DumpWriter::OpenDump(char* dumpFileName) fprintf(stderr, "Could not open output %s: %s\n", dumpFileName, strerror(errno)); return false; } - printf("Writing core file %s\n", dumpFileName); return true; } @@ -175,7 +174,7 @@ DumpWriter::WriteDump() } offset += finalNoteAlignment; - printf("Writing memory region headers to core file\n"); + TRACE("Writing memory region headers to core file\n"); // Write memory region note headers for (const MemoryRegion& memoryRegion : m_crashInfo.MemoryRegions()) @@ -208,7 +207,7 @@ DumpWriter::WriteDump() return false; } - printf("Writing %ld thread entries to core file\n", m_crashInfo.Threads().size()); + TRACE("Writing %ld thread entries to core file\n", m_crashInfo.Threads().size()); // Write all the thread's state and registers for (const ThreadInfo* thread : m_crashInfo.Threads()) @@ -228,13 +227,15 @@ DumpWriter::WriteDump() } } - printf("Writing %ld memory regions to core file\n", m_crashInfo.MemoryRegions().size()); + TRACE("Writing %ld memory regions to core file\n", m_crashInfo.MemoryRegions().size()); // Read from target process and write memory regions to core + uint64_t total = 0; for (const MemoryRegion& memoryRegion : m_crashInfo.MemoryRegions()) { uint32_t size = memoryRegion.Size(); uint64_t address = memoryRegion.StartAddress(); + total += size; while (size > 0) { @@ -255,6 +256,8 @@ DumpWriter::WriteDump() } } + printf("Written %ld bytes (%ld pages) to core file\n", total, total >> PAGE_SHIFT); + return true; } @@ -275,7 +278,7 @@ DumpWriter::WriteProcessInfo() nhdr.n_descsz = sizeof(prpsinfo_t); nhdr.n_type = NT_PRPSINFO; - printf("Writing process information to core file\n"); + TRACE("Writing process information to core file\n"); // Write process info data to core file if (!WriteData(&nhdr, sizeof(nhdr)) || @@ -295,7 +298,7 @@ DumpWriter::WriteAuxv() nhdr.n_descsz = m_crashInfo.GetAuxvSize(); nhdr.n_type = NT_AUXV; - printf("Writing %ld auxv entries to core file\n", m_crashInfo.AuxvEntries().size()); + TRACE("Writing %ld auxv entries to core file\n", m_crashInfo.AuxvEntries().size()); if (!WriteData(&nhdr, sizeof(nhdr)) || !WriteData("CORE\0AUX", 8)) { @@ -373,7 +376,7 @@ DumpWriter::WriteNTFileInfo() size_t count = m_crashInfo.ModuleMappings().size(); size_t pageSize = PAGE_SIZE; - printf("Writing %ld NT_FILE entries to core file\n", m_crashInfo.ModuleMappings().size()); + TRACE("Writing %ld NT_FILE entries to core file\n", m_crashInfo.ModuleMappings().size()); if (!WriteData(&nhdr, sizeof(nhdr)) || !WriteData("CORE\0FIL", 8) || diff --git a/src/coreclr/src/pal/src/thread/process.cpp b/src/coreclr/src/pal/src/thread/process.cpp index e7380ee..e7a2d2f 100644 --- a/src/coreclr/src/pal/src/thread/process.cpp +++ b/src/coreclr/src/pal/src/thread/process.cpp @@ -149,7 +149,7 @@ DWORD gSID = (DWORD) -1; Volatile g_shutdownCallback = nullptr; // Crash dump generating program arguments. Initialized in PROCAbortInitialize(). -char *g_argvCreateDump[3] = { nullptr, nullptr, nullptr }; +char* g_argvCreateDump[8] = { nullptr }; // // Key used for associating CPalThread's with the underlying pthread @@ -2895,8 +2895,11 @@ PROCAbortInitialize() } const char* DumpGeneratorName = "createdump"; int programLen = strlen(g_szCoreCLRPath) + strlen(DumpGeneratorName); - char* program = new char[programLen]; - + char* program = (char*)InternalMalloc(programLen); + if (program == nullptr) + { + return FALSE; + } if (strcpy_s(program, programLen, g_szCoreCLRPath) != SAFECRT_SUCCESS) { return FALSE; @@ -2914,19 +2917,50 @@ PROCAbortInitialize() { return FALSE; } - char pidarg[128]; - if (sprintf_s(pidarg, sizeof(pidarg), "%d", gPID) == -1) + char* pidarg = (char*)InternalMalloc(128); + if (pidarg == nullptr) { return FALSE; } - g_argvCreateDump[0] = program; - g_argvCreateDump[1] = _strdup(pidarg); - g_argvCreateDump[2] = nullptr; - - if (g_argvCreateDump[0] == nullptr || g_argvCreateDump[1] == nullptr) + if (sprintf_s(pidarg, 128, "%d", gPID) == -1) { return FALSE; } + const char** argv = (const char**)g_argvCreateDump; + *argv++ = program; + + char* envvar = getenv("COMPlus_DbgMiniDumpName"); + if (envvar != nullptr) + { + *argv++ = "--name"; + *argv++ = envvar; + } + + envvar = getenv("COMPlus_DbgMiniDumpType"); + if (envvar != nullptr) + { + if (strcmp(envvar, "1") == 0) + { + *argv++ = "--normal"; + } + else if (strcmp(envvar, "2") == 0) + { + *argv++ = "--withheap"; + } + else if (strcmp(envvar, "3") == 0) + { + *argv++ = "--micro"; + } + } + + envvar = getenv("COMPlus_CreateDumpDiagnostics"); + if (envvar != nullptr && strcmp(envvar, "1") == 0) + { + *argv++ = "--diag"; + } + + *argv++ = pidarg; + *argv = nullptr; } return TRUE; }