📄 servrpc.c
字号:
/* ********************************************************************** * * 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. * * $Id: servrpc.c,v 1.3 2002/02/01 17:00:01 joel Exp $ * ********************************************************************** */#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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -