Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/utils/dumper.cc')
-rw-r--r--winsup/utils/dumper.cc882
1 files changed, 0 insertions, 882 deletions
diff --git a/winsup/utils/dumper.cc b/winsup/utils/dumper.cc
deleted file mode 100644
index e5e91e2ef..000000000
--- a/winsup/utils/dumper.cc
+++ /dev/null
@@ -1,882 +0,0 @@
-/* dumper.cc
-
- Copyright 1999, 2001, 2002, 2004 Red Hat Inc.
-
- Written by Egor Duda <deo@logos-m.ru>
-
- This file is part of Cygwin.
-
- This software is a copyrighted work licensed under the terms of the
- Cygwin license. Please consult the file "CYGWIN_LICENSE" for
- details. */
-
-#include <bfd.h>
-#include <elf/common.h>
-#include <elf/external.h>
-#include <sys/procfs.h>
-#include <sys/cygwin.h>
-#include <getopt.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <windows.h>
-
-#include "dumper.h"
-
-#define NOTE_NAME_SIZE 16
-
-typedef struct _note_header
- {
- Elf_External_Note elf_note_header;
- char name[NOTE_NAME_SIZE - 1]; /* external note contains first byte of data */
- }
-#ifdef __GNUC__
-__attribute__ ((packed))
-#endif
- note_header;
-
-static const char version[] = "$Revision$";
-
-BOOL verbose = FALSE;
-
-int deb_printf (const char *format,...)
-{
- if (!verbose)
- return 0;
- va_list va;
- va_start (va, format);
- int ret_val = vprintf (format, va);
- va_end (va);
- return ret_val;
-}
-
-dumper::dumper (DWORD pid, DWORD tid, const char *file_name)
-{
- this->file_name = strdup (file_name);
-
- this->pid = pid;
- this->tid = tid;
- core_bfd = NULL;
- excl_list = new exclusion (20);
-
- list = last = NULL;
-
- status_section = NULL;
-
- memory_num = module_num = thread_num = 0;
-
- hProcess = OpenProcess (PROCESS_ALL_ACCESS,
- FALSE, /* no inheritance */
- pid);
- if (!hProcess)
- {
- fprintf (stderr, "Failed to open process #%lu, error %ld\n", pid, GetLastError ());
- return;
- }
-
- init_core_dump ();
-
- if (!sane ())
- dumper_abort ();
-}
-
-dumper::~dumper ()
-{
- close ();
- free (file_name);
-}
-
-void
-dumper::dumper_abort ()
-{
- close ();
- unlink (file_name);
-}
-
-void
-dumper::close ()
-{
- if (core_bfd)
- bfd_close (core_bfd);
- if (excl_list)
- delete excl_list;
- if (hProcess)
- CloseHandle (hProcess);
- core_bfd = NULL;
- hProcess = NULL;
- excl_list = NULL;
-}
-
-int
-dumper::sane ()
-{
- if (hProcess == NULL || core_bfd == NULL || excl_list == NULL)
- return 0;
- return 1;
-}
-
-void
-print_section_name (bfd* abfd, asection* sect, PTR obj)
-{
- deb_printf (" %s", bfd_get_section_name (abfd, sect));
-}
-
-void
-dumper::print_core_section_list ()
-{
- deb_printf ("current sections:");
- bfd_map_over_sections (core_bfd, &print_section_name, NULL);
- deb_printf ("\n");
-}
-
-process_entity *
-dumper::add_process_entity_to_list (process_entity_type type)
-{
- if (!sane ())
- return NULL;
-
- process_entity *new_entity = (process_entity *) malloc (sizeof (process_entity));
- if (new_entity == NULL)
- return NULL;
- new_entity->next = NULL;
- new_entity->section = NULL;
- if (last == NULL)
- list = new_entity;
- else
- last->next = new_entity;
- last = new_entity;
- return new_entity;
-}
-
-int
-dumper::add_thread (DWORD tid, HANDLE hThread)
-{
- if (!sane ())
- return 0;
-
- CONTEXT *pcontext;
-
- process_entity *new_entity = add_process_entity_to_list (pr_ent_thread);
- if (new_entity == NULL)
- return 0;
- new_entity->type = pr_ent_thread;
- thread_num++;
-
- new_entity->u.thread.tid = tid;
- new_entity->u.thread.hThread = hThread;
-
- pcontext = &(new_entity->u.thread.context);
- pcontext->ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT;
- if (!GetThreadContext (hThread, pcontext))
- {
- deb_printf ("Failed to read thread context (tid=%x), error %ld\n", tid, GetLastError ());
- return 0;
- }
-
- deb_printf ("added thread %u\n", tid);
- return 1;
-}
-
-int
-dumper::add_mem_region (LPBYTE base, DWORD size)
-{
- if (!sane ())
- return 0;
-
- if (base == NULL || size == 0)
- return 1; // just ignore empty regions
-
- process_entity *new_entity = add_process_entity_to_list (pr_ent_memory);
- if (new_entity == NULL)
- return 0;
- new_entity->type = pr_ent_memory;
- memory_num++;
-
- new_entity->u.memory.base = base;
- new_entity->u.memory.size = size;
-
- deb_printf ("added memory region %08x-%08x\n", (DWORD) base, (DWORD) base + size);
- return 1;
-}
-
-/* split_add_mem_region scans list of regions to be excluded from dumping process
- (excl_list) and removes all "excluded" parts from given region. */
-int
-dumper::split_add_mem_region (LPBYTE base, DWORD size)
-{
- if (!sane ())
- return 0;
-
- if (base == NULL || size == 0)
- return 1; // just ignore empty regions
-
- LPBYTE last_base = base;
-
- for (process_mem_region * p = excl_list->region;
- p < excl_list->region + excl_list->last;
- p++)
- {
- if (p->base >= base + size || p->base + p->size <= base)
- continue;
-
- if (p->base <= base)
- {
- last_base = p->base + p->size;
- continue;
- }
-
- add_mem_region (last_base, p->base - last_base);
- last_base = p->base + p->size;
- }
-
- if (last_base < base + size)
- add_mem_region (last_base, base + size - last_base);
-
- return 1;
-}
-
-int
-dumper::add_module (LPVOID base_address)
-{
- if (!sane ())
- return 0;
-
- char *module_name = psapi_get_module_name (hProcess, (DWORD) base_address);
- if (module_name == NULL)
- return 1;
-
- process_entity *new_entity = add_process_entity_to_list (pr_ent_module);
- if (new_entity == NULL)
- return 0;
- new_entity->type = pr_ent_module;
- module_num++;
-
- new_entity->u.module.base_address = base_address;
- new_entity->u.module.name = module_name;
-
- parse_pe (module_name, excl_list);
-
- deb_printf ("added module %08x %s\n", base_address, module_name);
- return 1;
-}
-
-#define PAGE_BUFFER_SIZE 4096
-
-int
-dumper::collect_memory_sections ()
-{
- if (!sane ())
- return 0;
-
- LPBYTE current_page_address;
- LPBYTE last_base = (LPBYTE) 0xFFFFFFFF;
- DWORD last_size = 0;
- DWORD done;
-
- char mem_buf[PAGE_BUFFER_SIZE];
-
- MEMORY_BASIC_INFORMATION mbi;
-
- if (hProcess == NULL)
- return 0;
-
- for (current_page_address = 0; current_page_address < (LPBYTE) 0xFFFF0000;)
- {
- if (!VirtualQueryEx (hProcess, current_page_address, &mbi, sizeof (mbi)))
- break;
-
- int skip_region_p = 0;
-
- if (mbi.Protect & (PAGE_NOACCESS | PAGE_GUARD) ||
- mbi.State != MEM_COMMIT)
- skip_region_p = 1;
-
- if (!skip_region_p)
- {
- /* just to make sure that later we'll be able to read it.
- According to MS docs either region is all-readable or
- all-nonreadable */
- if (!ReadProcessMemory (hProcess, current_page_address, mem_buf, sizeof (mem_buf), &done))
- {
- DWORD err = GetLastError ();
- const char *pt[10];
- pt[0] = (mbi.Protect & PAGE_READONLY) ? "RO " : "";
- pt[1] = (mbi.Protect & PAGE_READWRITE) ? "RW " : "";
- pt[2] = (mbi.Protect & PAGE_WRITECOPY) ? "WC " : "";
- pt[3] = (mbi.Protect & PAGE_EXECUTE) ? "EX " : "";
- pt[4] = (mbi.Protect & PAGE_EXECUTE_READ) ? "EXRO " : "";
- pt[5] = (mbi.Protect & PAGE_EXECUTE_READWRITE) ? "EXRW " : "";
- pt[6] = (mbi.Protect & PAGE_EXECUTE_WRITECOPY) ? "EXWC " : "";
- pt[7] = (mbi.Protect & PAGE_GUARD) ? "GRD " : "";
- pt[8] = (mbi.Protect & PAGE_NOACCESS) ? "NA " : "";
- pt[9] = (mbi.Protect & PAGE_NOCACHE) ? "NC " : "";
- char buf[10 * 6];
- buf[0] = '\0';
- for (int i = 0; i < 10; i++)
- strcat (buf, pt[i]);
-
- deb_printf ("warning: failed to read memory at %08x-%08x (protect = %s), error %ld.\n",
- (DWORD) current_page_address,
- (DWORD) current_page_address + mbi.RegionSize,
- buf, err);
- skip_region_p = 1;
- }
- }
-
- if (!skip_region_p)
- {
- if (last_base + last_size == current_page_address)
- last_size += mbi.RegionSize;
- else
- {
- split_add_mem_region (last_base, last_size);
- last_base = (LPBYTE) mbi.BaseAddress;
- last_size = mbi.RegionSize;
- }
- }
- else
- {
- split_add_mem_region (last_base, last_size);
- last_base = NULL;
- last_size = 0;
- }
-
- current_page_address += mbi.RegionSize;
- }
-
- /* dump last sections, if any */
- split_add_mem_region (last_base, last_size);
- return 1;
-};
-
-int
-dumper::dump_memory_region (asection * to, process_mem_region * memory)
-{
- if (!sane ())
- return 0;
-
- DWORD size = memory->size;
- DWORD todo;
- DWORD done;
- LPBYTE pos = memory->base;
- DWORD sect_pos = 0;
-
- if (to == NULL || memory == NULL)
- return 0;
-
- char mem_buf[PAGE_BUFFER_SIZE];
-
- while (size > 0)
- {
- todo = min (size, PAGE_BUFFER_SIZE);
- if (!ReadProcessMemory (hProcess, pos, mem_buf, todo, &done))
- {
- deb_printf ("Failed to read process memory at %x(%x), error %ld\n", pos, todo, GetLastError ());
- return 0;
- }
- size -= done;
- pos += done;
- if (!bfd_set_section_contents (core_bfd, to, mem_buf, sect_pos, done))
- {
- bfd_perror ("writing memory region to bfd");
- dumper_abort ();
- return 0;
- };
- sect_pos += done;
- }
- return 1;
-}
-
-int
-dumper::dump_thread (asection * to, process_thread * thread)
-{
- if (!sane ())
- return 0;
-
- if (to == NULL || thread == NULL)
- return 0;
-
- win32_pstatus thread_pstatus;
-
- note_header header;
- bfd_putl32 (NOTE_NAME_SIZE, header.elf_note_header.namesz);
- bfd_putl32 (sizeof (thread_pstatus), header.elf_note_header.descsz);
- bfd_putl32 (NT_WIN32PSTATUS, header.elf_note_header.type);
- strncpy ((char *) &header.elf_note_header.name, "win32thread", NOTE_NAME_SIZE);
-
- thread_pstatus.data_type = NOTE_INFO_THREAD;
- thread_pstatus.data.thread_info.tid = thread->tid;
-
- if (tid == 0)
- {
- /* this is a special case. we don't know, which thread
- was active when exception occured, so let's blame
- the first one */
- thread_pstatus.data.thread_info.is_active_thread = TRUE;
- tid = (DWORD) - 1;
- }
- else if (tid > 0 && thread->tid == tid)
- thread_pstatus.data.thread_info.is_active_thread = TRUE;
- else
- thread_pstatus.data.thread_info.is_active_thread = FALSE;
-
- memcpy (&(thread_pstatus.data.thread_info.thread_context),
- &(thread->context),
- sizeof (thread->context));
-
- if (!bfd_set_section_contents (core_bfd, to, &header,
- 0,
- sizeof (header)) ||
- !bfd_set_section_contents (core_bfd, to, &thread_pstatus,
- sizeof (header),
- sizeof (thread_pstatus)))
- {
- bfd_perror ("writing thread info to bfd");
- dumper_abort ();
- return 0;
- };
- return 1;
-}
-
-int
-dumper::dump_module (asection * to, process_module * module)
-{
- if (!sane ())
- return 0;
-
- if (to == NULL || module == NULL)
- return 0;
-
- struct win32_pstatus *module_pstatus_ptr;
-
- int note_length = sizeof (struct win32_pstatus) + strlen (module->name);
-
- char *buf = (char *) malloc (note_length);
-
- if (!buf)
- {
- fprintf (stderr, "Error alloating memory. Dumping aborted.\n");
- goto out;
- };
-
- module_pstatus_ptr = (struct win32_pstatus *) buf;
-
- note_header header;
- bfd_putl32 (NOTE_NAME_SIZE, header.elf_note_header.namesz);
- bfd_putl32 (note_length, header.elf_note_header.descsz);
- bfd_putl32 (NT_WIN32PSTATUS, header.elf_note_header.type);
- strncpy ((char *) &header.elf_note_header.name, "win32module", NOTE_NAME_SIZE);
-
- module_pstatus_ptr->data_type = NOTE_INFO_MODULE;
- module_pstatus_ptr->data.module_info.base_address = module->base_address;
- module_pstatus_ptr->data.module_info.module_name_size = strlen (module->name) + 1;
- strcpy (module_pstatus_ptr->data.module_info.module_name, module->name);
-
- if (!bfd_set_section_contents (core_bfd, to, &header,
- 0,
- sizeof (header)) ||
- !bfd_set_section_contents (core_bfd, to, module_pstatus_ptr,
- sizeof (header),
- note_length))
- {
- bfd_perror ("writing module info to bfd");
- goto out;
- };
- return 1;
-
-out:
- if (buf)
- free (buf);
- dumper_abort ();
- return 0;
-
-}
-
-int
-dumper::collect_process_information ()
-{
- int exception_level = 0;
-
- if (!sane ())
- return 0;
-
- if (!DebugActiveProcess (pid))
- {
- fprintf (stderr, "Cannot attach to process #%lu, error %ld", pid, GetLastError ());
- return 0;
- }
-
- char event_name[sizeof ("cygwin_error_start_event") + 20];
- sprintf (event_name, "cygwin_error_start_event%16lx", pid);
- HANDLE sync_with_debugee = OpenEvent (EVENT_MODIFY_STATE, FALSE, event_name);
-
- DEBUG_EVENT current_event;
-
- while (1)
- {
- if (!WaitForDebugEvent (&current_event, 20000))
- return 0;
-
- deb_printf ("got debug event %d\n", current_event.dwDebugEventCode);
-
- switch (current_event.dwDebugEventCode)
- {
- case CREATE_THREAD_DEBUG_EVENT:
-
- if (!add_thread (current_event.dwThreadId,
- current_event.u.CreateThread.hThread))
- goto failed;
-
- break;
-
- case CREATE_PROCESS_DEBUG_EVENT:
-
- if (!add_module (current_event.u.CreateProcessInfo.lpBaseOfImage) ||
- !add_thread (current_event.dwThreadId,
- current_event.u.CreateProcessInfo.hThread))
- goto failed;
-
- break;
-
- case EXIT_PROCESS_DEBUG_EVENT:
-
- deb_printf ("debugee quits");
- ContinueDebugEvent (current_event.dwProcessId,
- current_event.dwThreadId,
- DBG_CONTINUE);
-
- return 1;
-
- break;
-
- case LOAD_DLL_DEBUG_EVENT:
-
- if (!add_module (current_event.u.LoadDll.lpBaseOfDll))
- goto failed;
-
- break;
-
- case EXCEPTION_DEBUG_EVENT:
-
- exception_level++;
- if (exception_level == 2)
- break;
- else if (exception_level > 2)
- return 0;
-
- collect_memory_sections ();
-
- /* got all info. time to dump */
-
- if (!prepare_core_dump ())
- {
- fprintf (stderr, "Failed to prepare core dump\n");
- goto failed;
- };
-
- if (!write_core_dump ())
- {
- fprintf (stderr, "Failed to write core dump\n");
- goto failed;
- };
-
- /* signal a debugee that we've finished */
- if (sync_with_debugee)
- SetEvent (sync_with_debugee);
-
- break;
-
- default:
-
- break;
-
- }
-
- ContinueDebugEvent (current_event.dwProcessId,
- current_event.dwThreadId,
- DBG_CONTINUE);
- }
-failed:
- /* set debugee free */
- if (sync_with_debugee)
- SetEvent (sync_with_debugee);
-
- return 0;
-}
-
-int
-dumper::init_core_dump ()
-{
- bfd_init ();
-
- core_bfd = bfd_openw (file_name, "elf32-i386");
- if (core_bfd == NULL)
- {
- bfd_perror ("opening bfd");
- goto failed;
- }
-
- if (!bfd_set_format (core_bfd, bfd_core))
- {
- bfd_perror ("setting bfd format");
- goto failed;
- }
-
- if (!bfd_set_arch_mach (core_bfd, bfd_arch_i386, 0))
- {
- bfd_perror ("setting bfd architecture");
- goto failed;
- }
-
- return 1;
-
-failed:
- dumper_abort ();
- return 0;
-
-}
-
-int
-dumper::prepare_core_dump ()
-{
- if (!sane ())
- return 0;
-
- int sect_no = 0;
- char sect_name[50];
-
- flagword sect_flags;
- DWORD sect_size;
- bfd_vma sect_vma;
-
- asection *new_section;
-
- for (process_entity * p = list; p != NULL; p = p->next)
- {
- sect_no++;
-
- switch (p->type)
- {
- case pr_ent_memory:
- sprintf (sect_name, ".mem/%u", sect_no);
- sect_flags = SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD;
- sect_size = p->u.memory.size;
- sect_vma = (bfd_vma) (p->u.memory.base);
-
- break;
-
- case pr_ent_thread:
- sprintf (sect_name, ".note/%u", sect_no);
- sect_flags = SEC_HAS_CONTENTS | SEC_LOAD;
- sect_size = sizeof (note_header) + sizeof (struct win32_pstatus);
- sect_vma = 0;
- break;
-
- case pr_ent_module:
- sprintf (sect_name, ".note/%u", sect_no);
- sect_flags = SEC_HAS_CONTENTS | SEC_LOAD;
- sect_size = sizeof (note_header) + sizeof (struct win32_pstatus) +
- (bfd_size_type) (strlen (p->u.module.name));
- sect_vma = 0;
- break;
-
- default:
- continue;
- }
-
- if (p->type == pr_ent_module && status_section != NULL)
- {
- if (!bfd_set_section_size (core_bfd,
- status_section,
- (bfd_get_section_size (status_section)
- + sect_size)))
- {
- bfd_perror ("resizing status section");
- goto failed;
- };
- continue;
- }
-
- deb_printf ("creating section (type%u) %s(%u), flags=%08x\n",
- p->type, sect_name, sect_size, sect_flags);
-
- bfd_set_error (bfd_error_no_error);
- char *buf = strdup (sect_name);
- new_section = bfd_make_section (core_bfd, buf);
- if (new_section == NULL)
- {
- if (bfd_get_error () == bfd_error_no_error)
- fprintf (stderr, "error creating new section (%s), section already exists.\n", buf);
- else
- bfd_perror ("creating section");
- goto failed;
- }
-
- if (!bfd_set_section_flags (core_bfd, new_section, sect_flags) ||
- !bfd_set_section_size (core_bfd, new_section, sect_size))
- {
- bfd_perror ("setting section attributes");
- goto failed;
- };
-
- new_section->vma = sect_vma;
- new_section->output_section = new_section;
- new_section->output_offset = 0;
- p->section = new_section;
- }
-
- return 1;
-
-failed:
- dumper_abort ();
- return 0;
-}
-
-int
-dumper::write_core_dump ()
-{
- if (!sane ())
- return 0;
-
- for (process_entity * p = list; p != NULL; p = p->next)
- {
- if (p->section == NULL)
- continue;
-
- deb_printf ("writing section type=%u base=%08x size=%08x flags=%08x\n",
- p->type,
- p->section->vma,
- bfd_get_section_size (p->section),
- p->section->flags);
-
- switch (p->type)
- {
- case pr_ent_memory:
- dump_memory_region (p->section, &(p->u.memory));
- break;
-
- case pr_ent_thread:
- dump_thread (p->section, &(p->u.thread));
- break;
-
- case pr_ent_module:
- dump_module (p->section, &(p->u.module));
- break;
-
- default:
- continue;
-
- }
- }
- return 1;
-}
-
-static void
-usage (FILE *stream, int status)
-{
- fprintf (stream, "\
-Usage: dumper [OPTION] FILENAME WIN32PID\n\
-Dump core from WIN32PID to FILENAME.core\n\
-\n\
- -d, --verbose be verbose while dumping\n\
- -h, --help output help information and exit\n\
- -q, --quiet be quiet while dumping (default)\n\
- -v, --version output version information and exit\n\
-");
- exit (status);
-}
-
-struct option longopts[] = {
- {"verbose", no_argument, NULL, 'd'},
- {"help", no_argument, NULL, 'h'},
- {"quiet", no_argument, NULL, 'q'},
- {"version", no_argument, 0, 'v'},
- {0, no_argument, NULL, 0}
-};
-
-static void
-print_version ()
-{
- const char *v = strchr (version, ':');
- int len;
- if (!v)
- {
- v = "?";
- len = 1;
- }
- else
- {
- v += 2;
- len = strchr (v, ' ') - v;
- }
- printf ("\
-dumper (cygwin) %.*s\n\
-Core Dumper for Cygwin\n\
-Copyright 1999, 2001, 2002 Red Hat, Inc.\n", len, v);
-}
-
-int
-main (int argc, char **argv)
-{
- int opt;
- const char *p = "";
- DWORD pid;
- char win32_name [MAX_PATH];
-
- while ((opt = getopt_long (argc, argv, "dqhv", longopts, NULL) ) != EOF)
- switch (opt)
- {
- case 'd':
- verbose = TRUE;
- break;
- case 'q':
- verbose = FALSE;
- break;
- case 'h':
- usage (stdout, 0);
- case 'v':
- print_version ();
- exit (0);
- default:
- usage (stderr, 1);
- break;
- }
-
- if (argv && *(argv + optind) && *(argv + optind +1))
- {
- *win32_name = '\0';
- cygwin_conv_to_win32_path (*(argv + optind), win32_name);
- if ((p = strrchr (win32_name, '\\')))
- p++;
- else
- p = win32_name;
- pid = strtoul (*(argv + optind + 1), NULL, 10);
- }
- else
- {
- usage (stderr, 1);
- return -1;
- }
-
- char *core_file = (char *) malloc (strlen (p) + sizeof (".core"));
- if (!core_file)
- {
- fprintf (stderr, "error allocating memory\n");
- return -1;
- }
- sprintf (core_file, "%s.core", p);
-
- DWORD tid = 0;
-
- if (verbose)
- printf ("dumping process #%lu to %s\n", pid, core_file);
-
- dumper d (pid, tid, core_file);
- if (!d.sane ())
- return -1;
- d.collect_process_information ();
- free (core_file);
-
- return 0;
-};