-
Notifications
You must be signed in to change notification settings - Fork 4.6k
/
createdumpwindows.cpp
137 lines (122 loc) · 4.11 KB
/
createdumpwindows.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#include "createdump.h"
#include <psapi.h>
// The Windows SDK (winternl.h) we use doesn't have the necessary field (InheritedFromUniqueProcessId)
typedef struct _PROCESS_BASIC_INFORMATION_ {
NTSTATUS ExitStatus;
PPEB PebBaseAddress;
ULONG_PTR AffinityMask;
KPRIORITY BasePriority;
ULONG_PTR UniqueProcessId;
ULONG_PTR InheritedFromUniqueProcessId;
} PROCESS_BASIC_INFORMATION_;
//
// The Windows create dump code
//
bool
CreateDump(const CreateDumpOptions& options)
{
HANDLE hFile = INVALID_HANDLE_VALUE;
HANDLE hProcess = NULL;
bool result = false;
_ASSERTE(options.CreateDump);
_ASSERTE(!options.CrashReport);
ArrayHolder<char> pszName = new char[MAX_LONGPATH + 1];
std::string dumpPath;
// On Windows, createdump is restricted for security reasons to only the .NET process (parent process) that launched createdump
PROCESS_BASIC_INFORMATION_ processInformation;
NTSTATUS status = NtQueryInformationProcess(GetCurrentProcess(), PROCESSINFOCLASS::ProcessBasicInformation, &processInformation, sizeof(processInformation), NULL);
if (status != 0)
{
printf_error("Failed to get parent process id status %d\n", status);
goto exit;
}
int pid = (int)processInformation.InheritedFromUniqueProcessId;
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
if (hProcess == NULL)
{
printf_error("Invalid process id '%d' - %s\n", pid, GetLastErrorString().c_str());
goto exit;
}
if (GetModuleBaseNameA(hProcess, NULL, pszName, MAX_LONGPATH) <= 0)
{
printf_error("Get process name FAILED - %s\n", GetLastErrorString().c_str());
goto exit;
}
if (!FormatDumpName(dumpPath, options.DumpPathTemplate, pszName, pid))
{
goto exit;
}
printf_status("Writing %s for process %d to file %s\n", GetDumpTypeString(options.DumpType), pid, dumpPath.c_str());
hFile = CreateFileA(dumpPath.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
printf_error("Invalid dump path '%s' - %s\n", dumpPath.c_str(), GetLastErrorString().c_str());
goto exit;
}
int retryCount = 10;
// Retry the write dump on ERROR_PARTIAL_COPY
for (int i = 0; i <= retryCount; i++)
{
if (MiniDumpWriteDump(hProcess, pid, hFile, GetMiniDumpType(options.DumpType), NULL, NULL, NULL))
{
result = true;
break;
}
else
{
int err = GetLastError();
if (err != ERROR_PARTIAL_COPY || i == retryCount)
{
printf_error("MiniDumpWriteDump - %s\n", GetLastErrorString().c_str());
break;
}
else
{
printf_error("Retry %d of MiniDumpWriteDump due to - %s\n", i, GetLastErrorString().c_str());
}
}
}
exit:
if (hProcess != NULL)
{
CloseHandle(hProcess);
}
if (hFile != INVALID_HANDLE_VALUE)
{
CloseHandle(hFile);
}
return result;
}
std::string
GetLastErrorString()
{
DWORD error = GetLastError();
std::string result;
LPSTR messageBuffer;
DWORD length = FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&messageBuffer,
0,
NULL);
if (length > 0)
{
result.append(messageBuffer, length);
LocalFree(messageBuffer);
// Remove the \r\n at the end of the system message. Assumes that the \r is first.
size_t found = result.find_last_of('\r');
if (found != std::string::npos)
{
result.erase(found);
}
result.append(" ");
}
char buffer[64];
_snprintf_s(buffer, sizeof(buffer), sizeof(buffer), "(%d)", error);
result.append(buffer);
return result;
}