2014-02-09 13:23:13 +01:00
/* minidumper.cc
Copyright 2014 Red Hat Inc .
This file is part of Cygwin .
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License ( file COPYING . dumper ) for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin Street - Fifth Floor , Boston , MA 02110 - 1301 , USA .
*/
# include <sys/cygwin.h>
# include <cygwin/version.h>
# include <getopt.h>
# include <errno.h>
# include <stdio.h>
# include <stdlib.h>
# include <windows.h>
2014-05-13 12:24:16 +02:00
# include <dbghelp.h>
2014-02-09 13:23:13 +01:00
2014-05-13 12:26:26 +02:00
DEFINE_ENUM_FLAG_OPERATORS ( MINIDUMP_TYPE ) ;
2014-02-09 13:23:13 +01:00
BOOL verbose = FALSE ;
BOOL nokill = FALSE ;
2014-05-13 12:26:26 +02:00
/* Not yet in dbghelp.h */
# define MiniDumpWithModuleHeaders (static_cast<MINIDUMP_TYPE>(0x00080000))
# define MiniDumpFilterTriage (static_cast<MINIDUMP_TYPE>(0x00100000))
static MINIDUMP_TYPE
filter_minidump_type ( MINIDUMP_TYPE dump_type )
{
API_VERSION build_version = { 6 , 0 , API_VERSION_NUMBER , 0 } ;
API_VERSION * v = ImagehlpApiVersionEx ( & build_version ) ;
if ( verbose )
printf ( " dbghelp version %d.%d.%d.%d \n " , v - > MajorVersion ,
v - > MinorVersion , v - > Revision , v - > Reserved ) ;
MINIDUMP_TYPE supported_types = MiniDumpNormal | MiniDumpWithDataSegs
| MiniDumpWithFullMemory | MiniDumpWithHandleData | MiniDumpFilterMemory
| MiniDumpScanMemory ;
/*
This mainly trial and error and guesswork , as the MSDN documentation only
says what version of " Debugging Tools for Windows " added these flags , but
doesn ' t actually tell us the dbghelp . dll version which was contained in that
( and seems to have errors as well )
*/
if ( v - > MajorVersion > = 5 )
supported_types | = MiniDumpWithUnloadedModules
| MiniDumpWithIndirectlyReferencedMemory | MiniDumpFilterModulePaths
| MiniDumpWithProcessThreadData | MiniDumpWithPrivateReadWriteMemory ;
if ( v - > MajorVersion > = 6 )
supported_types | = MiniDumpWithoutOptionalData | MiniDumpWithFullMemoryInfo
| MiniDumpWithThreadInfo | MiniDumpWithCodeSegs
| MiniDumpWithoutAuxiliaryState | MiniDumpWithFullAuxiliaryState // seems to be documentation error that these two aren't listed as 'Not supported prior to 6.1'
| MiniDumpWithPrivateWriteCopyMemory | MiniDumpIgnoreInaccessibleMemory
| MiniDumpWithTokenInformation ;
if ( ( v - > MajorVersion * 10 + v - > MinorVersion ) > = 62 )
supported_types | = MiniDumpWithModuleHeaders | MiniDumpFilterTriage ; // seems to be documentation error that these two are listed as 'Not supported prior to 6.1'
if ( verbose )
printf ( " supported MINIDUMP_TYPE flags 0x%x \n " , supported_types ) ;
return ( dump_type & supported_types ) ;
}
2014-02-09 13:23:13 +01:00
static void
minidump ( DWORD pid , MINIDUMP_TYPE dump_type , const char * minidump_file )
{
HANDLE dump_file ;
HANDLE process ;
dump_file = CreateFile ( minidump_file ,
GENERIC_READ | GENERIC_WRITE ,
0 ,
NULL ,
CREATE_ALWAYS ,
FILE_FLAG_BACKUP_SEMANTICS ,
NULL ) ;
if ( dump_file = = INVALID_HANDLE_VALUE )
{
fprintf ( stderr , " error opening file \n " ) ;
return ;
}
process = OpenProcess ( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_TERMINATE ,
FALSE ,
pid ) ;
2014-04-21 14:02:59 +02:00
if ( process = = NULL )
2014-02-09 13:23:13 +01:00
{
fprintf ( stderr , " error opening process \n " ) ;
return ;
}
2014-05-13 12:24:16 +02:00
BOOL success = MiniDumpWriteDump ( process ,
pid ,
dump_file ,
dump_type ,
NULL ,
NULL ,
NULL ) ;
2014-02-09 13:23:13 +01:00
if ( success )
{
if ( verbose )
printf ( " minidump created successfully \n " ) ;
}
else
{
fprintf ( stderr , " error creating minidump \n " ) ;
}
/* Unless nokill is given, behave like dumper and terminate the dumped
process */
if ( ! nokill )
{
TerminateProcess ( process , 128 + 9 ) ;
WaitForSingleObject ( process , INFINITE ) ;
}
CloseHandle ( process ) ;
CloseHandle ( dump_file ) ;
}
static void
usage ( FILE * stream , int status )
{
fprintf ( stream , " \
Usage : % s [ OPTION ] FILENAME WIN32PID \ n \
\ n \
Write minidump from WIN32PID to FILENAME . dmp \ n \
\ n \
- t , - - type minidump type flags \ n \
- n , - - nokill don ' t terminate the dumped process \ 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 \
\ n " , program_invocation_short_name);
exit ( status ) ;
}
struct option longopts [ ] = {
{ " type " , required_argument , NULL , ' t ' } ,
{ " nokill " , no_argument , NULL , ' n ' } ,
{ " 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 }
} ;
2014-02-23 12:34:31 +01:00
const char * opts = " t:ndhqV " ;
2014-02-09 13:23:13 +01:00
static void
print_version ( )
{
printf ( " minidumper (cygwin) %d.%d.%d \n "
" Minidump write for Cygwin \n "
" Copyright (C) 1999 - %s Red Hat, Inc. \n "
" This is free software; see the source for copying conditions. There is NO \n "
" warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. \n " ,
CYGWIN_VERSION_DLL_MAJOR / 1000 ,
CYGWIN_VERSION_DLL_MAJOR % 1000 ,
CYGWIN_VERSION_DLL_MINOR ,
strrchr ( __DATE__ , ' ' ) + 1 ) ;
}
int
main ( int argc , char * * argv )
{
int opt ;
const char * p = " " ;
DWORD pid ;
2014-05-13 12:26:26 +02:00
BOOL default_dump_type = TRUE ;
2014-05-13 12:24:16 +02:00
MINIDUMP_TYPE dump_type = MiniDumpNormal ;
2014-02-09 13:23:13 +01:00
while ( ( opt = getopt_long ( argc , argv , opts , longopts , NULL ) ) ! = EOF )
switch ( opt )
{
case ' t ' :
{
char * endptr ;
2014-05-13 12:26:26 +02:00
default_dump_type = FALSE ;
2014-05-13 12:24:16 +02:00
dump_type = ( MINIDUMP_TYPE ) strtoul ( optarg , & endptr , 0 ) ;
2014-02-09 13:23:13 +01:00
if ( * endptr ! = ' \0 ' )
{
fprintf ( stderr , " syntax error in minidump type \" %s \" near character #%d. \n " , optarg , ( int ) ( endptr - optarg ) ) ;
exit ( 1 ) ;
}
}
break ;
case ' n ' :
nokill = TRUE ;
break ;
case ' d ' :
verbose = TRUE ;
break ;
case ' q ' :
verbose = FALSE ;
break ;
case ' h ' :
usage ( stdout , 0 ) ;
case ' V ' :
print_version ( ) ;
exit ( 0 ) ;
default :
fprintf ( stderr , " Try `%s --help' for more information. \n " ,
program_invocation_short_name ) ;
exit ( 1 ) ;
}
if ( argv & & * ( argv + optind ) & & * ( argv + optind + 1 ) )
{
ssize_t len = cygwin_conv_path ( CCP_POSIX_TO_WIN_A | CCP_RELATIVE ,
* ( argv + optind ) , NULL , 0 ) ;
char * win32_name = ( char * ) alloca ( len ) ;
cygwin_conv_path ( CCP_POSIX_TO_WIN_A | CCP_RELATIVE , * ( argv + optind ) ,
win32_name , len ) ;
if ( ( p = strrchr ( win32_name , ' \\ ' ) ) )
p + + ;
else
p = win32_name ;
pid = strtoul ( * ( argv + optind + 1 ) , NULL , 10 ) ;
}
else
{
usage ( stderr , 1 ) ;
return - 1 ;
}
char * minidump_file = ( char * ) malloc ( strlen ( p ) + sizeof ( " .dmp " ) ) ;
if ( ! minidump_file )
{
fprintf ( stderr , " error allocating memory \n " ) ;
return - 1 ;
}
sprintf ( minidump_file , " %s.dmp " , p ) ;
2014-05-13 12:26:26 +02:00
if ( default_dump_type )
{
dump_type = MiniDumpWithHandleData | MiniDumpWithFullMemoryInfo
| MiniDumpWithThreadInfo | MiniDumpWithFullAuxiliaryState
| MiniDumpIgnoreInaccessibleMemory | MiniDumpWithTokenInformation
| MiniDumpWithIndirectlyReferencedMemory ;
/*
Only filter out unsupported dump_type flags if we are using the default
dump type , so that future dump_type flags can be explicitly used even if
we don ' t know about them
*/
dump_type = filter_minidump_type ( dump_type ) ;
}
2014-02-09 13:23:13 +01:00
if ( verbose )
printf ( " dumping process %u to %s using dump type flags 0x%x \n " , ( unsigned int ) pid , minidump_file , ( unsigned int ) dump_type ) ;
minidump ( pid , dump_type , minidump_file ) ;
free ( minidump_file ) ;
} ;