]> sourceware.org Git - newlib-cygwin.git/blob - 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
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 #include <psapi.h>
38
39 #include "dumper.h"
40
41 #define NOTE_NAME_SIZE 16
42
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
57 typedef struct _note_header
58 {
59 Elf_External_Note elf_note_header;
60 char name[NOTE_NAME_SIZE - 1]; /* external note contains first byte of data */
61 }
62 #ifdef __GNUC__
63 __attribute__ ((packed))
64 #endif
65 note_header;
66
67 BOOL verbose = FALSE;
68 BOOL nokill = FALSE;
69
70 int deb_printf (const char *format,...)
71 {
72 if (!verbose)
73 return 0;
74 va_list va;
75 va_start (va, format);
76 int ret_val = vprintf (format, va);
77 va_end (va);
78 return ret_val;
79 }
80
81 dumper::dumper (DWORD pid, DWORD tid, const char *file_name)
82 {
83 this->file_name = strdup (file_name);
84
85 this->pid = pid;
86 this->tid = tid;
87 core_bfd = NULL;
88
89 list = last = NULL;
90
91 status_section = NULL;
92
93 memory_num = module_num = thread_num = 0;
94
95 hProcess = OpenProcess (PROCESS_ALL_ACCESS,
96 FALSE, /* no inheritance */
97 pid);
98 if (!hProcess)
99 {
100 fprintf (stderr, "Failed to open process #%u, error %ld\n",
101 (unsigned int) pid, (long) GetLastError ());
102 return;
103 }
104
105 init_core_dump ();
106
107 if (!sane ())
108 dumper_abort ();
109 }
110
111 dumper::~dumper ()
112 {
113 close ();
114 free (file_name);
115 }
116
117 void
118 dumper::dumper_abort ()
119 {
120 close ();
121 unlink (file_name);
122 }
123
124 void
125 dumper::close ()
126 {
127 if (core_bfd)
128 bfd_close (core_bfd);
129 if (hProcess)
130 CloseHandle (hProcess);
131 core_bfd = NULL;
132 hProcess = NULL;
133 }
134
135 int
136 dumper::sane ()
137 {
138 if (hProcess == NULL || core_bfd == NULL)
139 return 0;
140 return 1;
141 }
142
143 void
144 print_section_name (bfd* abfd, asection* sect, PTR obj)
145 {
146 deb_printf (" %s", get_section_name (abfd, sect));
147 }
148
149 void
150 dumper::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
157 process_entity *
158 dumper::add_process_entity_to_list (process_entity_type type)
159 {
160 if (!sane ())
161 return NULL;
162
163 process_entity *new_entity = (process_entity *) malloc (sizeof (process_entity));
164 if (new_entity == NULL)
165 return NULL;
166 new_entity->next = NULL;
167 new_entity->section = NULL;
168 if (last == NULL)
169 list = new_entity;
170 else
171 last->next = new_entity;
172 last = new_entity;
173 return new_entity;
174 }
175
176 int
177 dumper::add_thread (DWORD tid, HANDLE hThread)
178 {
179 if (!sane ())
180 return 0;
181
182 CONTEXT *pcontext;
183
184 process_entity *new_entity = add_process_entity_to_list (pr_ent_thread);
185 if (new_entity == NULL)
186 return 0;
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
193 pcontext = &(new_entity->u.thread.context);
194 pcontext->ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT;
195 if (!GetThreadContext (hThread, pcontext))
196 {
197 deb_printf ("Failed to read thread context (tid=%x), error %ld\n", tid, GetLastError ());
198 return 0;
199 }
200
201 deb_printf ("added thread %u\n", tid);
202 return 1;
203 }
204
205 int
206 dumper::add_mem_region (LPBYTE base, SIZE_T size)
207 {
208 if (!sane ())
209 return 0;
210
211 if (base == NULL || size == 0)
212 return 1; // just ignore empty regions
213
214 process_entity *new_entity = add_process_entity_to_list (pr_ent_memory);
215 if (new_entity == NULL)
216 return 0;
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
223 deb_printf ("added memory region %p-%p\n", base, base + size);
224 return 1;
225 }
226
227 int
228 dumper::add_module (LPVOID base_address)
229 {
230 if (!sane ())
231 return 0;
232
233 char *module_name = psapi_get_module_name (hProcess, base_address);
234 if (module_name == NULL)
235 return 1;
236
237 process_entity *new_entity = add_process_entity_to_list (pr_ent_module);
238 if (new_entity == NULL)
239 return 0;
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
246 deb_printf ("added module %p %s\n", base_address, module_name);
247 return 1;
248 }
249
250 #define PAGE_BUFFER_SIZE 4096
251
252 void 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
271 #define PSWSEI_ATTRIB_SHARED (0x1 << 15)
272
273 static BOOL
274 getRegionAttributes(HANDLE hProcess, LPVOID address, DWORD &attribs)
275 {
276 PSAPI_WORKING_SET_EX_INFORMATION pswsei = { address };
277
278 if (QueryWorkingSetEx(hProcess, &pswsei, sizeof(pswsei)))
279 {
280 attribs = pswsei.VirtualAttributes.Flags;
281 return TRUE;
282 }
283
284 deb_printf("QueryWorkingSetEx failed status %08x\n", GetLastError());
285 return FALSE;
286 }
287
288 int
289 dumper::collect_memory_sections ()
290 {
291 if (!sane ())
292 return 0;
293
294 LPBYTE current_page_address;
295 LPBYTE last_base = (LPBYTE) -1;
296 SIZE_T last_size = (SIZE_T) 0;
297 SIZE_T done;
298
299 char mem_buf[PAGE_BUFFER_SIZE];
300
301 MEMORY_BASIC_INFORMATION mbi;
302
303 if (hProcess == NULL)
304 return 0;
305
306 for (current_page_address = 0; current_page_address < (LPBYTE) -1;)
307 {
308 if (!VirtualQueryEx (hProcess, current_page_address, &mbi, sizeof (mbi)))
309 break;
310
311 int skip_region_p = 0;
312 const char *disposition = "dumped";
313
314 if (mbi.Type & MEM_IMAGE)
315 {
316 DWORD attribs = 0;
317 if (getRegionAttributes(hProcess, current_page_address, attribs))
318 {
319 if (attribs & PSWSEI_ATTRIB_SHARED)
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 }
335 }
336
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 }
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 {
402 DWORD err = GetLastError ();
403
404 deb_printf ("warning: failed to read memory at %p-%p, error %ld.\n",
405 current_page_address,
406 current_page_address + mbi.RegionSize,
407 err);
408 skip_region_p = 1;
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 {
418 add_mem_region (last_base, last_size);
419 last_base = (LPBYTE) mbi.BaseAddress;
420 last_size = mbi.RegionSize;
421 }
422 }
423 else
424 {
425 add_mem_region (last_base, last_size);
426 last_base = NULL;
427 last_size = 0;
428 }
429
430 current_page_address += mbi.RegionSize;
431 }
432
433 /* dump last sections, if any */
434 add_mem_region (last_base, last_size);
435 return 1;
436 };
437
438 int
439 dumper::dump_memory_region (asection * to, process_mem_region * memory)
440 {
441 if (!sane ())
442 return 0;
443
444 SIZE_T size = memory->size;
445 SIZE_T todo;
446 SIZE_T done;
447 LPBYTE pos = memory->base;
448 DWORD sect_pos = 0;
449
450 if (to == NULL || memory == NULL)
451 return 0;
452
453 char mem_buf[PAGE_BUFFER_SIZE];
454
455 while (size > 0)
456 {
457 todo = MIN (size, PAGE_BUFFER_SIZE);
458 if (!ReadProcessMemory (hProcess, pos, mem_buf, todo, &done))
459 {
460 deb_printf ("Failed to read process memory at %x(%x), error %ld\n", pos, todo, GetLastError ());
461 return 0;
462 }
463 size -= done;
464 pos += done;
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 };
471 sect_pos += done;
472 }
473 return 1;
474 }
475
476 int
477 dumper::dump_thread (asection * to, process_thread * thread)
478 {
479 if (!sane ())
480 return 0;
481
482 if (to == NULL || thread == NULL)
483 return 0;
484
485 win32_pstatus thread_pstatus;
486
487 note_header header;
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);
491 #pragma GCC diagnostic push
492 #pragma GCC diagnostic ignored "-Wstringop-overflow"
493 #pragma GCC diagnostic ignored "-Warray-bounds"
494 strncpy (header.elf_note_header.name, "win32thread", NOTE_NAME_SIZE);
495 #pragma GCC diagnostic pop
496
497 thread_pstatus.data_type = NOTE_INFO_THREAD;
498 thread_pstatus.data.thread_info.tid = thread->tid;
499
500 if (tid == 0)
501 {
502 /* this is a special case. we don't know, which thread
503 was active when exception occured, so let's blame
504 the first one */
505 thread_pstatus.data.thread_info.is_active_thread = TRUE;
506 tid = (DWORD) - 1;
507 }
508 else if (tid > 0 && thread->tid == tid)
509 thread_pstatus.data.thread_info.is_active_thread = TRUE;
510 else
511 thread_pstatus.data.thread_info.is_active_thread = FALSE;
512
513 memcpy (&(thread_pstatus.data.thread_info.thread_context),
514 &(thread->context),
515 sizeof (thread->context));
516
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)))
523 {
524 bfd_perror ("writing thread info to bfd");
525 dumper_abort ();
526 return 0;
527 };
528 return 1;
529 }
530
531 int
532 dumper::dump_module (asection * to, process_module * module)
533 {
534 if (!sane ())
535 return 0;
536
537 if (to == NULL || module == NULL)
538 return 0;
539
540 struct win32_pstatus *module_pstatus_ptr;
541
542 int note_length = sizeof (struct win32_pstatus) + strlen (module->name);
543
544 char *buf = (char *) malloc (note_length);
545
546 if (!buf)
547 {
548 fprintf (stderr, "Error alloating memory. Dumping aborted.\n");
549 goto out;
550 };
551
552 module_pstatus_ptr = (struct win32_pstatus *) buf;
553
554 note_header header;
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);
558 #pragma GCC diagnostic push
559 #pragma GCC diagnostic ignored "-Wstringop-overflow"
560 #pragma GCC diagnostic ignored "-Warray-bounds"
561 strncpy (header.elf_note_header.name, "win32module", NOTE_NAME_SIZE);
562 #pragma GCC diagnostic pop
563
564 #ifdef __x86_64__
565 module_pstatus_ptr->data_type = NOTE_INFO_MODULE64;
566 #else
567 module_pstatus_ptr->data_type = NOTE_INFO_MODULE;
568 #endif
569 module_pstatus_ptr->data.module_info.base_address = module->base_address;
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))
579 {
580 bfd_perror ("writing module info to bfd");
581 goto out;
582 };
583 return 1;
584
585 out:
586 if (buf)
587 free (buf);
588 dumper_abort ();
589 return 0;
590
591 }
592
593 int
594 dumper::collect_process_information ()
595 {
596 if (!sane ())
597 return 0;
598
599 if (!DebugActiveProcess (pid))
600 {
601 fprintf (stderr, "Cannot attach to process #%u, error %ld",
602 (unsigned int) pid, (long) GetLastError ());
603 return 0;
604 }
605
606 DEBUG_EVENT current_event;
607
608 while (1)
609 {
610 if (!WaitForDebugEvent (&current_event, INFINITE))
611 return 0;
612
613 deb_printf ("got debug event %d\n", current_event.dwDebugEventCode);
614
615 switch (current_event.dwDebugEventCode)
616 {
617 case CREATE_THREAD_DEBUG_EVENT:
618
619 if (!add_thread (current_event.dwThreadId,
620 current_event.u.CreateThread.hThread))
621 goto failed;
622
623 break;
624
625 case CREATE_PROCESS_DEBUG_EVENT:
626
627 if (!add_module (current_event.u.CreateProcessInfo.lpBaseOfImage) ||
628 !add_thread (current_event.dwThreadId,
629 current_event.u.CreateProcessInfo.hThread))
630 goto failed;
631
632 break;
633
634 case EXIT_PROCESS_DEBUG_EVENT:
635
636 deb_printf ("debugee quits");
637 ContinueDebugEvent (current_event.dwProcessId,
638 current_event.dwThreadId,
639 DBG_CONTINUE);
640
641 return 1;
642
643 break;
644
645 case LOAD_DLL_DEBUG_EVENT:
646
647 if (!add_module (current_event.u.LoadDll.lpBaseOfDll))
648 goto failed;
649
650 break;
651
652 case EXCEPTION_DEBUG_EVENT:
653
654 collect_memory_sections ();
655
656 /* got all info. time to dump */
657
658 if (!prepare_core_dump ())
659 {
660 fprintf (stderr, "Failed to prepare core dump\n");
661 goto failed;
662 };
663
664 if (!write_core_dump ())
665 {
666 fprintf (stderr, "Failed to write core dump\n");
667 goto failed;
668 };
669
670 /* We're done */
671 goto failed;
672
673 break;
674
675 default:
676
677 break;
678
679 }
680
681 ContinueDebugEvent (current_event.dwProcessId,
682 current_event.dwThreadId,
683 DBG_CONTINUE);
684 }
685
686 failed:
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
698 return 0;
699 }
700
701 int
702 dumper::init_core_dump ()
703 {
704 bfd_init ();
705
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);
713 if (core_bfd == NULL)
714 {
715 bfd_perror ("opening bfd");
716 goto failed;
717 }
718
719 if (!bfd_set_format (core_bfd, bfd_core))
720 {
721 bfd_perror ("setting bfd format");
722 goto failed;
723 }
724
725 if (!bfd_set_arch_mach (core_bfd, bfd_arch_i386, 0 /* = default */))
726 {
727 bfd_perror ("setting bfd architecture");
728 goto failed;
729 }
730
731 return 1;
732
733 failed:
734 dumper_abort ();
735 return 0;
736
737 }
738
739 int
740 dumper::prepare_core_dump ()
741 {
742 if (!sane ())
743 return 0;
744
745 int sect_no = 0;
746 char sect_name[50];
747
748 flagword sect_flags;
749 SIZE_T sect_size;
750 bfd_vma sect_vma;
751
752 asection *new_section;
753
754 for (process_entity * p = list; p != NULL; p = p->next)
755 {
756 sect_no++;
757
758 unsigned long phdr_type = PT_LOAD;
759
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);
767 phdr_type = PT_LOAD;
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;
775 phdr_type = PT_NOTE;
776 break;
777
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;
784 phdr_type = PT_NOTE;
785 break;
786
787 default:
788 continue;
789 }
790
791 if (p->type == pr_ent_module && status_section != NULL)
792 {
793 if (!set_section_size (core_bfd,
794 status_section,
795 (get_section_size (status_section)
796 + sect_size)))
797 {
798 bfd_perror ("resizing status section");
799 goto failed;
800 };
801 continue;
802 }
803
804 deb_printf ("creating section (type%u) %s(%u), flags=%08x\n",
805 p->type, sect_name, sect_size, sect_flags);
806
807 bfd_set_error (bfd_error_no_error);
808 char *buf = strdup (sect_name);
809 new_section = bfd_make_section (core_bfd, buf);
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 }
818
819 if (!set_section_flags (core_bfd, new_section, sect_flags) ||
820 !set_section_size (core_bfd, new_section, sect_size))
821 {
822 bfd_perror ("setting section attributes");
823 goto failed;
824 };
825
826 new_section->vma = sect_vma;
827 new_section->lma = 0;
828 new_section->output_section = new_section;
829 new_section->output_offset = 0;
830 p->section = new_section;
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 }
872
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 }
883 return 1;
884
885 failed:
886 dumper_abort ();
887 return 0;
888 }
889
890 int
891 dumper::write_core_dump ()
892 {
893 if (!sane ())
894 return 0;
895
896 for (process_entity * p = list; p != NULL; p = p->next)
897 {
898 if (p->section == NULL)
899 continue;
900
901 deb_printf ("writing section type=%u base=%p size=%p flags=%08x\n",
902 p->type,
903 p->section->vma,
904 get_section_size (p->section),
905 p->section->flags);
906
907 switch (p->type)
908 {
909 case pr_ent_memory:
910 dump_memory_region (p->section, &(p->u.memory));
911 break;
912
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;
920
921 default:
922 continue;
923
924 }
925 }
926 return 1;
927 }
928
929 static void __attribute__ ((__noreturn__))
930 usage (FILE *stream, int status)
931 {
932 fprintf (stream, "\
933 Usage: %s [OPTION] FILENAME WIN32PID\n\
934 \n\
935 Dump core from WIN32PID to FILENAME.core\n\
936 \n\
937 -n, --nokill don't terminate the dumped process\n\
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\
941 -V, --version output version information and exit\n\
942 \n", program_invocation_short_name);
943 exit (status);
944 }
945
946 struct option longopts[] = {
947 {"nokill", no_argument, NULL, 'n'},
948 {"verbose", no_argument, NULL, 'd'},
949 {"help", no_argument, NULL, 'h'},
950 {"quiet", no_argument, NULL, 'q'},
951 {"version", no_argument, 0, 'V'},
952 {0, no_argument, NULL, 0}
953 };
954 const char *opts = "ndhqV";
955
956 static void
957 print_version ()
958 {
959 printf ("dumper (cygwin) %d.%d.%d\n"
960 "Core Dumper for Cygwin\n"
961 "Copyright (C) 1999 - %s Cygwin Authors\n"
962 "This is free software; see the source for copying conditions. There is NO\n"
963 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
964 CYGWIN_VERSION_DLL_MAJOR / 1000,
965 CYGWIN_VERSION_DLL_MAJOR % 1000,
966 CYGWIN_VERSION_DLL_MINOR,
967 strrchr (__DATE__, ' ') + 1);
968 }
969
970 int
971 main (int argc, char **argv)
972 {
973 int opt;
974 const char *p = "";
975 DWORD pid;
976
977 while ((opt = getopt_long (argc, argv, opts, longopts, NULL) ) != EOF)
978 switch (opt)
979 {
980 case 'n':
981 nokill = TRUE;
982 break;
983 case 'd':
984 verbose = TRUE;
985 break;
986 case 'q':
987 verbose = FALSE;
988 break;
989 case 'h':
990 usage (stdout, 0);
991 case 'V':
992 print_version ();
993 exit (0);
994 default:
995 fprintf (stderr, "Try `%s --help' for more information.\n",
996 program_invocation_short_name);
997 exit (1);
998 }
999
1000 if (argv && *(argv + optind) && *(argv + optind +1))
1001 {
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);
1007 if ((p = strrchr (win32_name, '\\')))
1008 p++;
1009 else
1010 p = win32_name;
1011 pid = strtoul (*(argv + optind + 1), NULL, 10);
1012 }
1013 else
1014 {
1015 usage (stderr, 1);
1016 return -1;
1017 }
1018
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
1027 DWORD tid = 0;
1028
1029 if (verbose)
1030 printf ("dumping process #%u to %s\n", (unsigned int) pid, core_file);
1031
1032 dumper d (pid, tid, core_file);
1033 if (!d.sane ())
1034 return -1;
1035 d.collect_process_information ();
1036 free (core_file);
1037
1038 return 0;
1039 };
This page took 0.07904 seconds and 5 git commands to generate.