summaryrefslogtreecommitdiffstats
path: root/c/src/librdbg/src/servrpc.c
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/librdbg/src/servrpc.c')
-rw-r--r--c/src/librdbg/src/servrpc.c720
1 files changed, 720 insertions, 0 deletions
diff --git a/c/src/librdbg/src/servrpc.c b/c/src/librdbg/src/servrpc.c
new file mode 100644
index 0000000000..f62a2ecbb8
--- /dev/null
+++ b/c/src/librdbg/src/servrpc.c
@@ -0,0 +1,720 @@
+/*
+ **********************************************************************
+ *
+ * Component: RDBG
+ * Module: servrpc.c
+ *
+ * Synopsis: support routines for RPC dispatch for remote debug server.
+ * Main server dispatch routines from RPC to support remote debug.
+ *
+ **********************************************************************
+ */
+
+#include <string.h>
+#include <sys/errno.h>
+#include <rdbg/rdbg.h>
+#include <rdbg/remdeb.h>
+#include <rdbg/servrpc.h>
+
+/************************************************************************/
+
+/* -----------------------------------------------------------------------
+ open_connex_2_svc - setup a new connection from a client.
+
+ Notes:
+ - this function creates a new connection to a client. It allocates
+ an entry in the connection structure and fills in the information
+ sent and implied by the message.
+ - a client connection entry is needed for all further messages to work
+ properly.
+ ----------------------------------------------------------------------- */
+
+open_out* RPCGENSRVNAME(open_connex_2_svc) (open_in *in, struct svc_req *rqstp)
+{
+ static open_out out; /* output response. This could be heap local */
+ int idx;
+ static int one_time = 0; /* we do one-time setup on back port */
+
+ /* need to support in->debug_type, in->flags, and in->destination!!! */
+
+ if (!one_time)
+ { /* only setup one backport socket */
+ /* now setup signals and the like for handling process changes */
+ setErrno(0);
+ TspInit(rqstp->rq_xprt->xp_sock); /* init transport system */
+ if (getErrno())
+ { /* failed in setup */
+ out.port = (u_long)-1;
+ out.fp = getErrno(); /* error causing to fail */
+ return(&out); /* fail */
+ }
+ one_time = True; /* disable doing this again */
+ }
+
+ DPRINTF(("open_connex_2_svc: Opening connection from '%s'\n",
+ in->user_name));
+
+ /* now setup a validation of all other connections */
+ for (idx = 0; idx < conn_list_cnt; idx++)
+ if (conn_list[idx].in_use)
+ { /* setup retry timer */
+ DPRINTF(("open_connex_2_svc: Still have connection %d with port %d\n",
+ idx, HL_W(*((UINT16*)&conn_list[idx].back_port.c[2]))));
+ }
+
+ idx = ConnCreate(rqstp, in); /* setup the connection */
+ out.port = idx; /* connection number */
+ if (idx == -1)
+ out.fp = getErrno(); /* error causing to fail */
+ else
+ out.fp = TARGET_PROC_TYPE;
+
+ out.server_vers = SERVER_VERS;
+ return(&out);
+}
+
+/* -----------------------------------------------------------------------
+ send_signal_2_svc - send a kill/signal to the specified process.
+
+ Notes:
+ - this function sends a signal to the process specified. This process
+ does not have to be under debug nor attached by this server. The kill
+ may be refused on other grounds though.
+ - kill(pid, 0) can be used to validate the process still exists if
+ needed.
+ ----------------------------------------------------------------------- */
+
+signal_out *RPCGENSRVNAME(send_signal_2_svc) (signal_in *in, struct svc_req *rqstp)
+{
+ static signal_out out; /* return code from kill */
+
+ /* we do not care if connected */
+ setErrno(0);
+ out.kill_return = 0;
+ out.errNo = 0;
+ TotalReboot = 1;
+ return(&out);
+}
+
+/* -----------------------------------------------------------------------
+ close_connex_2_svc - close a connection from a client.
+ ----------------------------------------------------------------------- */
+
+void *RPCGENSRVNAME(close_connex_2_svc) (close_in *in, struct svc_req *rqstp)
+{
+ int conn_idx = TspConnGetIndex(rqstp);
+
+ if (conn_idx != -1) /* found it, clear out */
+ ConnDelete(conn_idx, rqstp, in->control);
+
+ return (void*) ""; /* need to return something */
+}
+
+/* -----------------------------------------------------------------------
+ ptrace_2_svc - control process under debug.
+ ----------------------------------------------------------------------- */
+
+#define REG_COUNT \
+ (sizeof (xdr_regs) / sizeof (int))
+
+ptrace_out *RPCGENSRVNAME(ptrace_2_svc) (ptrace_in *in, struct svc_req *rqstp)
+{
+ int conn_idx = rqstp ? TspConnGetIndex(rqstp) : -1;
+ static ptrace_out out; /* outut response (error or data) */
+ void *addr, *addr2; /* used for actual ptrace call */
+ unsigned int data;
+ int req, pid, ret, pid_idx, idx;
+ static union
+ { /* local buffer for returned data */
+ Objects_Id t_list[UTHREAD_MAX]; /* thread_list return */
+ char t_name[THREADNAMEMAX]; /* thread name return */
+ } local_buff; /* for return handling of strings and the like */
+ PID_LIST *plst = NULL; /* current pid_list entry */
+
+ DPRINTF (("ptrace_2_svc: entered (%s (%d), %d, XXXX, %d, XXXX)\n",
+ PtraceName (in->addr.req), in->addr.req, in->pid,
+ in->data));
+
+ out.addr.ptrace_addr_data_out_u.addr = 0;
+
+ /* validate the connection */
+ if (conn_idx == -1 && rqstp != NULL)
+ { /* no connection, error */
+ DPRINTF(("ptrace_2_svc: msg from unknown debugger!\n"));
+ out.result = -1;
+ out.errNo = ECHILD; /* closest error */
+ out.addr.req = 0; /* to avoid copies that should not occur */
+ return(&out);
+ }
+ /* Consider that the last back-message is acknowledged */
+ if (conn_idx >= 0 && conn_list[conn_idx].retry) {
+ TspMessageReceive(conn_idx, in->pid);
+ }
+
+ req = in->addr.req;
+ out.addr.req = req; /* needed for RPC */
+ pid = in->pid;
+ addr = addr2 = NULL;
+ data = in->data;
+ setErrno(0); /* assume works */
+ out.result = 0; /* assume worked ok */
+ out.errNo = 0;
+
+ /* lookup process to make sure we have under control */
+ pid_idx = FindPidEntry (in->pid);
+ if (pid_idx >= 0) /* found it */
+ {
+ plst = &pid_list[pid_idx];
+ if (conn_idx < 0)
+ conn_idx = plst->primary_conn;
+ }
+
+ /* now we handle the special case of ATTACH to a pid we already control */
+ if (req == RPT_ATTACH)
+ { /* look it up first */
+ if (plst)
+ { /* we have controlled , so return ok+show conn */
+ ret = 2; /* normally secondary connection */
+ if (! PIDMAP_TEST (conn_idx, pid_idx))
+ { /* mark as an owner if not already */
+ plst->owners++;
+ PIDMAP_SET (conn_idx, pid_idx); /* mask in */
+ }
+ else if (plst->primary_conn != NO_PRIMARY)
+ { /* regrab makes primary */
+ /* Only if not primary already */
+ if (plst->primary_conn != conn_idx) {
+ TspSendWaitChange(plst->primary_conn, BMSG_NOT_PRIM,
+ conn_idx, plst->pid, 0, False); /* tell old owner */
+ }
+ plst->primary_conn = NO_PRIMARY;
+ }
+
+ if (plst->primary_conn == NO_PRIMARY)
+ { /* none now, so take over */
+ plst->primary_conn = conn_idx; /* new primary */
+ ret = 1; /* primary */
+ }
+ out.result = ret; /* primary or secondary owner */
+ return(&out);
+ }
+ /* else attach process using target code */
+ setErrno(ESRCH); /* assume the worst */
+ if (!TgtAttach(conn_idx, pid))
+ { /* failed */
+ out.errNo = getErrno();
+ out.result = 0;
+ }
+ return(&out);
+ }
+ else if (req == RPT_DETACH)
+ { /* see which kind of detach */
+ if (data == PTRDET_UNOWN)
+ { /* only want to disconnect from */
+ TgtDetachCon(conn_idx, pid_idx, True); /* remove from control */
+ return(&out); /* done */
+ }
+ }
+ else if (plst && (req == RPT_GETNAME || req == RPT_GETBREAK))
+ {
+ /* do nothing */
+ }
+
+ else if (plst && req == RPT_CLRBREAK) {
+ /* To be able to remove breakpoints from a "running" system */
+ DPRINTF (("ptrace_2_svc: allowing RPT_CLRBREAK %d\n", data));
+ /* do nothing */
+ }
+
+ else if (plst && plst->running)
+ { /* error, process is running and not detach */
+ out.result = -1;
+ out.errNo = ETXTBSY; /* closest error */
+ DPRINTF (("ptrace_2_svc: failed, still running.\n"));
+ return(&out);
+ }
+ if (plst == NULL) {
+ out.result = -1;
+ out.errNo = ESRCH;
+ DPRINTF (("ptrace_2_svc: No such process.\n"));
+ return (&out);
+ }
+
+ /* now make sure secondary owner is not trying to modify */
+ if (!(in->flags & PTRFLG_NON_OWNER)) /* if not overriden */
+ if (conn_idx != plst->primary_conn
+ && ( (req >= RPT_POKETEXT && req <= RPT_SINGLESTEP)
+ || (req >= RPT_SETREGS && req <= RPT_SETFPAREGS && (req & 1))
+ || (req >= RPT_SYSCALL && req <= RPT_DUMPCORE)
+ || (req >= RPT_SETTARGETTHREAD && req <= RPT_THREADRESUME)
+ || (req >= RPT_SETTHREADNAME && req <= RPT_SETTHREADREGS)
+ || (req >= RPT_STEPRANGE && req <= RPT_CLRBREAK)
+ || (req == RPT_STOP)
+ || (req >= RPT_PSETREGS && req <= RPT_PSETTHREADREGS)))
+ { /* not owner */
+ out.result = -1;
+ out.errNo = EPERM; /* cannot alter as not primary */
+ DPRINTF (("ptrace_2_svc: refused, not owner, flags %d conn_idx %d primary_conn %d\n", in->flags, conn_idx,
+ plst->primary_conn));
+ return(&out);
+ }
+
+ addr = (void *)in->addr.ptrace_addr_data_in_u.address; /* default */
+ /* now setup normal ptrace request by unpacking. May execute here. */
+ switch (req)
+ { /* handle unpacking or setup for real call */
+ /* first the ones where addr points to input data */
+ case RPT_SETREGS:
+ case RPT_SETTHREADREGS:
+ addr = (void *)&in->addr.ptrace_addr_data_in_u.regs; /* reg list */
+ break;
+
+ case RPT_PSETREGS:
+ case RPT_PSETTHREADREGS:
+ if (in->addr.ptrace_addr_data_in_u.pregs.pregs_len != REG_COUNT) {
+ DPRINTF(("ptrace_2_svc: pid %d got %d expected %d\n", pid,
+ in->addr.ptrace_addr_data_in_u.pregs.pregs_len, REG_COUNT));
+ setErrno(EINVAL);
+ break;
+ }
+ req = req == RPT_PSETREGS ? RPT_SETREGS : RPT_SETTHREADREGS;
+ addr = (void *) in->addr.ptrace_addr_data_in_u.pregs.pregs_val;
+ break;
+
+ case RPT_SETTHREADNAME:
+ addr = (void *)in->addr.ptrace_addr_data_in_u.name;
+ break;
+ case RPT_WRITETEXT:
+ case RPT_WRITEDATA:
+ if ((int) data < 0) {
+ setErrno(EINVAL);
+ break;
+ }
+ addr = (void *)in->addr.ptrace_addr_data_in_u.mem.addr; /* targ addr */
+ addr2 = (void *)in->addr.ptrace_addr_data_in_u.mem.data; /* buff */
+
+ /* Forbid writing over breakpoints */
+ if (BreakOverwrite (plst, addr, data)) {
+ setErrno(EBUSY);
+ }
+ break;
+
+ case RPT_POKETEXT:
+ case RPT_POKEDATA:
+ /* Forbid writing over breakpoints */
+ if (BreakOverwrite (plst, addr, sizeof (int))) {
+ setErrno(EBUSY);
+ }
+ break;
+
+ /* now ones where we handle locally */
+ case RPT_GETTARGETTHREAD:
+ out.result = plst->thread;
+ req = 0; /* force exit */
+ break;
+
+ case RPT_PGETREGS: /* return from our buffer */
+ out.addr.ptrace_addr_data_out_u.pregs.pregs_len = REG_COUNT;
+ out.addr.ptrace_addr_data_out_u.pregs.pregs_val = (u_int*) &plst->regs;
+ req = 0; /* force exit */
+ break;
+
+ case RPT_GETREGS:
+ /* return directly from our buffer */
+ /* this buffer is refreshed when changing target thread */
+ out.addr.ptrace_addr_data_out_u.regs = plst->regs;
+ req = 0; /* force exit */
+ break;
+
+ case RPT_SETBREAK:
+ idx = BreakSet (plst, conn_idx, &in->addr.ptrace_addr_data_in_u.breakp);
+ if (idx < 0) break;
+ req = 0; /* force exit */
+ out.result = idx; /* return break index (>0) */
+ break;
+
+ case RPT_CLRBREAK:
+ if (conn_list[conn_idx].flags & DEBUGGER_IS_GDB) {
+ data = BreakGetIndex (plst, addr);
+ }
+ out.result = BreakClear (plst, conn_idx, data);
+ /* if errored, errno will still be set */
+ req = 0;
+ break;
+
+ case RPT_GETBREAK:
+ /* data=handle, addr=in_buffer, returns next break. Data=0, returns cnt */
+ out.result = BreakGet (plst, data, &out.addr.
+ ptrace_addr_data_out_u.breakp);
+ req = 0; /* handle locally */
+ break;
+
+ case RPT_GETNAME: /* get the name of the process */
+ if (!plst->name)
+ out.addr.ptrace_addr_data_out_u.mem.dataNb = 0;
+ else
+ {
+ int maxLen = sizeof out.addr.ptrace_addr_data_out_u.mem.data - 1;
+ data = strlen(plst->name);
+ if (data > maxLen)
+ data = maxLen;
+ out.addr.ptrace_addr_data_out_u.mem.dataNb = data+1;
+ memcpy(out.addr.ptrace_addr_data_out_u.mem.data, plst->name, data+1);
+ out.addr.ptrace_addr_data_out_u.mem.data [maxLen] = '\0';
+ }
+ req = 0;
+ break;
+
+ case RPT_CONTTO:
+ if (BreakSetAt (plst, conn_idx, (u_long) addr, BRKT_STEPEMUL) < 0)
+ {
+ DPRINTF(("ptrace_2_svc: BreakSet failed at %x", addr));
+ break;
+ }
+ req = RPT_CONT;
+ /* data can contain a signal number, addr2 is unused */
+ goto case_RPT_CONT;
+
+ case RPT_STEPRANGE:
+ /* convert to step */
+ if (!data)
+ data = 1; /* should we give an error?? */
+ BreakStepRange (plst, addr, data);
+ if (getErrno()) break;
+
+ req = RPT_SINGLESTEP; /* do by stepping */
+ addr = (void*) 1; /* start from current PC */
+ data = -2; /* want non-atomic stepping */
+ /* fall through to other exec cases */
+
+ case RPT_CONT:
+ case_RPT_CONT:
+ case RPT_SINGLESTEP:
+
+ if (BreakStepOff (plst, &addr2))
+ { /* need clear then step off break */
+ /* clear break, step, then do exec */
+ if (addr == (void*) 1)
+ addr = (void*) plst->regs.REG_PC;/* need for patch */
+
+ /* data is always 0, so atomic single-step */
+ } else if (req == RPT_SINGLESTEP) {
+ data = -2; /* want non-atomic stepping */
+ }
+ break;
+
+ /* now ones where addr points to an output area */
+ case RPT_PGETTHREADREGS:
+ addr = (void*) out.addr.ptrace_addr_data_out_u.mem.data;
+ if (sizeof out.addr.ptrace_addr_data_out_u.mem.data <
+ REG_COUNT * sizeof(int)) {
+ setErrno(EINVAL);
+ break;
+ }
+ if (data == plst->thread) {
+ out.addr.ptrace_addr_data_out_u.pregs.pregs_len = REG_COUNT;
+ out.addr.ptrace_addr_data_out_u.pregs.pregs_val = (u_int*) &plst->regs;
+ req = 0; /* force exit */
+ break;
+ }
+ req = RPT_GETTHREADREGS;
+ break;
+
+ case RPT_GETTHREADREGS:
+ addr = (void*) &out.addr.ptrace_addr_data_out_u.regs;
+ break;
+ case RPT_GETTHREADNAME:
+ out.addr.ptrace_addr_data_out_u.name = local_buff.t_name;
+ addr = (void*) out.addr.ptrace_addr_data_out_u.name;
+ break;
+ case RPT_THREADLIST:
+ out.addr.ptrace_addr_data_out_u.threads.threads =(ptThreadList) local_buff.t_list;
+ addr = (void*) out.addr.ptrace_addr_data_out_u.threads.threads;
+ break;
+ case RPT_READTEXT:
+ case RPT_READDATA:
+ if ((int) data < 0) {
+ setErrno(EINVAL);
+ break;
+ }
+ addr = (void *)in->addr.ptrace_addr_data_in_u.address;
+ addr2 = (void *)out.addr.ptrace_addr_data_out_u.mem.data;
+ out.addr.ptrace_addr_data_out_u.mem.dataNb = data;
+ break;
+ case RPT_DETACH:
+ /* Do not allow detaching if breakpoints still there */
+ if (BreakGet (plst, 0, NULL))
+ { /* some bkpts still set */
+ setErrno(EINVAL); /* cannot detach safely */
+ break;
+ }
+ /* fall through */
+ case RPT_KILL:
+ /* in the event they are trying to detach or kill a terminated process,
+ we just delete the entry. */
+ if (PROC_TERMINATED (plst))
+ {
+ TgtDelete(plst, -1, BMSG_KILLED); /* just blow off */
+ req = 0; /* now exit */
+ }
+ break;
+ }
+
+ if (getErrno())
+ { /* failed in code above */
+ out.result = -1;
+ out.errNo = getErrno();
+ DPRINTF(("ptrace_2_svc: result %d errNo %d\n", out.result, out.errNo));
+ return(&out);
+ }
+ else if (!req)
+ { /* bail out now */
+ DPRINTF(("ptrace_2_svc: result %d errNo %d\n", out.result, out.errNo));
+ return(&out);
+ }
+
+ /* OK, make the call */
+ out.result = TgtPtrace(req, pid, addr, data, addr2);
+ out.errNo = getErrno();
+
+ /* if no error, cleanup afterwards */
+ if (getErrno())
+ {
+ /* Remove step-emul breakpoints if any */
+ if (req == RPT_SINGLESTEP || req == RPT_CONT) {
+ BreakClear (plst, -1, -1);
+ }
+ DPRINTF(("ptrace_2_svc: result %d errNo %d\n", out.result, out.errNo));
+ return(&out); /* return error */
+ }
+
+ switch (in->addr.req)
+ { /* handle some special calls that affect state */
+ case RPT_CONT:
+ case RPT_STEPRANGE:
+ /* change to running */
+ if (in->addr.req == RPT_STEPRANGE)
+ plst->last_start = LAST_RANGE; /* so range steps */
+ else if (addr2)
+ plst->last_start = LAST_STEPOFF; /* now continue after wait */
+ else
+ plst->last_start = LAST_CONT;
+ plst->running = 1; /* mark as running */
+ if (!rqstp) /* Called internally to restart bkpt, no msg to anybody */
+ break;
+ TgtNotifyAll(pid_idx, BMSG_WAIT, 0, 0, (in->flags & PTRFLG_NON_OWNER)
+ ? -1 : conn_idx, True);
+ break;
+ case RPT_SINGLESTEP:
+ /* mark as step */
+ plst->last_start = LAST_STEP; /* so we know how started */
+ plst->running = 1; /* mark as running (wait should catch fast) */
+ break;
+ case RPT_DETACH: /* mark as disconnected */
+ case RPT_KILL: /* mark as killed */
+ if (in->flags & PTRFLG_FREE) /* notify and delete entry */
+ TgtDelete(plst, -1, (in->addr.req==RPT_KILL) ? BMSG_KILLED : BMSG_DETACH);
+ else
+ { /* notify and mark */
+ plst->last_start = (in->addr.req==RPT_KILL) ?
+ LAST_KILLED : LAST_DETACHED;
+ plst->state = -1;
+ plst->running = False;
+ TgtNotifyAll(pid_idx, (in->addr.req==RPT_KILL) ?
+ BMSG_KILLED : BMSG_DETACH, 0, 0, -1, True);
+ }
+ break;
+ case RPT_SETTHREADREGS:
+ case RPT_PSETTHREADREGS:
+ if (data != plst->thread)
+ break;
+ DPRINTF(("ptrace_2_svc: pid %d target thread regs changed!\n", pid));
+
+ case RPT_SETREGS:
+ case RPT_PSETREGS:
+ /* change our buffer as well */
+ if (plst->regs.REG_PC != ((xdr_regs*)addr)->REG_PC)
+ BreakPcChanged (plst);
+ plst->regs = *(xdr_regs*) addr; /* copy in */
+ break;
+
+ /* case RPT_PGETREGS has been handled locally above */
+ case RPT_PGETTHREADREGS:
+ /* We need to update pointer so that XDR works on return */
+ out.addr.ptrace_addr_data_out_u.pregs.pregs_len = REG_COUNT;
+ out.addr.ptrace_addr_data_out_u.pregs.pregs_val =
+ (void*) out.addr.ptrace_addr_data_out_u.mem.data;
+ break;
+
+ case RPT_PEEKTEXT:
+ case RPT_PEEKDATA:
+ case RPT_READDATA:
+ case RPT_READTEXT:
+ if (req < RPT_READDATA)
+ { /* peek */
+ /* addr is start */
+ data = sizeof(int);
+ addr2 = &out.result; /* data buffer */
+ /* Like read: addr is start, data is length, addr2 is buffer */
+ }
+ BreakHide (plst, addr, data, addr2);
+ break;
+
+ case RPT_SETTARGETTHREAD:
+ DPRINTF(("ptrace_2_svc: pid %d new target thread %d\n", pid, data));
+ TgtPtrace (RPT_GETREGS, pid, (char*) &plst->regs, 0, NULL);
+ plst->thread = data;
+ if (plst->break_list) { /* Forget we had to step off breakpoint */
+ BASE_BREAK* base = (BASE_BREAK*) plst->break_list;
+ DPRINTF(("ptrace_2_svc: clr_step %d last_break %d\n", base->clr_step,
+ base->last_break));
+ base->clr_step = 0; /* Not stopped on break */
+ base->last_break = 0;
+ }
+ break;
+
+ case RPT_THREADLIST:
+ out.addr.ptrace_addr_data_out_u.threads.nbThread = out.result;
+ break;
+
+ default:
+ break;
+ } /* end switch */
+ DPRINTF(("ptrace_2_svc 2: result %d errNo %d\n", out.result, out.errNo));
+ return(&out);
+}
+
+/* -----------------------------------------------------------------------
+ wait_info_2_svc - non-blocking wait request to check status.
+ ----------------------------------------------------------------------- */
+
+wait_out *RPCGENSRVNAME(wait_info_2_svc) (in, rqstp)
+ wait_in *in;
+ struct svc_req *rqstp; /* server info */
+{
+ int conn_idx = TspConnGetIndex(rqstp);
+ static wait_out out; /* output of pid and status */
+ int idx;
+ PID_LIST *plst;
+
+ memset(&out, 0, sizeof(out)); /* zero for safety */
+ out.reason = STOP_ERROR; /* assume the worst */
+
+ if (conn_idx == -1)
+ { /* no connection, error */
+ DPRINTF(("wait_info_2_svc: msg from unknown debugger!\n"));
+ out.wait_return = -1;
+ out.errNo = ECHILD; /* closest error */
+ return(&out);
+ }
+ else
+ { /* see if confirming message received */
+ if (conn_list[conn_idx].retry)
+ TspMessageReceive(conn_idx, in->pid);
+ }
+
+ if (!in->pid)
+ { /* warm test verify only */
+ /* this call (pid==0) is made to confirm that that connection is still
+ active. */
+ /* we let it fall through as an error since any use other than connection
+ reset would be an error (there is no pid0). */
+ }
+ else
+ { /* normal request */
+ idx = FindPidEntry (in->pid);
+ if (idx >= 0)
+ { /* found process they requested on */
+ plst = &pid_list[idx];
+ out.wait_return = plst->running ? 0 : in->pid;
+ /* return: 0 is running, pid is stopped/term */
+ out.errNo = 0;
+ out.status = plst->state; /* last stopped reason if stopped */
+ out.thread = plst->thread;/* current thread (or -1 if none) from stop */
+ if (!out.wait_return)
+ out.reason = STOP_NONE; /* running, no action */
+ else if (STS_SIGNALLED (out.status))
+ { /* stopped on signal */
+ out.handle = STS_GETSIG (out.status); /* signal number */
+ if (out.handle == SIGTRAP)
+ if (plst->is_step)
+ { /* single step with hitting a break */
+ out.reason = STOP_STEP;
+ out.handle = 0; /* no information */
+ }
+ else
+ { /* stopped on break */
+ out.reason = STOP_BREAK;
+ if (plst->break_list)
+ out.handle = ((BASE_BREAK*)plst->break_list)->last_break;
+ else
+ out.handle = 0; /* no break */
+ }
+ else
+ out.reason = STOP_SIGNAL;
+ out.PC = plst->regs.REG_PC; /* copy standard regs */
+ out.SP = plst->regs.REG_SP;
+ out.FP = plst->regs.REG_FP;
+ }
+ else
+ { /* terminated, so lower use count */
+ if (plst->last_start == LAST_KILLED)
+ out.reason = STOP_KILLED;
+ else if (plst->last_start == LAST_DETACHED)
+ out.reason = STOP_DETACHED;
+ else if (plst->last_start == LAST_START)
+ { /* failed in exec */
+ out.reason = STOP_SPAWN_FAILED;
+ out.handle = STS_GETCODE (out.status); /* errno reason */
+ }
+ else if (STS_TERMONSIG (out.status))
+ { /* terminated on signal */
+ out.reason = STOP_TERM_SIG;
+ /* mask off the core-dumped bit 7 */
+ out.handle = (int)(unsigned)(u_char) STS_TERMGETSIG (out.status);
+ }
+ else
+ { /* exit(2)ed */
+ out.reason = STOP_TERM_EXIT;
+ out.handle = STS_GETCODE (out.status); /* code */
+ }
+ }
+ DPRINTF(("wait_info_2_svc: pid %d return %d status %x errNo %d"
+ " reason %d handle %d pc %x sp %x fp %x thread %d\n",
+ in->pid, out.wait_return, out.status, out.errNo, out.reason,
+ out.handle, out.PC, out.SP, out.FP, out.thread));
+ return(&out);
+ }
+ }
+ /* if not found in list, we return error: no such process */
+ out.wait_return = -1;
+ out.errNo = ESRCH; /* no process */
+ out.status = 0;
+ return(&out);
+}
+
+/* -----------------------------------------------------------------------
+ get_signal_names_2_svc - return names for signals
+ ----------------------------------------------------------------------- */
+
+static one_signal SignalNames[] = {
+ {SIGILL, "SIGILL/EVT_ILL"},
+ {SIGTRAP, "SIGTRAP/EVT_BKPT"},
+ {SIGFPE, "SIGFPE/EVT_FPE"},
+ {SIGKILL, "SIGKILL/EVT_AKILL"},
+ {SIGSEGV, "SIGSEGV/EVT_SEGV"},
+ {17, "SIGSTOP"},
+ {23, "SIGSTOP"}
+};
+
+get_signal_names_out* RPCGENSRVNAME(get_signal_names_2_svc) (in, rqstp)
+ void* in;
+ struct svc_req *rqstp; /* server info */
+{
+ static get_signal_names_out out;
+
+ out.signals.all_signals_len = sizeof SignalNames / sizeof SignalNames[0];
+ out.signals.all_signals_val = SignalNames;
+
+ return(&out);
+}