1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sal.hxx"
26
27 #include <tchar.h>
28
29 #ifdef _MSC_VER
30 #pragma warning(push,1) // disable warnings within system headers
31 #endif
32 #define WIN32_LEAN_AND_MEAN
33 #include <windows.h>
34 #include <tlhelp32.h>
35 #include <psapi.h>
36 #ifdef _MSC_VER
37 #pragma warning(pop)
38 #endif
39
40 #include <signal.h>
41 #include <stdarg.h>
42 #include <stdlib.h>
43 #include <stdio.h>
44
45 #ifndef SIGNULL
46 #define SIGNULL 0
47 #endif
48
49 #ifndef SIGKILL
50 #define SIGKILL 9
51 #endif
52
53 #include <signal.h>
54
55 #define MAX_MODULES 1024
56
57 /////////////////////////////////////////////////////////////////////////////
58 // Determines if a returned handle value is valid
59 /////////////////////////////////////////////////////////////////////////////
60
IsValidHandle(HANDLE handle)61 static inline bool IsValidHandle( HANDLE handle )
62 {
63 return INVALID_HANDLE_VALUE != handle && NULL != handle;
64 }
65
66
67 #define elementsof( a ) (sizeof(a) / sizeof( (a)[0] ))
68
69 /////////////////////////////////////////////////////////////////////////////
70 // Retrieves function address in another process
71 /////////////////////////////////////////////////////////////////////////////
72
73 #if 1
74 #define GetProcAddressEx( hProcess, hModule, lpProcName ) GetProcAddress( hModule, lpProcName )
75 #else
GetProcAddressEx(HANDLE hProcess,HMODULE hModule,LPCSTR lpProcName)76 FARPROC WINAPI GetProcAddressEx( HANDLE hProcess, HMODULE hModule, LPCSTR lpProcName )
77 {
78 FARPROC lpfnProcAddress = GetProcAddress( hModule, lpProcName );
79
80 if ( lpfnProcAddress )
81 {
82 DWORD dwProcessId = GetProcessId( hProcess );
83
84 if ( GetCurrentProcessId() != dwProcessId )
85 {
86 FARPROC lpfnRemoteProcAddress = NULL;
87 TCHAR szBaseName[MAX_PATH];
88
89 if ( GetModuleBaseName( GetCurrentProcess(), hModule, szBaseName, elementsof(szBaseName) ) )
90 {
91 HMODULE ahModules[MAX_MODULES];
92 DWORD cbNeeded = 0;
93
94 if ( EnumProcessModules( hProcess, ahModules, sizeof(ahModules), &cbNeeded ) )
95 {
96 ULONG nModules = cbNeeded / sizeof(ahModules[0]);
97
98 for ( ULONG n = 0; n < nModules; n++ )
99 {
100 TCHAR szRemoteBaseName[MAX_PATH];
101
102 if ( GetModuleBaseName(
103 hProcess, ahModules[n], szRemoteBaseName, elementsof(szRemoteBaseName) ) &&
104 0 == lstrcmpi( szRemoteBaseName, szBaseName )
105 )
106 {
107 lpfnRemoteProcAddress = lpfnProcAddress;
108
109 if ( ahModules[n] != hModule )
110 *(LPBYTE*)&lpfnRemoteProcAddress += (LPBYTE)ahModules[n] - (LPBYTE)hModule;
111 break;
112 }
113 }
114 }
115 }
116
117 lpfnProcAddress = lpfnRemoteProcAddress;
118 }
119 }
120
121 return lpfnProcAddress;
122 }
123 #endif
124
125 /////////////////////////////////////////////////////////////////////////////
126 // Raises a signal in an other process
127 /////////////////////////////////////////////////////////////////////////////
128
SignalToExceptionCode(int signal)129 static DWORD SignalToExceptionCode( int signal )
130 {
131 switch ( signal )
132 {
133 case SIGSEGV:
134 return EXCEPTION_ACCESS_VIOLATION;
135 case SIGFPE:
136 return EXCEPTION_FLT_INVALID_OPERATION;
137 case SIGILL:
138 return EXCEPTION_ILLEGAL_INSTRUCTION;
139 case SIGINT:
140 return CONTROL_C_EXIT;
141 case SIGBREAK:
142 return CONTROL_C_EXIT;
143 default:
144 return 0;
145 }
146 }
147
RaiseSignalEx(HANDLE hProcess,int sig)148 static BOOL RaiseSignalEx( HANDLE hProcess, int sig )
149 {
150 DWORD dwProcessId = GetProcessId( hProcess );
151
152 HANDLE hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
153 HANDLE hThread = 0;
154 BOOL fSuccess = FALSE;
155
156 if ( IsValidHandle(hSnapshot) )
157 {
158 THREADENTRY32 te;
159
160 te.dwSize = sizeof(te);
161 fSuccess = Thread32First( hSnapshot, &te );
162 while ( fSuccess )
163 {
164 if ( te.th32OwnerProcessID == dwProcessId )
165 {
166 hThread = OpenThread(
167 THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION |
168 THREAD_GET_CONTEXT | THREAD_SET_CONTEXT,
169 FALSE, te.th32ThreadID );
170 if ( IsValidHandle(hThread) )
171 break;
172 }
173
174 fSuccess = Thread32Next( hSnapshot, &te );
175 }
176
177 CloseHandle( hSnapshot );
178 }
179
180 if ( fSuccess )
181 {
182 CONTEXT aContext;
183
184 if ( SuspendThread( hThread ) != (DWORD)-1 )
185 {
186 ZeroMemory( &aContext, sizeof(aContext) );
187 aContext.ContextFlags = CONTEXT_FULL;
188
189 fSuccess = GetThreadContext( hThread, &aContext );
190
191 if ( fSuccess )
192 {
193 #if defined(INTEL)
194 if ( sig )
195 {
196 DWORD dwStackBuffer[] =
197 {
198 aContext.Eip,
199 SignalToExceptionCode( sig ),
200 EXCEPTION_NONCONTINUABLE,
201 0,
202 0
203 };
204
205 aContext.Esp -= sizeof(dwStackBuffer);
206 WriteProcessMemory( hProcess, (LPVOID)aContext.Esp, dwStackBuffer, sizeof(dwStackBuffer), NULL );
207 aContext.Eip = (DWORD)GetProcAddressEx( hProcess, GetModuleHandleA("KERNEL32"), "RaiseException" );
208 }
209 else
210 {
211 // FIXME: why? Does AMD64 need it too?
212 aContext.Ecx = aContext.Eax = aContext.Ebx = aContext.Edx = aContext.Esi = aContext.Edi = 0;
213 }
214 #elif defined(X86_64)
215 if ( sig )
216 {
217 DWORD dwStackBuffer[] =
218 {
219 (DWORD)(aContext.Rip >> 32),
220 (DWORD)(aContext.Rip),
221 SignalToExceptionCode( sig ),
222 EXCEPTION_NONCONTINUABLE,
223 0,
224 0,
225 0
226 };
227
228 aContext.Rsp -= sizeof(dwStackBuffer);
229 WriteProcessMemory( hProcess, (LPVOID)aContext.Rsp, dwStackBuffer, sizeof(dwStackBuffer), NULL );
230 aContext.Rip = (DWORD64) GetProcAddressEx( hProcess, GetModuleHandleA("KERNEL32"), "RaiseException" );
231 }
232 #endif
233
234 fSuccess = SetThreadContext( hThread, &aContext );
235 }
236
237 fSuccess = ResumeThread( hThread ) && fSuccess;
238
239 DWORD dwLastError = GetLastError();
240 CloseHandle( hThread );
241 SetLastError( dwLastError );
242
243 return fSuccess;
244 }
245 }
246
247 return FALSE;
248 }
249 /////////////////////////////////////////////////////////////////////////////
250 // Command line parameter parsing
251 /////////////////////////////////////////////////////////////////////////////
252
ParseCommandArgs(LPDWORD lpProcesses,LPDWORD lpdwNumProcesses,int * pSig)253 static void ParseCommandArgs( LPDWORD lpProcesses, LPDWORD lpdwNumProcesses, int *pSig )
254 {
255 typedef struct _SignalEntry
256 {
257 LPCTSTR lpSignalName;
258 int iSignalValue;
259 } SignalEntry;
260
261 #define SIG_ENTRY( signal ) { TEXT(#signal), SIG##signal }
262
263 static SignalEntry SupportedSignals[] =
264 {
265 SIG_ENTRY( NULL ),
266 SIG_ENTRY( SEGV ),
267 SIG_ENTRY( ILL ),
268 SIG_ENTRY( FPE ),
269 SIG_ENTRY( INT ),
270 SIG_ENTRY( BREAK ),
271 SIG_ENTRY( TERM ),
272 SIG_ENTRY( ABRT ),
273 SIG_ENTRY( KILL )
274 };
275
276 const int NumSupportedSignals = elementsof(SupportedSignals);
277
278 DWORD dwMaxProcesses = *lpdwNumProcesses;
279 int argc = __argc;
280 TCHAR **argv = __targv;
281
282 *lpdwNumProcesses = 0;
283
284 for ( int argn = 1; argn < argc; argn++ )
285 {
286 if ( 0 == lstrcmpi( argv[argn], TEXT("-l") ) ||
287 0 == lstrcmpi( argv[argn], TEXT("/l") ) )
288
289 {
290 for ( int n = 0; n < NumSupportedSignals; n++ )
291 {
292 _tprintf( _T("%s "), SupportedSignals[n].lpSignalName );
293 }
294 _tprintf( _T("\n") );
295 ExitProcess( 0 );
296 }
297 else if ( 0 == lstrcmpi( argv[argn], TEXT("-?") ) ||
298 0 == lstrcmpi( argv[argn], TEXT("/?") ) ||
299 0 == lstrcmpi( argv[argn], TEXT("-h") ) ||
300 0 == lstrcmpi( argv[argn], TEXT("/h") ) ||
301 0 == lstrcmpi( argv[argn], TEXT("--help") ) )
302 {
303 _tprintf(
304 _T("Terminates a process by sending a signal.\n\n")
305 _T("Usage: kill [ -l ] [ -signal ] pid ...\n\n")
306 _T("-l Lists supported signals\n")
307 _T("-signal Sends the specified signal to the given processes.\n")
308 _T(" signal can be a numeric value specifying the signal number\n")
309 _T(" or a string listed by the -l parameter. If no signal is\n")
310 _T(" given SIGTERM (-TERM) is used.\n")
311 _T("pid Process id(s) or executables names(s) of processes to \n")
312 _T(" signal or terminate.\n\n")
313 );
314 ExitProcess( 0 );
315 }
316 else if ( argv[argn] && ( *argv[argn] == '-' || *argv[argn] == '/' ) )
317 {
318 LPCTSTR argsig = CharNext( argv[argn] );
319
320 int n;
321 for ( n = 0; n < NumSupportedSignals; n++ )
322 {
323 _TCHAR *endptr = NULL;
324
325 if ( 0 == lstrcmpi( SupportedSignals[n].lpSignalName, argsig ) ||
326 _tcstoul( argsig, &endptr, 0 ) == static_cast< unsigned >(SupportedSignals[n].iSignalValue) && (!endptr || !*endptr) )
327 {
328 *pSig = SupportedSignals[n].iSignalValue;
329 break;
330 }
331 }
332
333 if ( n >= NumSupportedSignals )
334 {
335 _ftprintf( stderr,
336 _T("kill: Illegal argument %s\n")
337 _T("Type 'kill --help' to show allowed syntax.\n")
338 _T("Type 'kill -l' to show supported signals.\n"),
339 argv[argn] );
340 ExitProcess( 0 );
341 }
342 }
343 else
344 {
345 unsigned long value = 0;
346 _TCHAR *endptr = NULL;
347
348 value = _tcstoul( argv[argn], &endptr, 0 );
349
350 if ( !endptr || !*endptr )
351 {
352 if ( *lpdwNumProcesses < dwMaxProcesses )
353 {
354 *(lpProcesses++) = value;
355 (*lpdwNumProcesses)++;
356 }
357 }
358 else
359 {
360 HANDLE hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
361
362 if ( IsValidHandle( hSnapshot ) )
363 {
364 PROCESSENTRY32 pe;
365
366 pe.dwSize = sizeof(pe);
367 BOOL fSuccess = Process32First( hSnapshot, &pe );
368
369 while ( fSuccess )
370 {
371 if ( 0 == lstrcmpi( argv[argn], pe.szExeFile ) )
372 {
373 if ( *lpdwNumProcesses < dwMaxProcesses )
374 {
375 *(lpProcesses++) = pe.th32ProcessID;
376 (*lpdwNumProcesses)++;
377 }
378 }
379 fSuccess = Process32Next( hSnapshot, &pe );
380 }
381
382 CloseHandle( hSnapshot );
383 }
384 }
385 }
386 }
387
388 if ( !*lpdwNumProcesses )
389 {
390 _ftprintf( stderr,
391 _T("kill: No process specified.\n")
392 _T("Use kill --help to show allowed syntax.\n")
393 );
394 ExitProcess( 0 );
395 }
396
397 }
398
OutputSystemMessage(DWORD dwErrorCode)399 void OutputSystemMessage( DWORD dwErrorCode )
400 {
401 LPVOID lpMsgBuf;
402 FormatMessageA(
403 FORMAT_MESSAGE_ALLOCATE_BUFFER |
404 FORMAT_MESSAGE_FROM_SYSTEM |
405 FORMAT_MESSAGE_IGNORE_INSERTS,
406 NULL,
407 dwErrorCode,
408 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
409 (LPSTR)&lpMsgBuf,
410 0,
411 NULL
412 );
413
414 printf( (LPSTR)lpMsgBuf );
415 LocalFree( lpMsgBuf );
416 }
417
_tmain()418 int _tmain()
419 {
420 DWORD dwProcessIds[1024];
421 DWORD nProcesses = elementsof(dwProcessIds);
422 int sig = SIGTERM;
423
424
425 ParseCommandArgs( dwProcessIds, &nProcesses, &sig );
426
427 for ( ULONG n = 0; n < nProcesses; n++ )
428 {
429 HANDLE hProcess;
430
431 _tprintf( _T("Sending signal to process id %d..."), dwProcessIds[n] );
432 hProcess = OpenProcess( PROCESS_TERMINATE | PROCESS_CREATE_THREAD | SYNCHRONIZE |
433 PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ,
434 FALSE, dwProcessIds[n] );
435
436 if ( IsValidHandle( hProcess ) )
437 {
438 if ( SIGKILL == sig )
439 TerminateProcess( hProcess, 255 );
440 else
441 {
442 if ( RaiseSignalEx( hProcess, sig ) )
443 _tprintf( _T("OK\n") );
444 else
445 {
446 OutputSystemMessage( GetLastError() );
447 }
448 }
449
450 CloseHandle( hProcess );
451 }
452 else
453 {
454 OutputSystemMessage( GetLastError() );
455 }
456 }
457
458 return 0;
459 }
460
461