예제 #1
0
void recover_from_breakpoint
  (LPDBGPROCESS process, LPDBGTHREAD thread, BOOL resume)
{
  CONTEXT          context;
  LPDEBUG_POINT    breakpoint;
  BOOL             status;

  context.ContextFlags = CONTEXT_CONTROL;
  status = get_thread_context(process, thread, &context);

  thread->NeedsBreakpointReplacement = FALSE;
  breakpoint = thread->BreakpointToReplace;

  drop_breakpoint(process, breakpoint);

  // In order to recover from the breakpoint, we will have put the
  // processor into single-step mode. We now need to take it
  // out of single-step mode UNLESS the thread was being
  // single-stepped anyway!

  if (!(thread->SingleStepping)) {
    context.EFlags = context.EFlags & 0xFFFFFEFF;
    /*
      dylan_debugger_message("Resuming all threads for breakpoint recovery %=",
                             thread->ThreadHandle, 0);
      if (resume)
      resume_all_except(process, thread);
      */
  }

  status = SetThreadContext(thread->ThreadHandle, &context);
}
예제 #2
0
		void bedrock::event_move(core_window_t* wd, int x, int y)
		{
			if (wd)
			{
				arg_move arg;
				arg.window_handle = reinterpret_cast<window>(wd);
				arg.x = x;
				arg.y = y;
				if (emit(event_code::move, wd, arg, false, get_thread_context()))
					wd_manager.update(wd, false, true);
			}
		}
예제 #3
0
		bool bedrock::event_msleave(core_window_t* hovered)
		{
			if (wd_manager.available(hovered) && hovered->flags.enabled)
			{
				hovered->flags.action = mouse_action::normal;

				arg_mouse arg;
				arg.evt_code = event_code::mouse_leave;
				arg.window_handle = reinterpret_cast<window>(hovered);
				arg.pos.x = arg.pos.y = 0;
				arg.left_button = arg.right_button = arg.mid_button = false;
				arg.ctrl = arg.shift = false;
				emit(event_code::mouse_leave, hovered, arg, true, get_thread_context());
				return true;
			}
			return false;
		}
예제 #4
0
파일: itest.c 프로젝트: 1u4nx/ChezScheme
static ptr eval(ptr x) {
  if (Spairp(x)) {
    switch (Schar_value(Scar(x))) {
      case '+': return S_add(First(x), Second(x));
      case '-': return S_sub(First(x), Second(x));
      case '*': return S_mul(First(x), Second(x));
      case '/': return S_div(First(x), Second(x));
      case 'q': return S_trunc(First(x), Second(x));
      case 'r': return S_rem(First(x), Second(x));
      case 'g': return S_gcd(First(x), Second(x));
      case '=': {
        ptr x1 = First(x), x2 = Second(x);
        if (Sfixnump(x1) && Sfixnump(x2))
          return Sboolean(x1 == x2);
        else if (Sbignump(x1) && Sbignump(x2))
          return Sboolean(S_big_eq(x1, x2));
        else return Sfalse;
      }
      case '<': {
        ptr x1 = First(x), x2 = Second(x);
        if (Sfixnump(x1))
          if (Sfixnump(x2))
            return Sboolean(x1 < x2);
          else
            return Sboolean(!BIGSIGN(x2));
        else
          if (Sfixnump(x2))
            return Sboolean(BIGSIGN(x1));
          else
            return Sboolean(S_big_lt(x1, x2));
      }
      case 'f': return Sflonum(S_floatify(First(x)));
      case 'c':
        S_gc(get_thread_context(), UNFIX(First(x)),UNFIX(Second(x)));
        return Svoid;
      case 'd': return S_decode_float(Sflonum_value(First(x)));
      default:
        S_prin1(x);
        putchar('\n');
        printf("unrecognized operator, returning zero\n");
        return FIX(0);
    }
  } else
    return x;
}
예제 #5
0
	void get_debug_event()
	{
		PCONTEXT ctx;

		debug_event = DEBUG_EVENT();
		ctn_status = DBG_CONTINUE;

		if (WaitForDebugEvent(&debug_event, INFINITE))
		{
			h_thread = open_thread(debug_event.dwThreadId);
			ctx = get_thread_context(h_thread, NULL);

			std::cout << "[E] Event Code : " << debug_event.dwDebugEventCode
					 << " Thread ID : " << debug_event.dwThreadId << std::endl;

			if (debug_event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT)
			{
				exception = debug_event.u.Exception.ExceptionRecord.ExceptionCode;
				exception_address = debug_event.u.Exception.ExceptionRecord.ExceptionAddress;

				switch (exception)
				{
				case EXCEPTION_ACCESS_VIOLATION:
					std::cout << "[EXCEPTION] ACCESS VIOLATION." << std::endl;
					break;
				case EXCEPTION_BREAKPOINT:
					ctn_status = exception_handler_breakpoint();
					break;
				case EXCEPTION_GUARD_PAGE:
					std::cout << "[EXCEPTION] Guard Page Access Detected." << std::endl;
					break;
				case EXCEPTION_SINGLE_STEP:
					std::cout << "[EXCEPTION] Single Stepping." << std::endl;
					break;
				default:
					break;
				}

				ContinueDebugEvent(debug_event.dwProcessId,
					debug_event.dwThreadId, ctn_status);
			}
		}

		ContinueDebugEvent(debug_event.dwProcessId, debug_event.dwThreadId, ctn_status);
	}
예제 #6
0
		void bedrock::update_cursor(core_window_t * wd)
		{
			internal_scope_guard isg;
			if (wd_manager.available(wd))
			{
				auto * thrd = get_thread_context(wd->thread_id);
				if (nullptr == thrd)
					return;

				auto pos = native_interface::cursor_position();
				auto native_handle = native_interface::find_window(pos.x, pos.y);
				if (!native_handle)
					return;

				native_interface::calc_window_point(native_handle, pos);
				if (wd != wd_manager.find_window(native_handle, pos.x, pos.y))
					return;

				set_cursor(wd, wd->predef_cursor, thrd);
			}
		}
예제 #7
0
		void bedrock::event_expose(core_window_t * wd, bool exposed)
		{
			if (nullptr == wd) return;

			wd->visible = exposed;

			arg_expose arg;
			arg.exposed = exposed;
			arg.window_handle = reinterpret_cast<window>(wd);
			if (emit(event_code::expose, wd, arg, false, get_thread_context()))
			{
				const core_window_t * caret_wd = (wd->together.caret ? wd : wd->child_caret());
				if (caret_wd)
				{
					if (exposed)
					{
						if (wd->root_widget->other.attribute.root->focus == caret_wd)
							caret_wd->together.caret->visible(true);
					}
					else
						caret_wd->together.caret->visible(false);
				}

				if (!exposed)
				{
					if (category::flags::root != wd->other.category)
					{
						//find an ancestor until it is not a lite_widget
						wd = wd->seek_non_lite_widget_ancestor();
					}
					else if (category::flags::frame == wd->other.category)
						wd = wd_manager.find_window(wd->root, wd->pos_root.x, wd->pos_root.y);
				}

				wd_manager.refresh_tree(wd);
				wd_manager.map(wd, false);
			}
		}
예제 #8
0
static void main_init() {
    ptr tc = get_thread_context();
    ptr p;
    INT i;

  /* force thread inline allocation to go through find_room until ready */
    AP(tc) = (ptr)0;
    EAP(tc) = (ptr)0;
    REAL_EAP(tc) = (ptr)0;
  /* set up dummy CP so locking in read/write/Scall won't choke */
    CP(tc) = Svoid;
    CODERANGESTOFLUSH(tc) = Snil;

    if (S_boot_time) S_G.protect_next = 0;

    S_segment_init();
    S_alloc_init();
    S_thread_init();
    S_intern_init();
    S_gc_init();
    S_number_init();
    S_schsig_init();
    S_new_io_init();
    S_print_init();
    S_stats_init();
    S_foreign_init();
    S_prim_init();
    S_prim5_init();
    S_fasl_init();
    S_machine_init();
    S_flushcache_init(); /* must come after S_machine_init(); */
#ifdef FEATURE_EXPEDITOR
    S_expeditor_init();
#endif /* FEATURE_EXPEDITOR */

    if (!S_boot_time) return;

    FXLENGTHBV(tc) = p = S_bytevector(256);
    for (i = 0; i < 256; i += 1) {
      BVIT(p, i) =
       (iptr)FIX(i & 0x80 ? 8 : i & 0x40 ? 7 : i & 0x20 ? 6 : i & 0x10 ? 5 :
                 i & 0x08 ? 4 : i & 0x04 ? 3 : i & 0x02 ? 2 : i & 0x01 ? 1 : 0);
    }

    FXFIRSTBITSETBV(tc) = p = S_bytevector(256);
    for (i = 0; i < 256; i += 1) {
      BVIT(p, i) =
       (iptr)FIX(i & 0x01 ? 0 : i & 0x02 ? 1 : i & 0x04 ? 2 : i & 0x08 ? 3 :
                 i & 0x10 ? 4 : i & 0x20 ? 5 : i & 0x40 ? 6 : i & 0x80 ? 7 : 0);
    }

    NULLIMMUTABLEVECTOR(tc) = S_null_immutable_vector();
    NULLIMMUTABLEFXVECTOR(tc) = S_null_immutable_fxvector();
    NULLIMMUTABLEBYTEVECTOR(tc) = S_null_immutable_bytevector();
    NULLIMMUTABLESTRING(tc) = S_null_immutable_string();

    PARAMETERS(tc) = S_G.null_vector;
    for (i = 0 ; i < virtual_register_count ; i += 1) {
      VIRTREG(tc, i) = FIX(0);
    }

    p = S_code(tc, type_code, size_rp_header);
    CODERELOC(p) = S_relocation_table(0);
    CODENAME(p) = Sfalse;
    CODEARITYMASK(p) = FIX(0);
    CODEFREE(p) = 0;
    CODEINFO(p) = Sfalse;
    CODEPINFOS(p) = Snil;
    RPHEADERFRAMESIZE(&CODEIT(p, 0)) = 0;
    RPHEADERLIVEMASK(&CODEIT(p, 0)) = 0;
    RPHEADERTOPLINK(&CODEIT(p, 0)) =
       (uptr)&RPHEADERTOPLINK(&CODEIT(p, 0)) - (uptr)p;
    S_protect(&S_G.dummy_code_object);
    S_G.dummy_code_object = p;

    S_protect(&S_G.error_invoke_code_object);
    S_G.error_invoke_code_object = Snil;
    S_protect(&S_G.invoke_code_object);
    S_G.invoke_code_object = Snil;

    S_protect(&S_G.active_threads_id);
    S_G.active_threads_id = S_intern((const unsigned char *)"$active-threads");
    S_set_symbol_value(S_G.active_threads_id, FIX(0));

    S_protect(&S_G.heap_reserve_ratio_id);
    S_G.heap_reserve_ratio_id = S_intern((const unsigned char *)"$heap-reserve-ratio");
    SETSYMVAL(S_G.heap_reserve_ratio_id, Sflonum(default_heap_reserve_ratio));

    S_protect(&S_G.scheme_version_id);
    S_G.scheme_version_id = S_intern((const unsigned char *)"$scheme-version");
    S_protect(&S_G.make_load_binary_id);
    S_G.make_load_binary_id = S_intern((const unsigned char *)"$make-load-binary");
    S_protect(&S_G.load_binary);
    S_G.load_binary = Sfalse;
}
예제 #9
0
TARGET_ADDRESS nub_allocate_stack_space
  (NUB nub,
   NUBTHREAD nubthread,
   NUBINT byte_count)
{
  LPDBGPROCESS                   process = (LPDBGPROCESS) nub;
  LPDBGTHREAD                    thread = (LPDBGTHREAD) nubthread;
  NUBINT                         code;
  DWORD                          count = (DWORD) byte_count;
  CONTEXT                        context;
  CONTEXT                        context_as_was;
  BOOL                           status_get_context, 
                                 status_set_context, 
                                 status_write,
                                 status_read;
  ALLOCATOR_INSTRUCTION_SEQUENCE instruction_sequence;
  ALLOCATOR_INSTRUCTION_SEQUENCE saved_stack_memory;
  DWORD                          SP;
  DWORD                          IP;
  DWORD                          instruction_position;
  DWORD                          bytes_written,
                                 bytes_read;
  DWORD                          expected_bp_address;
  BOOL                           spy_has_returned = FALSE;
  int                            second_chance_counter = 0;

  // Get the context for the thread.

  context.ContextFlags = CONTEXT_FULL;
  status_get_context =  get_thread_context(process, thread, &context);

  dylan_debugger_message("nub_allocate_stack_space: Thread Context before: %= : %=",
			 thread->ThreadHandle, status_get_context);
  dylan_debugger_message("Esp: %=  Eip: %=",
			 context.Esp,
			 context.Eip);

  context_as_was = context;

  if (thread->NeedsBreakpointReplacement)
    context.EFlags = context.EFlags & 0xFFFFFEFF;

  // Fill in the instruction sequence SUB ESP, <count>; INT 3

  instruction_sequence.Nop1 = 0x90;
  instruction_sequence.Nop2 = 0x90;
  instruction_sequence.SubInstruction = 0x81;
  instruction_sequence.SpecifyEsp = 0xEC;
  instruction_sequence.Immediate32 = count;
  instruction_sequence.BreakInstruction = 0xCC;

  SP = context.Esp;
  IP = context.Eip;

  // Write the instruction sequence onto the stack. The number of words we
  // are writing is small enough that this should work on both NT and
  // 95.

//context.Esp -= sizeof(ALLOCATOR_INSTRUCTION_SEQUENCE);
  instruction_position = context.Esp;
  context.Eip = instruction_position;

  // Save the data that was there originally. As a precaution, we will
  // re-write this back again if we have to abort the whole procedure.

  status_read =
     ReadProcessMemory
         (process->ProcessHandle,
          (LPCVOID) instruction_position,
          (LPVOID) &saved_stack_memory,
          sizeof(ALLOCATOR_INSTRUCTION_SEQUENCE),
          &bytes_read);

  // Out with the old, in with the new...

  status_write =
     ValidatedWriteProcessMemory 
         (process->ProcessHandle,
          (LPVOID) instruction_position,
          (LPVOID) &instruction_sequence,
          sizeof(ALLOCATOR_INSTRUCTION_SEQUENCE),
          &bytes_written);

  // Flush the instruction cache because we have written a segment of
  // code.

  FlushInstructionCache(process->ProcessHandle,
                        (LPCVOID) instruction_position,
                        sizeof(ALLOCATOR_INSTRUCTION_SEQUENCE));

  // Set the context of the thread so that it will execute the SUB instruction
  // and then return control to the debugger.

  status_set_context = SetThreadContext(thread->ThreadHandle, &context);

  if (!status_set_context) {
    status_write =
       ValidatedWriteProcessMemory 
           (process->ProcessHandle,
            (LPVOID) instruction_position,
            (LPVOID) &saved_stack_memory,
            sizeof(ALLOCATOR_INSTRUCTION_SEQUENCE),
            &bytes_written);
    SetThreadContext(thread->ThreadHandle, &context_as_was); // Just in case
    return(NULL);
  }

  // Remember the address at which we expect the breakpoint.

  expected_bp_address = instruction_position + 8;

  // Let the thread execute the fragment of code. Hopefully, that will give
  // us space on the stack that Windows 95 won't crap all over.

  suspend_all(process);
  process->ThreadRunningSpy = thread;
  thread->AddressOfSpyBreakpoint = expected_bp_address;

  // Explicitly continue all threads to release frozen threads;
  // they are all suspended at this point so won't be put back
  // into execution

  nub_threads_continue(nub);

  // Now do what it takes to put this Spy running Thread alone into execution

  execute_thread(thread);

  wait_for_stop_reason_internal
     (process, TRUE, 30000, &code, STOP_REASON_WAIT_SPY);

  if (code == SPY_RETURN_DBG_EVENT) {
    // Resume the suspended threads.
    resume_all_except(process, thread);

    // Write back the stack data that we crapped all over.
    status_write =
       ValidatedWriteProcessMemory 
           (process->ProcessHandle,
            (LPVOID) instruction_position,
            (LPVOID) &saved_stack_memory,
            sizeof(ALLOCATOR_INSTRUCTION_SEQUENCE),
            &bytes_written);

    // Get the context again. This should have ESP correctly set.
    status_get_context = GetThreadContext(thread->ThreadHandle, &context);

    dylan_debugger_message("nub_allocate_stack_space: Thread Context after: %= : %=",
			   thread->ThreadHandle, status_get_context);
    dylan_debugger_message("Esp: %=  Eip: %=",
			   context.Esp,
			   context.Eip);


    return((TARGET_ADDRESS) (context.Esp));
  }
  else {
    resume_all_except(process, thread);
    status_write =
       ValidatedWriteProcessMemory 
           (process->ProcessHandle,
            (LPVOID) instruction_position,
            (LPVOID) &saved_stack_memory,
            sizeof(ALLOCATOR_INSTRUCTION_SEQUENCE),
            &bytes_written);
    SetThreadContext(thread->ThreadHandle, &context_as_was);
    nub_debug_message("Error: Micro Spy call failed on Thread %=, code: %=",
		      (TARGET_ADDRESS)thread->ThreadHandle,
		      (TARGET_ADDRESS)code);
    return (NULL);
  }
  // Resume the suspended threads.
  resume_all_except(process, thread);

  // Write back the stack data that we crapped all over.

  status_write =
     ValidatedWriteProcessMemory 
         (process->ProcessHandle,
          (LPVOID) instruction_position,
          (LPVOID) &saved_stack_memory,
          sizeof(ALLOCATOR_INSTRUCTION_SEQUENCE),
          &bytes_written);

  // Get the context again. This should have ESP correctly set.
  status_get_context = GetThreadContext(thread->ThreadHandle, &context);

  return((TARGET_ADDRESS) (context.Esp));
}
예제 #10
0
TARGET_ADDRESS nub_setup_function_call 
  (NUB nub, 
   NUBTHREAD thread,
   TARGET_ADDRESS function, 
   NUBINT arg_count,
   TARGET_ADDRESS *args,
   NUBHANDLE *context_cookie)
{
  LPDBGPROCESS        process = (LPDBGPROCESS) nub;
  LPDBGTHREAD         threadC = (LPDBGTHREAD) thread;
  CONTEXT             context;
  THREAD_MEMORY       *saved_thread 
                       = (THREAD_MEMORY*) malloc (sizeof(THREAD_MEMORY));
  BOOL                status;
  DWORD               stack_position;
  DWORD               original_IP;
  DWORD               i = 0;
  BOOL                write_status;
  DWORD               bytes_written;
  TARGET_ADDRESS      address_to_break;

  // suspend_thread(threadC);

  // Now get context information. We need to know the return address
  // for our frame-to-be, and also the stack pointer + frame pointer
  // as is.

  context.ContextFlags = CONTEXT_FULL;

  status = get_thread_context(process, threadC, &context);

  dylan_debugger_message("nub_setup_function_call: Thread Context: %= : %=",
			 threadC->ThreadHandle, status);
  dylan_debugger_message("Esp: %=  Eip: %=",
			 context.Esp,
			 context.Eip);

  //print_context("Context pulled from thread state", &context);

  // Now remember everything about the debug state of this thread.

  saved_thread->ThreadState = threadC->ThreadState;
  saved_thread->WaitingForDebugger = threadC->WaitingForDebugger;
  saved_thread->SingleStepping = threadC->SingleStepping;
  saved_thread->NeedsBreakpointReplacement 
     = threadC->NeedsBreakpointReplacement;
  saved_thread->BreakpointToReplace = threadC->BreakpointToReplace;
  saved_thread->StoppedState = threadC->StoppedState;
  saved_thread->LastReceivedEvent = threadC->LastReceivedEvent;
  saved_thread->NubCodeOfLastEvent = threadC->NubCodeOfLastEvent;
  saved_thread->ThreadContext = context;

  // Allocate enough space on the stack to hold the arguments to the
  // remote function, and the return address.

  stack_position = 
     (DWORD) nub_allocate_stack_space
       (nub, 
        thread,
        ((DWORD) (arg_count + 1)) * sizeof(DWORD));

  if (stack_position == 0x0) {
    debugger_error("Serious Error: Failed to allocate stack in Spy call on Thread %=",
		   (TARGET_ADDRESS)threadC->ThreadHandle,
		   (TARGET_ADDRESS)NULL);
    // Internal error
    return(NULL);
  }

  // And get ready for the remote call. If the thread was stopped at a
  // breakpoint, we need to override that, because we are going to alter
  // the instruction pointer.

  if (saved_thread->NeedsBreakpointReplacement) {
    LPDEBUG_POINT breakpoint = saved_thread->BreakpointToReplace;
    drop_breakpoint(process, breakpoint);
    threadC->NeedsBreakpointReplacement = FALSE;
    if (!(saved_thread->SingleStepping)) {
      context.EFlags = context.EFlags & 0xFFFFFEFF;
    }
    // And resume those threads that will have been suspended.
    // resume_all_except(process, thread);
  }

  if (!status) {
    // Internal nub error.
    return (NULL);
  }

  //print_context("Context being saved", &(saved_thread->ThreadContext));

  // Grab the return address so that the access path chappies can set a
  // breakpoint on it to clean up the stack.

  address_to_break = (TARGET_ADDRESS) context.Eip;
  original_IP = context.Eip;

  // DIY stack frame!!!!
  // We are using the C calling convention to bring about our remote
  // call. At the point of call, the new stack frame must have all the
  // arguments pushed, followed by the return address.

  context.Esp = stack_position;

  // And make the instruction pointer point to our function.

  context.Eip = (DWORD) function;

  // The stack should now be fooling this thread into thinking that
  // it has to execute our remote function, which it will go off and do
  // as soon as the application resumes. But we have to set the context.

  status = SetThreadContext (threadC->ThreadHandle, &context);

  if (!status) {
    // Internal nub error.
    return(NULL);
  }

  // print_context("Context set back to thread", &context);
  // Push the return address - ie, the next instruction that was going
  // to be executed, before we started messing about...

  write_status =
    ValidatedWriteProcessMemory 
      (process->ProcessHandle,
       (LPVOID) stack_position,
       (LPVOID) &(original_IP),
       sizeof(TARGET_ADDRESS),
       &bytes_written);

  stack_position += sizeof(TARGET_ADDRESS);

  if ((!write_status) || (bytes_written != sizeof(TARGET_ADDRESS))) {
    // Internal nub error.
    return (NULL);
  }

  // Push the argument array.

  for (i = 0; i < (DWORD) arg_count; i++) {

    write_status =
      ValidatedWriteProcessMemory 
        (process->ProcessHandle,
         (LPVOID) stack_position,
         (LPVOID) &(args[i]),
         sizeof(TARGET_ADDRESS),
         &bytes_written);

    if ((!write_status) || (bytes_written != sizeof(TARGET_ADDRESS))) {
      // Internal nub error.
      return (NULL);
    }
    else {
      //printf ("Wrote the argument %x at %x.\n", args[i], stack_position);
    }
    stack_position += sizeof(TARGET_ADDRESS);
  }


  //print_context("Context set back to thread", &context);

  (*context_cookie) = (NUBHANDLE) saved_thread;
  //resume_thread(threadC);
  return (address_to_break);
}
예제 #11
0
void clear_application_breakpoint (LPDBGPROCESS process, DWORD address)
{
  LPDEBUG_POINT this_debug_point, last_debug_point;
  LPDBGTHREAD   this_thread;

  if (!process->ExitingProcess) {

  dylan_debugger_message("clear_application_breakpoint %=", address, 0);

  this_debug_point = process->DebugPointList;
  this_thread = process->ThreadList;
  last_debug_point = NULL;

  while (this_debug_point != NULL) {

    if ((this_debug_point->DebugPointType == DBG_POINT_BREAKPOINT) &&
        (this_debug_point->u.Breakpoint.Type == APPLICATION_BREAKPOINT) &&
        (this_debug_point->u.Breakpoint.Address == address)) {

      // Lift out the breakpoint.

      lift_breakpoint(process, this_debug_point);

      // One or more threads might actually be stopped at this breakpoint.
      // If so, they must be stopped from writing it back into the
      // process.

      this_thread = process->ThreadList;
      while (this_thread != NULL) {
        CONTEXT  context;
        if (this_thread->NeedsBreakpointReplacement) {

          // This thread is waiting at a breakpoint. If that breakpoint
          // is the one we're removing now, we have to hack its state.

          if (this_thread->BreakpointToReplace == this_debug_point) {

            dylan_debugger_message("Thread no longer needs breakpoint replacement %= %=",
                                   this_thread->ThreadHandle, address);

            this_thread->NeedsBreakpointReplacement = FALSE;

            // The thread will have been put into single-step mode in order
            // to recover from the breakpoint. But it might also be in
            // single-step mode anyway! If it isn't, take it out of
            // single-step mode.

            if (!(this_thread->SingleStepping)) {
              context.ContextFlags = CONTEXT_CONTROL;
              get_thread_context(process, this_thread, &context);
              context.EFlags = context.EFlags & 0xFFFFFEFF;
              SetThreadContext(this_thread->ThreadHandle, &context);
              // resume_all_except(process, this_thread);
            }
          }
        }
        this_thread = this_thread->Next;
      }

      // Delete the descriptor from the list.

      if (last_debug_point == NULL) {
        // This shouldn't happen, but we might as well handle it.
        (process->DebugPointList) = this_debug_point->Next;
        free(this_debug_point);
        this_debug_point = (process->DebugPointList);
      }
      else {
        last_debug_point->Next = this_debug_point->Next;
        free(this_debug_point);
        this_debug_point = (last_debug_point->Next);
      }

    }
    else {
        last_debug_point = this_debug_point;
        this_debug_point = this_debug_point->Next;
    }
  }
  }
}