#include "defs.h"
#include "inferior.h"
#include "target.h"
#include "gdbcore.h"
#include "elf-bfd.h"
#include "gdbcmd.h"
#include "gdbthread.h"
#if defined (NEW_PROC_API)
#define _STRUCTURED_PROC 1
#endif
#include <sys/procfs.h>
#ifdef HAVE_SYS_FAULT_H
#include <sys/fault.h>
#endif
#ifdef HAVE_SYS_SYSCALL_H
#include <sys/syscall.h>
#endif
#include <sys/errno.h>
#include "gdb_wait.h"
#include <signal.h>
#include <ctype.h>
#include "gdb_string.h"
#include "gdb_assert.h"
#include "inflow.h"
#include "auxv.h"
#ifdef NEW_PROC_API
#include <sys/types.h>
#include "gdb_dirent.h"
#endif
#include <fcntl.h>
#include <unistd.h>
#include "gdb_stat.h"
#include "proc-utils.h"
#include "gregset.h"
static void procfs_open (char *, int);
static void procfs_attach (char *, int);
static void procfs_detach (char *, int);
static void procfs_resume (ptid_t, int, enum target_signal);
static int procfs_can_run (void);
static void procfs_stop (void);
static void procfs_files_info (struct target_ops *);
static void procfs_fetch_registers (int);
static void procfs_store_registers (int);
static void procfs_notice_signals (ptid_t);
static void procfs_prepare_to_store (void);
static void procfs_kill_inferior (void);
static void procfs_mourn_inferior (void);
static void procfs_create_inferior (char *, char *, char **, int);
static ptid_t procfs_wait (ptid_t, struct target_waitstatus *);
static int procfs_xfer_memory (CORE_ADDR, char *, int, int,
struct mem_attrib *attrib,
struct target_ops *);
static LONGEST procfs_xfer_partial (struct target_ops *ops,
enum target_object object,
const char *annex,
void *readbuf, const void *writebuf,
ULONGEST offset, LONGEST len);
static int procfs_thread_alive (ptid_t);
void procfs_find_new_threads (void);
char *procfs_pid_to_str (ptid_t);
static int proc_find_memory_regions (int (*) (CORE_ADDR,
unsigned long,
int, int, int,
void *),
void *);
static char * procfs_make_note_section (bfd *, int *);
static int procfs_can_use_hw_breakpoint (int, int, int);
struct target_ops procfs_ops;
static void
init_procfs_ops (void)
{
procfs_ops.to_shortname = "procfs";
procfs_ops.to_longname = "Unix /proc child process";
procfs_ops.to_doc =
"Unix /proc child process (started by the \"run\" command).";
procfs_ops.to_open = procfs_open;
procfs_ops.to_can_run = procfs_can_run;
procfs_ops.to_create_inferior = procfs_create_inferior;
procfs_ops.to_kill = procfs_kill_inferior;
procfs_ops.to_mourn_inferior = procfs_mourn_inferior;
procfs_ops.to_attach = procfs_attach;
procfs_ops.to_detach = procfs_detach;
procfs_ops.to_wait = procfs_wait;
procfs_ops.to_resume = procfs_resume;
procfs_ops.to_prepare_to_store = procfs_prepare_to_store;
procfs_ops.to_fetch_registers = procfs_fetch_registers;
procfs_ops.to_store_registers = procfs_store_registers;
procfs_ops.to_xfer_partial = procfs_xfer_partial;
procfs_ops.deprecated_xfer_memory = procfs_xfer_memory;
procfs_ops.to_insert_breakpoint = memory_insert_breakpoint;
procfs_ops.to_remove_breakpoint = memory_remove_breakpoint;
procfs_ops.to_notice_signals = procfs_notice_signals;
procfs_ops.to_files_info = procfs_files_info;
procfs_ops.to_stop = procfs_stop;
procfs_ops.to_terminal_init = terminal_init_inferior;
procfs_ops.to_terminal_inferior = terminal_inferior;
procfs_ops.to_terminal_ours_for_output = terminal_ours_for_output;
procfs_ops.to_terminal_ours = terminal_ours;
procfs_ops.to_terminal_save_ours = terminal_save_ours;
procfs_ops.to_terminal_info = child_terminal_info;
procfs_ops.to_find_new_threads = procfs_find_new_threads;
procfs_ops.to_thread_alive = procfs_thread_alive;
procfs_ops.to_pid_to_str = procfs_pid_to_str;
procfs_ops.to_has_all_memory = 1;
procfs_ops.to_has_memory = 1;
procfs_ops.to_has_execution = 1;
procfs_ops.to_has_stack = 1;
procfs_ops.to_has_registers = 1;
procfs_ops.to_stratum = process_stratum;
procfs_ops.to_has_thread_control = tc_schedlock;
procfs_ops.to_find_memory_regions = proc_find_memory_regions;
procfs_ops.to_make_corefile_notes = procfs_make_note_section;
procfs_ops.to_can_use_hw_breakpoint = procfs_can_use_hw_breakpoint;
procfs_ops.to_magic = OPS_MAGIC;
}
#ifdef NEW_PROC_API
#ifdef WA_READ
enum { READ_WATCHFLAG = WA_READ,
WRITE_WATCHFLAG = WA_WRITE,
EXEC_WATCHFLAG = WA_EXEC,
AFTER_WATCHFLAG = WA_TRAPAFTER
};
#endif
#else
enum { READ_WATCHFLAG = MA_READ,
WRITE_WATCHFLAG = MA_WRITE,
EXEC_WATCHFLAG = MA_EXEC,
AFTER_WATCHFLAG = 0
};
#endif
#ifdef HAVE_PR_SIGSET_T
typedef pr_sigset_t gdb_sigset_t;
#else
typedef sigset_t gdb_sigset_t;
#endif
#ifdef HAVE_PR_SIGACTION64_T
typedef pr_sigaction64_t gdb_sigaction_t;
#else
typedef struct sigaction gdb_sigaction_t;
#endif
#ifdef HAVE_PR_SIGINFO64_T
typedef pr_siginfo64_t gdb_siginfo_t;
#else
typedef struct siginfo gdb_siginfo_t;
#endif
#ifdef premptysysset
#define gdb_premptysysset premptysysset
#else
#define gdb_premptysysset premptyset
#endif
#ifdef praddsysset
#define gdb_praddsysset praddsysset
#else
#define gdb_praddsysset praddset
#endif
#ifdef prdelsysset
#define gdb_prdelsysset prdelsysset
#else
#define gdb_prdelsysset prdelset
#endif
#ifdef prissyssetmember
#define gdb_pr_issyssetmember prissyssetmember
#else
#define gdb_pr_issyssetmember prismember
#endif
#ifdef HAVE_PRSYSENT_T
#define DYNAMIC_SYSCALLS
#endif
#ifdef NEW_PROC_API
# ifndef CTL_PROC_NAME_FMT
# define MAIN_PROC_NAME_FMT "/proc/%d"
# define CTL_PROC_NAME_FMT "/proc/%d/ctl"
# define AS_PROC_NAME_FMT "/proc/%d/as"
# define MAP_PROC_NAME_FMT "/proc/%d/map"
# define STATUS_PROC_NAME_FMT "/proc/%d/status"
# define MAX_PROC_NAME_SIZE sizeof("/proc/99999/lwp/8096/lstatus")
# endif
typedef pstatus_t gdb_prstatus_t;
typedef lwpstatus_t gdb_lwpstatus_t;
#else
# ifndef CTL_PROC_NAME_FMT
# define MAIN_PROC_NAME_FMT "/proc/%05d"
# define CTL_PROC_NAME_FMT "/proc/%05d"
# define AS_PROC_NAME_FMT "/proc/%05d"
# define MAP_PROC_NAME_FMT "/proc/%05d"
# define STATUS_PROC_NAME_FMT "/proc/%05d"
# define MAX_PROC_NAME_SIZE sizeof("/proc/ttttppppp")
# endif
typedef prstatus_t gdb_prstatus_t;
typedef prstatus_t gdb_lwpstatus_t;
#endif
typedef struct procinfo {
struct procinfo *next;
int pid;
int tid;
int was_stopped;
int ignore_next_sigstop;
int ctl_fd;
int status_fd;
int as_fd;
char pathname[MAX_PROC_NAME_SIZE];
fltset_t saved_fltset;
gdb_sigset_t saved_sigset;
gdb_sigset_t saved_sighold;
sysset_t *saved_exitset;
sysset_t *saved_entryset;
gdb_prstatus_t prstatus;
#ifndef NEW_PROC_API
gdb_fpregset_t fpregset;
#endif
#ifdef DYNAMIC_SYSCALLS
int num_syscalls;
char **syscall_names;
#endif
struct procinfo *thread_list;
int status_valid : 1;
int gregs_valid : 1;
int fpregs_valid : 1;
int threads_valid: 1;
} procinfo;
static char errmsg[128];
static procinfo *find_procinfo_or_die (int pid, int tid);
static procinfo *find_procinfo (int pid, int tid);
static procinfo *create_procinfo (int pid, int tid);
static void destroy_procinfo (procinfo * p);
static void do_destroy_procinfo_cleanup (void *);
static void dead_procinfo (procinfo * p, char *msg, int killp);
static int open_procinfo_files (procinfo * p, int which);
static void close_procinfo_files (procinfo * p);
static int sysset_t_size (procinfo *p);
static sysset_t *sysset_t_alloc (procinfo * pi);
#ifdef DYNAMIC_SYSCALLS
static void load_syscalls (procinfo *pi);
static void free_syscalls (procinfo *pi);
static int find_syscall (procinfo *pi, char *name);
#endif
static procinfo * procinfo_list;
static procinfo *
find_procinfo (int pid, int tid)
{
procinfo *pi;
for (pi = procinfo_list; pi; pi = pi->next)
if (pi->pid == pid)
break;
if (pi)
if (tid)
{
for (pi = pi->thread_list; pi; pi = pi->next)
if (pi->tid == tid)
break;
}
return pi;
}
static procinfo *
find_procinfo_or_die (int pid, int tid)
{
procinfo *pi = find_procinfo (pid, tid);
if (pi == NULL)
{
if (tid)
error (_("procfs: couldn't find pid %d (kernel thread %d) in procinfo list."),
pid, tid);
else
error (_("procfs: couldn't find pid %d in procinfo list."), pid);
}
return pi;
}
static int
open_with_retry (const char *pathname, int flags)
{
int retries_remaining, status;
retries_remaining = 2;
while (1)
{
status = open (pathname, flags);
if (status >= 0 || retries_remaining == 0)
break;
else if (errno != EINTR && errno != EAGAIN)
{
retries_remaining--;
sleep (1);
}
}
return status;
}
enum { FD_CTL, FD_STATUS, FD_AS };
static int
open_procinfo_files (procinfo *pi, int which)
{
#ifdef NEW_PROC_API
char tmp[MAX_PROC_NAME_SIZE];
#endif
int fd;
#ifdef NEW_PROC_API
strcpy (tmp, pi->pathname);
switch (which) {
case FD_CTL:
if (pi->tid)
strcat (tmp, "/lwpctl");
else
strcat (tmp, "/ctl");
fd = open_with_retry (tmp, O_WRONLY);
if (fd <= 0)
return 0;
pi->ctl_fd = fd;
break;
case FD_AS:
if (pi->tid)
return 0;
strcat (tmp, "/as");
fd = open_with_retry (tmp, O_RDWR);
if (fd <= 0)
return 0;
pi->as_fd = fd;
break;
case FD_STATUS:
if (pi->tid)
strcat (tmp, "/lwpstatus");
else
strcat (tmp, "/status");
fd = open_with_retry (tmp, O_RDONLY);
if (fd <= 0)
return 0;
pi->status_fd = fd;
break;
default:
return 0;
}
#else
#ifdef PIOCTSTATUS
if ((fd = open_with_retry (pi->pathname, O_RDWR)) == 0)
return 0;
#else
if (pi->tid == 0)
{
fd = open_with_retry (pi->pathname, O_RDWR);
if (fd <= 0)
return 0;
}
else
{
#ifdef PIOCOPENLWP
procinfo *process;
int lwpid = pi->tid;
if ((process = find_procinfo (pi->pid, 0)) == NULL)
return 0;
if ((fd = ioctl (process->ctl_fd, PIOCOPENLWP, &lwpid)) <= 0)
return 0;
#else
return 0;
#endif
}
#endif
pi->ctl_fd = pi->as_fd = pi->status_fd = fd;
#endif
return 1;
}
static procinfo *
create_procinfo (int pid, int tid)
{
procinfo *pi, *parent;
if ((pi = find_procinfo (pid, tid)))
return pi;
if (tid != 0)
parent = find_procinfo_or_die (pid, 0);
pi = (procinfo *) xmalloc (sizeof (procinfo));
memset (pi, 0, sizeof (procinfo));
pi->pid = pid;
pi->tid = tid;
#ifdef DYNAMIC_SYSCALLS
load_syscalls (pi);
#endif
pi->saved_entryset = sysset_t_alloc (pi);
pi->saved_exitset = sysset_t_alloc (pi);
if (tid == 0)
{
sprintf (pi->pathname, MAIN_PROC_NAME_FMT, pid);
pi->next = procinfo_list;
procinfo_list = pi;
}
else
{
#ifdef NEW_PROC_API
sprintf (pi->pathname, "/proc/%05d/lwp/%d", pid, tid);
#else
sprintf (pi->pathname, MAIN_PROC_NAME_FMT, pid);
#endif
pi->next = parent->thread_list;
parent->thread_list = pi;
}
return pi;
}
static void
close_procinfo_files (procinfo *pi)
{
if (pi->ctl_fd > 0)
close (pi->ctl_fd);
#ifdef NEW_PROC_API
if (pi->as_fd > 0)
close (pi->as_fd);
if (pi->status_fd > 0)
close (pi->status_fd);
#endif
pi->ctl_fd = pi->as_fd = pi->status_fd = 0;
}
static void
destroy_one_procinfo (procinfo **list, procinfo *pi)
{
procinfo *ptr;
if (pi == *list)
*list = pi->next;
else
for (ptr = *list; ptr; ptr = ptr->next)
if (ptr->next == pi)
{
ptr->next = pi->next;
break;
}
close_procinfo_files (pi);
#ifdef DYNAMIC_SYSCALLS
free_syscalls (pi);
#endif
xfree (pi->saved_entryset);
xfree (pi->saved_exitset);
xfree (pi);
}
static void
destroy_procinfo (procinfo *pi)
{
procinfo *tmp;
if (pi->tid != 0)
{
tmp = find_procinfo (pi->pid, 0);
destroy_one_procinfo (&tmp->thread_list, pi);
}
else
{
while (pi->thread_list != NULL)
destroy_one_procinfo (&pi->thread_list, pi->thread_list);
destroy_one_procinfo (&procinfo_list, pi);
}
}
static void
do_destroy_procinfo_cleanup (void *pi)
{
destroy_procinfo (pi);
}
enum { NOKILL, KILL };
static void
dead_procinfo (procinfo *pi, char *msg, int kill_p)
{
char procfile[80];
if (pi->pathname)
{
print_sys_errmsg (pi->pathname, errno);
}
else
{
sprintf (procfile, "process %d", pi->pid);
print_sys_errmsg (procfile, errno);
}
if (kill_p == KILL)
kill (pi->pid, SIGKILL);
destroy_procinfo (pi);
error ((msg));
}
static int
sysset_t_size (procinfo * pi)
{
#ifndef DYNAMIC_SYSCALLS
return sizeof (sysset_t);
#else
return sizeof (sysset_t) - sizeof (uint64_t)
+ sizeof (uint64_t) * ((pi->num_syscalls + (8 * sizeof (uint64_t) - 1))
/ (8 * sizeof (uint64_t)));
#endif
}
static sysset_t *
sysset_t_alloc (procinfo * pi)
{
sysset_t *ret;
int size = sysset_t_size (pi);
ret = xmalloc (size);
#ifdef DYNAMIC_SYSCALLS
ret->pr_size = (pi->num_syscalls + (8 * sizeof (uint64_t) - 1))
/ (8 * sizeof (uint64_t));
#endif
return ret;
}
#ifdef DYNAMIC_SYSCALLS
#define MAX_SYSCALL_NAME_LENGTH 256
#define MAX_SYSCALLS 65536
static void
load_syscalls (procinfo *pi)
{
char pathname[MAX_PROC_NAME_SIZE];
int sysent_fd;
prsysent_t header;
prsyscall_t *syscalls;
int i, size, maxcall;
pi->num_syscalls = 0;
pi->syscall_names = 0;
sprintf (pathname, "/proc/%d/sysent", pi->pid);
sysent_fd = open_with_retry (pathname, O_RDONLY);
if (sysent_fd < 0)
{
error (_("load_syscalls: Can't open /proc/%d/sysent"), pi->pid);
}
size = sizeof header - sizeof (prsyscall_t);
if (read (sysent_fd, &header, size) != size)
{
error (_("load_syscalls: Error reading /proc/%d/sysent"), pi->pid);
}
if (header.pr_nsyscalls == 0)
{
error (_("load_syscalls: /proc/%d/sysent contains no syscalls!"), pi->pid);
}
size = header.pr_nsyscalls * sizeof (prsyscall_t);
syscalls = xmalloc (size);
if (read (sysent_fd, syscalls, size) != size)
{
xfree (syscalls);
error (_("load_syscalls: Error reading /proc/%d/sysent"), pi->pid);
}
maxcall = syscalls[0].pr_number;
for (i = 1; i < header.pr_nsyscalls; i++)
if (syscalls[i].pr_number > maxcall
&& syscalls[i].pr_nameoff > 0
&& syscalls[i].pr_number < MAX_SYSCALLS)
maxcall = syscalls[i].pr_number;
pi->num_syscalls = maxcall+1;
pi->syscall_names = xmalloc (pi->num_syscalls * sizeof (char *));
for (i = 0; i < pi->num_syscalls; i++)
pi->syscall_names[i] = NULL;
for (i = 0; i < header.pr_nsyscalls; i++)
{
char namebuf[MAX_SYSCALL_NAME_LENGTH];
int nread;
int callnum;
if (syscalls[i].pr_number >= MAX_SYSCALLS
|| syscalls[i].pr_number < 0
|| syscalls[i].pr_nameoff <= 0
|| (lseek (sysent_fd, (off_t) syscalls[i].pr_nameoff, SEEK_SET)
!= (off_t) syscalls[i].pr_nameoff))
continue;
nread = read (sysent_fd, namebuf, sizeof namebuf);
if (nread <= 0)
continue;
callnum = syscalls[i].pr_number;
if (pi->syscall_names[callnum] != NULL)
{
continue;
}
namebuf[nread-1] = '\0';
size = strlen (namebuf) + 1;
pi->syscall_names[callnum] = xmalloc (size);
strncpy (pi->syscall_names[callnum], namebuf, size-1);
pi->syscall_names[callnum][size-1] = '\0';
}
close (sysent_fd);
xfree (syscalls);
}
static void
free_syscalls (procinfo *pi)
{
if (pi->syscall_names)
{
int i;
for (i = 0; i < pi->num_syscalls; i++)
if (pi->syscall_names[i] != NULL)
xfree (pi->syscall_names[i]);
xfree (pi->syscall_names);
pi->syscall_names = 0;
}
}
static int
find_syscall (procinfo *pi, char *name)
{
int i;
for (i = 0; i < pi->num_syscalls; i++)
{
if (pi->syscall_names[i] && strcmp (name, pi->syscall_names[i]) == 0)
return i;
}
return -1;
}
#endif
int proc_get_status (procinfo * pi);
long proc_flags (procinfo * pi);
int proc_why (procinfo * pi);
int proc_what (procinfo * pi);
int proc_set_run_on_last_close (procinfo * pi);
int proc_unset_run_on_last_close (procinfo * pi);
int proc_set_inherit_on_fork (procinfo * pi);
int proc_unset_inherit_on_fork (procinfo * pi);
int proc_set_async (procinfo * pi);
int proc_unset_async (procinfo * pi);
int proc_stop_process (procinfo * pi);
int proc_trace_signal (procinfo * pi, int signo);
int proc_ignore_signal (procinfo * pi, int signo);
int proc_clear_current_fault (procinfo * pi);
int proc_set_current_signal (procinfo * pi, int signo);
int proc_clear_current_signal (procinfo * pi);
int proc_set_gregs (procinfo * pi);
int proc_set_fpregs (procinfo * pi);
int proc_wait_for_stop (procinfo * pi);
int proc_run_process (procinfo * pi, int step, int signo);
int proc_kill (procinfo * pi, int signo);
int proc_parent_pid (procinfo * pi);
int proc_get_nthreads (procinfo * pi);
int proc_get_current_thread (procinfo * pi);
int proc_set_held_signals (procinfo * pi, gdb_sigset_t * sighold);
int proc_set_traced_sysexit (procinfo * pi, sysset_t * sysset);
int proc_set_traced_sysentry (procinfo * pi, sysset_t * sysset);
int proc_set_traced_faults (procinfo * pi, fltset_t * fltset);
int proc_set_traced_signals (procinfo * pi, gdb_sigset_t * sigset);
int proc_update_threads (procinfo * pi);
int proc_iterate_over_threads (procinfo * pi,
int (*func) (procinfo *, procinfo *, void *),
void *ptr);
gdb_gregset_t *proc_get_gregs (procinfo * pi);
gdb_fpregset_t *proc_get_fpregs (procinfo * pi);
sysset_t *proc_get_traced_sysexit (procinfo * pi, sysset_t * save);
sysset_t *proc_get_traced_sysentry (procinfo * pi, sysset_t * save);
fltset_t *proc_get_traced_faults (procinfo * pi, fltset_t * save);
gdb_sigset_t *proc_get_traced_signals (procinfo * pi, gdb_sigset_t * save);
gdb_sigset_t *proc_get_held_signals (procinfo * pi, gdb_sigset_t * save);
gdb_sigset_t *proc_get_pending_signals (procinfo * pi, gdb_sigset_t * save);
gdb_sigaction_t *proc_get_signal_actions (procinfo * pi, gdb_sigaction_t *save);
void proc_warn (procinfo * pi, char *func, int line);
void proc_error (procinfo * pi, char *func, int line);
void
proc_warn (procinfo *pi, char *func, int line)
{
sprintf (errmsg, "procfs: %s line %d, %s", func, line, pi->pathname);
print_sys_errmsg (errmsg, errno);
}
void
proc_error (procinfo *pi, char *func, int line)
{
sprintf (errmsg, "procfs: %s line %d, %s", func, line, pi->pathname);
perror_with_name (errmsg);
}
int
proc_get_status (procinfo *pi)
{
if (pi->status_fd == 0 &&
open_procinfo_files (pi, FD_STATUS) == 0)
{
pi->status_valid = 0;
return 0;
}
#ifdef NEW_PROC_API
if (lseek (pi->status_fd, 0, SEEK_SET) < 0)
pi->status_valid = 0;
else
{
if (pi->tid)
pi->status_valid = (read (pi->status_fd,
(char *) &pi->prstatus.pr_lwp,
sizeof (lwpstatus_t))
== sizeof (lwpstatus_t));
else
{
pi->status_valid = (read (pi->status_fd,
(char *) &pi->prstatus,
sizeof (gdb_prstatus_t))
== sizeof (gdb_prstatus_t));
#if 0
if (pi->status_valid &&
(pi->prstatus.pr_lwp.pr_flags & PR_ISTOP) &&
pi->prstatus.pr_lwp.pr_why == PR_REQUESTED)
pi->status_valid = (read (pi->status_fd,
(char *) &pi->prstatus,
sizeof (gdb_prstatus_t))
== sizeof (gdb_prstatus_t));
#endif
}
}
#else
#ifdef PIOCTSTATUS
if (pi->tid == 0)
{
pi->status_valid =
(ioctl (pi->status_fd, PIOCSTATUS, &pi->prstatus) >= 0);
}
else
{
int win;
struct {
long pr_count;
tid_t pr_error_thread;
struct prstatus status;
} thread_status;
thread_status.pr_count = 1;
thread_status.status.pr_tid = pi->tid;
win = (ioctl (pi->status_fd, PIOCTSTATUS, &thread_status) >= 0);
if (win)
{
memcpy (&pi->prstatus, &thread_status.status,
sizeof (pi->prstatus));
pi->status_valid = 1;
}
}
#else
pi->status_valid = (ioctl (pi->status_fd, PIOCSTATUS, &pi->prstatus) >= 0);
#endif
#endif
if (pi->status_valid)
{
PROC_PRETTYFPRINT_STATUS (proc_flags (pi),
proc_why (pi),
proc_what (pi),
proc_get_current_thread (pi));
}
pi->gregs_valid = pi->status_valid;
#ifdef NEW_PROC_API
pi->fpregs_valid = pi->status_valid;
#endif
return pi->status_valid;
}
long
proc_flags (procinfo *pi)
{
if (!pi->status_valid)
if (!proc_get_status (pi))
return 0;
#ifdef NEW_PROC_API
# ifdef UNIXWARE
return pi->prstatus.pr_flags | pi->prstatus.pr_lwp.pr_flags;
# else
return pi->prstatus.pr_lwp.pr_flags;
# endif
#else
return pi->prstatus.pr_flags;
#endif
}
int
proc_why (procinfo *pi)
{
if (!pi->status_valid)
if (!proc_get_status (pi))
return 0;
#ifdef NEW_PROC_API
return pi->prstatus.pr_lwp.pr_why;
#else
return pi->prstatus.pr_why;
#endif
}
int
proc_what (procinfo *pi)
{
if (!pi->status_valid)
if (!proc_get_status (pi))
return 0;
#ifdef NEW_PROC_API
return pi->prstatus.pr_lwp.pr_what;
#else
return pi->prstatus.pr_what;
#endif
}
#ifndef PIOCSSPCACT
int
proc_nsysarg (procinfo *pi)
{
if (!pi->status_valid)
if (!proc_get_status (pi))
return 0;
#ifdef NEW_PROC_API
return pi->prstatus.pr_lwp.pr_nsysarg;
#else
return pi->prstatus.pr_nsysarg;
#endif
}
long *
proc_sysargs (procinfo *pi)
{
if (!pi->status_valid)
if (!proc_get_status (pi))
return NULL;
#ifdef NEW_PROC_API
return (long *) &pi->prstatus.pr_lwp.pr_sysarg;
#else
return (long *) &pi->prstatus.pr_sysarg;
#endif
}
int
proc_syscall (procinfo *pi)
{
if (!pi->status_valid)
if (!proc_get_status (pi))
return 0;
#ifdef NEW_PROC_API
return pi->prstatus.pr_lwp.pr_syscall;
#else
return pi->prstatus.pr_syscall;
#endif
}
#endif
long
proc_cursig (struct procinfo *pi)
{
if (!pi->status_valid)
if (!proc_get_status (pi))
return 0;
#ifdef NEW_PROC_API
return pi->prstatus.pr_lwp.pr_cursig;
#else
return pi->prstatus.pr_cursig;
#endif
}
enum { FLAG_RESET, FLAG_SET };
static int
proc_modify_flag (procinfo *pi, long flag, long mode)
{
long win = 0;
if (pi->pid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
#ifdef NEW_PROC_API
#ifdef PCUNSET
#define GDBRESET PCUNSET
#else
#ifdef PCRESET
#define GDBRESET PCRESET
#endif
#endif
{
procfs_ctl_t arg[2];
if (mode == FLAG_SET)
arg[0] = PCSET;
else
arg[0] = GDBRESET;
arg[1] = flag;
win = (write (pi->ctl_fd, (void *) &arg, sizeof (arg)) == sizeof (arg));
}
#else
#ifdef PIOCSET
if (mode == FLAG_SET)
{
win = (ioctl (pi->ctl_fd, PIOCSET, &flag) >= 0);
}
else
{
win = (ioctl (pi->ctl_fd, PIOCRESET, &flag) >= 0);
}
#else
#ifdef PIOCSRLC
switch (flag) {
case PR_RLC:
if (mode == FLAG_SET)
{
win = (ioctl (pi->ctl_fd, PIOCSRLC, NULL) >= 0);
}
else
{
win = (ioctl (pi->ctl_fd, PIOCRRLC, NULL) >= 0);
}
break;
case PR_FORK:
if (mode == FLAG_SET)
{
win = (ioctl (pi->ctl_fd, PIOCSFORK, NULL) >= 0);
}
else
{
win = (ioctl (pi->ctl_fd, PIOCRFORK, NULL) >= 0);
}
break;
default:
win = 0;
break;
}
#endif
#endif
#endif
#undef GDBRESET
pi->status_valid = 0;
if (!win)
warning (_("procfs: modify_flag failed to turn %s %s"),
flag == PR_FORK ? "PR_FORK" :
flag == PR_RLC ? "PR_RLC" :
#ifdef PR_ASYNC
flag == PR_ASYNC ? "PR_ASYNC" :
#endif
#ifdef PR_KLC
flag == PR_KLC ? "PR_KLC" :
#endif
"<unknown flag>",
mode == FLAG_RESET ? "off" : "on");
return win;
}
int
proc_set_run_on_last_close (procinfo *pi)
{
return proc_modify_flag (pi, PR_RLC, FLAG_SET);
}
int
proc_unset_run_on_last_close (procinfo *pi)
{
return proc_modify_flag (pi, PR_RLC, FLAG_RESET);
}
#ifdef PR_KLC
int
proc_set_kill_on_last_close (procinfo *pi)
{
return proc_modify_flag (pi, PR_KLC, FLAG_SET);
}
int
proc_unset_kill_on_last_close (procinfo *pi)
{
return proc_modify_flag (pi, PR_KLC, FLAG_RESET);
}
#endif
int
proc_set_inherit_on_fork (procinfo *pi)
{
return proc_modify_flag (pi, PR_FORK, FLAG_SET);
}
int
proc_unset_inherit_on_fork (procinfo *pi)
{
return proc_modify_flag (pi, PR_FORK, FLAG_RESET);
}
#ifdef PR_ASYNC
int
proc_set_async (procinfo *pi)
{
return proc_modify_flag (pi, PR_ASYNC, FLAG_SET);
}
int
proc_unset_async (procinfo *pi)
{
return proc_modify_flag (pi, PR_ASYNC, FLAG_RESET);
}
#endif
int
proc_stop_process (procinfo *pi)
{
int win;
if (pi->ctl_fd == 0 &&
open_procinfo_files (pi, FD_CTL) == 0)
return 0;
else
{
#ifdef NEW_PROC_API
procfs_ctl_t cmd = PCSTOP;
win = (write (pi->ctl_fd, (char *) &cmd, sizeof (cmd)) == sizeof (cmd));
#else
win = (ioctl (pi->ctl_fd, PIOCSTOP, &pi->prstatus) >= 0);
if (win)
{
pi->status_valid = 1;
PROC_PRETTYFPRINT_STATUS (proc_flags (pi),
proc_why (pi),
proc_what (pi),
proc_get_current_thread (pi));
}
#endif
}
return win;
}
int
proc_wait_for_stop (procinfo *pi)
{
int win;
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
#ifdef NEW_PROC_API
{
procfs_ctl_t cmd = PCWSTOP;
win = (write (pi->ctl_fd, (char *) &cmd, sizeof (cmd)) == sizeof (cmd));
pi->status_valid = 0;
}
#else
win = (ioctl (pi->ctl_fd, PIOCWSTOP, &pi->prstatus) >= 0);
if (win)
{
pi->status_valid = 1;
PROC_PRETTYFPRINT_STATUS (proc_flags (pi),
proc_why (pi),
proc_what (pi),
proc_get_current_thread (pi));
}
#endif
return win;
}
int
proc_run_process (procinfo *pi, int step, int signo)
{
int win;
int runflags;
if (pi->ctl_fd == 0 &&
open_procinfo_files (pi, FD_CTL) == 0)
{
return 0;
}
runflags = PRCFAULT;
if (step)
runflags |= PRSTEP;
if (signo == 0)
runflags |= PRCSIG;
else if (signo != -1)
proc_set_current_signal (pi, signo);
#ifdef NEW_PROC_API
{
procfs_ctl_t cmd[2];
cmd[0] = PCRUN;
cmd[1] = runflags;
win = (write (pi->ctl_fd, (char *) &cmd, sizeof (cmd)) == sizeof (cmd));
}
#else
{
prrun_t prrun;
memset (&prrun, 0, sizeof (prrun));
prrun.pr_flags = runflags;
win = (ioctl (pi->ctl_fd, PIOCRUN, &prrun) >= 0);
}
#endif
return win;
}
int
proc_set_traced_signals (procinfo *pi, gdb_sigset_t *sigset)
{
int win;
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
#ifdef NEW_PROC_API
{
struct {
procfs_ctl_t cmd;
char sigset[sizeof (gdb_sigset_t)];
} arg;
arg.cmd = PCSTRACE;
memcpy (&arg.sigset, sigset, sizeof (gdb_sigset_t));
win = (write (pi->ctl_fd, (char *) &arg, sizeof (arg)) == sizeof (arg));
}
#else
win = (ioctl (pi->ctl_fd, PIOCSTRACE, sigset) >= 0);
#endif
pi->status_valid = 0;
if (!win)
warning (_("procfs: set_traced_signals failed"));
return win;
}
int
proc_set_traced_faults (procinfo *pi, fltset_t *fltset)
{
int win;
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
#ifdef NEW_PROC_API
{
struct {
procfs_ctl_t cmd;
char fltset[sizeof (fltset_t)];
} arg;
arg.cmd = PCSFAULT;
memcpy (&arg.fltset, fltset, sizeof (fltset_t));
win = (write (pi->ctl_fd, (char *) &arg, sizeof (arg)) == sizeof (arg));
}
#else
win = (ioctl (pi->ctl_fd, PIOCSFAULT, fltset) >= 0);
#endif
pi->status_valid = 0;
return win;
}
int
proc_set_traced_sysentry (procinfo *pi, sysset_t *sysset)
{
int win;
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
#ifdef NEW_PROC_API
{
struct gdb_proc_ctl_pcsentry {
procfs_ctl_t cmd;
char sysset[sizeof (sysset_t)];
} *argp;
int argp_size = sizeof (struct gdb_proc_ctl_pcsentry)
- sizeof (sysset_t)
+ sysset_t_size (pi);
argp = xmalloc (argp_size);
argp->cmd = PCSENTRY;
memcpy (&argp->sysset, sysset, sysset_t_size (pi));
win = (write (pi->ctl_fd, (char *) argp, argp_size) == argp_size);
xfree (argp);
}
#else
win = (ioctl (pi->ctl_fd, PIOCSENTRY, sysset) >= 0);
#endif
pi->status_valid = 0;
return win;
}
int
proc_set_traced_sysexit (procinfo *pi, sysset_t *sysset)
{
int win;
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
#ifdef NEW_PROC_API
{
struct gdb_proc_ctl_pcsexit {
procfs_ctl_t cmd;
char sysset[sizeof (sysset_t)];
} *argp;
int argp_size = sizeof (struct gdb_proc_ctl_pcsexit)
- sizeof (sysset_t)
+ sysset_t_size (pi);
argp = xmalloc (argp_size);
argp->cmd = PCSEXIT;
memcpy (&argp->sysset, sysset, sysset_t_size (pi));
win = (write (pi->ctl_fd, (char *) argp, argp_size) == argp_size);
xfree (argp);
}
#else
win = (ioctl (pi->ctl_fd, PIOCSEXIT, sysset) >= 0);
#endif
pi->status_valid = 0;
return win;
}
int
proc_set_held_signals (procinfo *pi, gdb_sigset_t *sighold)
{
int win;
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
#ifdef NEW_PROC_API
{
struct {
procfs_ctl_t cmd;
char hold[sizeof (gdb_sigset_t)];
} arg;
arg.cmd = PCSHOLD;
memcpy (&arg.hold, sighold, sizeof (gdb_sigset_t));
win = (write (pi->ctl_fd, (void *) &arg, sizeof (arg)) == sizeof (arg));
}
#else
win = (ioctl (pi->ctl_fd, PIOCSHOLD, sighold) >= 0);
#endif
pi->status_valid = 0;
return win;
}
gdb_sigset_t *
proc_get_pending_signals (procinfo *pi, gdb_sigset_t *save)
{
gdb_sigset_t *ret = NULL;
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
if (!pi->status_valid)
if (!proc_get_status (pi))
return NULL;
#ifdef NEW_PROC_API
ret = &pi->prstatus.pr_lwp.pr_lwppend;
#else
ret = &pi->prstatus.pr_sigpend;
#endif
if (save && ret)
memcpy (save, ret, sizeof (gdb_sigset_t));
return ret;
}
gdb_sigaction_t *
proc_get_signal_actions (procinfo *pi, gdb_sigaction_t *save)
{
gdb_sigaction_t *ret = NULL;
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
if (!pi->status_valid)
if (!proc_get_status (pi))
return NULL;
#ifdef NEW_PROC_API
ret = &pi->prstatus.pr_lwp.pr_action;
#else
ret = &pi->prstatus.pr_action;
#endif
if (save && ret)
memcpy (save, ret, sizeof (gdb_sigaction_t));
return ret;
}
gdb_sigset_t *
proc_get_held_signals (procinfo *pi, gdb_sigset_t *save)
{
gdb_sigset_t *ret = NULL;
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
#ifdef NEW_PROC_API
if (!pi->status_valid)
if (!proc_get_status (pi))
return NULL;
#ifdef UNIXWARE
ret = &pi->prstatus.pr_lwp.pr_context.uc_sigmask;
#else
ret = &pi->prstatus.pr_lwp.pr_lwphold;
#endif
#else
{
static gdb_sigset_t sigheld;
if (ioctl (pi->ctl_fd, PIOCGHOLD, &sigheld) >= 0)
ret = &sigheld;
}
#endif
if (save && ret)
memcpy (save, ret, sizeof (gdb_sigset_t));
return ret;
}
gdb_sigset_t *
proc_get_traced_signals (procinfo *pi, gdb_sigset_t *save)
{
gdb_sigset_t *ret = NULL;
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
#ifdef NEW_PROC_API
if (!pi->status_valid)
if (!proc_get_status (pi))
return NULL;
ret = &pi->prstatus.pr_sigtrace;
#else
{
static gdb_sigset_t sigtrace;
if (ioctl (pi->ctl_fd, PIOCGTRACE, &sigtrace) >= 0)
ret = &sigtrace;
}
#endif
if (save && ret)
memcpy (save, ret, sizeof (gdb_sigset_t));
return ret;
}
int
proc_trace_signal (procinfo *pi, int signo)
{
gdb_sigset_t temp;
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
if (pi)
{
if (proc_get_traced_signals (pi, &temp))
{
praddset (&temp, signo);
return proc_set_traced_signals (pi, &temp);
}
}
return 0;
}
int
proc_ignore_signal (procinfo *pi, int signo)
{
gdb_sigset_t temp;
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
if (pi)
{
if (proc_get_traced_signals (pi, &temp))
{
prdelset (&temp, signo);
return proc_set_traced_signals (pi, &temp);
}
}
return 0;
}
fltset_t *
proc_get_traced_faults (procinfo *pi, fltset_t *save)
{
fltset_t *ret = NULL;
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
#ifdef NEW_PROC_API
if (!pi->status_valid)
if (!proc_get_status (pi))
return NULL;
ret = &pi->prstatus.pr_flttrace;
#else
{
static fltset_t flttrace;
if (ioctl (pi->ctl_fd, PIOCGFAULT, &flttrace) >= 0)
ret = &flttrace;
}
#endif
if (save && ret)
memcpy (save, ret, sizeof (fltset_t));
return ret;
}
sysset_t *
proc_get_traced_sysentry (procinfo *pi, sysset_t *save)
{
sysset_t *ret = NULL;
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
#ifdef NEW_PROC_API
if (!pi->status_valid)
if (!proc_get_status (pi))
return NULL;
#ifndef DYNAMIC_SYSCALLS
ret = &pi->prstatus.pr_sysentry;
#else
{
static sysset_t *sysentry;
size_t size;
if (!sysentry)
sysentry = sysset_t_alloc (pi);
ret = sysentry;
if (pi->status_fd == 0 && open_procinfo_files (pi, FD_STATUS) == 0)
return NULL;
if (pi->prstatus.pr_sysentry_offset == 0)
{
gdb_premptysysset (sysentry);
}
else
{
int rsize;
if (lseek (pi->status_fd, (off_t) pi->prstatus.pr_sysentry_offset,
SEEK_SET)
!= (off_t) pi->prstatus.pr_sysentry_offset)
return NULL;
size = sysset_t_size (pi);
gdb_premptysysset (sysentry);
rsize = read (pi->status_fd, sysentry, size);
if (rsize < 0)
return NULL;
}
}
#endif
#else
{
static sysset_t sysentry;
if (ioctl (pi->ctl_fd, PIOCGENTRY, &sysentry) >= 0)
ret = &sysentry;
}
#endif
if (save && ret)
memcpy (save, ret, sysset_t_size (pi));
return ret;
}
sysset_t *
proc_get_traced_sysexit (procinfo *pi, sysset_t *save)
{
sysset_t * ret = NULL;
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
#ifdef NEW_PROC_API
if (!pi->status_valid)
if (!proc_get_status (pi))
return NULL;
#ifndef DYNAMIC_SYSCALLS
ret = &pi->prstatus.pr_sysexit;
#else
{
static sysset_t *sysexit;
size_t size;
if (!sysexit)
sysexit = sysset_t_alloc (pi);
ret = sysexit;
if (pi->status_fd == 0 && open_procinfo_files (pi, FD_STATUS) == 0)
return NULL;
if (pi->prstatus.pr_sysexit_offset == 0)
{
gdb_premptysysset (sysexit);
}
else
{
int rsize;
if (lseek (pi->status_fd, (off_t) pi->prstatus.pr_sysexit_offset, SEEK_SET)
!= (off_t) pi->prstatus.pr_sysexit_offset)
return NULL;
size = sysset_t_size (pi);
gdb_premptysysset (sysexit);
rsize = read (pi->status_fd, sysexit, size);
if (rsize < 0)
return NULL;
}
}
#endif
#else
{
static sysset_t sysexit;
if (ioctl (pi->ctl_fd, PIOCGEXIT, &sysexit) >= 0)
ret = &sysexit;
}
#endif
if (save && ret)
memcpy (save, ret, sysset_t_size (pi));
return ret;
}
int
proc_clear_current_fault (procinfo *pi)
{
int win;
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
#ifdef NEW_PROC_API
{
procfs_ctl_t cmd = PCCFAULT;
win = (write (pi->ctl_fd, (void *) &cmd, sizeof (cmd)) == sizeof (cmd));
}
#else
win = (ioctl (pi->ctl_fd, PIOCCFAULT, 0) >= 0);
#endif
return win;
}
int
proc_set_current_signal (procinfo *pi, int signo)
{
int win;
struct {
procfs_ctl_t cmd;
char sinfo[sizeof (gdb_siginfo_t)];
} arg;
gdb_siginfo_t *mysinfo;
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
#ifdef PROCFS_DONT_PIOCSSIG_CURSIG
if (signo > 0 &&
signo == proc_cursig (pi))
return 1;
#endif
mysinfo = (gdb_siginfo_t *) &arg.sinfo;
mysinfo->si_signo = signo;
mysinfo->si_code = 0;
mysinfo->si_pid = getpid ();
mysinfo->si_uid = getuid ();
#ifdef NEW_PROC_API
arg.cmd = PCSSIG;
win = (write (pi->ctl_fd, (void *) &arg, sizeof (arg)) == sizeof (arg));
#else
win = (ioctl (pi->ctl_fd, PIOCSSIG, (void *) &arg.sinfo) >= 0);
#endif
return win;
}
int
proc_clear_current_signal (procinfo *pi)
{
int win;
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
#ifdef NEW_PROC_API
{
struct {
procfs_ctl_t cmd;
char sinfo[sizeof (gdb_siginfo_t)];
} arg;
gdb_siginfo_t *mysinfo;
arg.cmd = PCSSIG;
mysinfo = (gdb_siginfo_t *) &arg.sinfo;
mysinfo->si_signo = 0;
mysinfo->si_code = 0;
mysinfo->si_errno = 0;
mysinfo->si_pid = getpid ();
mysinfo->si_uid = getuid ();
win = (write (pi->ctl_fd, (void *) &arg, sizeof (arg)) == sizeof (arg));
}
#else
win = (ioctl (pi->ctl_fd, PIOCSSIG, 0) >= 0);
#endif
return win;
}
gdb_gregset_t *
proc_get_gregs (procinfo *pi)
{
if (!pi->status_valid || !pi->gregs_valid)
if (!proc_get_status (pi))
return NULL;
#ifdef NEW_PROC_API
# ifdef UNIXWARE
return &pi->prstatus.pr_lwp.pr_context.uc_mcontext.gregs;
# else
return &pi->prstatus.pr_lwp.pr_reg;
# endif
#else
return &pi->prstatus.pr_reg;
#endif
}
gdb_fpregset_t *
proc_get_fpregs (procinfo *pi)
{
#ifdef NEW_PROC_API
if (!pi->status_valid || !pi->fpregs_valid)
if (!proc_get_status (pi))
return NULL;
# ifdef UNIXWARE
return &pi->prstatus.pr_lwp.pr_context.uc_mcontext.fpregs;
# else
return &pi->prstatus.pr_lwp.pr_fpreg;
# endif
#else
if (pi->fpregs_valid)
return &pi->fpregset;
else
{
if (pi->ctl_fd == 0 && open_procinfo_files (pi, FD_CTL) == 0)
{
return NULL;
}
else
{
# ifdef PIOCTGFPREG
struct {
long pr_count;
tid_t pr_error_thread;
tfpregset_t thread_1;
} thread_fpregs;
thread_fpregs.pr_count = 1;
thread_fpregs.thread_1.tid = pi->tid;
if (pi->tid == 0
&& ioctl (pi->ctl_fd, PIOCGFPREG, &pi->fpregset) >= 0)
{
pi->fpregs_valid = 1;
return &pi->fpregset;
}
else if (pi->tid != 0
&& ioctl (pi->ctl_fd, PIOCTGFPREG, &thread_fpregs) >= 0)
{
memcpy (&pi->fpregset, &thread_fpregs.thread_1.pr_fpregs,
sizeof (pi->fpregset));
pi->fpregs_valid = 1;
return &pi->fpregset;
}
else
{
return NULL;
}
# else
if (ioctl (pi->ctl_fd, PIOCGFPREG, &pi->fpregset) >= 0)
{
pi->fpregs_valid = 1;
return &pi->fpregset;
}
else
{
return NULL;
}
# endif
}
}
#endif
}
int
proc_set_gregs (procinfo *pi)
{
gdb_gregset_t *gregs;
int win;
gregs = proc_get_gregs (pi);
if (gregs == NULL)
return 0;
if (pi->ctl_fd == 0 && open_procinfo_files (pi, FD_CTL) == 0)
{
return 0;
}
else
{
#ifdef NEW_PROC_API
struct {
procfs_ctl_t cmd;
char gregs[sizeof (gdb_gregset_t)];
} arg;
arg.cmd = PCSREG;
memcpy (&arg.gregs, gregs, sizeof (arg.gregs));
win = (write (pi->ctl_fd, (void *) &arg, sizeof (arg)) == sizeof (arg));
#else
win = (ioctl (pi->ctl_fd, PIOCSREG, gregs) >= 0);
#endif
}
pi->gregs_valid = 0;
return win;
}
int
proc_set_fpregs (procinfo *pi)
{
gdb_fpregset_t *fpregs;
int win;
fpregs = proc_get_fpregs (pi);
if (fpregs == NULL)
return 0;
if (pi->ctl_fd == 0 && open_procinfo_files (pi, FD_CTL) == 0)
{
return 0;
}
else
{
#ifdef NEW_PROC_API
struct {
procfs_ctl_t cmd;
char fpregs[sizeof (gdb_fpregset_t)];
} arg;
arg.cmd = PCSFPREG;
memcpy (&arg.fpregs, fpregs, sizeof (arg.fpregs));
win = (write (pi->ctl_fd, (void *) &arg, sizeof (arg)) == sizeof (arg));
#else
# ifdef PIOCTSFPREG
if (pi->tid == 0)
win = (ioctl (pi->ctl_fd, PIOCSFPREG, fpregs) >= 0);
else
{
struct {
long pr_count;
tid_t pr_error_thread;
tfpregset_t thread_1;
} thread_fpregs;
thread_fpregs.pr_count = 1;
thread_fpregs.thread_1.tid = pi->tid;
memcpy (&thread_fpregs.thread_1.pr_fpregs, fpregs,
sizeof (*fpregs));
win = (ioctl (pi->ctl_fd, PIOCTSFPREG, &thread_fpregs) >= 0);
}
# else
win = (ioctl (pi->ctl_fd, PIOCSFPREG, fpregs) >= 0);
# endif
#endif
}
pi->fpregs_valid = 0;
return win;
}
int
proc_kill (procinfo *pi, int signo)
{
int win;
if (pi->ctl_fd == 0 &&
open_procinfo_files (pi, FD_CTL) == 0)
{
return 0;
}
else
{
#ifdef NEW_PROC_API
procfs_ctl_t cmd[2];
cmd[0] = PCKILL;
cmd[1] = signo;
win = (write (pi->ctl_fd, (char *) &cmd, sizeof (cmd)) == sizeof (cmd));
#else
win = (ioctl (pi->ctl_fd, PIOCKILL, &signo) >= 0);
#endif
}
return win;
}
int
proc_parent_pid (procinfo *pi)
{
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
if (!pi->status_valid)
if (!proc_get_status (pi))
return 0;
return pi->prstatus.pr_ppid;
}
static void *
procfs_address_to_host_pointer (CORE_ADDR addr)
{
void *ptr;
gdb_assert (sizeof (ptr) == TYPE_LENGTH (builtin_type_void_data_ptr));
ADDRESS_TO_POINTER (builtin_type_void_data_ptr, &ptr, addr);
return ptr;
}
int
proc_set_watchpoint (procinfo *pi, CORE_ADDR addr, int len, int wflags)
{
#if !defined (TARGET_HAS_HARDWARE_WATCHPOINTS)
return 0;
#else
#if defined (PIOCOPENLWP) || defined (UNIXWARE)
return 0;
#else
struct {
procfs_ctl_t cmd;
char watch[sizeof (prwatch_t)];
} arg;
prwatch_t *pwatch;
pwatch = (prwatch_t *) &arg.watch;
#ifdef PCAGENT
pwatch->pr_vaddr = (uintptr_t) procfs_address_to_host_pointer (addr);
#else
pwatch->pr_vaddr = (caddr_t) procfs_address_to_host_pointer (addr);
#endif
pwatch->pr_size = len;
pwatch->pr_wflags = wflags;
#if defined(NEW_PROC_API) && defined (PCWATCH)
arg.cmd = PCWATCH;
return (write (pi->ctl_fd, &arg, sizeof (arg)) == sizeof (arg));
#else
#if defined (PIOCSWATCH)
return (ioctl (pi->ctl_fd, PIOCSWATCH, pwatch) >= 0);
#else
return 0;
#endif
#endif
#endif
#endif
}
#ifdef TM_I386SOL2_H
#include <sys/sysi86.h>
struct ssd *
proc_get_LDT_entry (procinfo *pi, int key)
{
static struct ssd *ldt_entry = NULL;
#ifdef NEW_PROC_API
char pathname[MAX_PROC_NAME_SIZE];
struct cleanup *old_chain = NULL;
int fd;
if (ldt_entry == NULL)
ldt_entry = (struct ssd *) xmalloc (sizeof (struct ssd));
sprintf (pathname, "/proc/%d/ldt", pi->pid);
if ((fd = open_with_retry (pathname, O_RDONLY)) < 0)
{
proc_warn (pi, "proc_get_LDT_entry (open)", __LINE__);
return NULL;
}
old_chain = make_cleanup_close (fd);
while (read (fd, ldt_entry, sizeof (struct ssd)) == sizeof (struct ssd))
{
if (ldt_entry->sel == 0 &&
ldt_entry->bo == 0 &&
ldt_entry->acc1 == 0 &&
ldt_entry->acc2 == 0)
break;
if (ldt_entry->sel == key)
return ldt_entry;
}
return NULL;
#else
int nldt, i;
static int nalloc = 0;
if (ioctl (pi->ctl_fd, PIOCNLDT, &nldt) < 0)
{
proc_warn (pi, "proc_get_LDT_entry (PIOCNLDT)", __LINE__);
return NULL;
}
if (nldt > nalloc)
{
ldt_entry = (struct ssd *)
xrealloc (ldt_entry, (nldt + 1) * sizeof (struct ssd));
nalloc = nldt;
}
if (ioctl (pi->ctl_fd, PIOCLDT, ldt_entry) < 0)
{
proc_warn (pi, "proc_get_LDT_entry (PIOCLDT)", __LINE__);
return NULL;
}
for (i = 0; i < nldt; i++)
if (ldt_entry[i].sel == key)
return &ldt_entry[i];
return NULL;
#endif
}
#endif
#if defined (PIOCNTHR) && defined (PIOCTLIST)
int
proc_get_nthreads (procinfo *pi)
{
int nthreads = 0;
if (ioctl (pi->ctl_fd, PIOCNTHR, &nthreads) < 0)
proc_warn (pi, "procfs: PIOCNTHR failed", __LINE__);
return nthreads;
}
#else
#if defined (SYS_lwpcreate) || defined (SYS_lwp_create)
int
proc_get_nthreads (procinfo *pi)
{
if (!pi->status_valid)
if (!proc_get_status (pi))
return 0;
#ifdef NEW_PROC_API
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
#endif
return pi->prstatus.pr_nlwp;
}
#else
int
proc_get_nthreads (procinfo *pi)
{
return 0;
}
#endif
#endif
#if defined (SYS_lwpcreate) || defined (SYS_lwp_create)
int
proc_get_current_thread (procinfo *pi)
{
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
if (!pi->status_valid)
if (!proc_get_status (pi))
return 0;
#ifdef NEW_PROC_API
return pi->prstatus.pr_lwp.pr_lwpid;
#else
return pi->prstatus.pr_who;
#endif
}
#else
#if defined (PIOCNTHR) && defined (PIOCTLIST)
int
proc_get_current_thread (procinfo *pi)
{
#if 0
return pi->prstatus.pr_tid;
#else
return 0;
#endif
}
#else
int
proc_get_current_thread (procinfo *pi)
{
return 0;
}
#endif
#endif
int
proc_delete_dead_threads (procinfo *parent, procinfo *thread, void *ignore)
{
if (thread && parent)
{
thread->status_valid = 0;
if (!proc_get_status (thread))
destroy_one_procinfo (&parent->thread_list, thread);
}
return 0;
}
#if defined (PIOCLSTATUS)
int
proc_update_threads (procinfo *pi)
{
gdb_prstatus_t *prstatus;
struct cleanup *old_chain = NULL;
procinfo *thread;
int nlwp, i;
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
proc_iterate_over_threads (pi, proc_delete_dead_threads, NULL);
if ((nlwp = proc_get_nthreads (pi)) <= 1)
return 1;
prstatus = xmalloc (sizeof (gdb_prstatus_t) * (nlwp + 1));
old_chain = make_cleanup (xfree, prstatus);
if (ioctl (pi->ctl_fd, PIOCLSTATUS, prstatus) < 0)
proc_error (pi, "update_threads (PIOCLSTATUS)", __LINE__);
for (i = 1; i < nlwp + 1; i++)
{
if ((thread = create_procinfo (pi->pid, prstatus[i].pr_who)) == NULL)
proc_error (pi, "update_threads, create_procinfo", __LINE__);
memcpy (&thread->prstatus, &prstatus[i], sizeof (*prstatus));
thread->status_valid = 1;
}
pi->threads_valid = 1;
do_cleanups (old_chain);
return 1;
}
#else
#ifdef NEW_PROC_API
static void
do_closedir_cleanup (void *dir)
{
closedir (dir);
}
int
proc_update_threads (procinfo *pi)
{
char pathname[MAX_PROC_NAME_SIZE + 16];
struct dirent *direntry;
struct cleanup *old_chain = NULL;
procinfo *thread;
DIR *dirp;
int lwpid;
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
proc_iterate_over_threads (pi, proc_delete_dead_threads, NULL);
strcpy (pathname, pi->pathname);
strcat (pathname, "/lwp");
if ((dirp = opendir (pathname)) == NULL)
proc_error (pi, "update_threads, opendir", __LINE__);
old_chain = make_cleanup (do_closedir_cleanup, dirp);
while ((direntry = readdir (dirp)) != NULL)
if (direntry->d_name[0] != '.')
{
lwpid = atoi (&direntry->d_name[0]);
if ((thread = create_procinfo (pi->pid, lwpid)) == NULL)
proc_error (pi, "update_threads, create_procinfo", __LINE__);
}
pi->threads_valid = 1;
do_cleanups (old_chain);
return 1;
}
#else
#ifdef PIOCTLIST
int
proc_update_threads (procinfo *pi)
{
int nthreads, i;
tid_t *threads;
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
proc_iterate_over_threads (pi, proc_delete_dead_threads, NULL);
nthreads = proc_get_nthreads (pi);
if (nthreads < 2)
return 0;
threads = xmalloc (nthreads * sizeof (tid_t));
if (ioctl (pi->ctl_fd, PIOCTLIST, threads) < 0)
proc_error (pi, "procfs: update_threads (PIOCTLIST)", __LINE__);
for (i = 0; i < nthreads; i++)
{
if (!find_procinfo (pi->pid, threads[i]))
if (!create_procinfo (pi->pid, threads[i]))
proc_error (pi, "update_threads, create_procinfo", __LINE__);
}
pi->threads_valid = 1;
return 1;
}
#else
int
proc_update_threads (procinfo *pi)
{
return 0;
}
#endif
#endif
#endif
int
proc_iterate_over_threads (procinfo *pi,
int (*func) (procinfo *, procinfo *, void *),
void *ptr)
{
procinfo *thread, *next;
int retval = 0;
if (pi->tid != 0)
pi = find_procinfo_or_die (pi->pid, 0);
for (thread = pi->thread_list; thread != NULL; thread = next)
{
next = thread->next;
if ((retval = (*func) (pi, thread, ptr)) != 0)
break;
}
return retval;
}
static ptid_t do_attach (ptid_t ptid);
static void do_detach (int signo);
static int register_gdb_signals (procinfo *, gdb_sigset_t *);
static void proc_trace_syscalls_1 (procinfo *pi, int syscallnum,
int entry_or_exit, int mode, int from_tty);
static int insert_dbx_link_breakpoint (procinfo *pi);
static void remove_dbx_link_breakpoint (void);
static int dbx_link_bpt_addr = 0;
static char dbx_link_shadow_contents[BREAKPOINT_MAX];
static int
procfs_debug_inferior (procinfo *pi)
{
fltset_t traced_faults;
gdb_sigset_t traced_signals;
sysset_t *traced_syscall_entries;
sysset_t *traced_syscall_exits;
int status;
#ifdef PROCFS_DONT_TRACE_FAULTS
premptyset (&traced_faults);
#else
prfillset (&traced_faults);
prdelset (&traced_faults, FLTPAGE);
#endif
if (!proc_set_traced_faults (pi, &traced_faults))
return __LINE__;
premptyset (&traced_signals);
if (!register_gdb_signals (pi, &traced_signals))
return __LINE__;
traced_syscall_entries = sysset_t_alloc (pi);
gdb_premptysysset (traced_syscall_entries);
#ifdef SYS_exit
gdb_praddsysset (traced_syscall_entries, SYS_exit);
#endif
#ifdef SYS_lwpexit
gdb_praddsysset (traced_syscall_entries, SYS_lwpexit);
#endif
#ifdef SYS_lwp_exit
gdb_praddsysset (traced_syscall_entries, SYS_lwp_exit);
#endif
#ifdef DYNAMIC_SYSCALLS
{
int callnum = find_syscall (pi, "_exit");
if (callnum >= 0)
gdb_praddsysset (traced_syscall_entries, callnum);
}
#endif
status = proc_set_traced_sysentry (pi, traced_syscall_entries);
xfree (traced_syscall_entries);
if (!status)
return __LINE__;
#ifdef PRFS_STOPEXEC
{
int prfs_flags;
if (ioctl (pi->ctl_fd, PIOCGSPCACT, &prfs_flags) < 0)
return __LINE__;
prfs_flags |= PRFS_STOPEXEC;
if (ioctl (pi->ctl_fd, PIOCSSPCACT, &prfs_flags) < 0)
return __LINE__;
}
#else
traced_syscall_exits = sysset_t_alloc (pi);
gdb_premptysysset (traced_syscall_exits);
#ifdef SYS_exec
gdb_praddsysset (traced_syscall_exits, SYS_exec);
#endif
#ifdef SYS_execve
gdb_praddsysset (traced_syscall_exits, SYS_execve);
#endif
#ifdef SYS_execv
gdb_praddsysset (traced_syscall_exits, SYS_execv);
#endif
#ifdef SYS_lwpcreate
gdb_praddsysset (traced_syscall_exits, SYS_lwpcreate);
gdb_praddsysset (traced_syscall_exits, SYS_lwpexit);
#endif
#ifdef SYS_lwp_create
gdb_praddsysset (traced_syscall_exits, SYS_lwp_create);
gdb_praddsysset (traced_syscall_exits, SYS_lwp_exit);
#endif
#ifdef DYNAMIC_SYSCALLS
{
int callnum = find_syscall (pi, "execve");
if (callnum >= 0)
gdb_praddsysset (traced_syscall_exits, callnum);
callnum = find_syscall (pi, "ra_execve");
if (callnum >= 0)
gdb_praddsysset (traced_syscall_exits, callnum);
}
#endif
status = proc_set_traced_sysexit (pi, traced_syscall_exits);
xfree (traced_syscall_exits);
if (!status)
return __LINE__;
#endif
return 0;
}
static void
procfs_attach (char *args, int from_tty)
{
char *exec_file;
int pid;
if (!args)
error_no_arg (_("process-id to attach"));
pid = atoi (args);
if (pid == getpid ())
error (_("Attaching GDB to itself is not a good idea..."));
if (from_tty)
{
exec_file = get_exec_file (0);
if (exec_file)
printf_filtered (_("Attaching to program `%s', %s\n"),
exec_file, target_pid_to_str (pid_to_ptid (pid)));
else
printf_filtered (_("Attaching to %s\n"),
target_pid_to_str (pid_to_ptid (pid)));
fflush (stdout);
}
inferior_ptid = do_attach (pid_to_ptid (pid));
push_target (&procfs_ops);
}
static void
procfs_detach (char *args, int from_tty)
{
int sig = 0;
if (args)
sig = atoi (args);
if (from_tty)
{
int pid = PIDGET (inferior_ptid);
char *exec_file;
exec_file = get_exec_file (0);
if (exec_file == NULL)
exec_file = "";
printf_filtered (_("Detaching from program: %s, %s\n"), exec_file,
target_pid_to_str (pid_to_ptid (pid)));
gdb_flush (gdb_stdout);
}
do_detach (sig);
inferior_ptid = null_ptid;
unpush_target (&procfs_ops);
}
static ptid_t
do_attach (ptid_t ptid)
{
procinfo *pi;
int fail;
if ((pi = create_procinfo (PIDGET (ptid), 0)) == NULL)
perror (_("procfs: out of memory in 'attach'"));
if (!open_procinfo_files (pi, FD_CTL))
{
fprintf_filtered (gdb_stderr, "procfs:%d -- ", __LINE__);
sprintf (errmsg, "do_attach: couldn't open /proc file for process %d",
PIDGET (ptid));
dead_procinfo (pi, errmsg, NOKILL);
}
if (proc_flags (pi) & (PR_STOPPED | PR_ISTOP))
{
pi->was_stopped = 1;
proc_prettyprint_why (proc_why (pi), proc_what (pi), 1);
}
else
{
pi->was_stopped = 0;
if (!proc_set_run_on_last_close (pi))
dead_procinfo (pi, "do_attach: couldn't set RLC.", NOKILL);
if (!proc_stop_process (pi))
dead_procinfo (pi, "do_attach: couldn't stop the process.", NOKILL);
pi->ignore_next_sigstop = 1;
}
if (!proc_get_traced_faults (pi, &pi->saved_fltset))
dead_procinfo (pi, "do_attach: couldn't save traced faults.", NOKILL);
if (!proc_get_traced_signals (pi, &pi->saved_sigset))
dead_procinfo (pi, "do_attach: couldn't save traced signals.", NOKILL);
if (!proc_get_traced_sysentry (pi, pi->saved_entryset))
dead_procinfo (pi, "do_attach: couldn't save traced syscall entries.",
NOKILL);
if (!proc_get_traced_sysexit (pi, pi->saved_exitset))
dead_procinfo (pi, "do_attach: couldn't save traced syscall exits.",
NOKILL);
if (!proc_get_held_signals (pi, &pi->saved_sighold))
dead_procinfo (pi, "do_attach: couldn't save held signals.", NOKILL);
if ((fail = procfs_debug_inferior (pi)) != 0)
dead_procinfo (pi, "do_attach: failed in procfs_debug_inferior", NOKILL);
attach_flag = 1;
return MERGEPID (pi->pid, proc_get_current_thread (pi));
}
static void
do_detach (int signo)
{
procinfo *pi;
pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0);
if (signo)
if (!proc_set_current_signal (pi, signo))
proc_warn (pi, "do_detach, set_current_signal", __LINE__);
if (!proc_set_traced_signals (pi, &pi->saved_sigset))
proc_warn (pi, "do_detach, set_traced_signal", __LINE__);
if (!proc_set_traced_faults (pi, &pi->saved_fltset))
proc_warn (pi, "do_detach, set_traced_faults", __LINE__);
if (!proc_set_traced_sysentry (pi, pi->saved_entryset))
proc_warn (pi, "do_detach, set_traced_sysentry", __LINE__);
if (!proc_set_traced_sysexit (pi, pi->saved_exitset))
proc_warn (pi, "do_detach, set_traced_sysexit", __LINE__);
if (!proc_set_held_signals (pi, &pi->saved_sighold))
proc_warn (pi, "do_detach, set_held_signals", __LINE__);
if (signo || (proc_flags (pi) & (PR_STOPPED | PR_ISTOP)))
if (signo || !(pi->was_stopped) ||
query (_("Was stopped when attached, make it runnable again? ")))
{
if (!proc_clear_current_fault (pi))
proc_warn (pi, "do_detach, clear_current_fault", __LINE__);
if (signo == 0 && !proc_clear_current_signal (pi))
proc_warn (pi, "do_detach, clear_current_signal", __LINE__);
if (!proc_set_run_on_last_close (pi))
proc_warn (pi, "do_detach, set_rlc", __LINE__);
}
attach_flag = 0;
destroy_procinfo (pi);
}
static void
procfs_fetch_registers (int regnum)
{
gdb_gregset_t *gregs;
procinfo *pi;
int pid = PIDGET (inferior_ptid);
int tid = TIDGET (inferior_ptid);
pi = find_procinfo_or_die (pid, 0);
if (tid != 0 && tid != proc_get_current_thread (pi))
pi = find_procinfo_or_die (pid, tid);
if (pi == NULL)
error (_("procfs: fetch_registers failed to find procinfo for %s"),
target_pid_to_str (inferior_ptid));
gregs = proc_get_gregs (pi);
if (gregs == NULL)
proc_error (pi, "fetch_registers, get_gregs", __LINE__);
supply_gregset (gregs);
if (FP0_REGNUM >= 0)
{
gdb_fpregset_t *fpregs;
if ((regnum >= 0 && regnum < FP0_REGNUM)
|| regnum == PC_REGNUM
|| regnum == SP_REGNUM)
return;
fpregs = proc_get_fpregs (pi);
if (fpregs == NULL)
proc_error (pi, "fetch_registers, get_fpregs", __LINE__);
supply_fpregset (fpregs);
}
}
static void
procfs_prepare_to_store (void)
{
#ifdef CHILD_PREPARE_TO_STORE
CHILD_PREPARE_TO_STORE ();
#endif
}
static void
procfs_store_registers (int regnum)
{
gdb_gregset_t *gregs;
procinfo *pi;
int pid = PIDGET (inferior_ptid);
int tid = TIDGET (inferior_ptid);
pi = find_procinfo_or_die (pid, 0);
if (tid != 0 && tid != proc_get_current_thread (pi))
pi = find_procinfo_or_die (pid, tid);
if (pi == NULL)
error (_("procfs: store_registers: failed to find procinfo for %s"),
target_pid_to_str (inferior_ptid));
gregs = proc_get_gregs (pi);
if (gregs == NULL)
proc_error (pi, "store_registers, get_gregs", __LINE__);
fill_gregset (gregs, regnum);
if (!proc_set_gregs (pi))
proc_error (pi, "store_registers, set_gregs", __LINE__);
if (FP0_REGNUM >= 0)
{
gdb_fpregset_t *fpregs;
if ((regnum >= 0 && regnum < FP0_REGNUM)
|| regnum == PC_REGNUM
|| regnum == SP_REGNUM)
return;
fpregs = proc_get_fpregs (pi);
if (fpregs == NULL)
proc_error (pi, "store_registers, get_fpregs", __LINE__);
fill_fpregset (fpregs, regnum);
if (!proc_set_fpregs (pi))
proc_error (pi, "store_registers, set_fpregs", __LINE__);
}
}
static int
syscall_is_lwp_exit (procinfo *pi, int scall)
{
#ifdef SYS_lwp_exit
if (scall == SYS_lwp_exit)
return 1;
#endif
#ifdef SYS_lwpexit
if (scall == SYS_lwpexit)
return 1;
#endif
return 0;
}
static int
syscall_is_exit (procinfo *pi, int scall)
{
#ifdef SYS_exit
if (scall == SYS_exit)
return 1;
#endif
#ifdef DYNAMIC_SYSCALLS
if (find_syscall (pi, "_exit") == scall)
return 1;
#endif
return 0;
}
static int
syscall_is_exec (procinfo *pi, int scall)
{
#ifdef SYS_exec
if (scall == SYS_exec)
return 1;
#endif
#ifdef SYS_execv
if (scall == SYS_execv)
return 1;
#endif
#ifdef SYS_execve
if (scall == SYS_execve)
return 1;
#endif
#ifdef DYNAMIC_SYSCALLS
if (find_syscall (pi, "_execve"))
return 1;
if (find_syscall (pi, "ra_execve"))
return 1;
#endif
return 0;
}
static int
syscall_is_lwp_create (procinfo *pi, int scall)
{
#ifdef SYS_lwp_create
if (scall == SYS_lwp_create)
return 1;
#endif
#ifdef SYS_lwpcreate
if (scall == SYS_lwpcreate)
return 1;
#endif
return 0;
}
static ptid_t
procfs_wait (ptid_t ptid, struct target_waitstatus *status)
{
procinfo *pi;
int wstat;
int temp_tid;
ptid_t retval, temp_ptid;
int why, what, flags;
int retry = 0;
wait_again:
retry++;
wstat = 0;
retval = pid_to_ptid (-1);
pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0);
if (pi)
{
pi->status_valid = 0;
pi->gregs_valid = 0;
pi->fpregs_valid = 0;
#if 0
flags = proc_flags (pi);
why = proc_why (pi);
if ((flags & PR_STOPPED) && (why == PR_REQUESTED))
pi->status_valid = 0;
#endif
if (!(proc_flags (pi) & (PR_STOPPED | PR_ISTOP)) &&
!proc_wait_for_stop (pi))
{
if (errno == ENOENT)
{
int wait_retval;
wait_retval = wait (&wstat);
if (wait_retval != PIDGET (inferior_ptid))
error (_("procfs: couldn't stop process %d: wait returned %d."),
PIDGET (inferior_ptid), wait_retval);
retval = pid_to_ptid (wait_retval);
}
else if (errno == EINTR)
goto wait_again;
else
{
proc_error (pi, "target_wait (wait_for_stop)", __LINE__);
}
}
else
{
flags = proc_flags (pi);
why = proc_why (pi);
what = proc_what (pi);
if (flags & (PR_STOPPED | PR_ISTOP))
{
#ifdef PR_ASYNC
if (flags & PR_ASYNC)
if (!proc_unset_async (pi))
proc_error (pi, "target_wait, unset_async", __LINE__);
#endif
if (info_verbose)
proc_prettyprint_why (why, what, 1);
retval = MERGEPID (pi->pid, proc_get_current_thread (pi));
switch (why) {
case PR_SIGNALLED:
wstat = (what << 8) | 0177;
break;
case PR_SYSENTRY:
if (syscall_is_lwp_exit (pi, what))
{
printf_filtered (_("[%s exited]\n"),
target_pid_to_str (retval));
delete_thread (retval);
status->kind = TARGET_WAITKIND_SPURIOUS;
return retval;
}
else if (syscall_is_exit (pi, what))
{
pi->status_valid = 0;
wstat = 0;
if (!proc_run_process (pi, 0, 0))
proc_error (pi, "target_wait, run_process", __LINE__);
if (attach_flag)
{
wstat = 0;
retval = inferior_ptid;
}
else
{
int temp = wait (&wstat);
if (temp < 0)
retval = pid_to_ptid (temp);
}
}
else
{
printf_filtered (_("procfs: trapped on entry to "));
proc_prettyprint_syscall (proc_what (pi), 0);
printf_filtered ("\n");
#ifndef PIOCSSPCACT
{
long i, nsysargs, *sysargs;
if ((nsysargs = proc_nsysarg (pi)) > 0 &&
(sysargs = proc_sysargs (pi)) != NULL)
{
printf_filtered (_("%ld syscall arguments:\n"), nsysargs);
for (i = 0; i < nsysargs; i++)
printf_filtered ("#%ld: 0x%08lx\n",
i, sysargs[i]);
}
}
#endif
if (status)
{
status->kind = TARGET_WAITKIND_SPURIOUS;
return inferior_ptid;
}
else
{
target_resume (ptid, 0, TARGET_SIGNAL_0);
goto wait_again;
}
}
break;
case PR_SYSEXIT:
if (syscall_is_exec (pi, what))
{
wstat = (SIGTRAP << 8) | 0177;
}
#ifdef SYS_syssgi
else if (what == SYS_syssgi)
{
if (insert_dbx_link_breakpoint (pi))
proc_trace_syscalls_1 (pi, SYS_syssgi, PR_SYSEXIT,
FLAG_RESET, 0);
target_resume (ptid, 0, TARGET_SIGNAL_0);
goto wait_again;
}
#endif
else if (syscall_is_lwp_create (pi, what))
{
temp_tid = proc_get_current_thread (pi);
if (!find_procinfo (pi->pid, temp_tid))
create_procinfo (pi->pid, temp_tid);
temp_ptid = MERGEPID (pi->pid, temp_tid);
if (!in_thread_list (temp_ptid))
{
printf_filtered (_("[New %s]\n"),
target_pid_to_str (temp_ptid));
add_thread (temp_ptid);
}
status->kind = TARGET_WAITKIND_SPURIOUS;
return inferior_ptid;
}
else if (syscall_is_lwp_exit (pi, what))
{
printf_filtered (_("[%s exited]\n"),
target_pid_to_str (retval));
delete_thread (retval);
status->kind = TARGET_WAITKIND_SPURIOUS;
return retval;
}
else if (0)
{
}
else
{
printf_filtered (_("procfs: trapped on exit from "));
proc_prettyprint_syscall (proc_what (pi), 0);
printf_filtered ("\n");
#ifndef PIOCSSPCACT
{
long i, nsysargs, *sysargs;
if ((nsysargs = proc_nsysarg (pi)) > 0 &&
(sysargs = proc_sysargs (pi)) != NULL)
{
printf_filtered (_("%ld syscall arguments:\n"), nsysargs);
for (i = 0; i < nsysargs; i++)
printf_filtered ("#%ld: 0x%08lx\n",
i, sysargs[i]);
}
}
#endif
status->kind = TARGET_WAITKIND_SPURIOUS;
return inferior_ptid;
}
break;
case PR_REQUESTED:
#if 0
wstat = (SIGSTOP << 8) | 0177;
break;
#else
if (retry < 5)
{
printf_filtered (_("Retry #%d:\n"), retry);
pi->status_valid = 0;
goto wait_again;
}
else
{
temp_tid = proc_get_current_thread (pi);
if (!find_procinfo (pi->pid, temp_tid))
create_procinfo (pi->pid, temp_tid);
temp_ptid = MERGEPID (pi->pid, temp_tid);
if (!in_thread_list (temp_ptid))
{
printf_filtered (_("[New %s]\n"),
target_pid_to_str (temp_ptid));
add_thread (temp_ptid);
}
status->kind = TARGET_WAITKIND_STOPPED;
status->value.sig = 0;
return retval;
}
#endif
case PR_JOBCONTROL:
wstat = (what << 8) | 0177;
break;
case PR_FAULTED:
switch (what) {
#ifdef FLTWATCH
case FLTWATCH:
wstat = (SIGTRAP << 8) | 0177;
break;
#endif
#ifdef FLTKWATCH
case FLTKWATCH:
wstat = (SIGTRAP << 8) | 0177;
break;
#endif
case FLTPRIV:
#if (FLTILL != FLTPRIV)
case FLTILL:
#endif
wstat = (SIGILL << 8) | 0177;
break;
case FLTBPT:
#if (FLTTRACE != FLTBPT)
case FLTTRACE:
#endif
if (dbx_link_bpt_addr != 0
&& dbx_link_bpt_addr == read_pc ())
remove_dbx_link_breakpoint ();
wstat = (SIGTRAP << 8) | 0177;
break;
case FLTSTACK:
case FLTACCESS:
#if (FLTBOUNDS != FLTSTACK)
case FLTBOUNDS:
#endif
wstat = (SIGSEGV << 8) | 0177;
break;
case FLTIOVF:
case FLTIZDIV:
#if (FLTFPE != FLTIOVF)
case FLTFPE:
#endif
wstat = (SIGFPE << 8) | 0177;
break;
case FLTPAGE:
default:
retval = pid_to_ptid (-1);
printf_filtered ("procfs:%d -- ", __LINE__);
printf_filtered (_("child stopped for unknown reason:\n"));
proc_prettyprint_why (why, what, 1);
error (_("... giving up..."));
break;
}
break;
default:
printf_filtered ("procfs:%d -- ", __LINE__);
printf_filtered (_("child stopped for unknown reason:\n"));
proc_prettyprint_why (why, what, 1);
error (_("... giving up..."));
break;
}
if (PIDGET (retval) > 0 &&
!ptid_equal (retval, inferior_ptid) &&
!in_thread_list (retval))
{
printf_filtered (_("[New %s]\n"), target_pid_to_str (retval));
add_thread (retval);
if (find_procinfo (PIDGET (retval), TIDGET (retval)) == NULL)
create_procinfo (PIDGET (retval), TIDGET (retval));
if (TIDGET (inferior_ptid) != 0)
{
if (!in_thread_list (inferior_ptid))
add_thread (inferior_ptid);
if (find_procinfo (PIDGET (inferior_ptid),
TIDGET (inferior_ptid)) == NULL)
create_procinfo (PIDGET (inferior_ptid),
TIDGET (inferior_ptid));
}
}
}
else
{
printf_filtered ("procfs:%d -- process not stopped.\n",
__LINE__);
proc_prettyprint_flags (flags, 1);
error (_("procfs: ...giving up..."));
}
}
if (status)
store_waitstatus (status, wstat);
}
return retval;
}
static LONGEST
procfs_xfer_partial (struct target_ops *ops, enum target_object object,
const char *annex, void *readbuf,
const void *writebuf, ULONGEST offset, LONGEST len)
{
switch (object)
{
case TARGET_OBJECT_MEMORY:
if (readbuf)
return (*ops->deprecated_xfer_memory) (offset, readbuf, len,
0, NULL, ops);
if (writebuf)
return (*ops->deprecated_xfer_memory) (offset, writebuf, len,
1, NULL, ops);
return -1;
#ifdef NEW_PROC_API
case TARGET_OBJECT_AUXV:
return procfs_xfer_auxv (ops, object, annex, readbuf, writebuf,
offset, len);
#endif
default:
if (ops->beneath != NULL)
return ops->beneath->to_xfer_partial (ops->beneath, object, annex,
readbuf, writebuf, offset, len);
return -1;
}
}
static int
procfs_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int dowrite,
struct mem_attrib *attrib, struct target_ops *target)
{
procinfo *pi;
int nbytes = 0;
pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0);
if (pi->as_fd == 0 &&
open_procinfo_files (pi, FD_AS) == 0)
{
proc_warn (pi, "xfer_memory, open_proc_files", __LINE__);
return 0;
}
if (lseek (pi->as_fd, (off_t) memaddr, SEEK_SET) == (off_t) memaddr)
{
if (dowrite)
{
#ifdef NEW_PROC_API
PROCFS_NOTE ("write memory: ");
#else
PROCFS_NOTE ("write memory: \n");
#endif
nbytes = write (pi->as_fd, myaddr, len);
}
else
{
PROCFS_NOTE ("read memory: \n");
nbytes = read (pi->as_fd, myaddr, len);
}
if (nbytes < 0)
{
nbytes = 0;
}
}
return nbytes;
}
static int
invalidate_cache (procinfo *parent, procinfo *pi, void *ptr)
{
#if 0
if (pi->gregs_dirty)
if (parent == NULL ||
proc_get_current_thread (parent) != pi->tid)
if (!proc_set_gregs (pi))
proc_warn (pi, "target_resume, set_gregs",
__LINE__);
if (FP0_REGNUM >= 0)
if (pi->fpregs_dirty)
if (parent == NULL ||
proc_get_current_thread (parent) != pi->tid)
if (!proc_set_fpregs (pi))
proc_warn (pi, "target_resume, set_fpregs",
__LINE__);
#endif
if (parent != NULL)
{
close_procinfo_files (pi);
}
pi->gregs_valid = 0;
pi->fpregs_valid = 0;
#if 0
pi->gregs_dirty = 0;
pi->fpregs_dirty = 0;
#endif
pi->status_valid = 0;
pi->threads_valid = 0;
return 0;
}
#if 0
static int
make_signal_thread_runnable (procinfo *process, procinfo *pi, void *ptr)
{
#ifdef PR_ASLWP
if (proc_flags (pi) & PR_ASLWP)
{
if (!proc_run_process (pi, 0, -1))
proc_error (pi, "make_signal_thread_runnable", __LINE__);
return 1;
}
#endif
return 0;
}
#endif
static void
procfs_resume (ptid_t ptid, int step, enum target_signal signo)
{
procinfo *pi, *thread;
int native_signo;
pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0);
errno = 0;
if (signo == 0 ||
(signo == TARGET_SIGNAL_STOP && pi->ignore_next_sigstop))
native_signo = 0;
else
native_signo = target_signal_to_host (signo);
pi->ignore_next_sigstop = 0;
proc_iterate_over_threads (pi, invalidate_cache, NULL);
invalidate_cache (NULL, pi, NULL);
if (PIDGET (ptid) != -1)
{
thread = find_procinfo (PIDGET (ptid), TIDGET (ptid));
if (thread != NULL)
{
if (thread->tid != 0)
{
#ifdef PR_ASYNC
if (!proc_set_async (pi))
proc_error (pi, "target_resume, set_async", __LINE__);
#endif
#if 0
proc_iterate_over_threads (pi,
make_signal_thread_runnable,
NULL);
#endif
pi = thread;
}
}
}
if (!proc_run_process (pi, step, native_signo))
{
if (errno == EBUSY)
warning (_("resume: target already running. Pretend to resume, and hope for the best!"));
else
proc_error (pi, "target_resume", __LINE__);
}
}
static int
register_gdb_signals (procinfo *pi, gdb_sigset_t *signals)
{
int signo;
for (signo = 0; signo < NSIG; signo ++)
if (signal_stop_state (target_signal_from_host (signo)) == 0 &&
signal_print_state (target_signal_from_host (signo)) == 0 &&
signal_pass_state (target_signal_from_host (signo)) == 1)
prdelset (signals, signo);
else
praddset (signals, signo);
return proc_set_traced_signals (pi, signals);
}
static void
procfs_notice_signals (ptid_t ptid)
{
gdb_sigset_t signals;
procinfo *pi = find_procinfo_or_die (PIDGET (ptid), 0);
if (proc_get_traced_signals (pi, &signals) &&
register_gdb_signals (pi, &signals))
return;
else
proc_error (pi, "notice_signals", __LINE__);
}
static void
procfs_files_info (struct target_ops *ignore)
{
printf_filtered (_("\tUsing the running image of %s %s via /proc.\n"),
attach_flag? "attached": "child",
target_pid_to_str (inferior_ptid));
}
static void
procfs_open (char *args, int from_tty)
{
error (_("Use the \"run\" command to start a Unix child process."));
}
int procfs_suppress_run = 0;
static int
procfs_can_run (void)
{
return !procfs_suppress_run;
}
static void
procfs_stop (void)
{
kill (-inferior_process_group, SIGINT);
}
static void
unconditionally_kill_inferior (procinfo *pi)
{
int parent_pid;
parent_pid = proc_parent_pid (pi);
#ifdef PROCFS_NEED_CLEAR_CURSIG_FOR_KILL
if (ioctl (pi->ctl_fd, PIOCSSIG, NULL) < 0)
{
printf_filtered ("unconditionally_kill: SSIG failed!\n");
}
#endif
#ifdef PROCFS_NEED_PIOCSSIG_FOR_KILL
{
gdb_siginfo_t newsiginfo;
memset ((char *) &newsiginfo, 0, sizeof (newsiginfo));
newsiginfo.si_signo = SIGKILL;
newsiginfo.si_code = 0;
newsiginfo.si_errno = 0;
newsiginfo.si_pid = getpid ();
newsiginfo.si_uid = getuid ();
ioctl (pi->ctl_fd, PIOCSSIG, &newsiginfo);
}
#else
if (!proc_kill (pi, SIGKILL))
proc_error (pi, "unconditionally_kill, proc_kill", __LINE__);
#endif
destroy_procinfo (pi);
if (parent_pid == getpid ())
{
#if 0
int status, ret;
ret = waitpid (pi->pid, &status, 0);
#else
wait (NULL);
#endif
}
}
static void
procfs_kill_inferior (void)
{
if (!ptid_equal (inferior_ptid, null_ptid))
{
procinfo *pi = find_procinfo (PIDGET (inferior_ptid), 0);
if (pi)
unconditionally_kill_inferior (pi);
target_mourn_inferior ();
}
}
static void
procfs_mourn_inferior (void)
{
procinfo *pi;
if (!ptid_equal (inferior_ptid, null_ptid))
{
pi = find_procinfo (PIDGET (inferior_ptid), 0);
if (pi)
destroy_procinfo (pi);
}
unpush_target (&procfs_ops);
generic_mourn_inferior ();
}
static void
procfs_init_inferior (int pid)
{
procinfo *pi;
gdb_sigset_t signals;
int fail;
push_target (&procfs_ops);
if ((pi = create_procinfo (pid, 0)) == NULL)
perror ("procfs: out of memory in 'init_inferior'");
if (!open_procinfo_files (pi, FD_CTL))
proc_error (pi, "init_inferior, open_proc_files", __LINE__);
if (!(proc_flags (pi) & PR_STOPPED) &&
!(proc_wait_for_stop (pi)))
dead_procinfo (pi, "init_inferior: wait_for_stop failed", KILL);
if (!proc_get_traced_signals (pi, &pi->saved_sigset))
proc_error (pi, "init_inferior, get_traced_signals", __LINE__);
if (!proc_get_held_signals (pi, &pi->saved_sighold))
proc_error (pi, "init_inferior, get_held_signals", __LINE__);
if (!proc_get_traced_faults (pi, &pi->saved_fltset))
proc_error (pi, "init_inferior, get_traced_faults", __LINE__);
if (!proc_get_traced_sysentry (pi, pi->saved_entryset))
proc_error (pi, "init_inferior, get_traced_sysentry", __LINE__);
if (!proc_get_traced_sysexit (pi, pi->saved_exitset))
proc_error (pi, "init_inferior, get_traced_sysexit", __LINE__);
prfillset (&signals);
if (!register_gdb_signals (pi, &signals))
proc_error (pi, "init_inferior, register_signals", __LINE__);
if ((fail = procfs_debug_inferior (pi)) != 0)
proc_error (pi, "init_inferior (procfs_debug_inferior)", fail);
if (!proc_set_run_on_last_close (pi))
proc_error (pi, "init_inferior, set_RLC", __LINE__);
inferior_ptid = MERGEPID (pi->pid, proc_get_current_thread (pi));
startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
#ifdef SYS_syssgi
proc_trace_syscalls_1 (pi, SYS_syssgi, PR_SYSEXIT, FLAG_SET, 0);
dbx_link_bpt_addr = 0;
#endif
}
static void
procfs_set_exec_trap (void)
{
procinfo *pi;
sysset_t *exitset;
if ((pi = create_procinfo (getpid (), 0)) == NULL)
perror_with_name (_("procfs: create_procinfo failed in child."));
if (open_procinfo_files (pi, FD_CTL) == 0)
{
proc_warn (pi, "set_exec_trap, open_proc_files", __LINE__);
gdb_flush (gdb_stderr);
_exit (127);
}
#ifdef PRFS_STOPEXEC
{
int prfs_flags;
if (ioctl (pi->ctl_fd, PIOCGSPCACT, &prfs_flags) < 0)
{
proc_warn (pi, "set_exec_trap (PIOCGSPCACT)", __LINE__);
gdb_flush (gdb_stderr);
_exit (127);
}
prfs_flags |= PRFS_STOPEXEC;
if (ioctl (pi->ctl_fd, PIOCSSPCACT, &prfs_flags) < 0)
{
proc_warn (pi, "set_exec_trap (PIOCSSPCACT)", __LINE__);
gdb_flush (gdb_stderr);
_exit (127);
}
}
#else
exitset = sysset_t_alloc (pi);
gdb_premptysysset (exitset);
#ifdef SYS_exec
gdb_praddsysset (exitset, SYS_exec);
#endif
#ifdef SYS_execve
gdb_praddsysset (exitset, SYS_execve);
#endif
#ifdef SYS_execv
gdb_praddsysset (exitset, SYS_execv);
#endif
#ifdef DYNAMIC_SYSCALLS
{
int callnum = find_syscall (pi, "execve");
if (callnum >= 0)
gdb_praddsysset (exitset, callnum);
callnum = find_syscall (pi, "ra_execve");
if (callnum >= 0)
gdb_praddsysset (exitset, callnum);
}
#endif
if (!proc_set_traced_sysexit (pi, exitset))
{
proc_warn (pi, "set_exec_trap, set_traced_sysexit", __LINE__);
gdb_flush (gdb_stderr);
_exit (127);
}
#endif
if (!proc_unset_inherit_on_fork (pi))
proc_warn (pi, "set_exec_trap, unset_inherit", __LINE__);
if (!proc_unset_run_on_last_close (pi))
proc_warn (pi, "set_exec_trap, unset_RLC", __LINE__);
}
static void
procfs_create_inferior (char *exec_file, char *allargs, char **env,
int from_tty)
{
char *shell_file = getenv ("SHELL");
char *tryname;
if (shell_file != NULL && strchr (shell_file, '/') == NULL)
{
char *p;
char *p1;
char *path = getenv ("PATH");
int len;
struct stat statbuf;
if (path == NULL)
path = "/bin:/usr/bin";
tryname = alloca (strlen (path) + strlen (shell_file) + 2);
for (p = path; p != NULL; p = p1 ? p1 + 1: NULL)
{
p1 = strchr (p, ':');
if (p1 != NULL)
len = p1 - p;
else
len = strlen (p);
strncpy (tryname, p, len);
tryname[len] = '\0';
strcat (tryname, "/");
strcat (tryname, shell_file);
if (access (tryname, X_OK) < 0)
continue;
if (stat (tryname, &statbuf) < 0)
continue;
if (!S_ISREG (statbuf.st_mode))
continue;
break;
}
if (p == NULL)
error (_("procfs:%d -- Can't find shell %s in PATH"),
__LINE__, shell_file);
shell_file = tryname;
}
fork_inferior (exec_file, allargs, env, procfs_set_exec_trap,
procfs_init_inferior, NULL, shell_file);
#ifdef SYS_syssgi
proc_trace_syscalls_1 (find_procinfo_or_die (PIDGET (inferior_ptid), 0),
SYS_syssgi, PR_SYSEXIT, FLAG_RESET, 0);
#endif
proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0);
}
static int
procfs_notice_thread (procinfo *pi, procinfo *thread, void *ptr)
{
ptid_t gdb_threadid = MERGEPID (pi->pid, thread->tid);
if (!in_thread_list (gdb_threadid))
add_thread (gdb_threadid);
return 0;
}
void
procfs_find_new_threads (void)
{
procinfo *pi;
pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0);
proc_update_threads (pi);
proc_iterate_over_threads (pi, procfs_notice_thread, NULL);
}
static int
procfs_thread_alive (ptid_t ptid)
{
int proc, thread;
procinfo *pi;
proc = PIDGET (ptid);
thread = TIDGET (ptid);
if ((pi = find_procinfo (proc, thread)) == NULL)
return 0;
if (!proc_get_status (pi))
{
destroy_procinfo (pi);
return 0;
}
return 1;
}
char *
procfs_pid_to_str (ptid_t ptid)
{
static char buf[80];
if (TIDGET (ptid) == 0)
sprintf (buf, "process %d", PIDGET (ptid));
else
sprintf (buf, "LWP %ld", TIDGET (ptid));
return buf;
}
int
procfs_set_watchpoint (ptid_t ptid, CORE_ADDR addr, int len, int rwflag,
int after)
{
#ifndef UNIXWARE
#ifndef AIX5
int pflags = 0;
procinfo *pi;
pi = find_procinfo_or_die (PIDGET (ptid) == -1 ?
PIDGET (inferior_ptid) : PIDGET (ptid), 0);
if (len > 0)
{
switch (rwflag) {
case hw_write:
pflags = WRITE_WATCHFLAG;
break;
case hw_read:
pflags = READ_WATCHFLAG;
break;
case hw_access:
pflags = READ_WATCHFLAG | WRITE_WATCHFLAG;
break;
case hw_execute:
pflags = EXEC_WATCHFLAG;
break;
default:
return -1;
}
if (after)
pflags |= AFTER_WATCHFLAG;
}
if (!proc_set_watchpoint (pi, addr, len, pflags))
{
if (errno == E2BIG)
return -1;
if (errno == ESRCH && len == 0)
return 0;
proc_error (pi, "set_watchpoint", __LINE__);
}
#endif
#endif
return 0;
}
static int
procfs_can_use_hw_breakpoint (int type, int cnt, int othertype)
{
#ifndef TARGET_HAS_HARDWARE_WATCHPOINTS
return 0;
#else
if (sizeof (void *) != TYPE_LENGTH (builtin_type_void_data_ptr))
return 0;
return 1;
#endif
}
int
procfs_stopped_by_watchpoint (ptid_t ptid)
{
procinfo *pi;
pi = find_procinfo_or_die (PIDGET (ptid) == -1 ?
PIDGET (inferior_ptid) : PIDGET (ptid), 0);
if (!pi)
return 0;
if (proc_flags (pi) & (PR_STOPPED | PR_ISTOP))
{
if (proc_why (pi) == PR_FAULTED)
{
#ifdef FLTWATCH
if (proc_what (pi) == FLTWATCH)
return 1;
#endif
#ifdef FLTKWATCH
if (proc_what (pi) == FLTKWATCH)
return 1;
#endif
}
}
return 0;
}
#ifdef TM_I386SOL2_H
struct ssd *
procfs_find_LDT_entry (ptid_t ptid)
{
gdb_gregset_t *gregs;
int key;
procinfo *pi;
if ((pi = find_procinfo (PIDGET (ptid), TIDGET (ptid))) == NULL)
{
warning (_("procfs_find_LDT_entry: could not find procinfo for %d:%d."),
PIDGET (ptid), TIDGET (ptid));
return NULL;
}
if ((gregs = proc_get_gregs (pi)) == NULL)
{
warning (_("procfs_find_LDT_entry: could not read gregs for %d:%d."),
PIDGET (ptid), TIDGET (ptid));
return NULL;
}
key = (*gregs)[GS] & 0xffff;
return proc_get_LDT_entry (pi, key);
}
#endif
static int
iterate_over_mappings (procinfo *pi, int (*child_func) (), void *data,
int (*func) (struct prmap *map,
int (*child_func) (),
void *data))
{
char pathname[MAX_PROC_NAME_SIZE];
struct prmap *prmaps;
struct prmap *prmap;
int funcstat;
int map_fd;
int nmap;
#ifdef NEW_PROC_API
struct stat sbuf;
#endif
#ifdef NEW_PROC_API
sprintf (pathname, "/proc/%d/map", pi->pid);
if ((map_fd = open (pathname, O_RDONLY)) < 0)
proc_error (pi, "iterate_over_mappings (open)", __LINE__);
make_cleanup_close (map_fd);
if (fstat (map_fd, &sbuf) != 0)
proc_error (pi, "iterate_over_mappings (fstat)", __LINE__);
nmap = sbuf.st_size / sizeof (prmap_t);
prmaps = (struct prmap *) alloca ((nmap + 1) * sizeof (*prmaps));
if (read (map_fd, (char *) prmaps, nmap * sizeof (*prmaps))
!= (nmap * sizeof (*prmaps)))
proc_error (pi, "iterate_over_mappings (read)", __LINE__);
#else
if (ioctl (pi->ctl_fd, PIOCNMAP, &nmap) != 0)
proc_error (pi, "iterate_over_mappings (PIOCNMAP)", __LINE__);
prmaps = (struct prmap *) alloca ((nmap + 1) * sizeof (*prmaps));
if (ioctl (pi->ctl_fd, PIOCMAP, prmaps) != 0)
proc_error (pi, "iterate_over_mappings (PIOCMAP)", __LINE__);
#endif
for (prmap = prmaps; nmap > 0; prmap++, nmap--)
if ((funcstat = (*func) (prmap, child_func, data)) != 0)
return funcstat;
return 0;
}
int solib_mappings_callback (struct prmap *map,
int (*func) (int, CORE_ADDR),
void *data)
{
procinfo *pi = data;
int fd;
#ifdef NEW_PROC_API
char name[MAX_PROC_NAME_SIZE + sizeof (map->pr_mapname)];
if (map->pr_vaddr == 0 && map->pr_size == 0)
return -1;
if (map->pr_mapname[0] == 0)
{
fd = -1;
}
else
{
sprintf (name, "/proc/%d/object/%s", pi->pid, map->pr_mapname);
fd = open_with_retry (name, O_RDONLY);
}
#else
fd = ioctl (pi->ctl_fd, PIOCOPENM, &map->pr_vaddr);
#endif
return (*func) (fd, (CORE_ADDR) map->pr_vaddr);
}
int
proc_iterate_over_mappings (int (*func) (int, CORE_ADDR))
{
procinfo *pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0);
return iterate_over_mappings (pi, func, pi, solib_mappings_callback);
}
static int
find_memory_regions_callback (struct prmap *map,
int (*func) (CORE_ADDR,
unsigned long,
int, int, int,
void *),
void *data)
{
return (*func) ((CORE_ADDR) map->pr_vaddr,
map->pr_size,
(map->pr_mflags & MA_READ) != 0,
(map->pr_mflags & MA_WRITE) != 0,
(map->pr_mflags & MA_EXEC) != 0,
data);
}
static int
proc_find_memory_regions (int (*func) (CORE_ADDR,
unsigned long,
int, int, int,
void *),
void *data)
{
procinfo *pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0);
return iterate_over_mappings (pi, func, data,
find_memory_regions_callback);
}
static void
remove_dbx_link_breakpoint (void)
{
if (dbx_link_bpt_addr == 0)
return;
if (memory_remove_breakpoint (dbx_link_bpt_addr,
dbx_link_shadow_contents) != 0)
warning (_("Unable to remove __dbx_link breakpoint."));
dbx_link_bpt_addr = 0;
}
static CORE_ADDR
dbx_link_addr (bfd *abfd)
{
long storage_needed;
asymbol **symbol_table;
long number_of_symbols;
long i;
storage_needed = bfd_get_symtab_upper_bound (abfd);
if (storage_needed <= 0)
return 0;
symbol_table = (asymbol **) xmalloc (storage_needed);
make_cleanup (xfree, symbol_table);
number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);
for (i = 0; i < number_of_symbols; i++)
{
asymbol *sym = symbol_table[i];
if ((sym->flags & BSF_GLOBAL)
&& sym->name != NULL && strcmp (sym->name, "__dbx_link") == 0)
return (sym->value + sym->section->vma);
}
return 0;
}
static int
insert_dbx_link_bpt_in_file (int fd, CORE_ADDR ignored)
{
bfd *abfd;
long storage_needed;
CORE_ADDR sym_addr;
abfd = bfd_fdopenr ("unamed", 0, fd);
if (abfd == NULL)
{
warning (_("Failed to create a bfd: %s."), bfd_errmsg (bfd_get_error ()));
return 0;
}
if (!bfd_check_format (abfd, bfd_object))
{
bfd_close (abfd);
return 0;
}
sym_addr = dbx_link_addr (abfd);
if (sym_addr != 0)
{
dbx_link_bpt_addr = sym_addr;
if (target_insert_breakpoint (sym_addr, dbx_link_shadow_contents) != 0)
{
warning (_("Failed to insert dbx_link breakpoint."));
bfd_close (abfd);
return 0;
}
bfd_close (abfd);
return 1;
}
bfd_close (abfd);
return 0;
}
static int
insert_dbx_link_bpt_in_region (struct prmap *map,
int (*child_func) (),
void *data)
{
procinfo *pi = (procinfo *) data;
if (map->pr_mflags & MA_EXEC)
return solib_mappings_callback (map, insert_dbx_link_bpt_in_file, pi);
return 0;
}
static int
insert_dbx_link_breakpoint (procinfo *pi)
{
return iterate_over_mappings (pi, NULL, pi, insert_dbx_link_bpt_in_region);
}
static char *
mappingflags (long flags)
{
static char asciiflags[8];
strcpy (asciiflags, "-------");
#if defined (MA_PHYS)
if (flags & MA_PHYS)
asciiflags[0] = 'd';
#endif
if (flags & MA_STACK)
asciiflags[1] = 's';
if (flags & MA_BREAK)
asciiflags[2] = 'b';
if (flags & MA_SHARED)
asciiflags[3] = 's';
if (flags & MA_READ)
asciiflags[4] = 'r';
if (flags & MA_WRITE)
asciiflags[5] = 'w';
if (flags & MA_EXEC)
asciiflags[6] = 'x';
return (asciiflags);
}
static int
info_mappings_callback (struct prmap *map, int (*ignore) (), void *unused)
{
char *data_fmt_string;
if (TARGET_ADDR_BIT == 32)
data_fmt_string = "\t%#10lx %#10lx %#10x %#10x %7s\n";
else
data_fmt_string = " %#18lx %#18lx %#10x %#10x %7s\n";
printf_filtered (data_fmt_string,
(unsigned long) map->pr_vaddr,
(unsigned long) map->pr_vaddr + map->pr_size - 1,
map->pr_size,
#ifdef PCAGENT
(unsigned int) map->pr_offset,
#else
map->pr_off,
#endif
mappingflags (map->pr_mflags));
return 0;
}
static void
info_proc_mappings (procinfo *pi, int summary)
{
char *header_fmt_string;
if (TARGET_PTR_BIT == 32)
header_fmt_string = "\t%10s %10s %10s %10s %7s\n";
else
header_fmt_string = " %18s %18s %10s %10s %7s\n";
if (summary)
return;
printf_filtered (_("Mapped address spaces:\n\n"));
printf_filtered (header_fmt_string,
"Start Addr",
" End Addr",
" Size",
" Offset",
"Flags");
iterate_over_mappings (pi, NULL, NULL, info_mappings_callback);
printf_filtered ("\n");
}
static void
info_proc_cmd (char *args, int from_tty)
{
struct cleanup *old_chain;
procinfo *process = NULL;
procinfo *thread = NULL;
char **argv = NULL;
char *tmp = NULL;
int pid = 0;
int tid = 0;
int mappings = 0;
old_chain = make_cleanup (null_cleanup, 0);
if (args)
{
if ((argv = buildargv (args)) == NULL)
nomem (0);
else
make_cleanup_freeargv (argv);
}
while (argv != NULL && *argv != NULL)
{
if (isdigit (argv[0][0]))
{
pid = strtoul (argv[0], &tmp, 10);
if (*tmp == '/')
tid = strtoul (++tmp, NULL, 10);
}
else if (argv[0][0] == '/')
{
tid = strtoul (argv[0] + 1, NULL, 10);
}
else if (strncmp (argv[0], "mappings", strlen (argv[0])) == 0)
{
mappings = 1;
}
else
{
}
argv++;
}
if (pid == 0)
pid = PIDGET (inferior_ptid);
if (pid == 0)
error (_("No current process: you must name one."));
else
{
process = find_procinfo (pid, 0);
if (process == NULL)
{
process = create_procinfo (pid, 0);
make_cleanup (do_destroy_procinfo_cleanup, process);
if (!open_procinfo_files (process, FD_CTL))
proc_error (process, "info proc, open_procinfo_files", __LINE__);
}
}
if (tid != 0)
thread = create_procinfo (pid, tid);
if (process)
{
printf_filtered (_("process %d flags:\n"), process->pid);
proc_prettyprint_flags (proc_flags (process), 1);
if (proc_flags (process) & (PR_STOPPED | PR_ISTOP))
proc_prettyprint_why (proc_why (process), proc_what (process), 1);
if (proc_get_nthreads (process) > 1)
printf_filtered ("Process has %d threads.\n",
proc_get_nthreads (process));
}
if (thread)
{
printf_filtered (_("thread %d flags:\n"), thread->tid);
proc_prettyprint_flags (proc_flags (thread), 1);
if (proc_flags (thread) & (PR_STOPPED | PR_ISTOP))
proc_prettyprint_why (proc_why (thread), proc_what (thread), 1);
}
if (mappings)
{
info_proc_mappings (process, 0);
}
do_cleanups (old_chain);
}
static void
proc_trace_syscalls_1 (procinfo *pi, int syscallnum, int entry_or_exit,
int mode, int from_tty)
{
sysset_t *sysset;
if (entry_or_exit == PR_SYSENTRY)
sysset = proc_get_traced_sysentry (pi, NULL);
else
sysset = proc_get_traced_sysexit (pi, NULL);
if (sysset == NULL)
proc_error (pi, "proc-trace, get_traced_sysset", __LINE__);
if (mode == FLAG_SET)
gdb_praddsysset (sysset, syscallnum);
else
gdb_prdelsysset (sysset, syscallnum);
if (entry_or_exit == PR_SYSENTRY)
{
if (!proc_set_traced_sysentry (pi, sysset))
proc_error (pi, "proc-trace, set_traced_sysentry", __LINE__);
}
else
{
if (!proc_set_traced_sysexit (pi, sysset))
proc_error (pi, "proc-trace, set_traced_sysexit", __LINE__);
}
}
static void
proc_trace_syscalls (char *args, int from_tty, int entry_or_exit, int mode)
{
procinfo *pi;
if (PIDGET (inferior_ptid) <= 0)
error (_("you must be debugging a process to use this command."));
if (args == NULL || args[0] == 0)
error_no_arg (_("system call to trace"));
pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0);
if (isdigit (args[0]))
{
const int syscallnum = atoi (args);
proc_trace_syscalls_1 (pi, syscallnum, entry_or_exit, mode, from_tty);
}
}
static void
proc_trace_sysentry_cmd (char *args, int from_tty)
{
proc_trace_syscalls (args, from_tty, PR_SYSENTRY, FLAG_SET);
}
static void
proc_trace_sysexit_cmd (char *args, int from_tty)
{
proc_trace_syscalls (args, from_tty, PR_SYSEXIT, FLAG_SET);
}
static void
proc_untrace_sysentry_cmd (char *args, int from_tty)
{
proc_trace_syscalls (args, from_tty, PR_SYSENTRY, FLAG_RESET);
}
static void
proc_untrace_sysexit_cmd (char *args, int from_tty)
{
proc_trace_syscalls (args, from_tty, PR_SYSEXIT, FLAG_RESET);
}
void
_initialize_procfs (void)
{
init_procfs_ops ();
add_target (&procfs_ops);
add_info ("proc", info_proc_cmd, _("\
Show /proc process information about any running process.\n\
Specify process id, or use the program being debugged by default.\n\
Specify keyword 'mappings' for detailed info on memory mappings."));
add_com ("proc-trace-entry", no_class, proc_trace_sysentry_cmd,
_("Give a trace of entries into the syscall."));
add_com ("proc-trace-exit", no_class, proc_trace_sysexit_cmd,
_("Give a trace of exits from the syscall."));
add_com ("proc-untrace-entry", no_class, proc_untrace_sysentry_cmd,
_("Cancel a trace of entries into the syscall."));
add_com ("proc-untrace-exit", no_class, proc_untrace_sysexit_cmd,
_("Cancel a trace of exits from the syscall."));
}
ptid_t
procfs_first_available (void)
{
return pid_to_ptid (procinfo_list ? procinfo_list->pid : -1);
}
#if defined (UNIXWARE) || defined (PIOCOPENLWP) || defined (PCAGENT)
static char *
procfs_do_thread_registers (bfd *obfd, ptid_t ptid,
char *note_data, int *note_size)
{
gdb_gregset_t gregs;
gdb_fpregset_t fpregs;
unsigned long merged_pid;
merged_pid = TIDGET (ptid) << 16 | PIDGET (ptid);
fill_gregset (&gregs, -1);
#if defined (UNIXWARE)
note_data = (char *) elfcore_write_lwpstatus (obfd,
note_data,
note_size,
merged_pid,
stop_signal,
&gregs);
#else
note_data = (char *) elfcore_write_prstatus (obfd,
note_data,
note_size,
merged_pid,
stop_signal,
&gregs);
#endif
fill_fpregset (&fpregs, -1);
note_data = (char *) elfcore_write_prfpreg (obfd,
note_data,
note_size,
&fpregs,
sizeof (fpregs));
return note_data;
}
struct procfs_corefile_thread_data {
bfd *obfd;
char *note_data;
int *note_size;
};
static int
procfs_corefile_thread_callback (procinfo *pi, procinfo *thread, void *data)
{
struct procfs_corefile_thread_data *args = data;
if (pi != NULL && thread->tid != 0)
{
ptid_t saved_ptid = inferior_ptid;
inferior_ptid = MERGEPID (pi->pid, thread->tid);
args->note_data = procfs_do_thread_registers (args->obfd, inferior_ptid,
args->note_data,
args->note_size);
inferior_ptid = saved_ptid;
}
return 0;
}
static char *
procfs_make_note_section (bfd *obfd, int *note_size)
{
struct cleanup *old_chain;
gdb_gregset_t gregs;
gdb_fpregset_t fpregs;
char fname[16] = {'\0'};
char psargs[80] = {'\0'};
procinfo *pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0);
char *note_data = NULL;
char *inf_args;
struct procfs_corefile_thread_data thread_args;
char *auxv;
int auxv_len;
if (get_exec_file (0))
{
strncpy (fname, strrchr (get_exec_file (0), '/') + 1, sizeof (fname));
strncpy (psargs, get_exec_file (0),
sizeof (psargs));
inf_args = get_inferior_args ();
if (inf_args && *inf_args &&
strlen (inf_args) < ((int) sizeof (psargs) - (int) strlen (psargs)))
{
strncat (psargs, " ",
sizeof (psargs) - strlen (psargs));
strncat (psargs, inf_args,
sizeof (psargs) - strlen (psargs));
}
}
note_data = (char *) elfcore_write_prpsinfo (obfd,
note_data,
note_size,
fname,
psargs);
#ifdef UNIXWARE
fill_gregset (&gregs, -1);
note_data = elfcore_write_pstatus (obfd, note_data, note_size,
PIDGET (inferior_ptid),
stop_signal, &gregs);
#endif
thread_args.obfd = obfd;
thread_args.note_data = note_data;
thread_args.note_size = note_size;
proc_iterate_over_threads (pi, procfs_corefile_thread_callback, &thread_args);
if (thread_args.note_data == note_data)
{
note_data = procfs_do_thread_registers (obfd, inferior_ptid,
note_data, note_size);
}
else
{
note_data = thread_args.note_data;
}
auxv_len = target_auxv_read (¤t_target, &auxv);
if (auxv_len > 0)
{
note_data = elfcore_write_note (obfd, note_data, note_size,
"CORE", NT_AUXV, auxv, auxv_len);
xfree (auxv);
}
make_cleanup (xfree, note_data);
return note_data;
}
#else
static char *
procfs_make_note_section (bfd *obfd, int *note_size)
{
error (_("gcore not implemented for this host."));
return NULL;
}
#endif