/* Machine independent support for QNX Neutrino /proc (process file system)
for GDB. Written by Colin Burgess at QNX Software Systems Limited.
- Copyright (C) 2003-2015 Free Software Foundation, Inc.
+ Copyright (C) 2003-2016 Free Software Foundation, Inc.
Contributed by QNX Software Systems Ltd.
#include <sys/syspage.h>
#include <dirent.h>
#include <sys/netmgr.h>
+#include <sys/auxv.h>
+
#include "gdbcore.h"
#include "inferior.h"
#include "target.h"
#include "regcache.h"
#include "solib.h"
#include "inf-child.h"
+#include "common/filestuff.h"
#define NULL_PID 0
#define _DEBUG_FLAG_TRACE (_DEBUG_FLAG_TRACE_EXEC|_DEBUG_FLAG_TRACE_RD|\
int ctl_fd;
-static void (*ofunc) ();
+static sighandler_t ofunc;
static procfs_run run;
static ptid_t do_attach (ptid_t ptid);
static int procfs_can_use_hw_breakpoint (struct target_ops *self,
- enum target_hw_bp_type, int, int);
+ enum bptype, int, int);
static int procfs_insert_hw_watchpoint (struct target_ops *self,
CORE_ADDR addr, int len,
referenced elsewhere. 'nto_procfs_node' is a flag used to say
whether we are local, or we should get the current node descriptor
for the remote QNX node. */
-static char nto_procfs_path[PATH_MAX] = { "/proc" };
+static char *nodestr;
static unsigned nto_procfs_node = ND_LOCAL_NODE;
/* Return the current QNX Node, or error out. This is a simple
{
unsigned node;
- if (ND_NODE_CMP (nto_procfs_node, ND_LOCAL_NODE) == 0)
+ if (ND_NODE_CMP (nto_procfs_node, ND_LOCAL_NODE) == 0
+ || nodestr == NULL)
return ND_LOCAL_NODE;
- node = netmgr_strtond (nto_procfs_path, 0);
+ node = netmgr_strtond (nodestr, 0);
if (node == -1)
error (_("Lost the QNX node. Debug session probably over."));
static void
procfs_open_1 (struct target_ops *ops, const char *arg, int from_tty)
{
- char *nodestr;
char *endstr;
char buffer[50];
int fd, total_size;
procfs_sysinfo *sysinfo;
struct cleanup *cleanups;
+ char nto_procfs_path[PATH_MAX];
/* Offer to kill previous inferiors before opening this target. */
target_preopen (from_tty);
/* Set the default node used for spawning to this one,
and only override it if there is a valid arg. */
+ xfree (nodestr);
+ nodestr = NULL;
+
nto_procfs_node = ND_LOCAL_NODE;
- nodestr = arg ? xstrdup (arg) : arg;
+ nodestr = (arg != NULL) ? xstrdup (arg) : NULL;
init_thread_list ();
*endstr = 0;
}
}
- snprintf (nto_procfs_path, PATH_MAX - 1, "%s%s", nodestr ? nodestr : "",
- "/proc");
- if (nodestr)
- xfree (nodestr);
+ snprintf (nto_procfs_path, PATH_MAX - 1, "%s%s",
+ (nodestr != NULL) ? nodestr : "", "/proc");
fd = open (nto_procfs_path, O_RDONLY);
if (fd == -1)
{
total_size = sysinfo->total_size;
sysinfo = alloca (total_size);
- if (!sysinfo)
+ if (sysinfo == NULL)
{
printf_filtered ("Memory error: %d (%s)\n", errno,
safe_strerror (errno));
closedir (dir);
}
-void
+static void
procfs_pidlist (char *args, int from_tty)
{
DIR *dp = NULL;
struct dirent *dirp = NULL;
- char buf[512];
+ char buf[PATH_MAX];
procfs_info *pidinfo = NULL;
procfs_debuginfo *info = NULL;
procfs_status *status = NULL;
pid_t pid;
char name[512];
struct cleanup *cleanups;
+ char procfs_dir[PATH_MAX];
- dp = opendir (nto_procfs_path);
+ snprintf (procfs_dir, sizeof (procfs_dir), "%s%s",
+ (nodestr != NULL) ? nodestr : "", "/proc");
+
+ dp = opendir (procfs_dir);
if (dp == NULL)
{
fprintf_unfiltered (gdb_stderr, "failed to opendir \"%s\" - %d (%s)",
- nto_procfs_path, errno, safe_strerror (errno));
+ procfs_dir, errno, safe_strerror (errno));
return;
}
do_cleanups (cleanups);
return;
}
- snprintf (buf, 511, "%s/%s/as", nto_procfs_path, dirp->d_name);
+ snprintf (buf, sizeof (buf), "%s%s/%s/as",
+ (nodestr != NULL) ? nodestr : "",
+ "/proc", dirp->d_name);
pid = atoi (dirp->d_name);
}
while (pid == 0);
{
fprintf_unfiltered (gdb_stderr, "failed to open %s - %d (%s)\n",
buf, errno, safe_strerror (errno));
- do_cleanups (cleanups);
- return;
+ continue;
}
inner_cleanup = make_cleanup_close (fd);
status = (procfs_status *) buf;
for (status->tid = 1; status->tid <= num_threads; status->tid++)
{
- if (devctl (fd, DCMD_PROC_TIDSTATUS, status, sizeof (buf), 0) != EOK
- && status->tid != 0)
- break;
- if (status->tid != 0)
- printf_filtered ("%s - %d/%d\n", name, pid, status->tid);
+ const int err
+ = devctl (fd, DCMD_PROC_TIDSTATUS, status, sizeof (buf), 0);
+ printf_filtered ("%s - %d", name, pid);
+ if (err == EOK && status->tid != 0)
+ printf_filtered ("/%d\n", status->tid);
+ else
+ {
+ printf_filtered ("\n");
+ break;
+ }
}
do_cleanups (inner_cleanup);
return;
}
-void
+static void
procfs_meminfo (char *args, int from_tty)
{
procfs_mapinfo *mapinfos = NULL;
return;
}
- mapinfos = xmalloc (num * sizeof (procfs_mapinfo));
+ mapinfos = XNEWVEC (procfs_mapinfo, num);
num_mapinfos = num;
mapinfo_p = mapinfos;
printf_unfiltered ("\tUsing the running image of %s %s via %s.\n",
inf->attach_flag ? "attached" : "child",
- target_pid_to_str (inferior_ptid), nto_procfs_path);
+ target_pid_to_str (inferior_ptid),
+ (nodestr != NULL) ? nodestr : "local node");
+}
+
+/* Target to_pid_to_exec_file implementation. */
+
+static char *
+procfs_pid_to_exec_file (struct target_ops *ops, const int pid)
+{
+ int proc_fd;
+ static char proc_path[PATH_MAX];
+ ssize_t rd;
+
+ /* Read exe file name. */
+ snprintf (proc_path, sizeof (proc_path), "%s/proc/%d/exefile",
+ (nodestr != NULL) ? nodestr : "", pid);
+ proc_fd = open (proc_path, O_RDONLY);
+ if (proc_fd == -1)
+ return NULL;
+
+ rd = read (proc_fd, proc_path, sizeof (proc_path) - 1);
+ close (proc_fd);
+ if (rd <= 0)
+ {
+ proc_path[0] = '\0';
+ return NULL;
+ }
+ proc_path[rd] = '\0';
+ return proc_path;
}
/* Attach to process PID, then initialize for debugging it. */
struct sigevent event;
char path[PATH_MAX];
- snprintf (path, PATH_MAX - 1, "%s/%d/as", nto_procfs_path,
- ptid_get_pid (ptid));
+ snprintf (path, PATH_MAX - 1, "%s%s/%d/as",
+ (nodestr != NULL) ? nodestr : "", "/proc", ptid_get_pid (ptid));
ctl_fd = open (path, O_RDWR);
if (ctl_fd == -1)
error (_("Couldn't open proc file %s, error %d (%s)"), path, errno,
devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0);
while (!(status.flags & _DEBUG_FLAG_ISTOP))
{
- ofunc = (void (*)()) signal (SIGINT, nto_handle_sigint);
+ ofunc = signal (SIGINT, nto_handle_sigint);
sigwaitinfo (&set, &info);
signal (SIGINT, ofunc);
devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0);
}
+ nto_inferior_data (NULL)->stopped_flags = status.flags;
+ nto_inferior_data (NULL)->stopped_pc = status.ip;
+
if (status.flags & _DEBUG_FLAG_SSTEP)
{
ourstatus->kind = TARGET_WAITKIND_STOPPED;
{
case TARGET_OBJECT_MEMORY:
return procfs_xfer_memory (readbuf, writebuf, offset, len, xfered_len);
+ case TARGET_OBJECT_AUXV:
+ if (readbuf != NULL)
+ {
+ int err;
+ CORE_ADDR initial_stack;
+ debug_process_t procinfo;
+ /* For 32-bit architecture, size of auxv_t is 8 bytes. */
+ const unsigned int sizeof_auxv_t = sizeof (auxv_t);
+ const unsigned int sizeof_tempbuf = 20 * sizeof_auxv_t;
+ int tempread;
+ gdb_byte *const tempbuf = alloca (sizeof_tempbuf);
+
+ if (tempbuf == NULL)
+ return TARGET_XFER_E_IO;
+
+ err = devctl (ctl_fd, DCMD_PROC_INFO, &procinfo,
+ sizeof procinfo, 0);
+ if (err != EOK)
+ return TARGET_XFER_E_IO;
+
+ initial_stack = procinfo.initial_stack;
+
+ /* procfs is always 'self-hosted', no byte-order manipulation. */
+ tempread = nto_read_auxv_from_initial_stack (initial_stack, tempbuf,
+ sizeof_tempbuf,
+ sizeof (auxv_t));
+ tempread = min (tempread, len) - offset;
+ memcpy (readbuf, tempbuf + offset, tempread);
+ *xfered_len = tempread;
+ return tempread ? TARGET_XFER_OK : TARGET_XFER_EOF;
+ }
+ /* Fallthru */
default:
return ops->beneath->to_xfer_partial (ops->beneath, object, annex,
- readbuf, writebuf, offset, len);
+ readbuf, writebuf, offset, len,
+ xfered_len);
}
}
}
args = xstrdup (allargs);
- breakup_args (args, exec_file ? &argv[1] : &argv[0]);
+ breakup_args (args, (exec_file != NULL) ? &argv[1] : &argv[0]);
argv = nto_parse_redirection (argv, &in, &out, &err);
return dev_set;
}
-void
+static void
procfs_store_registers (struct target_ops *ops,
struct regcache *regcache, int regno)
{
}
}
-static struct tidinfo *
-procfs_thread_info (pid_t pid, short tid)
-{
-/* NYI */
- return NULL;
-}
-
static char *
procfs_pid_to_str (struct target_ops *ops, ptid_t ptid)
{
t->to_interrupt = procfs_interrupt;
t->to_have_continuable_watchpoint = 1;
t->to_extra_thread_info = nto_extra_thread_info;
+ t->to_pid_to_exec_file = procfs_pid_to_exec_file;
nto_native_ops = t;
#define OSTYPE_NTO 1
+extern initialize_file_ftype _initialize_procfs;
+
void
_initialize_procfs (void)
{
static int
procfs_stopped_by_watchpoint (struct target_ops *ops)
{
- return 0;
+ /* NOTE: nto_stopped_by_watchpoint will be called ONLY while we are
+ stopped due to a SIGTRAP. This assumes gdb works in 'all-stop' mode;
+ future gdb versions will likely run in 'non-stop' mode in which case
+ we will have to store/examine statuses per thread in question.
+ Until then, this will work fine. */
+
+ struct inferior *inf = current_inferior ();
+ struct nto_inferior_data *inf_data;
+
+ gdb_assert (inf != NULL);
+
+ inf_data = nto_inferior_data (inf);
+
+ return inf_data->stopped_flags
+ & (_DEBUG_FLAG_TRACE_RD
+ | _DEBUG_FLAG_TRACE_WR
+ | _DEBUG_FLAG_TRACE_MODIFY);
}