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