else
{
fprintf(stderr, "ptrace(ATTACH, %d) FAILED %s\n", tid, strerror(errno));
+ closedir(taskDir);
+ return false;
}
}
}
}
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))
return false;
}
// Gather all the useful memory regions from the DAC
- if (!EnumerateMemoryRegionsWithDAC(pszExePath, minidumpType))
+ if (!EnumerateMemoryRegionsWithDAC(programPath, minidumpType))
{
return false;
}
}
bool
-CrashInfo::EnumerateMemoryRegionsWithDAC(const char *pszExePath, MINIDUMP_TYPE minidumpType)
+CrashInfo::EnumerateMemoryRegionsWithDAC(const char* programPath, MINIDUMP_TYPE minidumpType)
{
PFN_CLRDataCreateInstance pfnCLRDataCreateInstance = nullptr;
ICLRDataEnumMemoryRegions *clrDataEnumRegions = nullptr;
// We assume that the DAC is in the same location as this createdump exe
ArrayHolder<char> dacPath = new char[MAX_LONGPATH];
- strcpy_s(dacPath, MAX_LONGPATH, pszExePath);
+ strcpy_s(dacPath, MAX_LONGPATH, programPath);
char *last = strrchr(dacPath, '/');
if (last != nullptr)
{
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);
}
}
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);
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);
#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<char> 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
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;
}
{
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;
//
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;
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;
}
fprintf(stderr, "Could not open output %s: %s\n", dumpFileName, strerror(errno));
return false;
}
- printf("Writing core file %s\n", dumpFileName);
return true;
}
}
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())
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())
}
}
- 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)
{
}
}
+ printf("Written %ld bytes (%ld pages) to core file\n", total, total >> PAGE_SHIFT);
+
return true;
}
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)) ||
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)) {
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) ||
Volatile<PSHUTDOWN_CALLBACK> 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
}
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;
{
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;
}