From 4721cf1ecb949b37c98b6fce79163541711de2e5 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Thu, 3 Dec 1998 23:54:14 +0000 Subject: Patch from Emmanuel Raguet to add remote debug server and RPC support to RTEMS. Thanks. :) Email follows: Hello, For Xmas, here is the Remote Debugger on RTEMS ! Here are 2 patches for the Remote Debugger on RTEMS for pc386 from Linux host : - one for RTEMS it self, - one for GDB-4.17. 1/ RTEMS patch -------------- This patch adds 2 libraries : - a simplified SUN RPC library - the Remote Debugger library The configuration command is the following : ../rtems4/configure --target=i386-rtemself --enable-rtemsbsp=pc386 --enable-rdbg The SUN RPC library is built only if networking is set. The RDBG library is built if networking and enable-rdbg are set. The function used to initialize the debugger is : rtems_rdbg_initialize (); A special function has been created to force a task to be in a "debug" state : enterRdbg(). The use of this function is not mandatory. 2/ GDB-4.17 patch ----------------- This patch create a new RTEMS target for GDB-4.17. The configuration command is the following : ./configure --enable-shared --target=i386RTEMS To connect to a target, use : target rtems [your_site_address] Then, attach the target using : attach 1 And... Debug ;) You can obtain the original GDB-4.17 on ftp://ftp.debian.org/debian/dists/stable/main/source/devel/gdb_4.17.orig.tar.gz This has been tested from a Debian 2.0.1 linux host. --- c/src/librdbg/src/servrpc.c | 720 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 720 insertions(+) create mode 100644 c/src/librdbg/src/servrpc.c (limited to 'c/src/librdbg/src/servrpc.c') 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 +#include +#include +#include +#include + +/************************************************************************/ + +/* ----------------------------------------------------------------------- + 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); +} -- cgit v1.2.3