1/* Abstract base class inherited by all process_stratum targets
2
3   Copyright (C) 2018-2023 Free Software Foundation, Inc.
4
5   This file is part of GDB.
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 3 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19
20#include "defs.h"
21#include "process-stratum-target.h"
22#include "inferior.h"
23#include <algorithm>
24
25process_stratum_target::~process_stratum_target ()
26{
27}
28
29struct address_space *
30process_stratum_target::thread_address_space (ptid_t ptid)
31{
32  /* Fall-back to the "main" address space of the inferior.  */
33  inferior *inf = find_inferior_ptid (this, ptid);
34
35  if (inf == NULL || inf->aspace == NULL)
36    internal_error (_("Can't determine the current "
37		      "address space of thread %s\n"),
38		    target_pid_to_str (ptid).c_str ());
39
40  return inf->aspace;
41}
42
43struct gdbarch *
44process_stratum_target::thread_architecture (ptid_t ptid)
45{
46  inferior *inf = find_inferior_ptid (this, ptid);
47  gdb_assert (inf != NULL);
48  return inf->gdbarch;
49}
50
51bool
52process_stratum_target::has_all_memory ()
53{
54  /* If no inferior selected, then we can't read memory here.  */
55  return inferior_ptid != null_ptid;
56}
57
58bool
59process_stratum_target::has_memory ()
60{
61  /* If no inferior selected, then we can't read memory here.  */
62  return inferior_ptid != null_ptid;
63}
64
65bool
66process_stratum_target::has_stack ()
67{
68  /* If no inferior selected, there's no stack.  */
69  return inferior_ptid != null_ptid;
70}
71
72bool
73process_stratum_target::has_registers ()
74{
75  /* Can't read registers from no inferior.  */
76  return inferior_ptid != null_ptid;
77}
78
79bool
80process_stratum_target::has_execution (inferior *inf)
81{
82  /* If there's a process running already, we can't make it run
83     through hoops.  */
84  return inf->pid != 0;
85}
86
87/* See process-stratum-target.h.  */
88
89void
90process_stratum_target::follow_exec (inferior *follow_inf, ptid_t ptid,
91				     const char *execd_pathname)
92{
93  inferior *orig_inf = current_inferior ();
94
95  if (orig_inf != follow_inf)
96    {
97      /* Execution continues in a new inferior, push the original inferior's
98         process target on the new inferior's target stack.  The process target
99	 may decide to unpush itself from the original inferior's target stack
100	 after that, at its discretion.  */
101      follow_inf->push_target (orig_inf->process_target ());
102      thread_info *t = add_thread (follow_inf->process_target (), ptid);
103
104      /* Leave the new inferior / thread as the current inferior / thread.  */
105      switch_to_thread (t);
106    }
107}
108
109/* See process-stratum-target.h.  */
110
111void
112process_stratum_target::follow_fork (inferior *child_inf, ptid_t child_ptid,
113				     target_waitkind fork_kind,
114				     bool follow_child,
115				     bool detach_on_fork)
116{
117  if (child_inf != nullptr)
118    {
119      child_inf->push_target (this);
120      add_thread_silent (this, child_ptid);
121    }
122}
123
124/* See process-stratum-target.h.  */
125
126void
127process_stratum_target::maybe_add_resumed_with_pending_wait_status
128  (thread_info *thread)
129{
130  gdb_assert (!thread->resumed_with_pending_wait_status_node.is_linked ());
131
132  if (thread->resumed () && thread->has_pending_waitstatus ())
133    {
134      infrun_debug_printf ("adding to resumed threads with event list: %s",
135			   thread->ptid.to_string ().c_str ());
136      m_resumed_with_pending_wait_status.push_back (*thread);
137    }
138}
139
140/* See process-stratum-target.h.  */
141
142void
143process_stratum_target::maybe_remove_resumed_with_pending_wait_status
144  (thread_info *thread)
145{
146  if (thread->resumed () && thread->has_pending_waitstatus ())
147    {
148      infrun_debug_printf ("removing from resumed threads with event list: %s",
149			   thread->ptid.to_string ().c_str ());
150      gdb_assert (thread->resumed_with_pending_wait_status_node.is_linked ());
151      auto it = m_resumed_with_pending_wait_status.iterator_to (*thread);
152      m_resumed_with_pending_wait_status.erase (it);
153    }
154  else
155    gdb_assert (!thread->resumed_with_pending_wait_status_node.is_linked ());
156}
157
158/* See process-stratum-target.h.  */
159
160thread_info *
161process_stratum_target::random_resumed_with_pending_wait_status
162  (inferior *inf, ptid_t filter_ptid)
163{
164  auto matches = [inf, filter_ptid] (const thread_info &thread)
165    {
166      return thread.inf == inf && thread.ptid.matches (filter_ptid);
167    };
168
169  /* First see how many matching events we have.  */
170  const auto &l = m_resumed_with_pending_wait_status;
171  unsigned int count = std::count_if (l.begin (), l.end (), matches);
172
173  if (count == 0)
174    return nullptr;
175
176  /* Now randomly pick a thread out of those that match the criteria.  */
177  int random_selector
178    = (int) ((count * (double) rand ()) / (RAND_MAX + 1.0));
179
180  if (count > 1)
181    infrun_debug_printf ("Found %u events, selecting #%d",
182			 count, random_selector);
183
184  /* Select the Nth thread that matches.  */
185  auto it = std::find_if (l.begin (), l.end (),
186			  [&random_selector, &matches]
187			  (const thread_info &thread)
188    {
189      if (!matches (thread))
190	return false;
191
192      return random_selector-- == 0;
193    });
194
195  gdb_assert (it != l.end ());
196
197  return &*it;
198}
199
200/* See process-stratum-target.h.  */
201
202std::set<process_stratum_target *>
203all_non_exited_process_targets ()
204{
205  /* Inferiors may share targets.  To eliminate duplicates, use a set.  */
206  std::set<process_stratum_target *> targets;
207  for (inferior *inf : all_non_exited_inferiors ())
208    targets.insert (inf->process_target ());
209
210  return targets;
211}
212
213/* See process-stratum-target.h.  */
214
215void
216switch_to_target_no_thread (process_stratum_target *target)
217{
218  for (inferior *inf : all_inferiors (target))
219    {
220      switch_to_inferior_no_thread (inf);
221      break;
222    }
223}
224