blob: 219c416928c765ca5e0bb71d5c1e00c74e8ffce0 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sal.hxx"
#include <tchar.h>
#ifdef _MSC_VER
#pragma warning(push,1) // disable warnings within system headers
#endif
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <tlhelp32.h>
#include <psapi.h>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#include <signal.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#ifndef SIGNULL
#define SIGNULL 0
#endif
#ifndef SIGKILL
#define SIGKILL 9
#endif
#include <signal.h>
#define MAX_MODULES 1024
/////////////////////////////////////////////////////////////////////////////
// Determines if a returned handle value is valid
/////////////////////////////////////////////////////////////////////////////
static inline bool IsValidHandle( HANDLE handle )
{
return INVALID_HANDLE_VALUE != handle && NULL != handle;
}
#define elementsof( a ) (sizeof(a) / sizeof( (a)[0] ))
/////////////////////////////////////////////////////////////////////////////
// Retrieves function adress in another process
/////////////////////////////////////////////////////////////////////////////
#if 1
#define GetProcAddressEx( hProcess, hModule, lpProcName ) GetProcAddress( hModule, lpProcName )
#else
FARPROC WINAPI GetProcAddressEx( HANDLE hProcess, HMODULE hModule, LPCSTR lpProcName )
{
FARPROC lpfnProcAddress = GetProcAddress( hModule, lpProcName );
if ( lpfnProcAddress )
{
DWORD dwProcessId = GetProcessId( hProcess );
if ( GetCurrentProcessId() != dwProcessId )
{
FARPROC lpfnRemoteProcAddress = NULL;
TCHAR szBaseName[MAX_PATH];
if ( GetModuleBaseName( GetCurrentProcess(), hModule, szBaseName, elementsof(szBaseName) ) )
{
HMODULE ahModules[MAX_MODULES];
DWORD cbNeeded = 0;
if ( EnumProcessModules( hProcess, ahModules, sizeof(ahModules), &cbNeeded ) )
{
ULONG nModules = cbNeeded / sizeof(ahModules[0]);
for ( ULONG n = 0; n < nModules; n++ )
{
TCHAR szRemoteBaseName[MAX_PATH];
if ( GetModuleBaseName(
hProcess, ahModules[n], szRemoteBaseName, elementsof(szRemoteBaseName) ) &&
0 == lstrcmpi( szRemoteBaseName, szBaseName )
)
{
lpfnRemoteProcAddress = lpfnProcAddress;
if ( ahModules[n] != hModule )
*(LPBYTE*)&lpfnRemoteProcAddress += (LPBYTE)ahModules[n] - (LPBYTE)hModule;
break;
}
}
}
}
lpfnProcAddress = lpfnRemoteProcAddress;
}
}
return lpfnProcAddress;
}
#endif
/////////////////////////////////////////////////////////////////////////////
// Raises a signal in an other process
/////////////////////////////////////////////////////////////////////////////
static DWORD SignalToExceptionCode( int signal )
{
switch ( signal )
{
case SIGSEGV:
return EXCEPTION_ACCESS_VIOLATION;
case SIGFPE:
return EXCEPTION_FLT_INVALID_OPERATION;
case SIGILL:
return EXCEPTION_ILLEGAL_INSTRUCTION;
case SIGINT:
return CONTROL_C_EXIT;
case SIGBREAK:
return CONTROL_C_EXIT;
default:
return 0;
}
}
static BOOL RaiseSignalEx( HANDLE hProcess, int sig )
{
DWORD dwProcessId = GetProcessId( hProcess );
HANDLE hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
HANDLE hThread = 0;
BOOL fSuccess = FALSE;
if ( IsValidHandle(hSnapshot) )
{
THREADENTRY32 te;
te.dwSize = sizeof(te);
fSuccess = Thread32First( hSnapshot, &te );
while ( fSuccess )
{
if ( te.th32OwnerProcessID == dwProcessId )
{
hThread = OpenThread(
THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION |
THREAD_GET_CONTEXT | THREAD_SET_CONTEXT,
FALSE, te.th32ThreadID );
if ( IsValidHandle(hThread) )
break;
}
fSuccess = Thread32Next( hSnapshot, &te );
}
CloseHandle( hSnapshot );
}
if ( fSuccess )
{
CONTEXT aContext;
if ( SuspendThread( hThread ) != (DWORD)-1 )
{
ZeroMemory( &aContext, sizeof(aContext) );
aContext.ContextFlags = CONTEXT_FULL;
fSuccess = GetThreadContext( hThread, &aContext );
if ( fSuccess )
{
if ( sig )
{
DWORD dwStackBuffer[] =
{
aContext.Eip,
SignalToExceptionCode( sig ),
EXCEPTION_NONCONTINUABLE,
0,
0
};
aContext.Esp -= sizeof(dwStackBuffer);
WriteProcessMemory( hProcess, (LPVOID)aContext.Esp, dwStackBuffer, sizeof(dwStackBuffer), NULL );
aContext.Eip = (DWORD)GetProcAddressEx( hProcess, GetModuleHandleA("KERNEL32"), "RaiseException" );
}
else
{
aContext.Ecx = aContext.Eax = aContext.Ebx = aContext.Edx = aContext.Esi = aContext.Edi = 0;
}
fSuccess = SetThreadContext( hThread, &aContext );
}
fSuccess = ResumeThread( hThread ) && fSuccess;
DWORD dwLastError = GetLastError();
CloseHandle( hThread );
SetLastError( dwLastError );
return fSuccess;
}
}
return FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// Command line parameter parsing
/////////////////////////////////////////////////////////////////////////////
static void ParseCommandArgs( LPDWORD lpProcesses, LPDWORD lpdwNumProcesses, int *pSig )
{
typedef struct _SignalEntry
{
LPCTSTR lpSignalName;
int iSignalValue;
} SignalEntry;
#define SIG_ENTRY( signal ) { TEXT(#signal), SIG##signal }
static SignalEntry SupportedSignals[] =
{
SIG_ENTRY( NULL ),
SIG_ENTRY( SEGV ),
SIG_ENTRY( ILL ),
SIG_ENTRY( FPE ),
SIG_ENTRY( INT ),
SIG_ENTRY( BREAK ),
SIG_ENTRY( TERM ),
SIG_ENTRY( ABRT ),
SIG_ENTRY( KILL )
};
const int NumSupportedSignals = elementsof(SupportedSignals);
DWORD dwMaxProcesses = *lpdwNumProcesses;
int argc = __argc;
TCHAR **argv = __targv;
*lpdwNumProcesses = 0;
for ( int argn = 1; argn < argc; argn++ )
{
if ( 0 == lstrcmpi( argv[argn], TEXT("-l") ) ||
0 == lstrcmpi( argv[argn], TEXT("/l") ) )
{
for ( int n = 0; n < NumSupportedSignals; n++ )
{
_tprintf( _T("%s "), SupportedSignals[n].lpSignalName );
}
_tprintf( _T("\n") );
ExitProcess( 0 );
}
else if ( 0 == lstrcmpi( argv[argn], TEXT("-?") ) ||
0 == lstrcmpi( argv[argn], TEXT("/?") ) ||
0 == lstrcmpi( argv[argn], TEXT("-h") ) ||
0 == lstrcmpi( argv[argn], TEXT("/h") ) ||
0 == lstrcmpi( argv[argn], TEXT("--help") ) )
{
_tprintf(
_T("Terminates a process by sending a signal.\n\n")
_T("Usage: kill [ -l ] [ -signal ] pid ...\n\n")
_T("-l Lists supported signals\n")
_T("-signal Sends the specified signal to the given processes.\n")
_T(" signal can be a numeric value specifying the signal number\n")
_T(" or a string listed by the -l parameter. If no signal is\n")
_T(" given SIGTERM (-TERM) is used.\n")
_T("pid Process id(s) or executables names(s) of processes to \n")
_T(" signal or terminate.\n\n")
);
ExitProcess( 0 );
}
else if ( argv[argn] && ( *argv[argn] == '-' || *argv[argn] == '/' ) )
{
LPCTSTR argsig = CharNext( argv[argn] );
int n;
for ( n = 0; n < NumSupportedSignals; n++ )
{
_TCHAR *endptr = NULL;
if ( 0 == lstrcmpi( SupportedSignals[n].lpSignalName, argsig ) ||
_tcstoul( argsig, &endptr, 0 ) == static_cast< unsigned >(SupportedSignals[n].iSignalValue) && (!endptr || !*endptr) )
{
*pSig = SupportedSignals[n].iSignalValue;
break;
}
}
if ( n >= NumSupportedSignals )
{
_ftprintf( stderr,
_T("kill: Illegal argument %s\n")
_T("Type 'kill --help' to show allowed syntax.\n")
_T("Type 'kill -l' to show supported signals.\n"),
argv[argn] );
ExitProcess( 0 );
}
}
else
{
unsigned long value = 0;
_TCHAR *endptr = NULL;
value = _tcstoul( argv[argn], &endptr, 0 );
if ( !endptr || !*endptr )
{
if ( *lpdwNumProcesses < dwMaxProcesses )
{
*(lpProcesses++) = value;
(*lpdwNumProcesses)++;
}
}
else
{
HANDLE hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
if ( IsValidHandle( hSnapshot ) )
{
PROCESSENTRY32 pe;
pe.dwSize = sizeof(pe);
BOOL fSuccess = Process32First( hSnapshot, &pe );
while ( fSuccess )
{
if ( 0 == lstrcmpi( argv[argn], pe.szExeFile ) )
{
if ( *lpdwNumProcesses < dwMaxProcesses )
{
*(lpProcesses++) = pe.th32ProcessID;
(*lpdwNumProcesses)++;
}
}
fSuccess = Process32Next( hSnapshot, &pe );
}
CloseHandle( hSnapshot );
}
}
}
}
if ( !*lpdwNumProcesses )
{
_ftprintf( stderr,
_T("kill: No process specified.\n")
_T("Use kill --help to show allowed syntax.\n")
);
ExitProcess( 0 );
}
}
void OutputSystemMessage( DWORD dwErrorCode )
{
LPVOID lpMsgBuf;
FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dwErrorCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPSTR)&lpMsgBuf,
0,
NULL
);
printf( (LPSTR)lpMsgBuf );
LocalFree( lpMsgBuf );
}
int _tmain()
{
DWORD dwProcessIds[1024];
DWORD nProcesses = elementsof(dwProcessIds);
int sig = SIGTERM;
ParseCommandArgs( dwProcessIds, &nProcesses, &sig );
for ( ULONG n = 0; n < nProcesses; n++ )
{
HANDLE hProcess;
_tprintf( _T("Sending signal to process id %d..."), dwProcessIds[n] );
hProcess = OpenProcess( PROCESS_TERMINATE | PROCESS_CREATE_THREAD | SYNCHRONIZE |
PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ,
FALSE, dwProcessIds[n] );
if ( IsValidHandle( hProcess ) )
{
if ( SIGKILL == sig )
TerminateProcess( hProcess, 255 );
else
{
if ( RaiseSignalEx( hProcess, sig ) )
_tprintf( _T("OK\n") );
else
{
OutputSystemMessage( GetLastError() );
}
}
CloseHandle( hProcess );
}
else
{
OutputSystemMessage( GetLastError() );
}
}
return 0;
}