]> sourceware.org Git - newlib-cygwin.git/blame - winsup/utils/dumper.cc
Cygwin: add 3.2.1 release file and add fixes up to this point
[newlib-cygwin.git] / winsup / utils / dumper.cc
CommitLineData
0ad10c0f
CF
1/* dumper.cc
2
0ad10c0f
CF
3 Written by Egor Duda <deo@logos-m.ru>
4
eedc36cb 5 This file is part of Cygwin.
0ad10c0f 6
dd67e696
CV
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
6e623e93 9 the Free Software Foundation; either version 3 of the License, or
dd67e696
CV
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. */
0ad10c0f 20
6dcb2ec4 21#include <ansidecl.h>
4c36016b 22#define PACKAGE
f2af71ea 23#include <bfd.h>
0ad10c0f
CF
24#include <elf/common.h>
25#include <elf/external.h>
26#include <sys/procfs.h>
27#include <sys/cygwin.h>
92b499ac 28#include <cygwin/version.h>
0ad10c0f
CF
29#include <getopt.h>
30#include <stdarg.h>
92b499ac 31#include <errno.h>
0ad10c0f
CF
32#include <stdio.h>
33#include <stdlib.h>
34#include <unistd.h>
9cfc9511 35#include <sys/param.h>
0ad10c0f 36#include <windows.h>
1be41b80 37#include <psapi.h>
0ad10c0f
CF
38
39#include "dumper.h"
40
41#define NOTE_NAME_SIZE 16
42
ba2f251d
JT
43#ifdef bfd_get_section_size
44/* for bfd < 2.34 */
45#define get_section_name(abfd, sect) bfd_get_section_name (abfd, sect)
46#define get_section_size(sect) bfd_get_section_size(sect)
47#define set_section_size(abfd, sect, size) bfd_set_section_size(abfd, sect, size)
48#define set_section_flags(abfd, sect, flags) bfd_set_section_flags(abfd, sect, flags)
49#else
50/* otherwise bfd >= 2.34 */
51#define get_section_name(afbd, sect) bfd_section_name (sect)
52#define get_section_size(sect) bfd_section_size(sect)
53#define set_section_size(abfd, sect, size) bfd_set_section_size(sect, size)
54#define set_section_flags(abfd, sect, flags) bfd_set_section_flags(sect, flags)
55#endif
56
0ad10c0f 57typedef struct _note_header
eedc36cb
CF
58 {
59 Elf_External_Note elf_note_header;
60 char name[NOTE_NAME_SIZE - 1]; /* external note contains first byte of data */
61 }
0ad10c0f 62#ifdef __GNUC__
eedc36cb 63__attribute__ ((packed))
0ad10c0f 64#endif
eedc36cb 65 note_header;
0ad10c0f 66
92ef5188 67BOOL verbose = FALSE;
a5218ff7 68BOOL nokill = FALSE;
0ad10c0f 69
92ef5188 70int deb_printf (const char *format,...)
0ad10c0f 71{
eedc36cb
CF
72 if (!verbose)
73 return 0;
0ad10c0f 74 va_list va;
eedc36cb
CF
75 va_start (va, format);
76 int ret_val = vprintf (format, va);
77 va_end (va);
0ad10c0f
CF
78 return ret_val;
79}
80
eedc36cb 81dumper::dumper (DWORD pid, DWORD tid, const char *file_name)
0ad10c0f 82{
eedc36cb 83 this->file_name = strdup (file_name);
0ad10c0f
CF
84
85 this->pid = pid;
86 this->tid = tid;
87 core_bfd = NULL;
0ad10c0f
CF
88
89 list = last = NULL;
90
91 status_section = NULL;
92
93 memory_num = module_num = thread_num = 0;
94
eedc36cb
CF
95 hProcess = OpenProcess (PROCESS_ALL_ACCESS,
96 FALSE, /* no inheritance */
97 pid);
98 if (!hProcess)
0ad10c0f 99 {
61522196
CV
100 fprintf (stderr, "Failed to open process #%u, error %ld\n",
101 (unsigned int) pid, (long) GetLastError ());
0ad10c0f
CF
102 return;
103 }
104
105 init_core_dump ();
106
eedc36cb
CF
107 if (!sane ())
108 dumper_abort ();
0ad10c0f
CF
109}
110
ce475802 111dumper::~dumper ()
0ad10c0f
CF
112{
113 close ();
eedc36cb 114 free (file_name);
0ad10c0f
CF
115}
116
117void
118dumper::dumper_abort ()
119{
120 close ();
eedc36cb 121 unlink (file_name);
0ad10c0f
CF
122}
123
124void
125dumper::close ()
126{
eedc36cb
CF
127 if (core_bfd)
128 bfd_close (core_bfd);
eedc36cb
CF
129 if (hProcess)
130 CloseHandle (hProcess);
0ad10c0f
CF
131 core_bfd = NULL;
132 hProcess = NULL;
0ad10c0f
CF
133}
134
135int
136dumper::sane ()
137{
44103c06 138 if (hProcess == NULL || core_bfd == NULL)
eedc36cb 139 return 0;
0ad10c0f
CF
140 return 1;
141}
142
33bc8247
ED
143void
144print_section_name (bfd* abfd, asection* sect, PTR obj)
145{
ba2f251d 146 deb_printf (" %s", get_section_name (abfd, sect));
33bc8247
ED
147}
148
149void
150dumper::print_core_section_list ()
151{
152 deb_printf ("current sections:");
153 bfd_map_over_sections (core_bfd, &print_section_name, NULL);
154 deb_printf ("\n");
155}
156
eedc36cb
CF
157process_entity *
158dumper::add_process_entity_to_list (process_entity_type type)
0ad10c0f 159{
eedc36cb
CF
160 if (!sane ())
161 return NULL;
0ad10c0f 162
eedc36cb
CF
163 process_entity *new_entity = (process_entity *) malloc (sizeof (process_entity));
164 if (new_entity == NULL)
165 return NULL;
0ad10c0f
CF
166 new_entity->next = NULL;
167 new_entity->section = NULL;
eedc36cb 168 if (last == NULL)
0ad10c0f
CF
169 list = new_entity;
170 else
171 last->next = new_entity;
172 last = new_entity;
173 return new_entity;
174}
175
176int
eedc36cb 177dumper::add_thread (DWORD tid, HANDLE hThread)
0ad10c0f 178{
eedc36cb
CF
179 if (!sane ())
180 return 0;
0ad10c0f 181
eedc36cb 182 CONTEXT *pcontext;
0ad10c0f 183
eedc36cb
CF
184 process_entity *new_entity = add_process_entity_to_list (pr_ent_thread);
185 if (new_entity == NULL)
186 return 0;
0ad10c0f
CF
187 new_entity->type = pr_ent_thread;
188 thread_num++;
189
190 new_entity->u.thread.tid = tid;
191 new_entity->u.thread.hThread = hThread;
192
eedc36cb 193 pcontext = &(new_entity->u.thread.context);
0ad10c0f 194 pcontext->ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT;
eedc36cb 195 if (!GetThreadContext (hThread, pcontext))
d353d5d6
ED
196 {
197 deb_printf ("Failed to read thread context (tid=%x), error %ld\n", tid, GetLastError ());
198 return 0;
199 }
0ad10c0f 200
eedc36cb 201 deb_printf ("added thread %u\n", tid);
0ad10c0f
CF
202 return 1;
203}
204
205int
61522196 206dumper::add_mem_region (LPBYTE base, SIZE_T size)
0ad10c0f 207{
eedc36cb
CF
208 if (!sane ())
209 return 0;
0ad10c0f 210
eedc36cb
CF
211 if (base == NULL || size == 0)
212 return 1; // just ignore empty regions
0ad10c0f 213
eedc36cb
CF
214 process_entity *new_entity = add_process_entity_to_list (pr_ent_memory);
215 if (new_entity == NULL)
216 return 0;
0ad10c0f
CF
217 new_entity->type = pr_ent_memory;
218 memory_num++;
219
220 new_entity->u.memory.base = base;
221 new_entity->u.memory.size = size;
222
61522196 223 deb_printf ("added memory region %p-%p\n", base, base + size);
0ad10c0f
CF
224 return 1;
225}
226
0ad10c0f 227int
eedc36cb 228dumper::add_module (LPVOID base_address)
0ad10c0f 229{
eedc36cb
CF
230 if (!sane ())
231 return 0;
0ad10c0f 232
61522196 233 char *module_name = psapi_get_module_name (hProcess, base_address);
eedc36cb
CF
234 if (module_name == NULL)
235 return 1;
0ad10c0f 236
eedc36cb
CF
237 process_entity *new_entity = add_process_entity_to_list (pr_ent_module);
238 if (new_entity == NULL)
239 return 0;
0ad10c0f
CF
240 new_entity->type = pr_ent_module;
241 module_num++;
242
243 new_entity->u.module.base_address = base_address;
244 new_entity->u.module.name = module_name;
245
61522196 246 deb_printf ("added module %p %s\n", base_address, module_name);
0ad10c0f
CF
247 return 1;
248}
249
250#define PAGE_BUFFER_SIZE 4096
251
b40983ed
JT
252void protect_dump(DWORD protect, char *buf)
253{
254 const char *pt[10];
255 pt[0] = (protect & PAGE_READONLY) ? "RO " : "";
256 pt[1] = (protect & PAGE_READWRITE) ? "RW " : "";
257 pt[2] = (protect & PAGE_WRITECOPY) ? "WC " : "";
258 pt[3] = (protect & PAGE_EXECUTE) ? "EX " : "";
259 pt[4] = (protect & PAGE_EXECUTE_READ) ? "EXRO " : "";
260 pt[5] = (protect & PAGE_EXECUTE_READWRITE) ? "EXRW " : "";
261 pt[6] = (protect & PAGE_EXECUTE_WRITECOPY) ? "EXWC " : "";
262 pt[7] = (protect & PAGE_GUARD) ? "GRD " : "";
263 pt[8] = (protect & PAGE_NOACCESS) ? "NA " : "";
264 pt[9] = (protect & PAGE_NOCACHE) ? "NC " : "";
265
266 buf[0] = '\0';
267 for (int i = 0; i < 10; i++)
268 strcat (buf, pt[i]);
269}
270
1be41b80 271#define PSWSEI_ATTRIB_SHARED (0x1 << 15)
b245014a
JT
272
273static BOOL
274getRegionAttributes(HANDLE hProcess, LPVOID address, DWORD &attribs)
275{
1be41b80 276 PSAPI_WORKING_SET_EX_INFORMATION pswsei = { address };
b245014a 277
1be41b80 278 if (QueryWorkingSetEx(hProcess, &pswsei, sizeof(pswsei)))
b245014a 279 {
1be41b80 280 attribs = pswsei.VirtualAttributes.Flags;
b245014a
JT
281 return TRUE;
282 }
283
1be41b80 284 deb_printf("QueryWorkingSetEx failed status %08x\n", GetLastError());
b245014a
JT
285 return FALSE;
286}
287
0ad10c0f
CF
288int
289dumper::collect_memory_sections ()
290{
eedc36cb
CF
291 if (!sane ())
292 return 0;
0ad10c0f
CF
293
294 LPBYTE current_page_address;
2a0e84c8 295 LPBYTE last_base = (LPBYTE) -1;
61522196
CV
296 SIZE_T last_size = (SIZE_T) 0;
297 SIZE_T done;
0ad10c0f 298
eedc36cb 299 char mem_buf[PAGE_BUFFER_SIZE];
0ad10c0f
CF
300
301 MEMORY_BASIC_INFORMATION mbi;
302
eedc36cb
CF
303 if (hProcess == NULL)
304 return 0;
0ad10c0f 305
2a0e84c8 306 for (current_page_address = 0; current_page_address < (LPBYTE) -1;)
0ad10c0f 307 {
eedc36cb
CF
308 if (!VirtualQueryEx (hProcess, current_page_address, &mbi, sizeof (mbi)))
309 break;
0ad10c0f
CF
310
311 int skip_region_p = 0;
b40983ed 312 const char *disposition = "dumped";
0ad10c0f 313
b245014a 314 if (mbi.Type & MEM_IMAGE)
35227fec 315 {
b245014a
JT
316 DWORD attribs = 0;
317 if (getRegionAttributes(hProcess, current_page_address, attribs))
318 {
1be41b80 319 if (attribs & PSWSEI_ATTRIB_SHARED)
b245014a
JT
320 {
321 skip_region_p = 1;
322 disposition = "skipped due to shared MEM_IMAGE";
323 }
324 }
325 /*
326 The undocumented MemoryWorkingSetExInformation is allegedly
327 supported since XP, so should always succeed, but if it fails,
328 fallback to looking at region protection.
329 */
330 else if (!(mbi.Protect & (PAGE_EXECUTE_READWRITE | PAGE_READWRITE)))
331 {
332 skip_region_p = 1;
333 disposition = "skipped due to non-writeable MEM_IMAGE";
334 }
35227fec
JT
335 }
336
b40983ed
JT
337 if (mbi.Protect & PAGE_NOACCESS)
338 {
339 skip_region_p = 1;
340 disposition = "skipped due to noaccess";
341 }
342
343 if (mbi.Protect & PAGE_GUARD)
344 {
345 skip_region_p = 1;
346 disposition = "skipped due to guardpage";
347 }
348
349 if (mbi.State != MEM_COMMIT)
350 {
351 skip_region_p = 1;
352 disposition = "skipped due to uncommited";
353 }
354
355 {
356 char buf[10 * 6];
357 protect_dump(mbi.Protect, buf);
358
359 const char *state = "";
360 const char *type = "";
361
362 if (mbi.State & MEM_COMMIT)
363 {
364 state = "COMMIT";
365 }
366 else if (mbi.State & MEM_FREE)
367 {
368 state = "FREE";
369 type = "FREE";
370 }
371 else if (mbi.State & MEM_RESERVE)
372 {
373 state = "RESERVE";
374 }
375
376 if (mbi.Type & MEM_IMAGE)
377 {
378 type = "IMAGE";
379 }
380 else if (mbi.Type & MEM_MAPPED)
381 {
382 type = "MAPPED";
383 }
384 else if (mbi.Type & MEM_PRIVATE)
385 {
386 type = "PRIVATE";
387 }
388
389 deb_printf ("region 0x%016lx-0x%016lx (protect = %-8s, state = %-7s, type = %-7s, %s)\n",
390 current_page_address,
391 current_page_address + mbi.RegionSize,
392 buf, state, type, disposition);
393 }
eedc36cb
CF
394
395 if (!skip_region_p)
396 {
397 /* just to make sure that later we'll be able to read it.
398 According to MS docs either region is all-readable or
399 all-nonreadable */
400 if (!ReadProcessMemory (hProcess, current_page_address, mem_buf, sizeof (mem_buf), &done))
401 {
d353d5d6 402 DWORD err = GetLastError ();
b40983ed
JT
403
404 deb_printf ("warning: failed to read memory at %p-%p, error %ld.\n",
61522196
CV
405 current_page_address,
406 current_page_address + mbi.RegionSize,
b40983ed 407 err);
0ad10c0f 408 skip_region_p = 1;
eedc36cb
CF
409 }
410 }
411
412 if (!skip_region_p)
413 {
414 if (last_base + last_size == current_page_address)
415 last_size += mbi.RegionSize;
416 else
417 {
44103c06 418 add_mem_region (last_base, last_size);
eedc36cb
CF
419 last_base = (LPBYTE) mbi.BaseAddress;
420 last_size = mbi.RegionSize;
421 }
422 }
0ad10c0f 423 else
eedc36cb 424 {
44103c06 425 add_mem_region (last_base, last_size);
0ad10c0f 426 last_base = NULL;
eedc36cb
CF
427 last_size = 0;
428 }
0ad10c0f
CF
429
430 current_page_address += mbi.RegionSize;
431 }
432
433 /* dump last sections, if any */
44103c06 434 add_mem_region (last_base, last_size);
0ad10c0f
CF
435 return 1;
436};
437
438int
eedc36cb 439dumper::dump_memory_region (asection * to, process_mem_region * memory)
0ad10c0f 440{
eedc36cb
CF
441 if (!sane ())
442 return 0;
0ad10c0f 443
61522196
CV
444 SIZE_T size = memory->size;
445 SIZE_T todo;
446 SIZE_T done;
0ad10c0f
CF
447 LPBYTE pos = memory->base;
448 DWORD sect_pos = 0;
449
eedc36cb
CF
450 if (to == NULL || memory == NULL)
451 return 0;
0ad10c0f 452
eedc36cb 453 char mem_buf[PAGE_BUFFER_SIZE];
0ad10c0f 454
eedc36cb 455 while (size > 0)
0ad10c0f 456 {
9cfc9511 457 todo = MIN (size, PAGE_BUFFER_SIZE);
eedc36cb 458 if (!ReadProcessMemory (hProcess, pos, mem_buf, todo, &done))
0ad10c0f 459 {
d353d5d6 460 deb_printf ("Failed to read process memory at %x(%x), error %ld\n", pos, todo, GetLastError ());
0ad10c0f
CF
461 return 0;
462 }
463 size -= done;
464 pos += done;
eedc36cb
CF
465 if (!bfd_set_section_contents (core_bfd, to, mem_buf, sect_pos, done))
466 {
467 bfd_perror ("writing memory region to bfd");
468 dumper_abort ();
469 return 0;
470 };
0ad10c0f
CF
471 sect_pos += done;
472 }
473 return 1;
474}
475
476int
eedc36cb 477dumper::dump_thread (asection * to, process_thread * thread)
0ad10c0f 478{
eedc36cb
CF
479 if (!sane ())
480 return 0;
0ad10c0f 481
eedc36cb
CF
482 if (to == NULL || thread == NULL)
483 return 0;
0ad10c0f
CF
484
485 win32_pstatus thread_pstatus;
486
487 note_header header;
eedc36cb
CF
488 bfd_putl32 (NOTE_NAME_SIZE, header.elf_note_header.namesz);
489 bfd_putl32 (sizeof (thread_pstatus), header.elf_note_header.descsz);
490 bfd_putl32 (NT_WIN32PSTATUS, header.elf_note_header.type);
6497fdfa
CV
491#pragma GCC diagnostic push
492#pragma GCC diagnostic ignored "-Wstringop-overflow"
d730fa7b 493#pragma GCC diagnostic ignored "-Warray-bounds"
6497fdfa
CV
494 strncpy (header.elf_note_header.name, "win32thread", NOTE_NAME_SIZE);
495#pragma GCC diagnostic pop
0ad10c0f
CF
496
497 thread_pstatus.data_type = NOTE_INFO_THREAD;
498 thread_pstatus.data.thread_info.tid = thread->tid;
499
eedc36cb 500 if (tid == 0)
0ad10c0f
CF
501 {
502 /* this is a special case. we don't know, which thread
4bfc614b
CF
503 was active when exception occured, so let's blame
504 the first one */
eedc36cb
CF
505 thread_pstatus.data.thread_info.is_active_thread = TRUE;
506 tid = (DWORD) - 1;
0ad10c0f 507 }
eedc36cb 508 else if (tid > 0 && thread->tid == tid)
0ad10c0f
CF
509 thread_pstatus.data.thread_info.is_active_thread = TRUE;
510 else
511 thread_pstatus.data.thread_info.is_active_thread = FALSE;
512
eedc36cb
CF
513 memcpy (&(thread_pstatus.data.thread_info.thread_context),
514 &(thread->context),
515 sizeof (thread->context));
0ad10c0f 516
eedc36cb
CF
517 if (!bfd_set_section_contents (core_bfd, to, &header,
518 0,
519 sizeof (header)) ||
520 !bfd_set_section_contents (core_bfd, to, &thread_pstatus,
521 sizeof (header),
522 sizeof (thread_pstatus)))
0ad10c0f 523 {
eedc36cb 524 bfd_perror ("writing thread info to bfd");
0ad10c0f
CF
525 dumper_abort ();
526 return 0;
eedc36cb 527 };
0ad10c0f
CF
528 return 1;
529}
530
531int
eedc36cb 532dumper::dump_module (asection * to, process_module * module)
0ad10c0f 533{
eedc36cb
CF
534 if (!sane ())
535 return 0;
0ad10c0f 536
eedc36cb
CF
537 if (to == NULL || module == NULL)
538 return 0;
0ad10c0f 539
eedc36cb 540 struct win32_pstatus *module_pstatus_ptr;
0ad10c0f 541
eedc36cb 542 int note_length = sizeof (struct win32_pstatus) + strlen (module->name);
0ad10c0f 543
eedc36cb 544 char *buf = (char *) malloc (note_length);
0ad10c0f 545
eedc36cb 546 if (!buf)
0ad10c0f 547 {
eedc36cb 548 fprintf (stderr, "Error alloating memory. Dumping aborted.\n");
0ad10c0f 549 goto out;
eedc36cb 550 };
0ad10c0f 551
eedc36cb 552 module_pstatus_ptr = (struct win32_pstatus *) buf;
0ad10c0f
CF
553
554 note_header header;
eedc36cb
CF
555 bfd_putl32 (NOTE_NAME_SIZE, header.elf_note_header.namesz);
556 bfd_putl32 (note_length, header.elf_note_header.descsz);
557 bfd_putl32 (NT_WIN32PSTATUS, header.elf_note_header.type);
6497fdfa
CV
558#pragma GCC diagnostic push
559#pragma GCC diagnostic ignored "-Wstringop-overflow"
d730fa7b 560#pragma GCC diagnostic ignored "-Warray-bounds"
6497fdfa
CV
561 strncpy (header.elf_note_header.name, "win32module", NOTE_NAME_SIZE);
562#pragma GCC diagnostic pop
0ad10c0f 563
7dd1b088
JT
564#ifdef __x86_64__
565 module_pstatus_ptr->data_type = NOTE_INFO_MODULE64;
566#else
0ad10c0f 567 module_pstatus_ptr->data_type = NOTE_INFO_MODULE;
7dd1b088 568#endif
0ad10c0f 569 module_pstatus_ptr->data.module_info.base_address = module->base_address;
eedc36cb
CF
570 module_pstatus_ptr->data.module_info.module_name_size = strlen (module->name) + 1;
571 strcpy (module_pstatus_ptr->data.module_info.module_name, module->name);
572
573 if (!bfd_set_section_contents (core_bfd, to, &header,
574 0,
575 sizeof (header)) ||
576 !bfd_set_section_contents (core_bfd, to, module_pstatus_ptr,
577 sizeof (header),
578 note_length))
0ad10c0f 579 {
eedc36cb 580 bfd_perror ("writing module info to bfd");
0ad10c0f
CF
581 goto out;
582 };
583 return 1;
584
585out:
eedc36cb
CF
586 if (buf)
587 free (buf);
0ad10c0f
CF
588 dumper_abort ();
589 return 0;
590
591}
592
593int
594dumper::collect_process_information ()
595{
eedc36cb
CF
596 if (!sane ())
597 return 0;
0ad10c0f 598
eedc36cb 599 if (!DebugActiveProcess (pid))
0ad10c0f 600 {
61522196
CV
601 fprintf (stderr, "Cannot attach to process #%u, error %ld",
602 (unsigned int) pid, (long) GetLastError ());
0ad10c0f
CF
603 return 0;
604 }
605
0ad10c0f
CF
606 DEBUG_EVENT current_event;
607
608 while (1)
609 {
c222c1b2 610 if (!WaitForDebugEvent (&current_event, INFINITE))
eedc36cb 611 return 0;
0ad10c0f 612
33bc8247
ED
613 deb_printf ("got debug event %d\n", current_event.dwDebugEventCode);
614
0ad10c0f
CF
615 switch (current_event.dwDebugEventCode)
616 {
617 case CREATE_THREAD_DEBUG_EVENT:
618
eedc36cb
CF
619 if (!add_thread (current_event.dwThreadId,
620 current_event.u.CreateThread.hThread))
0ad10c0f
CF
621 goto failed;
622
623 break;
624
625 case CREATE_PROCESS_DEBUG_EVENT:
626
eedc36cb
CF
627 if (!add_module (current_event.u.CreateProcessInfo.lpBaseOfImage) ||
628 !add_thread (current_event.dwThreadId,
629 current_event.u.CreateProcessInfo.hThread))
630 goto failed;
0ad10c0f
CF
631
632 break;
633
634 case EXIT_PROCESS_DEBUG_EVENT:
635
eedc36cb
CF
636 deb_printf ("debugee quits");
637 ContinueDebugEvent (current_event.dwProcessId,
638 current_event.dwThreadId,
639 DBG_CONTINUE);
0ad10c0f
CF
640
641 return 1;
642
643 break;
644
645 case LOAD_DLL_DEBUG_EVENT:
646
eedc36cb
CF
647 if (!add_module (current_event.u.LoadDll.lpBaseOfDll))
648 goto failed;
0ad10c0f
CF
649
650 break;
651
652 case EXCEPTION_DEBUG_EVENT:
653
eedc36cb 654 collect_memory_sections ();
0ad10c0f 655
eedc36cb 656 /* got all info. time to dump */
0ad10c0f 657
eedc36cb 658 if (!prepare_core_dump ())
0ad10c0f 659 {
eedc36cb 660 fprintf (stderr, "Failed to prepare core dump\n");
0ad10c0f
CF
661 goto failed;
662 };
663
eedc36cb 664 if (!write_core_dump ())
0ad10c0f 665 {
eedc36cb 666 fprintf (stderr, "Failed to write core dump\n");
0ad10c0f
CF
667 goto failed;
668 };
669
c222c1b2
JT
670 /* We're done */
671 goto failed;
672
0ad10c0f
CF
673 break;
674
675 default:
676
677 break;
678
679 }
680
eedc36cb
CF
681 ContinueDebugEvent (current_event.dwProcessId,
682 current_event.dwThreadId,
683 DBG_CONTINUE);
0ad10c0f 684 }
a5218ff7 685
0ad10c0f 686failed:
a5218ff7
JT
687 if (nokill)
688 {
689 if (!DebugActiveProcessStop (pid))
690 {
691 fprintf (stderr, "Cannot detach from process #%u, error %ld",
692 (unsigned int) pid, (long) GetLastError ());
693 }
694 }
695 /* Otherwise, the debuggee is terminated when this process exits
696 (as DebugSetProcessKillOnExit() defaults to TRUE) */
697
0ad10c0f
CF
698 return 0;
699}
700
701int
702dumper::init_core_dump ()
703{
704 bfd_init ();
705
38f88601
JT
706#ifdef __x86_64__
707 const char *target = "elf64-x86-64";
708#else
709 const char *target = "elf32-i386";
710#endif
711
712 core_bfd = bfd_openw (file_name, target);
eedc36cb 713 if (core_bfd == NULL)
0ad10c0f 714 {
eedc36cb 715 bfd_perror ("opening bfd");
0ad10c0f
CF
716 goto failed;
717 }
718
eedc36cb 719 if (!bfd_set_format (core_bfd, bfd_core))
0ad10c0f 720 {
eedc36cb 721 bfd_perror ("setting bfd format");
0ad10c0f
CF
722 goto failed;
723 }
724
38f88601 725 if (!bfd_set_arch_mach (core_bfd, bfd_arch_i386, 0 /* = default */))
3ee14d68
ED
726 {
727 bfd_perror ("setting bfd architecture");
728 goto failed;
729 }
730
0ad10c0f
CF
731 return 1;
732
733failed:
734 dumper_abort ();
735 return 0;
736
737}
738
739int
740dumper::prepare_core_dump ()
741{
eedc36cb
CF
742 if (!sane ())
743 return 0;
0ad10c0f
CF
744
745 int sect_no = 0;
eedc36cb 746 char sect_name[50];
0ad10c0f
CF
747
748 flagword sect_flags;
61522196 749 SIZE_T sect_size;
0ad10c0f
CF
750 bfd_vma sect_vma;
751
eedc36cb 752 asection *new_section;
0ad10c0f 753
eedc36cb 754 for (process_entity * p = list; p != NULL; p = p->next)
0ad10c0f
CF
755 {
756 sect_no++;
757
8a11b13f
CV
758 unsigned long phdr_type = PT_LOAD;
759
eedc36cb
CF
760 switch (p->type)
761 {
762 case pr_ent_memory:
763 sprintf (sect_name, ".mem/%u", sect_no);
764 sect_flags = SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD;
765 sect_size = p->u.memory.size;
766 sect_vma = (bfd_vma) (p->u.memory.base);
8a11b13f 767 phdr_type = PT_LOAD;
eedc36cb
CF
768 break;
769
770 case pr_ent_thread:
771 sprintf (sect_name, ".note/%u", sect_no);
772 sect_flags = SEC_HAS_CONTENTS | SEC_LOAD;
773 sect_size = sizeof (note_header) + sizeof (struct win32_pstatus);
774 sect_vma = 0;
8a11b13f 775 phdr_type = PT_NOTE;
0ad10c0f
CF
776 break;
777
eedc36cb
CF
778 case pr_ent_module:
779 sprintf (sect_name, ".note/%u", sect_no);
780 sect_flags = SEC_HAS_CONTENTS | SEC_LOAD;
781 sect_size = sizeof (note_header) + sizeof (struct win32_pstatus) +
782 (bfd_size_type) (strlen (p->u.module.name));
783 sect_vma = 0;
8a11b13f 784 phdr_type = PT_NOTE;
eedc36cb 785 break;
0ad10c0f 786
eedc36cb 787 default:
0ad10c0f 788 continue;
eedc36cb 789 }
0ad10c0f 790
eedc36cb
CF
791 if (p->type == pr_ent_module && status_section != NULL)
792 {
ba2f251d
JT
793 if (!set_section_size (core_bfd,
794 status_section,
795 (get_section_size (status_section)
796 + sect_size)))
0ad10c0f 797 {
eedc36cb 798 bfd_perror ("resizing status section");
0ad10c0f
CF
799 goto failed;
800 };
eedc36cb
CF
801 continue;
802 }
0ad10c0f 803
eedc36cb
CF
804 deb_printf ("creating section (type%u) %s(%u), flags=%08x\n",
805 p->type, sect_name, sect_size, sect_flags);
0ad10c0f 806
33bc8247 807 bfd_set_error (bfd_error_no_error);
eedc36cb
CF
808 char *buf = strdup (sect_name);
809 new_section = bfd_make_section (core_bfd, buf);
33bc8247
ED
810 if (new_section == NULL)
811 {
812 if (bfd_get_error () == bfd_error_no_error)
813 fprintf (stderr, "error creating new section (%s), section already exists.\n", buf);
814 else
815 bfd_perror ("creating section");
816 goto failed;
817 }
0ad10c0f 818
ba2f251d
JT
819 if (!set_section_flags (core_bfd, new_section, sect_flags) ||
820 !set_section_size (core_bfd, new_section, sect_size))
0ad10c0f 821 {
33bc8247 822 bfd_perror ("setting section attributes");
0ad10c0f
CF
823 goto failed;
824 };
825
826 new_section->vma = sect_vma;
8a11b13f 827 new_section->lma = 0;
0ad10c0f
CF
828 new_section->output_section = new_section;
829 new_section->output_offset = 0;
830 p->section = new_section;
8a11b13f
CV
831 int section_count = 1;
832
833 bfd_boolean filehdr = 0;
834 bfd_boolean phdrs = 0;
835
836 bfd_vma at = 0;
837 bfd_boolean valid_at = 0;
838
839 flagword flags = 0;
840 bfd_boolean valid_flags = 1;
841
842 if (p->type == pr_ent_memory)
843 {
844 MEMORY_BASIC_INFORMATION mbi;
845 if (!VirtualQueryEx (hProcess, (LPVOID)sect_vma, &mbi, sizeof (mbi)))
846 {
847 bfd_perror ("getting mem region flags");
848 goto failed;
849 }
850
851 static const struct
852 {
853 DWORD protect;
854 flagword flags;
855 } mappings[] =
856 {
857 { PAGE_READONLY, PF_R },
858 { PAGE_READWRITE, PF_R | PF_W },
859 { PAGE_WRITECOPY, PF_W },
860 { PAGE_EXECUTE, PF_X },
861 { PAGE_EXECUTE_READ, PF_X | PF_R },
862 { PAGE_EXECUTE_READWRITE, PF_X | PF_R | PF_W },
863 { PAGE_EXECUTE_WRITECOPY, PF_X | PF_W }
864 };
865
866 for (size_t i = 0;
867 i < sizeof (mappings) / sizeof (mappings[0]);
868 i++)
869 if ((mbi.Protect & mappings[i].protect) != 0)
870 flags |= mappings[i].flags;
871 }
0ad10c0f 872
8a11b13f
CV
873 if (!bfd_record_phdr (core_bfd, phdr_type,
874 valid_flags, flags,
875 valid_at, at,
876 filehdr, phdrs,
877 section_count, &new_section))
878 {
879 bfd_perror ("recording program headers");
880 goto failed;
881 }
882 }
0ad10c0f
CF
883 return 1;
884
885failed:
886 dumper_abort ();
887 return 0;
888}
889
890int
891dumper::write_core_dump ()
892{
eedc36cb
CF
893 if (!sane ())
894 return 0;
0ad10c0f 895
eedc36cb 896 for (process_entity * p = list; p != NULL; p = p->next)
0ad10c0f 897 {
eedc36cb
CF
898 if (p->section == NULL)
899 continue;
900
61522196 901 deb_printf ("writing section type=%u base=%p size=%p flags=%08x\n",
eedc36cb
CF
902 p->type,
903 p->section->vma,
ba2f251d 904 get_section_size (p->section),
eedc36cb
CF
905 p->section->flags);
906
907 switch (p->type)
908 {
909 case pr_ent_memory:
910 dump_memory_region (p->section, &(p->u.memory));
0ad10c0f
CF
911 break;
912
eedc36cb
CF
913 case pr_ent_thread:
914 dump_thread (p->section, &(p->u.thread));
915 break;
916
917 case pr_ent_module:
918 dump_module (p->section, &(p->u.module));
919 break;
0ad10c0f 920
eedc36cb 921 default:
0ad10c0f
CF
922 continue;
923
eedc36cb 924 }
0ad10c0f
CF
925 }
926 return 1;
927}
928
e7fca6f8 929static void __attribute__ ((__noreturn__))
84d06cb6
CF
930usage (FILE *stream, int status)
931{
932 fprintf (stream, "\
92b499ac
CV
933Usage: %s [OPTION] FILENAME WIN32PID\n\
934\n\
84d06cb6 935Dump core from WIN32PID to FILENAME.core\n\
aa275fe0 936\n\
a5218ff7 937 -n, --nokill don't terminate the dumped process\n\
84d06cb6
CF
938 -d, --verbose be verbose while dumping\n\
939 -h, --help output help information and exit\n\
940 -q, --quiet be quiet while dumping (default)\n\
92b499ac
CV
941 -V, --version output version information and exit\n\
942\n", program_invocation_short_name);
84d06cb6
CF
943 exit (status);
944}
945
946struct option longopts[] = {
a5218ff7 947 {"nokill", no_argument, NULL, 'n'},
84d06cb6
CF
948 {"verbose", no_argument, NULL, 'd'},
949 {"help", no_argument, NULL, 'h'},
950 {"quiet", no_argument, NULL, 'q'},
92b499ac 951 {"version", no_argument, 0, 'V'},
84d06cb6
CF
952 {0, no_argument, NULL, 0}
953};
a5218ff7 954const char *opts = "ndhqV";
84d06cb6 955
4bfc614b 956static void
84d06cb6 957print_version ()
0ad10c0f 958{
92b499ac 959 printf ("dumper (cygwin) %d.%d.%d\n"
1b23b30b 960 "Core Dumper for Cygwin\n"
6e623e93 961 "Copyright (C) 1999 - %s Cygwin Authors\n"
1b23b30b 962 "This is free software; see the source for copying conditions. There is NO\n"
92b499ac 963 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
1b23b30b
CF
964 CYGWIN_VERSION_DLL_MAJOR / 1000,
965 CYGWIN_VERSION_DLL_MAJOR % 1000,
966 CYGWIN_VERSION_DLL_MINOR,
967 strrchr (__DATE__, ' ') + 1);
0ad10c0f
CF
968}
969
970int
eedc36cb 971main (int argc, char **argv)
0ad10c0f
CF
972{
973 int opt;
ce475802 974 const char *p = "";
0ad10c0f
CF
975 DWORD pid;
976
92b499ac 977 while ((opt = getopt_long (argc, argv, opts, longopts, NULL) ) != EOF)
0ad10c0f
CF
978 switch (opt)
979 {
a5218ff7
JT
980 case 'n':
981 nokill = TRUE;
982 break;
0ad10c0f
CF
983 case 'd':
984 verbose = TRUE;
985 break;
92ef5188
ED
986 case 'q':
987 verbose = FALSE;
988 break;
84d06cb6
CF
989 case 'h':
990 usage (stdout, 0);
92b499ac
CV
991 case 'V':
992 print_version ();
993 exit (0);
92ef5188 994 default:
92b499ac
CV
995 fprintf (stderr, "Try `%s --help' for more information.\n",
996 program_invocation_short_name);
997 exit (1);
0ad10c0f
CF
998 }
999
92ef5188 1000 if (argv && *(argv + optind) && *(argv + optind +1))
0ad10c0f 1001 {
2b2b42cf
CV
1002 ssize_t len = cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_RELATIVE,
1003 *(argv + optind), NULL, 0);
1004 char *win32_name = (char *) alloca (len);
1005 cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_RELATIVE, *(argv + optind),
1006 win32_name, len);
92ef5188
ED
1007 if ((p = strrchr (win32_name, '\\')))
1008 p++;
1009 else
1010 p = win32_name;
4e8b5fc3 1011 pid = strtoul (*(argv + optind + 1), NULL, 10);
0ad10c0f 1012 }
0ad10c0f
CF
1013 else
1014 {
84d06cb6 1015 usage (stderr, 1);
0ad10c0f
CF
1016 return -1;
1017 }
1018
92ef5188
ED
1019 char *core_file = (char *) malloc (strlen (p) + sizeof (".core"));
1020 if (!core_file)
1021 {
1022 fprintf (stderr, "error allocating memory\n");
1023 return -1;
1024 }
1025 sprintf (core_file, "%s.core", p);
1026
0ad10c0f
CF
1027 DWORD tid = 0;
1028
eedc36cb 1029 if (verbose)
61522196 1030 printf ("dumping process #%u to %s\n", (unsigned int) pid, core_file);
0ad10c0f 1031
eedc36cb
CF
1032 dumper d (pid, tid, core_file);
1033 if (!d.sane ())
0ad10c0f
CF
1034 return -1;
1035 d.collect_process_information ();
eedc36cb 1036 free (core_file);
0ad10c0f
CF
1037
1038 return 0;
1039};
This page took 0.472985 seconds and 5 git commands to generate.