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
path: root/winsup
diff options
context:
space:
mode:
authorChristopher Faylor <me@cgf.cx>2000-08-24 23:03:12 +0400
committerChristopher Faylor <me@cgf.cx>2000-08-24 23:03:12 +0400
commit0ad10c0f96c86c1727559b91efe347484c3c1fa1 (patch)
tree4a1f932fa596fbb8571bb1d4a524a5438f4cf0e6 /winsup
parent199359f062fbe9028de9de4741d365f932672241 (diff)
* Makefile.in: Add dumper.exe target and associated mechanisms for building it.
* dumper.cc: New file. * dumper.h: New file. * module_info.cc: New file. * parse_pe.cc: New file.
Diffstat (limited to 'winsup')
-rw-r--r--winsup/utils/ChangeLog8
-rw-r--r--winsup/utils/Makefile.in25
-rw-r--r--winsup/utils/dumper.cc754
-rw-r--r--winsup/utils/dumper.h131
-rw-r--r--winsup/utils/kill.cc2
-rw-r--r--winsup/utils/module_info.cc112
-rw-r--r--winsup/utils/parse_pe.cc88
-rw-r--r--winsup/utils/ps.cc3
8 files changed, 1120 insertions, 3 deletions
diff --git a/winsup/utils/ChangeLog b/winsup/utils/ChangeLog
index 4b5b1430a..8dcd6e7ca 100644
--- a/winsup/utils/ChangeLog
+++ b/winsup/utils/ChangeLog
@@ -1,3 +1,11 @@
+Thu Aug 24 15:00:31 2000 Christopher Faylor <cgf@cygnus.com>
+
+ * Makefile.in: Add dumper.exe target and associated mechanisms for building it.
+ * dumper.cc: New file.
+ * dumper.h: New file.
+ * module_info.cc: New file.
+ * parse_pe.cc: New file.
+
Mon Jul 31 15:12:00 2000 Corinna Vinschen <corinna@vinschen.de>
* passwd.c (main): Initialize oldpwd before beeing used.
diff --git a/winsup/utils/Makefile.in b/winsup/utils/Makefile.in
index 80fbdd86d..092829ac1 100644
--- a/winsup/utils/Makefile.in
+++ b/winsup/utils/Makefile.in
@@ -35,9 +35,13 @@ include $(srcdir)/../Makefile.common
MINGW_INCLUDES:=-I$(mingw_source)/include -I$(cygwin_source)/include -I$(w32api_include)
+DUMPER_INCLUDES:=-I$(bupdir2)/bfd -I$(updir1)/include
+
MINGW_CXXFLAGS:=$(CXXFLAGS) -mno-cygwin $(MINGW_INCLUDES)
MINGW_CFLAGS:=$(CFLAGS) -mno-cygwin $(MINGW_INCLUDES)
+DUMPER_CFLAGS:=$(CFLAGS) $(INCLUDES) $(DUMPER_INCLUDES)
+
libcygwin:=$(cygwin_build)/libcygwin.a
libuser32:=$(w32api_lib)/libuser32.a
libkernel32:=$(w32api_lib)/libkernel32.a
@@ -51,16 +55,18 @@ ALL_LDLIBS:=${patsubst $(w32api_lib)/lib%.a,-l%,\
${filter-out $(libcygwin), $(ALL_DEP_LDLIBS)}}}}
MINGW_LIB:=$(mingw_build)/libmingw32.a
+DUMPER_LIB:=-L$(bupdir2)/bfd -lbfd -L$(bupdir2)/libiberty -liberty -L$(bupdir2)/intl -lintl
MINGW_LDLIBS:=$(ALL_LDLIBS) $(MINGW_LIB)
MINGW_DEP_LDLIBS:=${ALL_DEP_LDLIBS} ${MINGW_LIB}
ALL_LDFLAGS:=-B$(newlib_build)/libc/ -B$(newlib_build)/libm/ -B$(w32api_lib)/ \
$(LDFLAGS) $(ALL_LDLIBS)
MINGW_LDFLAGS:=$(ALL_LDFLAGS) $(MINGW_LIB)
+DUMPER_LDFLAGS:=$(ALL_LDFLAGS) $(DUMPER_LIB)
PROGS:=mount$(EXEEXT) umount$(EXEEXT) ps$(EXEEXT) kill$(EXEEXT) \
mkpasswd$(EXEEXT) mkgroup$(EXEEXT) cygpath$(EXEEXT) cygcheck$(EXEEXT) \
passwd$(EXEEXT) getfacl$(EXEEXT) setfacl$(EXEEXT) strace$(EXEEXT) \
- regtool$(EXEEXT)
+ regtool$(EXEEXT) dumper$(EXEEXT)
.SUFFIXES:
.NOEXPORT:
@@ -77,6 +83,15 @@ else
$(CC) $(MINGW_CXXFLAGS) -o $@ ${wordlist 1,2,$^} -B$(mingw_build)/ $(MINGW_LDFLAGS)
endif
+dumper.o: dumper.cc dumper.h
+ -$(CC) -c -o $@ $(DUMPER_CFLAGS) ${firstword $^}
+
+module_info.o: module_info.cc
+ -$(CC) -c -o $@ $(DUMPER_CFLAGS) $^
+
+parse_pe.o: parse_pe.cc dumper.h
+ -$(CC) -c -o $@ $(DUMPER_CFLAGS) ${firstword $^}
+
mingw_getopt.o: $(cygwin_source)/lib/getopt.c
$(CC) -c -o $@ $(MINGW_CFLAGS) $^
@@ -99,6 +114,14 @@ $(cygwin_build)/libcygwin.a: $(cygwin_build)/Makefile
$(mingw_build)/libmingw32.a: $(mingw_build)/Makefile
@$(MAKE) -C $(@D) $(@F)
+dumper.exe: module_info.o parse_pe.o dumper.o $(ALL_DEP_LDLIBS)
+ifdef VERBOSE
+ $(CC) -o $@ ${wordlist 1,3,$^} -B$(cygwin_build)/ $(DUMPER_LDFLAGS)
+else
+ @echo $(CC) -o $@ ${wordlist 1,3,$^} ${filter-out -B%, $(DUMPER_LDFLAGS)};\
+ $(CC) -o $@ ${wordlist 1,3,$^} -B$(cygwin_build)/ $(DUMPER_LDFLAGS)
+endif
+
%.exe: %.o $(ALL_DEP_LDLIBS)
ifdef VERBOSE
$(CC) -o $@ ${firstword $^} -B$(cygwin_build)/ $(ALL_LDFLAGS)
diff --git a/winsup/utils/dumper.cc b/winsup/utils/dumper.cc
new file mode 100644
index 000000000..6ccf2f1c9
--- /dev/null
+++ b/winsup/utils/dumper.cc
@@ -0,0 +1,754 @@
+/* dumper.cc
+
+ Copyright 1999 Cygnus Solutions.
+
+ 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 ;
+
+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\n", pid );
+ 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;
+}
+
+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 ) ) 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 ) )
+ {
+ 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\n",
+ (DWORD)current_page_address,
+ (DWORD)current_page_address + mbi.RegionSize,
+ buf );
+ 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 ( "Error reading process memory at %x(%x) %u\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 ()
+{
+ if ( ! sane () ) return 0;
+
+ if ( ! DebugActiveProcess ( pid ) )
+ {
+ fprintf ( stderr, "Cannot attach to process #%lu", pid );
+ 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;
+
+ 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:
+
+ 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;
+ }
+
+ 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,
+ status_section->_raw_size + 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 );
+
+ char* buf = strdup ( sect_name );
+ new_section = bfd_make_section ( core_bfd, buf );
+
+ if ( new_section == NULL ||
+ ! bfd_set_section_flags ( core_bfd, new_section, sect_flags ) ||
+ ! bfd_set_section_size ( core_bfd, new_section, sect_size ) )
+ {
+ bfd_perror ( "creating section" );
+ 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,
+ p->section->_raw_size,
+ 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 ()
+{
+ fprintf ( stderr, "Usage: dumper [-v] [-c filename] pid\n" );
+ fprintf ( stderr, "-c filename -- dump core to filename.core\n" );
+ fprintf ( stderr, "-d -- print some debugging info while dumping\n" );
+ fprintf ( stderr, "pid -- win32-pid of process to dump\n" );
+}
+
+int
+main( int argc, char** argv )
+{
+ int opt;
+ char* p = "";
+ DWORD pid;
+
+ while ((opt = getopt (argc, argv, "dc:")) != EOF)
+ switch (opt)
+ {
+ case 'd':
+ verbose = TRUE;
+ break;
+ case 'c':
+ char win32_name [ MAX_PATH ];
+ cygwin_conv_to_win32_path ( optarg, win32_name );
+ if ( ( p = strrchr ( win32_name, '\\' ) ) )
+ p++;
+ else
+ p = win32_name;
+ break;
+ }
+
+ 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 );
+
+ if ( argv && *(argv+optind) )
+ pid = atoi ( *(argv+optind) );
+ else
+ {
+ usage ();
+ return -1;
+ }
+
+ 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;
+};
diff --git a/winsup/utils/dumper.h b/winsup/utils/dumper.h
new file mode 100644
index 000000000..673a0037e
--- /dev/null
+++ b/winsup/utils/dumper.h
@@ -0,0 +1,131 @@
+/* dumper.h
+
+ Copyright 1999 Cygnus Solutions.
+
+ 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. */
+
+#ifndef _DUMPER_H_
+#define _DUMPER_H_
+
+#include <windows.h>
+
+typedef struct
+{
+ LPBYTE base;
+ DWORD size;
+} process_mem_region;
+
+typedef struct
+{
+ DWORD tid;
+ HANDLE hThread;
+ CONTEXT context;
+} process_thread;
+
+typedef struct
+{
+ LPVOID base_address;
+ char* name;
+} process_module;
+
+enum process_entity_type
+{
+ pr_ent_memory,
+ pr_ent_thread,
+ pr_ent_module
+};
+
+typedef struct _process_entity
+{
+ process_entity_type type;
+ union
+ {
+ process_thread thread;
+ process_mem_region memory;
+ process_module module;
+ } u;
+ asection* section;
+ struct _process_entity* next;
+} process_entity;
+
+class exclusion
+{
+public:
+ int last;
+ int size;
+ int step;
+ process_mem_region* region;
+
+ exclusion ( int step ) { last = size = 0;
+ this->step = step;
+ region = NULL; }
+ ~exclusion () { free ( region ); }
+ int add ( LPBYTE mem_base, DWORD mem_size );
+ int sort_and_check ();
+};
+
+#define PAGE_BUFFER_SIZE 4096
+
+class dumper
+{
+ DWORD pid;
+ DWORD tid; /* thread id of active thread */
+ HANDLE hProcess;
+ process_entity* list;
+ process_entity* last;
+ exclusion* excl_list;
+
+ char* file_name;
+ bfd* core_bfd;
+
+ asection* status_section;
+
+ int memory_num;
+ int module_num;
+ int thread_num;
+
+ void close ();
+ void dumper_abort ();
+
+ process_entity* add_process_entity_to_list ( process_entity_type type );
+ int add_thread ( DWORD tid, HANDLE hThread );
+ int add_mem_region ( LPBYTE base, DWORD size );
+
+ /* break mem_region by excl_list and add add all subregions */
+ int split_add_mem_region ( LPBYTE base, DWORD size );
+
+ int add_module ( LPVOID base_address );
+
+ int collect_memory_sections ();
+ int dump_memory_region ( asection* to, process_mem_region* memory );
+ int dump_thread ( asection* to, process_thread* thread );
+ int dump_module ( asection* to, process_module* module );
+
+public:
+ int sane ();
+
+ int collect_process_information ();
+
+ dumper ( DWORD pid, DWORD tid, const char* name );
+ ~dumper ();
+
+ int init_core_dump ();
+ int prepare_core_dump ();
+ int write_core_dump ();
+};
+
+extern int deb_printf ( const char* format, ... );
+
+extern char* psapi_get_module_name ( HANDLE hProcess, DWORD BaseAddress );
+
+extern int parse_pe ( const char* file_name, exclusion* excl_list );
+
+extern BOOL verbose;
+
+#endif
diff --git a/winsup/utils/kill.cc b/winsup/utils/kill.cc
index a7913e43c..5e2a30d50 100644
--- a/winsup/utils/kill.cc
+++ b/winsup/utils/kill.cc
@@ -30,7 +30,7 @@ main (int argc, char **argv)
if (argc == 1)
usage ();
- while (*(++argv)[0] == '-')
+ while (*++argv && **argv == '-')
if (strcmp (*argv + 1, "f") == 0)
force = 1;
else if (gotsig)
diff --git a/winsup/utils/module_info.cc b/winsup/utils/module_info.cc
new file mode 100644
index 000000000..a48d7105c
--- /dev/null
+++ b/winsup/utils/module_info.cc
@@ -0,0 +1,112 @@
+/* module_info.cc
+
+ Copyright 1999 Cygnus Solutions.
+
+ 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 <stdlib.h>
+#include <windows.h>
+#include <psapi.h>
+
+static int psapi_loaded = 0;
+static HMODULE psapi_module_handle = NULL;
+
+typedef BOOL WINAPI (tf_EnumProcessModules ) ( HANDLE, HMODULE*, DWORD, LPDWORD );
+typedef BOOL WINAPI (tf_GetModuleInformation) ( HANDLE, HMODULE, LPMODULEINFO, DWORD );
+typedef DWORD WINAPI (tf_GetModuleFileNameExA) ( HANDLE, HMODULE, LPSTR, DWORD );
+
+static tf_EnumProcessModules *psapi_EnumProcessModules = NULL;
+static tf_GetModuleInformation *psapi_GetModuleInformation = NULL;
+static tf_GetModuleFileNameExA *psapi_GetModuleFileNameExA = NULL;
+
+/*
+ * Returns full name of Dll, which is loaded by hProcess at BaseAddress
+ * Uses psapi.dll
+ */
+
+char*
+psapi_get_module_name ( HANDLE hProcess, DWORD BaseAddress )
+{
+ DWORD len;
+ MODULEINFO mi;
+ unsigned int i;
+ HMODULE dh_buf [ 1 ];
+ HMODULE* DllHandle = dh_buf;
+ DWORD cbNeeded;
+ BOOL ok;
+
+ char name_buf [ MAX_PATH + 1 ];
+
+ if ( !psapi_loaded ||
+ psapi_EnumProcessModules == NULL ||
+ psapi_GetModuleInformation == NULL ||
+ psapi_GetModuleFileNameExA == NULL )
+ {
+ if ( psapi_loaded ) goto failed;
+ psapi_loaded = 1;
+ psapi_module_handle = LoadLibrary ( "psapi.dll" );
+ if ( ! psapi_module_handle )
+ goto failed;
+ psapi_EnumProcessModules = (tf_EnumProcessModules *) GetProcAddress ( psapi_module_handle, "EnumProcessModules" );
+ psapi_GetModuleInformation = (tf_GetModuleInformation *) GetProcAddress ( psapi_module_handle, "GetModuleInformation" );
+ psapi_GetModuleFileNameExA = (tf_GetModuleFileNameExA*) GetProcAddress ( psapi_module_handle, "GetModuleFileNameExA" );
+ if ( psapi_EnumProcessModules == NULL ||
+ psapi_GetModuleInformation == NULL ||
+ psapi_GetModuleFileNameExA == NULL ) goto failed;
+ }
+
+ ok = (*psapi_EnumProcessModules) ( hProcess,
+ DllHandle,
+ sizeof ( HMODULE ),
+ &cbNeeded );
+
+ if ( !ok || !cbNeeded ) goto failed;
+ DllHandle = (HMODULE*) malloc ( cbNeeded );
+ if ( ! DllHandle ) goto failed;
+ ok = (*psapi_EnumProcessModules) ( hProcess,
+ DllHandle,
+ cbNeeded,
+ &cbNeeded );
+ if ( ! ok )
+ {
+ free ( DllHandle );
+ goto failed;
+ }
+
+ for ( i = 0; i < cbNeeded / sizeof ( HMODULE ); i++ )
+ {
+ if ( ! (*psapi_GetModuleInformation) ( hProcess,
+ DllHandle [ i ],
+ &mi,
+ sizeof ( mi ) ) )
+ {
+ free ( DllHandle );
+ goto failed;
+ }
+
+ len = (*psapi_GetModuleFileNameExA) ( hProcess,
+ DllHandle [ i ],
+ name_buf,
+ MAX_PATH );
+ if ( len == 0 )
+ {
+ free ( DllHandle );
+ goto failed;
+ }
+
+ if ( (DWORD) (mi.lpBaseOfDll) == BaseAddress )
+ {
+ free ( DllHandle );
+ return strdup ( name_buf );
+ }
+ }
+
+failed:
+ return NULL;
+}
diff --git a/winsup/utils/parse_pe.cc b/winsup/utils/parse_pe.cc
new file mode 100644
index 000000000..00aeb5502
--- /dev/null
+++ b/winsup/utils/parse_pe.cc
@@ -0,0 +1,88 @@
+/* parse_pe.cc
+
+ Copyright 1999 Cygnus Solutions.
+
+ 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 <stdio.h>
+#include <stdlib.h>
+
+#include "dumper.h"
+
+int
+exclusion::add ( LPBYTE mem_base, DWORD mem_size )
+{
+ while ( last >= size ) size += step;
+ region = (process_mem_region*) realloc ( region, size * sizeof ( process_mem_region ) );
+ if ( region == NULL ) return 0;
+ region [ last ].base = mem_base;
+ region [ last ].size = mem_size;
+ last++;
+ return 1;
+};
+
+int cmp_regions ( const void* r1, const void* r2 )
+{
+ if ( ((process_mem_region*) r1)->base < ((process_mem_region*) r2)->base )
+ return -1;
+ if ( ((process_mem_region*) r1)->base > ((process_mem_region*) r2)->base )
+ return 1;
+ return 0;
+}
+
+int
+exclusion::sort_and_check ()
+{
+ qsort ( region, last, sizeof ( process_mem_region ), &cmp_regions );
+ for ( process_mem_region* p = region; p < region + last - 1; p++ )
+ {
+ process_mem_region* q = p + 1;
+ if ( p->base + size > q->base )
+ {
+ fprintf ( stderr, "region error @ %08x", p->base );
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static void
+select_data_section ( bfd *abfd, asection *sect, PTR obj )
+{
+ exclusion* excl_list = (exclusion*) obj;
+
+ if ( ( sect->flags & ( SEC_CODE | SEC_DEBUGGING ) ) &&
+ sect->vma && sect->_raw_size )
+ {
+ excl_list->add ( (LPBYTE)sect->vma, (DWORD)sect->_raw_size );
+ deb_printf ( "excluding section: %20s %08lx\n", sect->name, sect->_raw_size);
+ }
+}
+
+int
+parse_pe ( const char* file_name, exclusion* excl_list )
+{
+ if ( file_name == NULL || excl_list == NULL ) return 0;
+
+ bfd* abfd = bfd_openr ( file_name, "pei-i386" );
+ if ( abfd == NULL )
+ {
+ bfd_perror ( "failed to open file" );
+ return 0;
+ }
+
+ bfd_check_format ( abfd, bfd_object );
+ bfd_map_over_sections ( abfd, &select_data_section, (PTR)excl_list );
+ excl_list->sort_and_check ();
+
+ bfd_close ( abfd );
+ return 1;
+}
+
diff --git a/winsup/utils/ps.cc b/winsup/utils/ps.cc
index 593629c22..362761290 100644
--- a/winsup/utils/ps.cc
+++ b/winsup/utils/ps.cc
@@ -261,9 +261,10 @@ main (int argc, char *argv[])
char pname[MAX_PATH];
if (p->process_state & PID_ZOMBIE)
strcpy (pname, "<defunct>");
- else if (p->progname[0])
+ else if (query != CW_GETPINFO_FULL)
{
char *s;
+ pname[0] = '\0';
cygwin_conv_to_posix_path (p->progname, pname);
s = strchr (pname, '\0') - 4;
if (s > pname && strcasecmp (s, ".exe") == 0)