#include "solib.h"
#include "linux-osdata.h"
#include "linux-tdep.h"
+#include "symfile.h"
+#include "agent.h"
+#include "tracepoint.h"
+#include "exceptions.h"
+#include "linux-ptrace.h"
+#include "buffer.h"
#ifndef SPUFS_MAGIC
#define SPUFS_MAGIC 0x23c9b64e
/* The method to call, if any, when the siginfo object needs to be
converted between the layout returned by ptrace, and the layout in
the architecture of the inferior. */
-static int (*linux_nat_siginfo_fixup) (struct siginfo *,
+static int (*linux_nat_siginfo_fixup) (siginfo_t *,
gdb_byte *,
int);
struct lwp_info;
static struct lwp_info *add_lwp (ptid_t ptid);
static void purge_lwp_list (int pid);
+static void delete_lwp (ptid_t ptid);
static struct lwp_info *find_lwp_pid (ptid_t ptid);
\f
linux_enable_tracesysgood (ptid);
}
+/* Return the number of known LWPs in the tgid given by PID. */
+
+static int
+num_lwps (int pid)
+{
+ int count = 0;
+ struct lwp_info *lp;
+
+ for (lp = lwp_list; lp; lp = lp->next)
+ if (ptid_get_pid (lp->ptid) == pid)
+ count++;
+
+ return count;
+}
+
+/* Call delete_lwp with prototype compatible for make_cleanup. */
+
+static void
+delete_lwp_cleanup (void *lp_voidp)
+{
+ struct lwp_info *lp = lp_voidp;
+
+ delete_lwp (lp->ptid);
+}
+
static int
linux_child_follow_fork (struct target_ops *ops, int follow_child)
{
/* Detach new forked process? */
if (detach_fork)
{
+ struct cleanup *old_chain;
+
/* Before detaching from the child, remove all breakpoints
from it. If we forked, then this has already been taken
care of by infrun.c. If we vforked however, any
child_pid);
}
+ old_chain = save_inferior_ptid ();
+ inferior_ptid = ptid_build (child_pid, child_pid, 0);
+
+ child_lp = add_lwp (inferior_ptid);
+ child_lp->stopped = 1;
+ child_lp->last_resume_kind = resume_stop;
+ make_cleanup (delete_lwp_cleanup, child_lp);
+
+ /* CHILD_LP has new PID, therefore linux_nat_new_thread is not called for it.
+ See i386_inferior_data_get for the Linux kernel specifics.
+ Ensure linux_nat_prepare_to_resume will reset the hardware debug
+ registers. It is done by the linux_nat_new_thread call, which is
+ being skipped in add_lwp above for the first lwp of a pid. */
+ gdb_assert (num_lwps (GET_PID (child_lp->ptid)) == 1);
+ if (linux_nat_new_thread != NULL)
+ linux_nat_new_thread (child_lp);
+
+ if (linux_nat_prepare_to_resume != NULL)
+ linux_nat_prepare_to_resume (child_lp);
ptrace (PTRACE_DETACH, child_pid, 0, 0);
+
+ do_cleanups (old_chain);
}
else
{
child_lp = add_lwp (inferior_ptid);
child_lp->stopped = 1;
child_lp->last_resume_kind = resume_stop;
+ child_inf->symfile_flags = SYMFILE_NO_READ;
/* If this is a vfork child, then the address-space is
shared with the parent. */
child_inf->aspace = new_address_space ();
child_inf->pspace = add_program_space (child_inf->aspace);
child_inf->removable = 1;
+ child_inf->symfile_flags = SYMFILE_NO_READ;
set_current_program_space (child_inf->pspace);
clone_program_space (child_inf->pspace, parent_pspace);
}
}
-/* Return the number of known LWPs in the tgid given by PID. */
-
-static int
-num_lwps (int pid)
-{
- int count = 0;
- struct lwp_info *lp;
-
- for (lp = lwp_list; lp; lp = lp->next)
- if (ptid_get_pid (lp->ptid) == pid)
- count++;
-
- return count;
-}
-
/* Add the LWP specified by PID to the list. Return a pointer to the
structure describing the new LWP. The LWP should already be stopped
(with an exception for the very first LWP). */
return NULL;
}
+/* Iterate like iterate_over_lwps does except when forking-off a child call
+ CALLBACK with CALLBACK_DATA specifically only for that new child PID. */
+
+void
+linux_nat_iterate_watchpoint_lwps
+ (linux_nat_iterate_watchpoint_lwps_ftype callback, void *callback_data)
+{
+ int inferior_pid = ptid_get_pid (inferior_ptid);
+ struct inferior *inf = current_inferior ();
+
+ if (inf->pid == inferior_pid)
+ {
+ /* Iterate all the threads of the current inferior. Without specifying
+ INFERIOR_PID it would iterate all threads of all inferiors, which is
+ inappropriate for watchpoints. */
+
+ iterate_over_lwps (pid_to_ptid (inferior_pid), callback, callback_data);
+ }
+ else
+ {
+ /* Detaching a new child PID temporarily present in INFERIOR_PID. */
+
+ struct lwp_info *child_lp;
+ struct cleanup *old_chain;
+ pid_t child_pid = GET_PID (inferior_ptid);
+ ptid_t child_ptid = ptid_build (child_pid, child_pid, 0);
+
+ gdb_assert (!is_lwp (inferior_ptid));
+ gdb_assert (find_lwp_pid (child_ptid) == NULL);
+ child_lp = add_lwp (child_ptid);
+ child_lp->stopped = 1;
+ child_lp->last_resume_kind = resume_stop;
+ old_chain = make_cleanup (delete_lwp_cleanup, child_lp);
+
+ callback (child_lp, callback_data);
+
+ do_cleanups (old_chain);
+ }
+}
+
/* Update our internal state when changing from one checkpoint to
another indicated by NEW_PTID. We can only switch single-threaded
applications, so we only create one new LWP, and the previous list
delete_lwp (lp->ptid);
}
-/* Detect `T (stopped)' in `/proc/PID/status'.
- Other states including `T (tracing stop)' are reported as false. */
-
-static int
-pid_is_stopped (pid_t pid)
-{
- FILE *status_file;
- char buf[100];
- int retval = 0;
-
- snprintf (buf, sizeof (buf), "/proc/%d/status", (int) pid);
- status_file = fopen (buf, "r");
- if (status_file != NULL)
- {
- int have_state = 0;
-
- while (fgets (buf, sizeof (buf), status_file))
- {
- if (strncmp (buf, "State:", 6) == 0)
- {
- have_state = 1;
- break;
- }
- }
- if (have_state && strstr (buf, "T (stopped)") != NULL)
- retval = 1;
- fclose (status_file);
- }
- return retval;
-}
-
/* Wait for the LWP specified by LP, which we have just attached to.
Returns a wait status for that LWP, to cache. */
pid_t new_pid, pid = GET_LWP (ptid);
int status;
- if (pid_is_stopped (pid))
+ if (linux_proc_pid_is_stopped (pid))
{
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
struct lwp_info *lp;
int status;
ptid_t ptid;
+ volatile struct gdb_exception ex;
/* Make sure we report all signals during attach. */
linux_nat_pass_signals (0, NULL);
- linux_ops->to_attach (ops, args, from_tty);
+ TRY_CATCH (ex, RETURN_MASK_ERROR)
+ {
+ linux_ops->to_attach (ops, args, from_tty);
+ }
+ if (ex.reason < 0)
+ {
+ pid_t pid = parse_pid_to_attach (args);
+ struct buffer buffer;
+ char *message, *buffer_s;
+
+ message = xstrdup (ex.message);
+ make_cleanup (xfree, message);
+
+ buffer_init (&buffer);
+ linux_ptrace_attach_warnings (pid, &buffer);
+
+ buffer_grow_str0 (&buffer, "");
+ buffer_s = buffer_finish (&buffer);
+ make_cleanup (xfree, buffer_s);
+
+ throw_error (ex.error, "%s%s", buffer_s, message);
+ }
/* The ptrace base target adds the main thread with (pid,0,0)
format. Decorate it with lwp info. */
_("unknown ptrace event %d"), event);
}
-/* Return non-zero if LWP is a zombie. */
-
-static int
-linux_lwp_is_zombie (long lwp)
-{
- char buffer[MAXPATHLEN];
- FILE *procfile;
- int retval;
- int have_state;
-
- xsnprintf (buffer, sizeof (buffer), "/proc/%ld/status", lwp);
- procfile = fopen (buffer, "r");
- if (procfile == NULL)
- {
- warning (_("unable to open /proc file '%s'"), buffer);
- return 0;
- }
-
- have_state = 0;
- while (fgets (buffer, sizeof (buffer), procfile) != NULL)
- if (strncmp (buffer, "State:", 6) == 0)
- {
- have_state = 1;
- break;
- }
- retval = (have_state
- && strcmp (buffer, "State:\tZ (zombie)\n") == 0);
- fclose (procfile);
- return retval;
-}
-
/* Wait for LP to stop. Returns the wait status, or 0 if the LWP has
exited. */
This is racy, what if the tgl becomes a zombie right after we check?
Therefore always use WNOHANG with sigsuspend - it is equivalent to
- waiting waitpid but the linux_lwp_is_zombie is safe this way. */
+ waiting waitpid but linux_proc_pid_is_zombie is safe this way. */
if (GET_PID (lp->ptid) == GET_LWP (lp->ptid)
- && linux_lwp_is_zombie (GET_LWP (lp->ptid)))
+ && linux_proc_pid_is_zombie (GET_LWP (lp->ptid)))
{
thread_dead = 1;
if (debug_linux_nat)
/* Check if there are other threads in the group, as we may
have raced with the inferior simply exiting. */
&& num_lwps (inf->pid) > 1
- && linux_lwp_is_zombie (inf->pid))
+ && linux_proc_pid_is_zombie (inf->pid))
{
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
|| ourstatus->kind == TARGET_WAITKIND_SIGNALLED)
lp->core = -1;
else
- lp->core = linux_nat_core_of_thread_1 (lp->ptid);
+ lp->core = linux_common_core_of_thread (lp->ptid);
return lp->ptid;
}
layout of the inferiors' architecture. */
static void
-siginfo_fixup (struct siginfo *siginfo, gdb_byte *inf_siginfo, int direction)
+siginfo_fixup (siginfo_t *siginfo, gdb_byte *inf_siginfo, int direction)
{
int done = 0;
if (!done)
{
if (direction == 1)
- memcpy (siginfo, inf_siginfo, sizeof (struct siginfo));
+ memcpy (siginfo, inf_siginfo, sizeof (siginfo_t));
else
- memcpy (inf_siginfo, siginfo, sizeof (struct siginfo));
+ memcpy (inf_siginfo, siginfo, sizeof (siginfo_t));
}
}
const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
{
int pid;
- struct siginfo siginfo;
- gdb_byte inf_siginfo[sizeof (struct siginfo)];
+ siginfo_t siginfo;
+ gdb_byte inf_siginfo[sizeof (siginfo_t)];
gdb_assert (object == TARGET_OBJECT_SIGNAL_INFO);
gdb_assert (readbuf || writebuf);
offset, len);
}
+static void
+cleanup_target_stop (void *arg)
+{
+ ptid_t *ptid = (ptid_t *) arg;
+
+ gdb_assert (arg != NULL);
+
+ /* Unpause all */
+ target_resume (*ptid, 0, TARGET_SIGNAL_0);
+}
+
+static VEC(static_tracepoint_marker_p) *
+linux_child_static_tracepoint_markers_by_strid (const char *strid)
+{
+ char s[IPA_CMD_BUF_SIZE];
+ struct cleanup *old_chain;
+ int pid = ptid_get_pid (inferior_ptid);
+ VEC(static_tracepoint_marker_p) *markers = NULL;
+ struct static_tracepoint_marker *marker = NULL;
+ char *p = s;
+ ptid_t ptid = ptid_build (pid, 0, 0);
+
+ /* Pause all */
+ target_stop (ptid);
+
+ memcpy (s, "qTfSTM", sizeof ("qTfSTM"));
+ s[sizeof ("qTfSTM")] = 0;
+
+ agent_run_command (pid, s);
+
+ old_chain = make_cleanup (free_current_marker, &marker);
+ make_cleanup (cleanup_target_stop, &ptid);
+
+ while (*p++ == 'm')
+ {
+ if (marker == NULL)
+ marker = XCNEW (struct static_tracepoint_marker);
+
+ do
+ {
+ parse_static_tracepoint_marker_definition (p, &p, marker);
+
+ if (strid == NULL || strcmp (strid, marker->str_id) == 0)
+ {
+ VEC_safe_push (static_tracepoint_marker_p,
+ markers, marker);
+ marker = NULL;
+ }
+ else
+ {
+ release_static_tracepoint_marker (marker);
+ memset (marker, 0, sizeof (*marker));
+ }
+ }
+ while (*p++ == ','); /* comma-separated list */
+
+ memcpy (s, "qTsSTM", sizeof ("qTsSTM"));
+ s[sizeof ("qTsSTM")] = 0;
+ agent_run_command (pid, s);
+ p = s;
+ }
+
+ do_cleanups (old_chain);
+
+ return markers;
+}
+
/* Create a prototype generic GNU/Linux target. The client can override
it with local methods. */
super_xfer_partial = t->to_xfer_partial;
t->to_xfer_partial = linux_xfer_partial;
+
+ t->to_static_tracepoint_markers_by_strid
+ = linux_child_static_tracepoint_markers_by_strid;
}
struct target_ops *
lwpid is a "main" process id or not (it assumes so). We reverse
look up the "main" process id from the lwp here. */
-struct address_space *
+static struct address_space *
linux_nat_thread_address_space (struct target_ops *t, ptid_t ptid)
{
struct lwp_info *lwp;
return inf->aspace;
}
-int
-linux_nat_core_of_thread_1 (ptid_t ptid)
-{
- struct cleanup *back_to;
- char *filename;
- FILE *f;
- char *content = NULL;
- char *p;
- char *ts = 0;
- int content_read = 0;
- int i;
- int core;
-
- filename = xstrprintf ("/proc/%d/task/%ld/stat",
- GET_PID (ptid), GET_LWP (ptid));
- back_to = make_cleanup (xfree, filename);
-
- f = fopen (filename, "r");
- if (!f)
- {
- do_cleanups (back_to);
- return -1;
- }
-
- make_cleanup_fclose (f);
-
- for (;;)
- {
- int n;
-
- content = xrealloc (content, content_read + 1024);
- n = fread (content + content_read, 1, 1024, f);
- content_read += n;
- if (n < 1024)
- {
- content[content_read] = '\0';
- break;
- }
- }
-
- make_cleanup (xfree, content);
-
- p = strchr (content, '(');
-
- /* Skip ")". */
- if (p != NULL)
- p = strchr (p, ')');
- if (p != NULL)
- p++;
-
- /* If the first field after program name has index 0, then core number is
- the field with index 36. There's no constant for that anywhere. */
- if (p != NULL)
- p = strtok_r (p, " ", &ts);
- for (i = 0; p != NULL && i != 36; ++i)
- p = strtok_r (NULL, " ", &ts);
-
- if (p == NULL || sscanf (p, "%d", &core) == 0)
- core = -1;
-
- do_cleanups (back_to);
-
- return core;
-}
-
/* Return the cached value of the processor core for thread PTID. */
-int
+static int
linux_nat_core_of_thread (struct target_ops *ops, ptid_t ptid)
{
struct lwp_info *info = find_lwp_pid (ptid);
inferior. */
void
linux_nat_set_siginfo_fixup (struct target_ops *t,
- int (*siginfo_fixup) (struct siginfo *,
+ int (*siginfo_fixup) (siginfo_t *,
gdb_byte *,
int))
{
}
/* Return the saved siginfo associated with PTID. */
-struct siginfo *
+siginfo_t *
linux_nat_get_siginfo (ptid_t ptid)
{
struct lwp_info *lp = find_lwp_pid (ptid);