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