Пример #1
0
void
set_desired_inferior(int use_general)
{
  struct thread_info *found;

  if (use_general == 1)
    {
      found = (struct thread_info *)find_inferior_id(&all_threads,
                                                     general_thread);
    }
  else
    {
      found = NULL;

      /* If we are continuing any (all) thread(s), use step_thread
       * to decide which thread to step and/or send the specified
       * signal to.  */
      if (((step_thread != 0) && (step_thread != (unsigned long)-1L))
	  && ((cont_thread == 0) || (cont_thread == (unsigned long)-1L)))
	found = (struct thread_info *)find_inferior_id(&all_threads,
                                                       step_thread);

      if (found == NULL)
	found = (struct thread_info *)find_inferior_id(&all_threads,
                                                       cont_thread);
    }

  if (found == NULL)
    current_inferior = (struct thread_info *)all_threads.head;
  else
    current_inferior = found;
}
Пример #2
0
void set_desired_inferior (int use_general)
{
  struct thread_info *found;

  if (use_general == 1) {
     found = (struct thread_info *) find_inferior_id (&all_threads,
                                                      general_thread);
  } else {
     found = NULL;

     /* If we are continuing any (all) thread(s), use step_thread
        to decide which thread to step and/or send the specified
        signal to.  */
     if ((step_thread != 0 && step_thread != -1)
         && (cont_thread == 0 || cont_thread == -1))
	found = (struct thread_info *) find_inferior_id (&all_threads,
							 step_thread);

     if (found == NULL)
	found = (struct thread_info *) find_inferior_id (&all_threads,
							 cont_thread);
  }

  if (found == NULL)
     current_inferior = (struct thread_info *) all_threads.head;
  else
     current_inferior = found;
  {
     ThreadState *tst = (ThreadState *) inferior_target_data (current_inferior);
     ThreadId tid = tst->tid;
     dlog(1, "set_desired_inferior use_general %d found %p tid %d lwpid %d\n",
          use_general, found, tid, tst->os_state.lwpid);
  }
}
Пример #3
0
static void
linux_wait_for_process (struct process_info **childp, int *wstatp)
{
  int ret;
  int to_wait_for = -1;

  if (*childp != NULL)
    to_wait_for = (*childp)->lwpid;

  while (1)
    {
      ret = waitpid (to_wait_for, wstatp, WNOHANG);

      if (ret == -1)
	{
	  if (errno != ECHILD)
	    perror_with_name ("waitpid");
	}
      else if (ret > 0)
	break;

      ret = waitpid (to_wait_for, wstatp, WNOHANG | __WCLONE);

      if (ret == -1)
	{
	  if (errno != ECHILD)
	    perror_with_name ("waitpid (WCLONE)");
	}
      else if (ret > 0)
	break;

      usleep (1000);
    }

  if (debug_threads
      && (!WIFSTOPPED (*wstatp)
	  || (WSTOPSIG (*wstatp) != 32
	      && WSTOPSIG (*wstatp) != 33)))
    fprintf (stderr, "Got an event from %d (%x)\n", ret, *wstatp);

  if (to_wait_for == -1)
    *childp = (struct process_info *) find_inferior_id (&all_processes, ret);

  (*childp)->stopped = 1;
  (*childp)->pending_is_breakpoint = 0;

  if (debug_threads
      && WIFSTOPPED (*wstatp))
    {
      current_inferior = (struct thread_info *)
	find_inferior_id (&all_threads, (*childp)->tid);
      /* For testing only; i386_stop_pc prints out a diagnostic.  */
      if (the_low_target.get_pc != NULL)
	get_stop_pc ();
    }
}
Пример #4
0
static void
maybe_attach_thread (const td_thrhandle_t *th_p, td_thrinfo_t *ti_p)
{
  td_err_e err;
  struct thread_info *inferior;
  struct process_info *process;

  /* If we are attaching to our first thread, things are a little
     different.  */
  if (all_threads.head == all_threads.tail)
    {
      inferior = (struct thread_info *) all_threads.head;
      process = get_thread_process (inferior);
      if (process->thread_known == 0)
	{
	  /* Switch to indexing the threads list by TID.  */
	  change_inferior_id (&all_threads, ti_p->ti_tid);
	  goto found;
	}
    }
  
  inferior = (struct thread_info *) find_inferior_id (&all_threads,
						      ti_p->ti_tid);
  if (inferior != NULL)
    return;

  if (debug_threads)
    fprintf (stderr, "Attaching to thread %ld (LWP %d)\n",
	     ti_p->ti_tid, ti_p->ti_lid);
  linux_attach_lwp (ti_p->ti_lid, ti_p->ti_tid);
  inferior = (struct thread_info *) find_inferior_id (&all_threads,
						      ti_p->ti_tid);
  if (inferior == NULL)
    {
      warning ("Could not attach to thread %ld (LWP %d)\n",
	       ti_p->ti_tid, ti_p->ti_lid);
      return;
    }

  process = inferior_target_data (inferior);

found:
  new_thread_notify (ti_p->ti_tid);

  process->tid = ti_p->ti_tid;
  process->lwpid = ti_p->ti_lid;

  process->thread_known = 1;
  process->th = *th_p;
  err = td_thr_event_enable (th_p, 1);
  if (err != TD_OK)
    error ("Cannot enable thread event reporting for %d: %s",
           ti_p->ti_lid, thread_db_err_str (err));
}
Пример #5
0
/* Find a thread record given a thread id.  If GET_CONTEXT is set then
   also retrieve the context for this thread.  */
static win32_thread_info *
thread_rec (ptid_t ptid, int get_context)
{
  struct thread_info *thread;
  win32_thread_info *th;

  thread = (struct thread_info *) find_inferior_id (&all_threads, ptid);
  if (thread == NULL)
    return NULL;

  th = inferior_target_data (thread);
  if (get_context && th->context.ContextFlags == 0)
    {
      if (!th->suspended)
	{
	  if (SuspendThread (th->h) == (DWORD) -1)
	    {
	      DWORD err = GetLastError ();
	      OUTMSG (("warning: SuspendThread failed in thread_rec, "
		       "(error %d): %s\n", (int) err, strwinerror (err)));
	    }
	  else
	    th->suspended = 1;
	}

      win32_get_thread_context (th);
    }

  return th;
}
Пример #6
0
struct thread_info *
parse_thread_id (const char *tidstr, const char **end)
{
  const char *number = tidstr;
  const char *dot, *p1;
  struct thread_info *tp;
  struct inferior *inf;
  int thr_num;
  int explicit_inf_id = 0;

  dot = strchr (number, '.');

  if (dot != NULL)
    {
      /* Parse number to the left of the dot.  */
      int inf_num;

      p1 = number;
      inf_num = get_positive_number_trailer (&p1, '.', number);
      if (inf_num == 0)
	invalid_thread_id_error (number);

      inf = find_inferior_id (inf_num);
      if (inf == NULL)
	error (_("No inferior number '%d'"), inf_num);

      explicit_inf_id = 1;
      p1 = dot + 1;
    }
  else
    {
      inf = current_inferior ();

      p1 = number;
    }

  thr_num = get_positive_number_trailer (&p1, 0, number);
  if (thr_num == 0)
    invalid_thread_id_error (number);

  ALL_THREADS (tp)
    {
      if (ptid_get_pid (tp->ptid) == inf->pid
	  && tp->per_inf_num == thr_num)
	break;
    }

  if (tp == NULL)
    {
      if (show_inferior_qualified_tids () || explicit_inf_id)
	error (_("Unknown thread %d.%d."), inf->num, thr_num);
      else
	error (_("Unknown thread %d."), thr_num);
    }

  if (end != NULL)
    *end = p1;

  return tp;
}
ps_err_e
ps_lgetregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, prgregset_t gregset)
{
#ifdef HAVE_REGSETS
  struct process_info *process;
  struct thread_info *reg_inferior, *save_inferior;

  process = (struct process_info *) find_inferior_id (&all_processes,
						      lwpid);
  if (process == NULL)
    return PS_ERR;

  reg_inferior = get_process_thread (process);
  save_inferior = current_inferior;
  current_inferior = reg_inferior;

  the_target->fetch_registers (0);
  gregset_info()->fill_function (gregset);

  current_inferior = save_inferior;
  return PS_OK;
#else
  return PS_ERR;
#endif
}
Пример #8
0
/* Return nonzero if the given thread is still alive.  */
static int
fbsd_thread_alive (int tid)
{
  if (find_inferior_id (&all_threads, tid) != NULL)
    return 1;
  else
    return 0;
}
Пример #9
0
/* Return nonzero if the given thread is still alive.  */
static int
linux_thread_alive (unsigned long tid)
{
  if (find_inferior_id (&all_threads, tid) != NULL)
    return 1;
  else
    return 0;
}
Пример #10
0
static int
find_one_thread (ptid_t ptid)
{
  td_thrhandle_t th;
  td_thrinfo_t ti;
  td_err_e err;
  struct thread_info *inferior;
  struct lwp_info *lwp;
  struct thread_db *thread_db = current_process ()->priv->thread_db;
  int lwpid = ptid_get_lwp (ptid);

  inferior = (struct thread_info *) find_inferior_id (&all_threads, ptid);
  lwp = get_thread_lwp (inferior);
  if (lwp->thread_known)
    return 1;

  /* Get information about this thread.  */
  err = thread_db->td_ta_map_lwp2thr_p (thread_db->thread_agent, lwpid, &th);
  if (err != TD_OK)
    error ("Cannot get thread handle for LWP %d: %s",
	   lwpid, thread_db_err_str (err));

  err = thread_db->td_thr_get_info_p (&th, &ti);
  if (err != TD_OK)
    error ("Cannot get thread info for LWP %d: %s",
	   lwpid, thread_db_err_str (err));

  if (debug_threads)
    debug_printf ("Found thread %ld (LWP %d)\n",
		  ti.ti_tid, ti.ti_lid);

  if (lwpid != ti.ti_lid)
    {
      warning ("PID mismatch!  Expected %ld, got %ld",
	       (long) lwpid, (long) ti.ti_lid);
      return 0;
    }

  if (thread_db_use_events)
    {
      err = thread_db->td_thr_event_enable_p (&th, 1);
      if (err != TD_OK)
	error ("Cannot enable thread event reporting for %d: %s",
	       ti.ti_lid, thread_db_err_str (err));
    }

  /* If the new thread ID is zero, a final thread ID will be available
     later.  Do not enable thread debugging yet.  */
  if (ti.ti_tid == 0)
    return 0;

  lwp->thread_known = 1;
  lwp->th = th;

  return 1;
}
Пример #11
0
/* Return 1 iff the thread with thread ID TID is alive.  */
static int
win32_thread_alive (ptid_t ptid)
{
  int res;

  /* Our thread list is reliable; don't bother to poll target
     threads.  */
  if (find_inferior_id (&all_threads, ptid) != NULL)
    res = 1;
  else
    res = 0;
  return res;
}
Пример #12
0
int
fbsd_attach (int pid)
{
  struct process_info *process;

  fbsd_attach_lwp (pid, pid);

  /* Don't ignore the initial SIGSTOP if we just attached to this process.  */
  process = (struct process_info *) find_inferior_id (&all_processes, pid);
  process->stop_expected = 0;

  return 0;
}
Пример #13
0
/* Find a thread record given a thread id.  If GET_CONTEXT is set then
   also retrieve the context for this thread.  */
static win32_thread_info *
thread_rec (ptid_t ptid, int get_context)
{
  struct thread_info *thread;
  win32_thread_info *th;

  thread = (struct thread_info *) find_inferior_id (&all_threads, ptid);
  if (thread == NULL)
    return NULL;

  th = inferior_target_data (thread);
  if (get_context)
    win32_require_context (th);
  return th;
}
Пример #14
0
/* Delete a thread from the list of threads.  */
static void
child_delete_thread (DWORD id)
{
  struct inferior_list_entry *thread;

  /* If the last thread is exiting, just return.  */
  if (all_threads.head == all_threads.tail)
    return;

  thread = find_inferior_id (&all_threads, id);
  if (thread == NULL)
    return;

  delete_thread_info (thread);
}
Пример #15
0
int
pull_pid_from_list (struct inferior_list *list, unsigned long pid)
{
  struct inferior_list_entry *new_entry;

  new_entry = find_inferior_id (list, pid_to_ptid (pid));
  if (new_entry == NULL)
    return 0;
  else
    {
      remove_inferior (list, new_entry);
      free (new_entry);
      return 1;
    }
}
Пример #16
0
/* Delete a thread from the list of threads.  */
static void
child_delete_thread (DWORD pid, DWORD tid)
{
  struct inferior_list_entry *thread;
  ptid_t ptid;

  /* If the last thread is exiting, just return.  */
  if (all_threads.head == all_threads.tail)
    return;

  ptid = ptid_build (pid, tid, 0);
  thread = find_inferior_id (&all_threads, ptid);
  if (thread == NULL)
    return;

  delete_thread_info (thread);
}
Пример #17
0
static void
wait_for_sigstop (struct inferior_list_entry *entry)
{
  struct process_info *process = (struct process_info *) entry;
  struct thread_info *saved_inferior, *thread;
  int wstat;
  unsigned long saved_tid;

  if (process->stopped)
    return;

  saved_inferior = current_inferior;
  saved_tid = ((struct inferior_list_entry *) saved_inferior)->id;
  thread = (struct thread_info *) find_inferior_id (&all_threads,
						    process->tid);
  wstat = linux_wait_for_event (thread);

  /* If we stopped with a non-SIGSTOP signal, save it for later
     and record the pending SIGSTOP.  If the process exited, just
     return.  */
  if (WIFSTOPPED (wstat)
      && WSTOPSIG (wstat) != SIGSTOP)
    {
      if (debug_threads)
	fprintf (stderr, "Stopped with non-sigstop signal\n");
      process->status_pending_p = 1;
      process->status_pending = wstat;
      process->stop_expected = 1;
    }

  if (linux_thread_alive (saved_tid))
    current_inferior = saved_inferior;
  else
    {
      if (debug_threads)
	fprintf (stderr, "Previously current thread died.\n");

      /* Set a valid thread as current.  */
      set_desired_inferior (0);
    }
}
Пример #18
0
/* Add a thread to the thread list.  */
static thread_info *
child_add_thread (DWORD tid, HANDLE h)
{
  thread_info *th;

  if ((th = thread_rec (tid, FALSE)))
    return th;

  th = (thread_info *) malloc (sizeof (*th));
  memset (th, 0, sizeof (*th));
  th->tid = tid;
  th->h = h;

  add_thread (tid, th, (unsigned int) tid);
  set_inferior_regcache_data ((struct thread_info *)
			      find_inferior_id (&all_threads, tid),
			      new_register_cache ());

  /* Set the debug registers for the new thread if they are used.  */
  if (debug_registers_used)
    {
      /* Only change the value of the debug registers.  */
      th->context.ContextFlags = CONTEXT_DEBUGGER_DR;

      GetThreadContext (th->h, &th->context);

      th->context.Dr0 = dr[0];
      th->context.Dr1 = dr[1];
      th->context.Dr2 = dr[2];
      th->context.Dr3 = dr[3];
      /* th->context.Dr6 = dr[6];
         FIXME: should we set dr6 also ?? */
      th->context.Dr7 = dr[7];
      SetThreadContext (th->h, &th->context);
      th->context.ContextFlags = 0;
    }

  return th;
}
Пример #19
0
/* Add a thread to the thread list.  */
static win32_thread_info *
child_add_thread (DWORD tid, HANDLE h)
{
  win32_thread_info *th;

  if ((th = thread_rec (tid, FALSE)))
    return th;

  th = calloc (1, sizeof (*th));
  th->tid = tid;
  th->h = h;

  add_thread (tid, th, (unsigned int) tid);
  set_inferior_regcache_data ((struct thread_info *)
			      find_inferior_id (&all_threads, tid),
			      new_register_cache ());

  if (the_low_target.thread_added != NULL)
    (*the_low_target.thread_added) (th);

  return th;
}
Пример #20
0
/* Find a thread record given a thread id.  If GET_CONTEXT is set then
   also retrieve the context for this thread.  */
static thread_info *
thread_rec (DWORD id, int get_context)
{
  struct thread_info *thread;
  thread_info *th;

  thread = (struct thread_info *) find_inferior_id (&all_threads, id);
  if (thread == NULL)
    return NULL;

  th = inferior_target_data (thread);
  if (!th->suspend_count && get_context)
    {
      if (get_context > 0 && id != current_event.dwThreadId)
	th->suspend_count = SuspendThread (th->h) + 1;
      else if (get_context < 0)
	th->suspend_count = -1;

      th->context.ContextFlags = CONTEXT_DEBUGGER_DR;

      GetThreadContext (th->h, &th->context);

      if (id == current_event.dwThreadId)
	{
	  /* Copy dr values from that thread.  */
	  dr[0] = th->context.Dr0;
	  dr[1] = th->context.Dr1;
	  dr[2] = th->context.Dr2;
	  dr[3] = th->context.Dr3;
	  dr[6] = th->context.Dr6;
	  dr[7] = th->context.Dr7;
	}
    }

  return th;
}
Пример #21
0
/* Add a thread to the thread list.  */
static win32_thread_info *
child_add_thread (DWORD pid, DWORD tid, HANDLE h, void *tlb)
{
  win32_thread_info *th;
  ptid_t ptid = ptid_build (pid, tid, 0);

  if ((th = thread_rec (ptid, FALSE)))
    return th;

  th = xcalloc (1, sizeof (*th));
  th->tid = tid;
  th->h = h;
  th->thread_local_base = (CORE_ADDR) (uintptr_t) tlb;

  add_thread (ptid, th);
  set_inferior_regcache_data ((struct thread_info *)
			      find_inferior_id (&all_threads, ptid),
			      new_register_cache ());

  if (the_low_target.thread_added != NULL)
    (*the_low_target.thread_added) (th);

  return th;
}
Пример #22
0
static unsigned char
fbsd_wait (char *status)
{
  int w;
  struct thread_info *child = NULL;

retry:
  /* If we were only supposed to resume one thread, only wait for
     that thread - if it's still alive.  If it died, however - which
     can happen if we're coming from the thread death case below -
     then we need to make sure we restart the other threads.  We could
     pick a thread at random or restart all; restarting all is less
     arbitrary.  */
  if (cont_thread > 0)
    {
      child = (struct thread_info *) find_inferior_id (&all_threads,
						       cont_thread);

      /* No stepping, no signal - unless one is pending already, of course.  */
      if (child == NULL)
	{
	  struct thread_resume resume_info;
	  resume_info.thread = -1;
	  resume_info.step = resume_info.sig = resume_info.leave_stopped = 0;
	  fbsd_resume (&resume_info);
	}
    }

  enable_async_io ();
  unblock_async_io ();
  w = fbsd_wait_for_event (child);
  stop_all_processes ();
  disable_async_io ();

  /* If we are waiting for a particular child, and it exited,
     fbsd_wait_for_event will return its exit status.  Similarly if
     the last child exited.  If this is not the last child, however,
     do not report it as exited until there is a 'thread exited' response
     available in the remote protocol.  Instead, just wait for another event.
     This should be safe, because if the thread crashed we will already
     have reported the termination signal to GDB; that should stop any
     in-progress stepping operations, etc.

     Report the exit status of the last thread to exit.  This matches
     LinuxThreads' behavior.  */

  if (all_threads.head == all_threads.tail)
    {
      if (WIFEXITED (w))
	{
	  fprintf (stderr, "\nChild exited with retcode = %x \n", WEXITSTATUS (w));
	  *status = 'W';
	  clear_inferiors ();
	  free (all_processes.head);
	  all_processes.head = all_processes.tail = NULL;
	  return ((unsigned char) WEXITSTATUS (w));
	}
      else if (!WIFSTOPPED (w))
	{
	  fprintf (stderr, "\nChild terminated with signal = %x \n", WTERMSIG (w));
	  *status = 'X';
	  clear_inferiors ();
	  free (all_processes.head);
	  all_processes.head = all_processes.tail = NULL;
	  return ((unsigned char) WTERMSIG (w));
	}
    }
  else
    {
      if (!WIFSTOPPED (w))
	goto retry;
    }

  *status = 'T';
  return ((unsigned char) WSTOPSIG (w));
}
Пример #23
0
static int
fbsd_wait_for_event (struct thread_info *child)
{
  CORE_ADDR stop_pc;
  struct process_info *event_child;
  int wstat;

  /* Check for a process with a pending status.  */
  /* It is possible that the user changed the pending task's registers since
     it stopped.  We correctly handle the change of PC if we hit a breakpoint
     (in check_removed_breakpoint); signals should be reported anyway.  */
  if (child == NULL)
    {
      event_child = (struct process_info *)
	find_inferior (&all_processes, status_pending_p, NULL);
      if (debug_threads && event_child)
	fprintf (stderr, "Got a pending child %d\n", event_child->lwpid);
    }
  else
    {
      event_child = get_thread_process (child);
      if (event_child->status_pending_p
	  && check_removed_breakpoint (event_child))
	event_child = NULL;
    }

  if (event_child != NULL)
    {
      if (event_child->status_pending_p)
	{
	  if (debug_threads)
	    fprintf (stderr, "Got an event from pending child %d (%04x)\n",
		     event_child->lwpid, event_child->status_pending);
	  wstat = event_child->status_pending;
	  event_child->status_pending_p = 0;
	  event_child->status_pending = 0;
	  current_inferior = get_process_thread (event_child);
	  return wstat;
	}
    }

  /* We only enter this loop if no process has a pending wait status.  Thus
     any action taken in response to a wait status inside this loop is
     responding as soon as we detect the status, not after any pending
     events.  */
  while (1)
    {
      if (child == NULL)
	event_child = NULL;
      else
	event_child = get_thread_process (child);

      fbsd_wait_for_process (&event_child, &wstat);

      if (event_child == NULL)
	error ("event from unknown child");

      current_inferior = (struct thread_info *)
	find_inferior_id (&all_threads, event_child->tid);

      if (using_threads)
	{
	  /* Check for thread exit.  */
	  if (! WIFSTOPPED (wstat))
	    {
	      if (debug_threads)
		fprintf (stderr, "Thread %d (LWP %d) exiting\n",
			 event_child->tid, event_child->head.id);

	      /* If the last thread is exiting, just return.  */
	      if (all_threads.head == all_threads.tail)
		return wstat;

	      dead_thread_notify (event_child->tid);

	      remove_inferior (&all_processes, &event_child->head);
	      free (event_child);
	      remove_thread (current_inferior);
	      current_inferior = (struct thread_info *) all_threads.head;

	      /* If we were waiting for this particular child to do something...
		 well, it did something.  */
	      if (child != NULL)
		return wstat;

	      /* Wait for a more interesting event.  */
	      continue;
	    }

	  if (WIFSTOPPED (wstat)
	      && WSTOPSIG (wstat) == SIGSTOP
	      && event_child->stop_expected)
	    {
	      if (debug_threads)
		fprintf (stderr, "Expected stop.\n");
	      event_child->stop_expected = 0;
	      fbsd_resume_one_process (&event_child->head,
					event_child->stepping, 0);
	      continue;
	    }

	  /* FIXME drow/2002-06-09: Get signal numbers from the inferior's
	     thread library?  */
	  if (WIFSTOPPED (wstat))
	    {
	      if (debug_threads)
		fprintf (stderr, "Ignored signal %d for %d (LWP %d).\n",
			 WSTOPSIG (wstat), event_child->tid,
			 event_child->head.id);
	      fbsd_resume_one_process (&event_child->head,
					event_child->stepping,
					WSTOPSIG (wstat));
	      continue;
	    }
	}

      /* If this event was not handled above, and is not a SIGTRAP, report
	 it.  */
      if (!WIFSTOPPED (wstat) || WSTOPSIG (wstat) != SIGTRAP)
	return wstat;

      /* If this target does not support breakpoints, we simply report the
	 SIGTRAP; it's of no concern to us.  */
      if (the_low_target.get_pc == NULL)
	return wstat;

      stop_pc = get_stop_pc ();

      /* bp_reinsert will only be set if we were single-stepping.
	 Notice that we will resume the process after hitting
	 a gdbserver breakpoint; single-stepping to/over one
	 is not supported (yet).  */
      if (event_child->bp_reinsert != 0)
	{
	  if (debug_threads)
	    fprintf (stderr, "Reinserted breakpoint.\n");
	  reinsert_breakpoint (event_child->bp_reinsert);
	  event_child->bp_reinsert = 0;

	  /* Clear the single-stepping flag and SIGTRAP as we resume.  */
	  fbsd_resume_one_process (&event_child->head, 0, 0);
	  continue;
	}

      if (debug_threads)
	fprintf (stderr, "Hit a (non-reinsert) breakpoint.\n");

      if (check_breakpoints (stop_pc) != 0)
	{
	  /* We hit one of our own breakpoints.  We mark it as a pending
	     breakpoint, so that check_removed_breakpoint () will do the PC
	     adjustment for us at the appropriate time.  */
	  event_child->pending_is_breakpoint = 1;
	  event_child->pending_stop_pc = stop_pc;

	  /* Now we need to put the breakpoint back.  We continue in the event
	     loop instead of simply replacing the breakpoint right away,
	     in order to not lose signals sent to the thread that hit the
	     breakpoint.  Unfortunately this increases the window where another
	     thread could sneak past the removed breakpoint.  For the current
	     use of server-side breakpoints (thread creation) this is
	     acceptable; but it needs to be considered before this breakpoint
	     mechanism can be used in more general ways.  For some breakpoints
	     it may be necessary to stop all other threads, but that should
	     be avoided where possible.

	     If breakpoint_reinsert_addr is NULL, that means that we can
	     use PT_STEP on this platform.  Uninsert the breakpoint,
	     mark it for reinsertion, and single-step.

	     Otherwise, call the target function to figure out where we need
	     our temporary breakpoint, create it, and continue executing this
	     process.  */
	  if (the_low_target.breakpoint_reinsert_addr == NULL)
	    {
	      event_child->bp_reinsert = stop_pc;
	      uninsert_breakpoint (stop_pc);
	      fbsd_resume_one_process (&event_child->head, 1, 0);
	    }
	  else
	    {
	      reinsert_breakpoint_by_bp
		(stop_pc, (*the_low_target.breakpoint_reinsert_addr) ());
	      fbsd_resume_one_process (&event_child->head, 0, 0);
	    }

	  continue;
	}

      /* If we were single-stepping, we definitely want to report the
	 SIGTRAP.  The single-step operation has completed, so also
         clear the stepping flag; in general this does not matter,
	 because the SIGTRAP will be reported to the client, which
	 will give us a new action for this thread, but clear it for
	 consistency anyway.  It's safe to clear the stepping flag
         because the only consumer of get_stop_pc () after this point
	 is check_removed_breakpoint, and pending_is_breakpoint is not
	 set.  It might be wiser to use a step_completed flag instead.  */
      if (event_child->stepping)
	{
	  event_child->stepping = 0;
	  return wstat;
	}

      /* A SIGTRAP that we can't explain.  It may have been a breakpoint.
	 Check if it is a breakpoint, and if so mark the process information
	 accordingly.  This will handle both the necessary fiddling with the
	 PC on decr_pc_after_break targets and suppressing extra threads
	 hitting a breakpoint if two hit it at once and then GDB removes it
	 after the first is reported.  Arguably it would be better to report
	 multiple threads hitting breakpoints simultaneously, but the current
	 remote protocol does not allow this.  */
      if ((*the_low_target.breakpoint_at) (stop_pc))
	{
	  event_child->pending_is_breakpoint = 1;
	  event_child->pending_stop_pc = stop_pc;
	}

      return wstat;
    }

  /* NOTREACHED */
  return 0;
}
Пример #24
0
struct thread_info *
find_thread_ptid (ptid_t ptid)
{
  return (struct thread_info *) find_inferior_id (&all_threads, ptid);
}
Пример #25
0
struct process_info *
find_process_pid (int pid)
{
  return (struct process_info *)
    find_inferior_id (&all_processes, pid_to_ptid (pid));
}
Пример #26
0
static int
get_child_debug_event (struct target_waitstatus *ourstatus)
{
  ptid_t ptid;

  last_sig = TARGET_SIGNAL_0;
  ourstatus->kind = TARGET_WAITKIND_SPURIOUS;

  /* Check if GDB sent us an interrupt request.  */
  check_remote_input_interrupt_request ();

  if (soft_interrupt_requested)
    {
      soft_interrupt_requested = 0;
      fake_breakpoint_event ();
      goto gotevent;
    }

#ifndef _WIN32_WCE
  attaching = 0;
#else
  if (attaching)
    {
      /* WinCE doesn't set an initial breakpoint automatically.  To
	 stop the inferior, we flush all currently pending debug
	 events -- the thread list and the dll list are always
	 reported immediatelly without delay, then, we suspend all
	 threads and pretend we saw a trap at the current PC of the
	 main thread.

	 Contrary to desktop Windows, Windows CE *does* report the dll
	 names on LOAD_DLL_DEBUG_EVENTs resulting from a
	 DebugActiveProcess call.  This limits the way we can detect
	 if all the dlls have already been reported.  If we get a real
	 debug event before leaving attaching, the worst that will
	 happen is the user will see a spurious breakpoint.  */

      current_event.dwDebugEventCode = 0;
      if (!WaitForDebugEvent (&current_event, 0))
	{
	  OUTMSG2(("no attach events left\n"));
	  fake_breakpoint_event ();
	  attaching = 0;
	}
      else
	OUTMSG2(("got attach event\n"));
    }
  else
#endif
    {
      /* Keep the wait time low enough for confortable remote
	 interruption, but high enough so gdbserver doesn't become a
	 bottleneck.  */
      if (!WaitForDebugEvent (&current_event, 250))
        {
	  DWORD e  = GetLastError();

	  if (e == ERROR_PIPE_NOT_CONNECTED)
	    {
	      /* This will happen if the loader fails to succesfully
		 load the application, e.g., if the main executable
		 tries to pull in a non-existing export from a
		 DLL.  */
	      ourstatus->kind = TARGET_WAITKIND_EXITED;
	      ourstatus->value.integer = 1;
	      return 1;
	    }

	  return 0;
        }
    }

 gotevent:

  switch (current_event.dwDebugEventCode)
    {
    case CREATE_THREAD_DEBUG_EVENT:
      OUTMSG2 (("gdbserver: kernel event CREATE_THREAD_DEBUG_EVENT "
		"for pid=%d tid=%x)\n",
		(unsigned) current_event.dwProcessId,
		(unsigned) current_event.dwThreadId));

      /* Record the existence of this thread.  */
      child_add_thread (current_event.dwProcessId,
			current_event.dwThreadId,
			current_event.u.CreateThread.hThread,
			current_event.u.CreateThread.lpThreadLocalBase);
      break;

    case EXIT_THREAD_DEBUG_EVENT:
      OUTMSG2 (("gdbserver: kernel event EXIT_THREAD_DEBUG_EVENT "
		"for pid=%d tid=%x\n",
		(unsigned) current_event.dwProcessId,
		(unsigned) current_event.dwThreadId));
      child_delete_thread (current_event.dwProcessId,
			   current_event.dwThreadId);

      current_inferior = (struct thread_info *) all_threads.head;
      return 1;

    case CREATE_PROCESS_DEBUG_EVENT:
      OUTMSG2 (("gdbserver: kernel event CREATE_PROCESS_DEBUG_EVENT "
		"for pid=%d tid=%x\n",
		(unsigned) current_event.dwProcessId,
		(unsigned) current_event.dwThreadId));
      CloseHandle (current_event.u.CreateProcessInfo.hFile);

      current_process_handle = current_event.u.CreateProcessInfo.hProcess;
      main_thread_id = current_event.dwThreadId;

      ourstatus->kind = TARGET_WAITKIND_EXECD;
      ourstatus->value.execd_pathname = "Main executable";

      /* Add the main thread.  */
      child_add_thread (current_event.dwProcessId,
			main_thread_id,
			current_event.u.CreateProcessInfo.hThread,
			current_event.u.CreateProcessInfo.lpThreadLocalBase);

      ourstatus->value.related_pid = debug_event_ptid (&current_event);
#ifdef _WIN32_WCE
      if (!attaching)
	{
	  /* Windows CE doesn't set the initial breakpoint
	     automatically like the desktop versions of Windows do.
	     We add it explicitly here.	 It will be removed as soon as
	     it is hit.	 */
	  set_breakpoint_at ((CORE_ADDR) (long) current_event.u
			     .CreateProcessInfo.lpStartAddress,
			     auto_delete_breakpoint);
	}
#endif
      break;

    case EXIT_PROCESS_DEBUG_EVENT:
      OUTMSG2 (("gdbserver: kernel event EXIT_PROCESS_DEBUG_EVENT "
		"for pid=%d tid=%x\n",
		(unsigned) current_event.dwProcessId,
		(unsigned) current_event.dwThreadId));
      ourstatus->kind = TARGET_WAITKIND_EXITED;
      ourstatus->value.integer = current_event.u.ExitProcess.dwExitCode;
      child_continue (DBG_CONTINUE, -1);
      CloseHandle (current_process_handle);
      current_process_handle = NULL;
      break;

    case LOAD_DLL_DEBUG_EVENT:
      OUTMSG2 (("gdbserver: kernel event LOAD_DLL_DEBUG_EVENT "
		"for pid=%d tid=%x\n",
		(unsigned) current_event.dwProcessId,
		(unsigned) current_event.dwThreadId));
      CloseHandle (current_event.u.LoadDll.hFile);
      handle_load_dll ();

      ourstatus->kind = TARGET_WAITKIND_LOADED;
      ourstatus->value.sig = TARGET_SIGNAL_TRAP;
      break;

    case UNLOAD_DLL_DEBUG_EVENT:
      OUTMSG2 (("gdbserver: kernel event UNLOAD_DLL_DEBUG_EVENT "
		"for pid=%d tid=%x\n",
		(unsigned) current_event.dwProcessId,
		(unsigned) current_event.dwThreadId));
      handle_unload_dll ();
      ourstatus->kind = TARGET_WAITKIND_LOADED;
      ourstatus->value.sig = TARGET_SIGNAL_TRAP;
      break;

    case EXCEPTION_DEBUG_EVENT:
      OUTMSG2 (("gdbserver: kernel event EXCEPTION_DEBUG_EVENT "
		"for pid=%d tid=%x\n",
		(unsigned) current_event.dwProcessId,
		(unsigned) current_event.dwThreadId));
      handle_exception (ourstatus);
      break;

    case OUTPUT_DEBUG_STRING_EVENT:
      /* A message from the kernel (or Cygwin).  */
      OUTMSG2 (("gdbserver: kernel event OUTPUT_DEBUG_STRING_EVENT "
		"for pid=%d tid=%x\n",
		(unsigned) current_event.dwProcessId,
		(unsigned) current_event.dwThreadId));
      handle_output_debug_string (ourstatus);
      break;

    default:
      OUTMSG2 (("gdbserver: kernel event unknown "
		"for pid=%d tid=%x code=%ld\n",
		(unsigned) current_event.dwProcessId,
		(unsigned) current_event.dwThreadId,
		current_event.dwDebugEventCode));
      break;
    }

  ptid = debug_event_ptid (&current_event);
  current_inferior =
    (struct thread_info *) find_inferior_id (&all_threads, ptid);
  return 1;
}