]>
Commit | Line | Data |
---|---|---|
d0e5dd3a JT |
1 | /* minidumper.cc |
2 | ||
3 | Copyright 2014 Red Hat Inc. | |
4 | ||
5 | This file is part of Cygwin. | |
6 | ||
7 | This program is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 2 of the License, or | |
10 | (at your option) any later version. | |
11 | ||
12 | This program is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License (file COPYING.dumper) for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with this program; if not, write to the Free Software | |
19 | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. | |
20 | */ | |
21 | ||
22 | #include <sys/cygwin.h> | |
23 | #include <cygwin/version.h> | |
24 | #include <getopt.h> | |
25 | #include <errno.h> | |
26 | #include <stdio.h> | |
27 | #include <stdlib.h> | |
28 | #include <windows.h> | |
29 | ||
30 | BOOL verbose = FALSE; | |
31 | BOOL nokill = FALSE; | |
32 | ||
33 | typedef DWORD MINIDUMP_TYPE; | |
34 | ||
35 | typedef BOOL (WINAPI *MiniDumpWriteDump_type)( | |
36 | HANDLE hProcess, | |
37 | DWORD dwPid, | |
38 | HANDLE hFile, | |
39 | MINIDUMP_TYPE DumpType, | |
40 | CONST void *ExceptionParam, | |
41 | CONST void *UserStreamParam, | |
42 | CONST void *allbackParam); | |
43 | ||
44 | static void | |
45 | minidump(DWORD pid, MINIDUMP_TYPE dump_type, const char *minidump_file) | |
46 | { | |
47 | HANDLE dump_file; | |
48 | HANDLE process; | |
49 | MiniDumpWriteDump_type MiniDumpWriteDump_fp; | |
50 | HMODULE module; | |
51 | ||
52 | module = LoadLibrary("dbghelp.dll"); | |
53 | if (!module) | |
54 | { | |
55 | fprintf (stderr, "error loading DbgHelp\n"); | |
56 | return; | |
57 | } | |
58 | ||
59 | MiniDumpWriteDump_fp = (MiniDumpWriteDump_type)GetProcAddress(module, "MiniDumpWriteDump"); | |
60 | if (!MiniDumpWriteDump_fp) | |
61 | { | |
62 | fprintf (stderr, "error getting the address of MiniDumpWriteDump\n"); | |
63 | return; | |
64 | } | |
65 | ||
66 | dump_file = CreateFile(minidump_file, | |
67 | GENERIC_READ | GENERIC_WRITE, | |
68 | 0, | |
69 | NULL, | |
70 | CREATE_ALWAYS, | |
71 | FILE_FLAG_BACKUP_SEMANTICS, | |
72 | NULL); | |
73 | if (dump_file == INVALID_HANDLE_VALUE) | |
74 | { | |
75 | fprintf (stderr, "error opening file\n"); | |
76 | return; | |
77 | } | |
78 | ||
79 | process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_TERMINATE, | |
80 | FALSE, | |
81 | pid); | |
82 | if (dump_file == INVALID_HANDLE_VALUE) | |
83 | { | |
84 | fprintf (stderr, "error opening process\n"); | |
85 | return; | |
86 | } | |
87 | ||
88 | BOOL success = (*MiniDumpWriteDump_fp)(process, | |
89 | pid, | |
90 | dump_file, | |
91 | dump_type, | |
92 | NULL, | |
93 | NULL, | |
94 | NULL); | |
95 | if (success) | |
96 | { | |
97 | if (verbose) | |
98 | printf ("minidump created successfully\n"); | |
99 | } | |
100 | else | |
101 | { | |
102 | fprintf (stderr, "error creating minidump\n"); | |
103 | } | |
104 | ||
105 | /* Unless nokill is given, behave like dumper and terminate the dumped | |
106 | process */ | |
107 | if (!nokill) | |
108 | { | |
109 | TerminateProcess(process, 128 + 9); | |
110 | WaitForSingleObject(process, INFINITE); | |
111 | } | |
112 | ||
113 | CloseHandle(process); | |
114 | CloseHandle(dump_file); | |
115 | FreeLibrary(module); | |
116 | } | |
117 | ||
118 | static void | |
119 | usage (FILE *stream, int status) | |
120 | { | |
121 | fprintf (stream, "\ | |
122 | Usage: %s [OPTION] FILENAME WIN32PID\n\ | |
123 | \n\ | |
124 | Write minidump from WIN32PID to FILENAME.dmp\n\ | |
125 | \n\ | |
126 | -t, --type minidump type flags\n\ | |
127 | -n, --nokill don't terminate the dumped process\n\ | |
128 | -d, --verbose be verbose while dumping\n\ | |
129 | -h, --help output help information and exit\n\ | |
130 | -q, --quiet be quiet while dumping (default)\n\ | |
131 | -V, --version output version information and exit\n\ | |
132 | \n", program_invocation_short_name); | |
133 | exit (status); | |
134 | } | |
135 | ||
136 | struct option longopts[] = { | |
137 | {"type", required_argument, NULL, 't'}, | |
138 | {"nokill", no_argument, NULL, 'n'}, | |
139 | {"verbose", no_argument, NULL, 'd'}, | |
140 | {"help", no_argument, NULL, 'h'}, | |
141 | {"quiet", no_argument, NULL, 'q'}, | |
142 | {"version", no_argument, 0, 'V'}, | |
143 | {0, no_argument, NULL, 0} | |
144 | }; | |
145 | const char *opts = "tndhqV"; | |
146 | ||
147 | static void | |
148 | print_version () | |
149 | { | |
150 | printf ("minidumper (cygwin) %d.%d.%d\n" | |
151 | "Minidump write for Cygwin\n" | |
152 | "Copyright (C) 1999 - %s Red Hat, Inc.\n" | |
153 | "This is free software; see the source for copying conditions. There is NO\n" | |
154 | "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n", | |
155 | CYGWIN_VERSION_DLL_MAJOR / 1000, | |
156 | CYGWIN_VERSION_DLL_MAJOR % 1000, | |
157 | CYGWIN_VERSION_DLL_MINOR, | |
158 | strrchr (__DATE__, ' ') + 1); | |
159 | } | |
160 | ||
161 | int | |
162 | main (int argc, char **argv) | |
163 | { | |
164 | int opt; | |
165 | const char *p = ""; | |
166 | DWORD pid; | |
167 | MINIDUMP_TYPE dump_type = 0; // MINIDUMP_NORMAL | |
168 | ||
169 | while ((opt = getopt_long (argc, argv, opts, longopts, NULL) ) != EOF) | |
170 | switch (opt) | |
171 | { | |
172 | case 't': | |
173 | { | |
174 | char *endptr; | |
175 | dump_type = strtoul(optarg, &endptr, 0); | |
176 | if (*endptr != '\0') | |
177 | { | |
178 | fprintf (stderr, "syntax error in minidump type \"%s\" near character #%d.\n", optarg, (int) (endptr - optarg)); | |
179 | exit(1); | |
180 | } | |
181 | } | |
182 | break; | |
183 | case 'n': | |
184 | nokill = TRUE; | |
185 | break; | |
186 | case 'd': | |
187 | verbose = TRUE; | |
188 | break; | |
189 | case 'q': | |
190 | verbose = FALSE; | |
191 | break; | |
192 | case 'h': | |
193 | usage (stdout, 0); | |
194 | case 'V': | |
195 | print_version (); | |
196 | exit (0); | |
197 | default: | |
198 | fprintf (stderr, "Try `%s --help' for more information.\n", | |
199 | program_invocation_short_name); | |
200 | exit (1); | |
201 | } | |
202 | ||
203 | if (argv && *(argv + optind) && *(argv + optind +1)) | |
204 | { | |
205 | ssize_t len = cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_RELATIVE, | |
206 | *(argv + optind), NULL, 0); | |
207 | char *win32_name = (char *) alloca (len); | |
208 | cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_RELATIVE, *(argv + optind), | |
209 | win32_name, len); | |
210 | if ((p = strrchr (win32_name, '\\'))) | |
211 | p++; | |
212 | else | |
213 | p = win32_name; | |
214 | ||
215 | pid = strtoul (*(argv + optind + 1), NULL, 10); | |
216 | } | |
217 | else | |
218 | { | |
219 | usage (stderr, 1); | |
220 | return -1; | |
221 | } | |
222 | ||
223 | char *minidump_file = (char *) malloc (strlen (p) + sizeof (".dmp")); | |
224 | if (!minidump_file) | |
225 | { | |
226 | fprintf (stderr, "error allocating memory\n"); | |
227 | return -1; | |
228 | } | |
229 | sprintf (minidump_file, "%s.dmp", p); | |
230 | ||
231 | if (verbose) | |
232 | printf ("dumping process %u to %s using dump type flags 0x%x\n", (unsigned int)pid, minidump_file, (unsigned int)dump_type); | |
233 | ||
234 | minidump(pid, dump_type, minidump_file); | |
235 | ||
236 | free (minidump_file); | |
237 | }; |