aboutsummaryrefslogtreecommitdiff
path: root/gdbserver
diff options
context:
space:
mode:
Diffstat (limited to 'gdbserver')
-rw-r--r--gdbserver/linux-low.cc11
-rw-r--r--gdbserver/linux-low.h29
-rw-r--r--gdbserver/server.cc6
-rw-r--r--gdbserver/target.cc6
-rw-r--r--gdbserver/target.h10
5 files changed, 62 insertions, 0 deletions
diff --git a/gdbserver/linux-low.cc b/gdbserver/linux-low.cc
index d214aff..34991df 100644
--- a/gdbserver/linux-low.cc
+++ b/gdbserver/linux-low.cc
@@ -7119,6 +7119,17 @@ linux_process_target::thread_handle (ptid_t ptid, gdb_byte **handle,
}
#endif
+thread_info *
+linux_process_target::thread_pending_parent (thread_info *thread)
+{
+ lwp_info *parent = get_thread_lwp (thread)->pending_parent ();
+
+ if (parent == nullptr)
+ return nullptr;
+
+ return get_lwp_thread (parent);
+}
+
/* Default implementation of linux_target_ops method "set_pc" for
32-bit pc register which is literally named "pc". */
diff --git a/gdbserver/linux-low.h b/gdbserver/linux-low.h
index 05067ff..819f915 100644
--- a/gdbserver/linux-low.h
+++ b/gdbserver/linux-low.h
@@ -311,6 +311,8 @@ public:
int *handle_len) override;
#endif
+ thread_info *thread_pending_parent (thread_info *thread) override;
+
bool supports_catch_syscall () override;
/* Return the information to access registers. This has public
@@ -721,6 +723,33 @@ struct pending_signal
struct lwp_info
{
+ /* If this LWP is a fork child that wasn't reported to GDB yet, return
+ its parent, else nullptr. */
+ lwp_info *pending_parent () const
+ {
+ if (this->fork_relative == nullptr)
+ return nullptr;
+
+ gdb_assert (this->fork_relative->fork_relative == this);
+
+ /* In a fork parent/child relationship, the parent has a status pending and
+ the child does not, and a thread can only be in one such relationship
+ at most. So we can recognize who is the parent based on which one has
+ a pending status. */
+ gdb_assert (!!this->status_pending_p
+ != !!this->fork_relative->status_pending_p);
+
+ if (!this->fork_relative->status_pending_p)
+ return nullptr;
+
+ const target_waitstatus &ws
+ = this->fork_relative->waitstatus;
+ gdb_assert (ws.kind () == TARGET_WAITKIND_FORKED
+ || ws.kind () == TARGET_WAITKIND_VFORKED);
+
+ return this->fork_relative;
+ }
+
/* Backlink to the parent object. */
struct thread_info *thread = nullptr;
diff --git a/gdbserver/server.cc b/gdbserver/server.cc
index b1d4c92..8dde6fb 100644
--- a/gdbserver/server.cc
+++ b/gdbserver/server.cc
@@ -1656,6 +1656,12 @@ handle_qxfer_threads_worker (thread_info *thread, struct buffer *buffer)
gdb_byte *handle;
bool handle_status = target_thread_handle (ptid, &handle, &handle_len);
+ /* If this is a fork or vfork child (has a fork parent), GDB does not yet
+ know about this process, and must not know about it until it gets the
+ corresponding (v)fork event. Exclude this thread from the list. */
+ if (target_thread_pending_parent (thread) != nullptr)
+ return;
+
write_ptid (ptid_s, ptid);
buffer_xml_printf (buffer, "<thread id=\"%s\"", ptid_s);
diff --git a/gdbserver/target.cc b/gdbserver/target.cc
index bfa8605..136b510 100644
--- a/gdbserver/target.cc
+++ b/gdbserver/target.cc
@@ -835,6 +835,12 @@ process_stratum_target::thread_handle (ptid_t ptid, gdb_byte **handle,
return false;
}
+thread_info *
+process_stratum_target::thread_pending_parent (thread_info *thread)
+{
+ return nullptr;
+}
+
bool
process_stratum_target::supports_software_single_step ()
{
diff --git a/gdbserver/target.h b/gdbserver/target.h
index 6c863c8..1b0a120 100644
--- a/gdbserver/target.h
+++ b/gdbserver/target.h
@@ -488,6 +488,10 @@ public:
virtual bool thread_handle (ptid_t ptid, gdb_byte **handle,
int *handle_len);
+ /* If THREAD is a fork child that was not reported to GDB, return its parent
+ else nullptr. */
+ virtual thread_info *thread_pending_parent (thread_info *thread);
+
/* Returns true if the target can software single step. */
virtual bool supports_software_single_step ();
@@ -698,6 +702,12 @@ void done_accessing_memory (void);
#define target_thread_handle(ptid, handle, handle_len) \
the_target->thread_handle (ptid, handle, handle_len)
+static inline thread_info *
+target_thread_pending_parent (thread_info *thread)
+{
+ return the_target->thread_pending_parent (thread);
+}
+
int read_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len);
int set_desired_thread ();