3 Copyright 1999, 2001, 2002, 2004, 2006, 2007, 2011 Red Hat Inc.
5 Written by Egor Duda <deo@logos-m.ru>
7 This file is part of Cygwin.
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.
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.
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. */
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>
37 #include <sys/param.h>
42 #define NOTE_NAME_SIZE 16
44 typedef struct _note_header
46 Elf_External_Note elf_note_header
;
47 char name
[NOTE_NAME_SIZE
- 1]; /* external note contains first byte of data */
50 __attribute__ ((packed
))
56 int deb_printf (const char *format
,...)
61 va_start (va
, format
);
62 int ret_val
= vprintf (format
, va
);
67 dumper::dumper (DWORD pid
, DWORD tid
, const char *file_name
)
69 this->file_name
= strdup (file_name
);
74 excl_list
= new exclusion (20);
78 status_section
= NULL
;
80 memory_num
= module_num
= thread_num
= 0;
82 hProcess
= OpenProcess (PROCESS_ALL_ACCESS
,
83 FALSE
, /* no inheritance */
87 fprintf (stderr
, "Failed to open process #%lu, error %ld\n", pid
, GetLastError ());
104 dumper::dumper_abort ()
114 bfd_close (core_bfd
);
118 CloseHandle (hProcess
);
127 if (hProcess
== NULL
|| core_bfd
== NULL
|| excl_list
== NULL
)
133 print_section_name (bfd
* abfd
, asection
* sect
, PTR obj
)
135 deb_printf (" %s", bfd_get_section_name (abfd
, sect
));
139 dumper::print_core_section_list ()
141 deb_printf ("current sections:");
142 bfd_map_over_sections (core_bfd
, &print_section_name
, NULL
);
147 dumper::add_process_entity_to_list (process_entity_type type
)
152 process_entity
*new_entity
= (process_entity
*) malloc (sizeof (process_entity
));
153 if (new_entity
== NULL
)
155 new_entity
->next
= NULL
;
156 new_entity
->section
= NULL
;
160 last
->next
= new_entity
;
166 dumper::add_thread (DWORD tid
, HANDLE hThread
)
173 process_entity
*new_entity
= add_process_entity_to_list (pr_ent_thread
);
174 if (new_entity
== NULL
)
176 new_entity
->type
= pr_ent_thread
;
179 new_entity
->u
.thread
.tid
= tid
;
180 new_entity
->u
.thread
.hThread
= hThread
;
182 pcontext
= &(new_entity
->u
.thread
.context
);
183 pcontext
->ContextFlags
= CONTEXT_FULL
| CONTEXT_FLOATING_POINT
;
184 if (!GetThreadContext (hThread
, pcontext
))
186 deb_printf ("Failed to read thread context (tid=%x), error %ld\n", tid
, GetLastError ());
190 deb_printf ("added thread %u\n", tid
);
195 dumper::add_mem_region (LPBYTE base
, DWORD size
)
200 if (base
== NULL
|| size
== 0)
201 return 1; // just ignore empty regions
203 process_entity
*new_entity
= add_process_entity_to_list (pr_ent_memory
);
204 if (new_entity
== NULL
)
206 new_entity
->type
= pr_ent_memory
;
209 new_entity
->u
.memory
.base
= base
;
210 new_entity
->u
.memory
.size
= size
;
212 deb_printf ("added memory region %08x-%08x\n", (DWORD
) base
, (DWORD
) base
+ size
);
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. */
219 dumper::split_add_mem_region (LPBYTE base
, DWORD size
)
224 if (base
== NULL
|| size
== 0)
225 return 1; // just ignore empty regions
227 LPBYTE last_base
= base
;
229 for (process_mem_region
* p
= excl_list
->region
;
230 p
< excl_list
->region
+ excl_list
->last
;
233 if (p
->base
>= base
+ size
|| p
->base
+ p
->size
<= base
)
238 last_base
= p
->base
+ p
->size
;
242 add_mem_region (last_base
, p
->base
- last_base
);
243 last_base
= p
->base
+ p
->size
;
246 if (last_base
< base
+ size
)
247 add_mem_region (last_base
, base
+ size
- last_base
);
253 dumper::add_module (LPVOID base_address
)
258 char *module_name
= psapi_get_module_name (hProcess
, (DWORD
) base_address
);
259 if (module_name
== NULL
)
262 process_entity
*new_entity
= add_process_entity_to_list (pr_ent_module
);
263 if (new_entity
== NULL
)
265 new_entity
->type
= pr_ent_module
;
268 new_entity
->u
.module
.base_address
= base_address
;
269 new_entity
->u
.module
.name
= module_name
;
271 parse_pe (module_name
, excl_list
);
273 deb_printf ("added module %08x %s\n", base_address
, module_name
);
277 #define PAGE_BUFFER_SIZE 4096
280 dumper::collect_memory_sections ()
285 LPBYTE current_page_address
;
286 LPBYTE last_base
= (LPBYTE
) 0xFFFFFFFF;
290 char mem_buf
[PAGE_BUFFER_SIZE
];
292 MEMORY_BASIC_INFORMATION mbi
;
294 if (hProcess
== NULL
)
297 for (current_page_address
= 0; current_page_address
< (LPBYTE
) 0xFFFF0000;)
299 if (!VirtualQueryEx (hProcess
, current_page_address
, &mbi
, sizeof (mbi
)))
302 int skip_region_p
= 0;
304 if (mbi
.Protect
& (PAGE_NOACCESS
| PAGE_GUARD
) ||
305 mbi
.State
!= MEM_COMMIT
)
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
313 if (!ReadProcessMemory (hProcess
, current_page_address
, mem_buf
, sizeof (mem_buf
), &done
))
315 DWORD err
= GetLastError ();
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 " : "";
329 for (int i
= 0; i
< 10; i
++)
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
,
342 if (last_base
+ last_size
== current_page_address
)
343 last_size
+= mbi
.RegionSize
;
346 split_add_mem_region (last_base
, last_size
);
347 last_base
= (LPBYTE
) mbi
.BaseAddress
;
348 last_size
= mbi
.RegionSize
;
353 split_add_mem_region (last_base
, last_size
);
358 current_page_address
+= mbi
.RegionSize
;
361 /* dump last sections, if any */
362 split_add_mem_region (last_base
, last_size
);
367 dumper::dump_memory_region (asection
* to
, process_mem_region
* memory
)
372 DWORD size
= memory
->size
;
375 LPBYTE pos
= memory
->base
;
378 if (to
== NULL
|| memory
== NULL
)
381 char mem_buf
[PAGE_BUFFER_SIZE
];
385 todo
= MIN (size
, PAGE_BUFFER_SIZE
);
386 if (!ReadProcessMemory (hProcess
, pos
, mem_buf
, todo
, &done
))
388 deb_printf ("Failed to read process memory at %x(%x), error %ld\n", pos
, todo
, GetLastError ());
393 if (!bfd_set_section_contents (core_bfd
, to
, mem_buf
, sect_pos
, done
))
395 bfd_perror ("writing memory region to bfd");
405 dumper::dump_thread (asection
* to
, process_thread
* thread
)
410 if (to
== NULL
|| thread
== NULL
)
413 win32_pstatus thread_pstatus
;
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
);
421 thread_pstatus
.data_type
= NOTE_INFO_THREAD
;
422 thread_pstatus
.data
.thread_info
.tid
= thread
->tid
;
426 /* this is a special case. we don't know, which thread
427 was active when exception occured, so let's blame
429 thread_pstatus
.data
.thread_info
.is_active_thread
= TRUE
;
432 else if (tid
> 0 && thread
->tid
== tid
)
433 thread_pstatus
.data
.thread_info
.is_active_thread
= TRUE
;
435 thread_pstatus
.data
.thread_info
.is_active_thread
= FALSE
;
437 memcpy (&(thread_pstatus
.data
.thread_info
.thread_context
),
439 sizeof (thread
->context
));
441 if (!bfd_set_section_contents (core_bfd
, to
, &header
,
444 !bfd_set_section_contents (core_bfd
, to
, &thread_pstatus
,
446 sizeof (thread_pstatus
)))
448 bfd_perror ("writing thread info to bfd");
456 dumper::dump_module (asection
* to
, process_module
* module
)
461 if (to
== NULL
|| module
== NULL
)
464 struct win32_pstatus
*module_pstatus_ptr
;
466 int note_length
= sizeof (struct win32_pstatus
) + strlen (module
->name
);
468 char *buf
= (char *) malloc (note_length
);
472 fprintf (stderr
, "Error alloating memory. Dumping aborted.\n");
476 module_pstatus_ptr
= (struct win32_pstatus
*) buf
;
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
);
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
);
489 if (!bfd_set_section_contents (core_bfd
, to
, &header
,
492 !bfd_set_section_contents (core_bfd
, to
, module_pstatus_ptr
,
496 bfd_perror ("writing module info to bfd");
510 dumper::collect_process_information ()
512 int exception_level
= 0;
517 if (!DebugActiveProcess (pid
))
519 fprintf (stderr
, "Cannot attach to process #%lu, error %ld", pid
, GetLastError ());
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
);
527 DEBUG_EVENT current_event
;
531 if (!WaitForDebugEvent (¤t_event
, 20000))
534 deb_printf ("got debug event %d\n", current_event
.dwDebugEventCode
);
536 switch (current_event
.dwDebugEventCode
)
538 case CREATE_THREAD_DEBUG_EVENT
:
540 if (!add_thread (current_event
.dwThreadId
,
541 current_event
.u
.CreateThread
.hThread
))
546 case CREATE_PROCESS_DEBUG_EVENT
:
548 if (!add_module (current_event
.u
.CreateProcessInfo
.lpBaseOfImage
) ||
549 !add_thread (current_event
.dwThreadId
,
550 current_event
.u
.CreateProcessInfo
.hThread
))
555 case EXIT_PROCESS_DEBUG_EVENT
:
557 deb_printf ("debugee quits");
558 ContinueDebugEvent (current_event
.dwProcessId
,
559 current_event
.dwThreadId
,
566 case LOAD_DLL_DEBUG_EVENT
:
568 if (!add_module (current_event
.u
.LoadDll
.lpBaseOfDll
))
573 case EXCEPTION_DEBUG_EVENT
:
576 if (exception_level
== 2)
578 else if (exception_level
> 2)
581 collect_memory_sections ();
583 /* got all info. time to dump */
585 if (!prepare_core_dump ())
587 fprintf (stderr
, "Failed to prepare core dump\n");
591 if (!write_core_dump ())
593 fprintf (stderr
, "Failed to write core dump\n");
597 /* signal a debugee that we've finished */
598 if (sync_with_debugee
)
599 SetEvent (sync_with_debugee
);
609 ContinueDebugEvent (current_event
.dwProcessId
,
610 current_event
.dwThreadId
,
614 /* set debugee free */
615 if (sync_with_debugee
)
616 SetEvent (sync_with_debugee
);
622 dumper::init_core_dump ()
626 core_bfd
= bfd_openw (file_name
, "elf32-i386");
627 if (core_bfd
== NULL
)
629 bfd_perror ("opening bfd");
633 if (!bfd_set_format (core_bfd
, bfd_core
))
635 bfd_perror ("setting bfd format");
639 if (!bfd_set_arch_mach (core_bfd
, bfd_arch_i386
, 0))
641 bfd_perror ("setting bfd architecture");
654 dumper::prepare_core_dump ()
666 asection
*new_section
;
668 for (process_entity
* p
= list
; p
!= NULL
; p
= p
->next
)
672 unsigned long phdr_type
= PT_LOAD
;
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
);
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
);
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
));
705 if (p
->type
== pr_ent_module
&& status_section
!= NULL
)
707 if (!bfd_set_section_size (core_bfd
,
709 (bfd_get_section_size (status_section
)
712 bfd_perror ("resizing status section");
718 deb_printf ("creating section (type%u) %s(%u), flags=%08x\n",
719 p
->type
, sect_name
, sect_size
, sect_flags
);
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
)
726 if (bfd_get_error () == bfd_error_no_error
)
727 fprintf (stderr
, "error creating new section (%s), section already exists.\n", buf
);
729 bfd_perror ("creating section");
733 if (!bfd_set_section_flags (core_bfd
, new_section
, sect_flags
) ||
734 !bfd_set_section_size (core_bfd
, new_section
, sect_size
))
736 bfd_perror ("setting section attributes");
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;
747 bfd_boolean filehdr
= 0;
748 bfd_boolean phdrs
= 0;
751 bfd_boolean valid_at
= 0;
754 bfd_boolean valid_flags
= 1;
756 if (p
->type
== pr_ent_memory
)
758 MEMORY_BASIC_INFORMATION mbi
;
759 if (!VirtualQueryEx (hProcess
, (LPVOID
)sect_vma
, &mbi
, sizeof (mbi
)))
761 bfd_perror ("getting mem region flags");
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
}
781 i
< sizeof (mappings
) / sizeof (mappings
[0]);
783 if ((mbi
.Protect
& mappings
[i
].protect
) != 0)
784 flags
|= mappings
[i
].flags
;
787 if (!bfd_record_phdr (core_bfd
, phdr_type
,
791 section_count
, &new_section
))
793 bfd_perror ("recording program headers");
805 dumper::write_core_dump ()
810 for (process_entity
* p
= list
; p
!= NULL
; p
= p
->next
)
812 if (p
->section
== NULL
)
815 deb_printf ("writing section type=%u base=%08x size=%08x flags=%08x\n",
818 bfd_get_section_size (p
->section
),
824 dump_memory_region (p
->section
, &(p
->u
.memory
));
828 dump_thread (p
->section
, &(p
->u
.thread
));
832 dump_module (p
->section
, &(p
->u
.module
));
844 usage (FILE *stream
, int status
)
847 Usage: %s [OPTION] FILENAME WIN32PID\n\
849 Dump core from WIN32PID to FILENAME.core\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
);
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}
866 const char *opts
= "dhqV";
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);
883 main (int argc
, char **argv
)
889 while ((opt
= getopt_long (argc
, argv
, opts
, longopts
, NULL
) ) != EOF
)
904 fprintf (stderr
, "Try `%s --help' for more information.\n",
905 program_invocation_short_name
);
909 if (argv
&& *(argv
+ optind
) && *(argv
+ optind
+1))
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
),
916 if ((p
= strrchr (win32_name
, '\\')))
920 pid
= strtoul (*(argv
+ optind
+ 1), NULL
, 10);
928 char *core_file
= (char *) malloc (strlen (p
) + sizeof (".core"));
931 fprintf (stderr
, "error allocating memory\n");
934 sprintf (core_file
, "%s.core", p
);
939 printf ("dumping process #%lu to %s\n", pid
, core_file
);
941 dumper
d (pid
, tid
, core_file
);
944 d
.collect_process_information ();