core/win32/os.c
/* dcontext is not needed for TERMINATE_PROCESS, so can pass NULL in
 */
dcontext is not needed for TERMINATE_PROCESS, so can pass NULL in
dcontext is not needed for TERMINATE_PROCESS so can pass NULL in
void
os_terminate(dcontext_t *dcontext, terminate_flags_t terminate_type)
{
    HANDLE currentThreadOrProcess = NT_CURRENT_PROCESS;
    bool exit_process = true;
    ASSERT(TEST(TERMINATE_PROCESS, terminate_type) != 
           TEST(TERMINATE_THREAD, terminate_type));
    if (terminate_type == TERMINATE_PROCESS) {
        if (TESTANY(DETACH_ON_TERMINATE|DETACH_ON_TERMINATE_NO_CLEAN, 
                    DYNAMO_OPTION(internal_detach_mask))) {
            detach_helper(TEST(DETACH_ON_TERMINATE_NO_CLEAN, 
                               DYNAMO_OPTION(internal_detach_mask)) ? 
                          DETACH_BAD_STATE_NO_CLEANUP : DETACH_BAD_STATE);
            SYSLOG_INTERNAL_NO_OPTION_SYNCH(SYSLOG_WARNING, 
                                            "detach on terminate failed or already started by another thread, killing thread %d\n", 
                                            get_thread_id());
            terminate_type = TERMINATE_THREAD;
        } else {
            config_exit(); 
            nt_terminate_process(currentThreadOrProcess, KILL_PROC_EXIT_STATUS);
            ASSERT_NOT_REACHED();
        }
    }
    if (TEST(TERMINATE_THREAD, terminate_type)) {
        exit_process = (!IS_CLIENT_THREAD(dcontext) &&
                        is_last_app_thread() && !dynamo_exited);
        if (!exit_process) {
            currentThreadOrProcess = NT_CURRENT_THREAD;
        } 
    }
    STATS_INC(num_threads_killed);
    if (TEST(TERMINATE_CLEANUP, terminate_type)) {
        byte *arguments = os_terminate_static_arguments(exit_process);
        ASSERT(does_syscall_ret_to_callsite() ||
               *(byte **)arguments == (byte *)&debug_infinite_loop ||
               (DYNAMO_OPTION(sygate_sysenter) && 
                *(((byte **)arguments)+1) == (byte *)&debug_infinite_loop));
        STATS_INC(num_threads_killed_cleanly);
        KSTOP_REWIND_UNTIL(thread_measured);
        ASSERT(dcontext != NULL);
        cleanup_and_terminate
            (dcontext, 
             syscalls[exit_process ? SYS_TerminateProcess : SYS_TerminateThread],
             (ptr_uint_t)
             IF_X64_ELSE((exit_process ? NT_CURRENT_PROCESS : NT_CURRENT_THREAD),
                         arguments),
             (ptr_uint_t)
             IF_X64_ELSE((exit_process ? KILL_PROC_EXIT_STATUS:KILL_THREAD_EXIT_STATUS),
                         arguments ),
             exit_process);
    } else {
        if (exit_process) {
            config_exit(); 
            nt_terminate_process(currentThreadOrProcess, KILL_PROC_EXIT_STATUS);
            ASSERT_NOT_REACHED();
        } else {
            if (all_threads != NULL)
                remove_thread(NULL, get_thread_id());
            nt_terminate_thread(currentThreadOrProcess, KILL_THREAD_EXIT_STATUS);
            ASSERT_NOT_REACHED();
        }
    }
    ASSERT_NOT_REACHED();
}
void os_terminate ( dcontext_t * dcontext , terminate_flags_t terminate_type ) { HANDLE currentThreadOrProcess = NT_CURRENT_PROCESS ; bool exit_process = true ; ASSERT ( TEST ( TERMINATE_PROCESS , terminate_type ) != TEST ( TERMINATE_THREAD , terminate_type ) ) ; if ( terminate_type == TERMINATE_PROCESS ) { if ( TESTANY ( DETACH_ON_TERMINATE | DETACH_ON_TERMINATE_NO_CLEAN , DYNAMO_OPTION ( internal_detach_mask ) ) ) { detach_helper ( TEST ( DETACH_ON_TERMINATE_NO_CLEAN , DYNAMO_OPTION ( internal_detach_mask ) ) ? DETACH_BAD_STATE_NO_CLEANUP : DETACH_BAD_STATE ) ; SYSLOG_INTERNAL_NO_OPTION_SYNCH ( SYSLOG_WARNING , " \n " , get_thread_id ( ) ) ; terminate_type = TERMINATE_THREAD ; } else { config_exit ( ) ; nt_terminate_process ( currentThreadOrProcess , KILL_PROC_EXIT_STATUS ) ; ASSERT_NOT_REACHED ( ) ; } } if ( TEST ( TERMINATE_THREAD , terminate_type ) ) { exit_process = ( ! IS_CLIENT_THREAD ( dcontext ) && is_last_app_thread ( ) && ! dynamo_exited ) ; if ( ! exit_process ) { currentThreadOrProcess = NT_CURRENT_THREAD ; } } STATS_INC ( num_threads_killed ) ; if ( TEST ( TERMINATE_CLEANUP , terminate_type ) ) { byte * arguments = os_terminate_static_arguments ( exit_process ) ; ASSERT ( does_syscall_ret_to_callsite ( ) || * ( byte * * ) arguments == ( byte * ) & debug_infinite_loop || ( DYNAMO_OPTION ( sygate_sysenter ) && * ( ( ( byte * * ) arguments ) + 1 ) == ( byte * ) & debug_infinite_loop ) ) ; STATS_INC ( num_threads_killed_cleanly ) ; KSTOP_REWIND_UNTIL ( thread_measured ) ; ASSERT ( dcontext != NULL ) ; cleanup_and_terminate ( dcontext , syscalls [ exit_process ? SYS_TerminateProcess : SYS_TerminateThread ] , ( ptr_uint_t ) IF_X64_ELSE ( ( exit_process ? NT_CURRENT_PROCESS : NT_CURRENT_THREAD ) , arguments ) , ( ptr_uint_t ) IF_X64_ELSE ( ( exit_process ? KILL_PROC_EXIT_STATUS : KILL_THREAD_EXIT_STATUS ) , arguments ) , exit_process ) ; } else { if ( exit_process ) { config_exit ( ) ; nt_terminate_process ( currentThreadOrProcess , KILL_PROC_EXIT_STATUS ) ; ASSERT_NOT_REACHED ( ) ; } else { if ( all_threads != NULL ) remove_thread ( NULL , get_thread_id ( ) ) ; nt_terminate_thread ( currentThreadOrProcess , KILL_THREAD_EXIT_STATUS ) ; ASSERT_NOT_REACHED ( ) ; } } ASSERT_NOT_REACHED ( ) ; }
dcontext is not needed for TERMINATE_PROCESS, so can pass NULL in
dcontext is not needed for TERMINATE_PROCESS so can pass NULL in
/* xor */ /* We could be holding the bb_building_lock at this point -- if we cleanup,
     * we will get a rank order violation with all_threads_synch_lock.  if we
     * unlock the bb lock, we risk an error about the non-owning thread
     * releasing the lock.
     * Our solution is for the caller to release it when possible --
     * on an attack we know if we hold it or not.  But for other callers
     * they do not know who holds it...for now we do nothing, none of them
     * terminate just a thread, so the process is going down anyway, and it's
     * just a debug build assertion :)
     */ /* clean up may be dangerous - just terminate */ /* skip synchronizing dynamic options, is risky and caller has almost 
         * certainly already done so for a syslog */ /* FIXME : if we run into stack problems we could reset the stack
             * here though caller has likely alredy gone as deep as detach 
             * will since almost everyone SYSLOG's before calling this */ /* skip option synch, make this as safe as possible */ /* if we get here, either we recursed or someone is already trying
             * to detach, just kill this thread so progress is made we don't
             * have anything better to do with it */ /* skip cleanup, our state is likely messed up and we'd just like 
             * to get out alive, also avoids recursion problems, see caveat at 
             * remove_thread below */ /* delete .1config file */ /* CHECK: Can a process disallow PROCESS_TERMINATE or THREAD_TERMINATE 
       access even to itself? 
    */ /* Make sure debug loop pointer is in expected place since this makes
         * assumptions about offsets.  We don't use the debug loop pointer for
         * int2e/syscall/wow64 system calls (since they return to the invocation
         * and can be handled there).  For SYSENTER the SYSCALL_PARAM_OFFSET should
         * match up with arguments such that arguments is pointing to debugme */ /* we enter from several different places, so rewind until top-level kstat */ /* now we issue a syscall by number */ /* we can't use issue_system_call_for_app because it relies on 
         * dstack that we should release */ /* FIXME: what happens now if we get some callbacks that are still on 
         * their way? Shouldn't happen since Terminate* are believed to be 
         * non-alertable. */ /* FIXME: we only want the last part of cleanup_and_terminate */ /* no 2nd arg, just a filler */ /* may have decided to terminate process */ /* delete .1config file */ /* FIXME: this is now very dangerous - we even leave our own state */ /* we should at least remove this thread from the all threads list 
             * to avoid synchronizing issues, though we are running the risk of
             * an infinite loop with a failure in this function and detach on 
             * failure */ /* CHECK: who is supposed to clean up the thread's stack?  
           ZwFreeVirtualMemory can be called by another thread
           waiting on the thread object, hopefully someone will do it */