1 | /* |
---|
2 | ********************************************************************** |
---|
3 | * |
---|
4 | * Component: RDBG |
---|
5 | * Module: servrpc.c |
---|
6 | * |
---|
7 | * Synopsis: support routines for RPC dispatch for remote debug server. |
---|
8 | * Main server dispatch routines from RPC to support remote debug. |
---|
9 | * |
---|
10 | ********************************************************************** |
---|
11 | */ |
---|
12 | |
---|
13 | #include <string.h> |
---|
14 | #include <sys/errno.h> |
---|
15 | #include <rdbg/rdbg.h> |
---|
16 | #include <rdbg/remdeb.h> |
---|
17 | #include <rdbg/servrpc.h> |
---|
18 | |
---|
19 | /************************************************************************/ |
---|
20 | |
---|
21 | /* ----------------------------------------------------------------------- |
---|
22 | open_connex_2_svc - setup a new connection from a client. |
---|
23 | |
---|
24 | Notes: |
---|
25 | - this function creates a new connection to a client. It allocates |
---|
26 | an entry in the connection structure and fills in the information |
---|
27 | sent and implied by the message. |
---|
28 | - a client connection entry is needed for all further messages to work |
---|
29 | properly. |
---|
30 | ----------------------------------------------------------------------- */ |
---|
31 | |
---|
32 | open_out* RPCGENSRVNAME(open_connex_2_svc) (open_in *in, struct svc_req *rqstp) |
---|
33 | { |
---|
34 | static open_out out; /* output response. This could be heap local */ |
---|
35 | int idx; |
---|
36 | static int one_time = 0; /* we do one-time setup on back port */ |
---|
37 | |
---|
38 | /* need to support in->debug_type, in->flags, and in->destination!!! */ |
---|
39 | |
---|
40 | if (!one_time) |
---|
41 | { /* only setup one backport socket */ |
---|
42 | /* now setup signals and the like for handling process changes */ |
---|
43 | setErrno(0); |
---|
44 | TspInit(rqstp->rq_xprt->xp_sock); /* init transport system */ |
---|
45 | if (getErrno()) |
---|
46 | { /* failed in setup */ |
---|
47 | out.port = (u_long)-1; |
---|
48 | out.fp = getErrno(); /* error causing to fail */ |
---|
49 | return(&out); /* fail */ |
---|
50 | } |
---|
51 | one_time = True; /* disable doing this again */ |
---|
52 | } |
---|
53 | |
---|
54 | DPRINTF(("open_connex_2_svc: Opening connection from '%s'\n", |
---|
55 | in->user_name)); |
---|
56 | |
---|
57 | /* now setup a validation of all other connections */ |
---|
58 | for (idx = 0; idx < conn_list_cnt; idx++) |
---|
59 | if (conn_list[idx].in_use) |
---|
60 | { /* setup retry timer */ |
---|
61 | DPRINTF(("open_connex_2_svc: Still have connection %d with port %d\n", |
---|
62 | idx, HL_W(*((UINT16*)&conn_list[idx].back_port.c[2])))); |
---|
63 | } |
---|
64 | |
---|
65 | idx = ConnCreate(rqstp, in); /* setup the connection */ |
---|
66 | out.port = idx; /* connection number */ |
---|
67 | if (idx == -1) |
---|
68 | out.fp = getErrno(); /* error causing to fail */ |
---|
69 | else |
---|
70 | out.fp = TARGET_PROC_TYPE; |
---|
71 | |
---|
72 | out.server_vers = SERVER_VERS; |
---|
73 | return(&out); |
---|
74 | } |
---|
75 | |
---|
76 | /* ----------------------------------------------------------------------- |
---|
77 | send_signal_2_svc - send a kill/signal to the specified process. |
---|
78 | |
---|
79 | Notes: |
---|
80 | - this function sends a signal to the process specified. This process |
---|
81 | does not have to be under debug nor attached by this server. The kill |
---|
82 | may be refused on other grounds though. |
---|
83 | - kill(pid, 0) can be used to validate the process still exists if |
---|
84 | needed. |
---|
85 | ----------------------------------------------------------------------- */ |
---|
86 | |
---|
87 | signal_out *RPCGENSRVNAME(send_signal_2_svc) (signal_in *in, struct svc_req *rqstp) |
---|
88 | { |
---|
89 | static signal_out out; /* return code from kill */ |
---|
90 | |
---|
91 | /* we do not care if connected */ |
---|
92 | setErrno(0); |
---|
93 | out.kill_return = 0; |
---|
94 | out.errNo = 0; |
---|
95 | TotalReboot = 1; |
---|
96 | return(&out); |
---|
97 | } |
---|
98 | |
---|
99 | /* ----------------------------------------------------------------------- |
---|
100 | close_connex_2_svc - close a connection from a client. |
---|
101 | ----------------------------------------------------------------------- */ |
---|
102 | |
---|
103 | void *RPCGENSRVNAME(close_connex_2_svc) (close_in *in, struct svc_req *rqstp) |
---|
104 | { |
---|
105 | int conn_idx = TspConnGetIndex(rqstp); |
---|
106 | |
---|
107 | if (conn_idx != -1) /* found it, clear out */ |
---|
108 | ConnDelete(conn_idx, rqstp, in->control); |
---|
109 | |
---|
110 | return (void*) ""; /* need to return something */ |
---|
111 | } |
---|
112 | |
---|
113 | /* ----------------------------------------------------------------------- |
---|
114 | ptrace_2_svc - control process under debug. |
---|
115 | ----------------------------------------------------------------------- */ |
---|
116 | |
---|
117 | #define REG_COUNT \ |
---|
118 | (sizeof (xdr_regs) / sizeof (int)) |
---|
119 | |
---|
120 | ptrace_out *RPCGENSRVNAME(ptrace_2_svc) (ptrace_in *in, struct svc_req *rqstp) |
---|
121 | { |
---|
122 | int conn_idx = rqstp ? TspConnGetIndex(rqstp) : -1; |
---|
123 | static ptrace_out out; /* outut response (error or data) */ |
---|
124 | void *addr, *addr2; /* used for actual ptrace call */ |
---|
125 | unsigned int data; |
---|
126 | int req, pid, ret, pid_idx, idx; |
---|
127 | static union |
---|
128 | { /* local buffer for returned data */ |
---|
129 | Objects_Id t_list[UTHREAD_MAX]; /* thread_list return */ |
---|
130 | char t_name[THREADNAMEMAX]; /* thread name return */ |
---|
131 | } local_buff; /* for return handling of strings and the like */ |
---|
132 | PID_LIST *plst = NULL; /* current pid_list entry */ |
---|
133 | |
---|
134 | DPRINTF (("ptrace_2_svc: entered (%s (%d), %d, XXXX, %d, XXXX)\n", |
---|
135 | PtraceName (in->addr.req), in->addr.req, in->pid, |
---|
136 | in->data)); |
---|
137 | |
---|
138 | out.addr.ptrace_addr_data_out_u.addr = 0; |
---|
139 | |
---|
140 | /* validate the connection */ |
---|
141 | if (conn_idx == -1 && rqstp != NULL) |
---|
142 | { /* no connection, error */ |
---|
143 | DPRINTF(("ptrace_2_svc: msg from unknown debugger!\n")); |
---|
144 | out.result = -1; |
---|
145 | out.errNo = ECHILD; /* closest error */ |
---|
146 | out.addr.req = 0; /* to avoid copies that should not occur */ |
---|
147 | return(&out); |
---|
148 | } |
---|
149 | /* Consider that the last back-message is acknowledged */ |
---|
150 | if (conn_idx >= 0 && conn_list[conn_idx].retry) { |
---|
151 | TspMessageReceive(conn_idx, in->pid); |
---|
152 | } |
---|
153 | |
---|
154 | req = in->addr.req; |
---|
155 | out.addr.req = req; /* needed for RPC */ |
---|
156 | pid = in->pid; |
---|
157 | addr = addr2 = NULL; |
---|
158 | data = in->data; |
---|
159 | setErrno(0); /* assume works */ |
---|
160 | out.result = 0; /* assume worked ok */ |
---|
161 | out.errNo = 0; |
---|
162 | |
---|
163 | /* lookup process to make sure we have under control */ |
---|
164 | pid_idx = FindPidEntry (in->pid); |
---|
165 | if (pid_idx >= 0) /* found it */ |
---|
166 | { |
---|
167 | plst = &pid_list[pid_idx]; |
---|
168 | if (conn_idx < 0) |
---|
169 | conn_idx = plst->primary_conn; |
---|
170 | } |
---|
171 | |
---|
172 | /* now we handle the special case of ATTACH to a pid we already control */ |
---|
173 | if (req == RPT_ATTACH) |
---|
174 | { /* look it up first */ |
---|
175 | if (plst) |
---|
176 | { /* we have controlled , so return ok+show conn */ |
---|
177 | ret = 2; /* normally secondary connection */ |
---|
178 | if (! PIDMAP_TEST (conn_idx, pid_idx)) |
---|
179 | { /* mark as an owner if not already */ |
---|
180 | plst->owners++; |
---|
181 | PIDMAP_SET (conn_idx, pid_idx); /* mask in */ |
---|
182 | } |
---|
183 | else if (plst->primary_conn != NO_PRIMARY) |
---|
184 | { /* regrab makes primary */ |
---|
185 | /* Only if not primary already */ |
---|
186 | if (plst->primary_conn != conn_idx) { |
---|
187 | TspSendWaitChange(plst->primary_conn, BMSG_NOT_PRIM, |
---|
188 | conn_idx, plst->pid, 0, False); /* tell old owner */ |
---|
189 | } |
---|
190 | plst->primary_conn = NO_PRIMARY; |
---|
191 | } |
---|
192 | |
---|
193 | if (plst->primary_conn == NO_PRIMARY) |
---|
194 | { /* none now, so take over */ |
---|
195 | plst->primary_conn = conn_idx; /* new primary */ |
---|
196 | ret = 1; /* primary */ |
---|
197 | } |
---|
198 | out.result = ret; /* primary or secondary owner */ |
---|
199 | return(&out); |
---|
200 | } |
---|
201 | /* else attach process using target code */ |
---|
202 | setErrno(ESRCH); /* assume the worst */ |
---|
203 | if (!TgtAttach(conn_idx, pid)) |
---|
204 | { /* failed */ |
---|
205 | out.errNo = getErrno(); |
---|
206 | out.result = 0; |
---|
207 | } |
---|
208 | return(&out); |
---|
209 | } |
---|
210 | else if (req == RPT_DETACH) |
---|
211 | { /* see which kind of detach */ |
---|
212 | if (data == PTRDET_UNOWN) |
---|
213 | { /* only want to disconnect from */ |
---|
214 | TgtDetachCon(conn_idx, pid_idx, True); /* remove from control */ |
---|
215 | return(&out); /* done */ |
---|
216 | } |
---|
217 | } |
---|
218 | else if (plst && (req == RPT_GETNAME || req == RPT_GETBREAK)) |
---|
219 | { |
---|
220 | /* do nothing */ |
---|
221 | } |
---|
222 | |
---|
223 | else if (plst && req == RPT_CLRBREAK) { |
---|
224 | /* To be able to remove breakpoints from a "running" system */ |
---|
225 | DPRINTF (("ptrace_2_svc: allowing RPT_CLRBREAK %d\n", data)); |
---|
226 | /* do nothing */ |
---|
227 | } |
---|
228 | |
---|
229 | else if (plst && plst->running) |
---|
230 | { /* error, process is running and not detach */ |
---|
231 | out.result = -1; |
---|
232 | out.errNo = ETXTBSY; /* closest error */ |
---|
233 | DPRINTF (("ptrace_2_svc: failed, still running.\n")); |
---|
234 | return(&out); |
---|
235 | } |
---|
236 | if (plst == NULL) { |
---|
237 | out.result = -1; |
---|
238 | out.errNo = ESRCH; |
---|
239 | DPRINTF (("ptrace_2_svc: No such process.\n")); |
---|
240 | return (&out); |
---|
241 | } |
---|
242 | |
---|
243 | /* now make sure secondary owner is not trying to modify */ |
---|
244 | if (!(in->flags & PTRFLG_NON_OWNER)) /* if not overriden */ |
---|
245 | if (conn_idx != plst->primary_conn |
---|
246 | && ( (req >= RPT_POKETEXT && req <= RPT_SINGLESTEP) |
---|
247 | || (req >= RPT_SETREGS && req <= RPT_SETFPAREGS && (req & 1)) |
---|
248 | || (req >= RPT_SYSCALL && req <= RPT_DUMPCORE) |
---|
249 | || (req >= RPT_SETTARGETTHREAD && req <= RPT_THREADRESUME) |
---|
250 | || (req >= RPT_SETTHREADNAME && req <= RPT_SETTHREADREGS) |
---|
251 | || (req >= RPT_STEPRANGE && req <= RPT_CLRBREAK) |
---|
252 | || (req == RPT_STOP) |
---|
253 | || (req >= RPT_PSETREGS && req <= RPT_PSETTHREADREGS))) |
---|
254 | { /* not owner */ |
---|
255 | out.result = -1; |
---|
256 | out.errNo = EPERM; /* cannot alter as not primary */ |
---|
257 | DPRINTF (("ptrace_2_svc: refused, not owner, flags %d conn_idx %d primary_conn %d\n", in->flags, conn_idx, |
---|
258 | plst->primary_conn)); |
---|
259 | return(&out); |
---|
260 | } |
---|
261 | |
---|
262 | addr = (void *)in->addr.ptrace_addr_data_in_u.address; /* default */ |
---|
263 | /* now setup normal ptrace request by unpacking. May execute here. */ |
---|
264 | switch (req) |
---|
265 | { /* handle unpacking or setup for real call */ |
---|
266 | /* first the ones where addr points to input data */ |
---|
267 | case RPT_SETREGS: |
---|
268 | case RPT_SETTHREADREGS: |
---|
269 | addr = (void *)&in->addr.ptrace_addr_data_in_u.regs; /* reg list */ |
---|
270 | break; |
---|
271 | |
---|
272 | case RPT_PSETREGS: |
---|
273 | case RPT_PSETTHREADREGS: |
---|
274 | if (in->addr.ptrace_addr_data_in_u.pregs.pregs_len != REG_COUNT) { |
---|
275 | DPRINTF(("ptrace_2_svc: pid %d got %d expected %d\n", pid, |
---|
276 | in->addr.ptrace_addr_data_in_u.pregs.pregs_len, REG_COUNT)); |
---|
277 | setErrno(EINVAL); |
---|
278 | break; |
---|
279 | } |
---|
280 | req = req == RPT_PSETREGS ? RPT_SETREGS : RPT_SETTHREADREGS; |
---|
281 | addr = (void *) in->addr.ptrace_addr_data_in_u.pregs.pregs_val; |
---|
282 | break; |
---|
283 | |
---|
284 | case RPT_SETTHREADNAME: |
---|
285 | addr = (void *)in->addr.ptrace_addr_data_in_u.name; |
---|
286 | break; |
---|
287 | case RPT_WRITETEXT: |
---|
288 | case RPT_WRITEDATA: |
---|
289 | if ((int) data < 0) { |
---|
290 | setErrno(EINVAL); |
---|
291 | break; |
---|
292 | } |
---|
293 | addr = (void *)in->addr.ptrace_addr_data_in_u.mem.addr; /* targ addr */ |
---|
294 | addr2 = (void *)in->addr.ptrace_addr_data_in_u.mem.data; /* buff */ |
---|
295 | |
---|
296 | /* Forbid writing over breakpoints */ |
---|
297 | if (BreakOverwrite (plst, addr, data)) { |
---|
298 | setErrno(EBUSY); |
---|
299 | } |
---|
300 | break; |
---|
301 | |
---|
302 | case RPT_POKETEXT: |
---|
303 | case RPT_POKEDATA: |
---|
304 | /* Forbid writing over breakpoints */ |
---|
305 | if (BreakOverwrite (plst, addr, sizeof (int))) { |
---|
306 | setErrno(EBUSY); |
---|
307 | } |
---|
308 | break; |
---|
309 | |
---|
310 | /* now ones where we handle locally */ |
---|
311 | case RPT_GETTARGETTHREAD: |
---|
312 | out.result = plst->thread; |
---|
313 | req = 0; /* force exit */ |
---|
314 | break; |
---|
315 | |
---|
316 | case RPT_PGETREGS: /* return from our buffer */ |
---|
317 | out.addr.ptrace_addr_data_out_u.pregs.pregs_len = REG_COUNT; |
---|
318 | out.addr.ptrace_addr_data_out_u.pregs.pregs_val = (u_int*) &plst->regs; |
---|
319 | req = 0; /* force exit */ |
---|
320 | break; |
---|
321 | |
---|
322 | case RPT_GETREGS: |
---|
323 | /* return directly from our buffer */ |
---|
324 | /* this buffer is refreshed when changing target thread */ |
---|
325 | out.addr.ptrace_addr_data_out_u.regs = plst->regs; |
---|
326 | req = 0; /* force exit */ |
---|
327 | break; |
---|
328 | |
---|
329 | case RPT_SETBREAK: |
---|
330 | idx = BreakSet (plst, conn_idx, &in->addr.ptrace_addr_data_in_u.breakp); |
---|
331 | if (idx < 0) break; |
---|
332 | req = 0; /* force exit */ |
---|
333 | out.result = idx; /* return break index (>0) */ |
---|
334 | break; |
---|
335 | |
---|
336 | case RPT_CLRBREAK: |
---|
337 | if (conn_list[conn_idx].flags & DEBUGGER_IS_GDB) { |
---|
338 | data = BreakGetIndex (plst, addr); |
---|
339 | } |
---|
340 | out.result = BreakClear (plst, conn_idx, data); |
---|
341 | /* if errored, errno will still be set */ |
---|
342 | req = 0; |
---|
343 | break; |
---|
344 | |
---|
345 | case RPT_GETBREAK: |
---|
346 | /* data=handle, addr=in_buffer, returns next break. Data=0, returns cnt */ |
---|
347 | out.result = BreakGet (plst, data, &out.addr. |
---|
348 | ptrace_addr_data_out_u.breakp); |
---|
349 | req = 0; /* handle locally */ |
---|
350 | break; |
---|
351 | |
---|
352 | case RPT_GETNAME: /* get the name of the process */ |
---|
353 | if (!plst->name) |
---|
354 | out.addr.ptrace_addr_data_out_u.mem.dataNb = 0; |
---|
355 | else |
---|
356 | { |
---|
357 | int maxLen = sizeof out.addr.ptrace_addr_data_out_u.mem.data - 1; |
---|
358 | data = strlen(plst->name); |
---|
359 | if (data > maxLen) |
---|
360 | data = maxLen; |
---|
361 | out.addr.ptrace_addr_data_out_u.mem.dataNb = data+1; |
---|
362 | memcpy(out.addr.ptrace_addr_data_out_u.mem.data, plst->name, data+1); |
---|
363 | out.addr.ptrace_addr_data_out_u.mem.data [maxLen] = '\0'; |
---|
364 | } |
---|
365 | req = 0; |
---|
366 | break; |
---|
367 | |
---|
368 | case RPT_CONTTO: |
---|
369 | if (BreakSetAt (plst, conn_idx, (u_long) addr, BRKT_STEPEMUL) < 0) |
---|
370 | { |
---|
371 | DPRINTF(("ptrace_2_svc: BreakSet failed at %x", addr)); |
---|
372 | break; |
---|
373 | } |
---|
374 | req = RPT_CONT; |
---|
375 | /* data can contain a signal number, addr2 is unused */ |
---|
376 | goto case_RPT_CONT; |
---|
377 | |
---|
378 | case RPT_STEPRANGE: |
---|
379 | /* convert to step */ |
---|
380 | if (!data) |
---|
381 | data = 1; /* should we give an error?? */ |
---|
382 | BreakStepRange (plst, addr, data); |
---|
383 | if (getErrno()) break; |
---|
384 | |
---|
385 | req = RPT_SINGLESTEP; /* do by stepping */ |
---|
386 | addr = (void*) 1; /* start from current PC */ |
---|
387 | data = -2; /* want non-atomic stepping */ |
---|
388 | /* fall through to other exec cases */ |
---|
389 | |
---|
390 | case RPT_CONT: |
---|
391 | case_RPT_CONT: |
---|
392 | case RPT_SINGLESTEP: |
---|
393 | |
---|
394 | if (BreakStepOff (plst, &addr2)) |
---|
395 | { /* need clear then step off break */ |
---|
396 | /* clear break, step, then do exec */ |
---|
397 | if (addr == (void*) 1) |
---|
398 | addr = (void*) plst->regs.REG_PC;/* need for patch */ |
---|
399 | |
---|
400 | /* data is always 0, so atomic single-step */ |
---|
401 | } else if (req == RPT_SINGLESTEP) { |
---|
402 | data = -2; /* want non-atomic stepping */ |
---|
403 | } |
---|
404 | break; |
---|
405 | |
---|
406 | /* now ones where addr points to an output area */ |
---|
407 | case RPT_PGETTHREADREGS: |
---|
408 | addr = (void*) out.addr.ptrace_addr_data_out_u.mem.data; |
---|
409 | if (sizeof out.addr.ptrace_addr_data_out_u.mem.data < |
---|
410 | REG_COUNT * sizeof(int)) { |
---|
411 | setErrno(EINVAL); |
---|
412 | break; |
---|
413 | } |
---|
414 | if (data == plst->thread) { |
---|
415 | out.addr.ptrace_addr_data_out_u.pregs.pregs_len = REG_COUNT; |
---|
416 | out.addr.ptrace_addr_data_out_u.pregs.pregs_val = (u_int*) &plst->regs; |
---|
417 | req = 0; /* force exit */ |
---|
418 | break; |
---|
419 | } |
---|
420 | req = RPT_GETTHREADREGS; |
---|
421 | break; |
---|
422 | |
---|
423 | case RPT_GETTHREADREGS: |
---|
424 | addr = (void*) &out.addr.ptrace_addr_data_out_u.regs; |
---|
425 | break; |
---|
426 | case RPT_GETTHREADNAME: |
---|
427 | out.addr.ptrace_addr_data_out_u.name = local_buff.t_name; |
---|
428 | addr = (void*) out.addr.ptrace_addr_data_out_u.name; |
---|
429 | break; |
---|
430 | case RPT_THREADLIST: |
---|
431 | out.addr.ptrace_addr_data_out_u.threads.threads =(ptThreadList) local_buff.t_list; |
---|
432 | addr = (void*) out.addr.ptrace_addr_data_out_u.threads.threads; |
---|
433 | break; |
---|
434 | case RPT_READTEXT: |
---|
435 | case RPT_READDATA: |
---|
436 | if ((int) data < 0) { |
---|
437 | setErrno(EINVAL); |
---|
438 | break; |
---|
439 | } |
---|
440 | addr = (void *)in->addr.ptrace_addr_data_in_u.address; |
---|
441 | addr2 = (void *)out.addr.ptrace_addr_data_out_u.mem.data; |
---|
442 | out.addr.ptrace_addr_data_out_u.mem.dataNb = data; |
---|
443 | break; |
---|
444 | case RPT_DETACH: |
---|
445 | /* Do not allow detaching if breakpoints still there */ |
---|
446 | if (BreakGet (plst, 0, NULL)) |
---|
447 | { /* some bkpts still set */ |
---|
448 | setErrno(EINVAL); /* cannot detach safely */ |
---|
449 | break; |
---|
450 | } |
---|
451 | /* fall through */ |
---|
452 | case RPT_KILL: |
---|
453 | /* in the event they are trying to detach or kill a terminated process, |
---|
454 | we just delete the entry. */ |
---|
455 | if (PROC_TERMINATED (plst)) |
---|
456 | { |
---|
457 | TgtDelete(plst, -1, BMSG_KILLED); /* just blow off */ |
---|
458 | req = 0; /* now exit */ |
---|
459 | } |
---|
460 | break; |
---|
461 | } |
---|
462 | |
---|
463 | if (getErrno()) |
---|
464 | { /* failed in code above */ |
---|
465 | out.result = -1; |
---|
466 | out.errNo = getErrno(); |
---|
467 | DPRINTF(("ptrace_2_svc: result %d errNo %d\n", out.result, out.errNo)); |
---|
468 | return(&out); |
---|
469 | } |
---|
470 | else if (!req) |
---|
471 | { /* bail out now */ |
---|
472 | DPRINTF(("ptrace_2_svc: result %d errNo %d\n", out.result, out.errNo)); |
---|
473 | return(&out); |
---|
474 | } |
---|
475 | |
---|
476 | /* OK, make the call */ |
---|
477 | out.result = TgtPtrace(req, pid, addr, data, addr2); |
---|
478 | out.errNo = getErrno(); |
---|
479 | |
---|
480 | /* if no error, cleanup afterwards */ |
---|
481 | if (getErrno()) |
---|
482 | { |
---|
483 | /* Remove step-emul breakpoints if any */ |
---|
484 | if (req == RPT_SINGLESTEP || req == RPT_CONT) { |
---|
485 | BreakClear (plst, -1, -1); |
---|
486 | } |
---|
487 | DPRINTF(("ptrace_2_svc: result %d errNo %d\n", out.result, out.errNo)); |
---|
488 | return(&out); /* return error */ |
---|
489 | } |
---|
490 | |
---|
491 | switch (in->addr.req) |
---|
492 | { /* handle some special calls that affect state */ |
---|
493 | case RPT_CONT: |
---|
494 | case RPT_STEPRANGE: |
---|
495 | /* change to running */ |
---|
496 | if (in->addr.req == RPT_STEPRANGE) |
---|
497 | plst->last_start = LAST_RANGE; /* so range steps */ |
---|
498 | else if (addr2) |
---|
499 | plst->last_start = LAST_STEPOFF; /* now continue after wait */ |
---|
500 | else |
---|
501 | plst->last_start = LAST_CONT; |
---|
502 | plst->running = 1; /* mark as running */ |
---|
503 | if (!rqstp) /* Called internally to restart bkpt, no msg to anybody */ |
---|
504 | break; |
---|
505 | TgtNotifyAll(pid_idx, BMSG_WAIT, 0, 0, (in->flags & PTRFLG_NON_OWNER) |
---|
506 | ? -1 : conn_idx, True); |
---|
507 | break; |
---|
508 | case RPT_SINGLESTEP: |
---|
509 | /* mark as step */ |
---|
510 | plst->last_start = LAST_STEP; /* so we know how started */ |
---|
511 | plst->running = 1; /* mark as running (wait should catch fast) */ |
---|
512 | break; |
---|
513 | case RPT_DETACH: /* mark as disconnected */ |
---|
514 | case RPT_KILL: /* mark as killed */ |
---|
515 | if (in->flags & PTRFLG_FREE) /* notify and delete entry */ |
---|
516 | TgtDelete(plst, -1, (in->addr.req==RPT_KILL) ? BMSG_KILLED : BMSG_DETACH); |
---|
517 | else |
---|
518 | { /* notify and mark */ |
---|
519 | plst->last_start = (in->addr.req==RPT_KILL) ? |
---|
520 | LAST_KILLED : LAST_DETACHED; |
---|
521 | plst->state = -1; |
---|
522 | plst->running = False; |
---|
523 | TgtNotifyAll(pid_idx, (in->addr.req==RPT_KILL) ? |
---|
524 | BMSG_KILLED : BMSG_DETACH, 0, 0, -1, True); |
---|
525 | } |
---|
526 | break; |
---|
527 | case RPT_SETTHREADREGS: |
---|
528 | case RPT_PSETTHREADREGS: |
---|
529 | if (data != plst->thread) |
---|
530 | break; |
---|
531 | DPRINTF(("ptrace_2_svc: pid %d target thread regs changed!\n", pid)); |
---|
532 | |
---|
533 | case RPT_SETREGS: |
---|
534 | case RPT_PSETREGS: |
---|
535 | /* change our buffer as well */ |
---|
536 | if (plst->regs.REG_PC != ((xdr_regs*)addr)->REG_PC) |
---|
537 | BreakPcChanged (plst); |
---|
538 | plst->regs = *(xdr_regs*) addr; /* copy in */ |
---|
539 | break; |
---|
540 | |
---|
541 | /* case RPT_PGETREGS has been handled locally above */ |
---|
542 | case RPT_PGETTHREADREGS: |
---|
543 | /* We need to update pointer so that XDR works on return */ |
---|
544 | out.addr.ptrace_addr_data_out_u.pregs.pregs_len = REG_COUNT; |
---|
545 | out.addr.ptrace_addr_data_out_u.pregs.pregs_val = |
---|
546 | (void*) out.addr.ptrace_addr_data_out_u.mem.data; |
---|
547 | break; |
---|
548 | |
---|
549 | case RPT_PEEKTEXT: |
---|
550 | case RPT_PEEKDATA: |
---|
551 | case RPT_READDATA: |
---|
552 | case RPT_READTEXT: |
---|
553 | if (req < RPT_READDATA) |
---|
554 | { /* peek */ |
---|
555 | /* addr is start */ |
---|
556 | data = sizeof(int); |
---|
557 | addr2 = &out.result; /* data buffer */ |
---|
558 | /* Like read: addr is start, data is length, addr2 is buffer */ |
---|
559 | } |
---|
560 | BreakHide (plst, addr, data, addr2); |
---|
561 | break; |
---|
562 | |
---|
563 | case RPT_SETTARGETTHREAD: |
---|
564 | DPRINTF(("ptrace_2_svc: pid %d new target thread %d\n", pid, data)); |
---|
565 | TgtPtrace (RPT_GETREGS, pid, (char*) &plst->regs, 0, NULL); |
---|
566 | plst->thread = data; |
---|
567 | if (plst->break_list) { /* Forget we had to step off breakpoint */ |
---|
568 | BASE_BREAK* base = (BASE_BREAK*) plst->break_list; |
---|
569 | DPRINTF(("ptrace_2_svc: clr_step %d last_break %d\n", base->clr_step, |
---|
570 | base->last_break)); |
---|
571 | base->clr_step = 0; /* Not stopped on break */ |
---|
572 | base->last_break = 0; |
---|
573 | } |
---|
574 | break; |
---|
575 | |
---|
576 | case RPT_THREADLIST: |
---|
577 | out.addr.ptrace_addr_data_out_u.threads.nbThread = out.result; |
---|
578 | break; |
---|
579 | |
---|
580 | default: |
---|
581 | break; |
---|
582 | } /* end switch */ |
---|
583 | DPRINTF(("ptrace_2_svc 2: result %d errNo %d\n", out.result, out.errNo)); |
---|
584 | return(&out); |
---|
585 | } |
---|
586 | |
---|
587 | /* ----------------------------------------------------------------------- |
---|
588 | wait_info_2_svc - non-blocking wait request to check status. |
---|
589 | ----------------------------------------------------------------------- */ |
---|
590 | |
---|
591 | wait_out *RPCGENSRVNAME(wait_info_2_svc) (in, rqstp) |
---|
592 | wait_in *in; |
---|
593 | struct svc_req *rqstp; /* server info */ |
---|
594 | { |
---|
595 | int conn_idx = TspConnGetIndex(rqstp); |
---|
596 | static wait_out out; /* output of pid and status */ |
---|
597 | int idx; |
---|
598 | PID_LIST *plst; |
---|
599 | |
---|
600 | memset(&out, 0, sizeof(out)); /* zero for safety */ |
---|
601 | out.reason = STOP_ERROR; /* assume the worst */ |
---|
602 | |
---|
603 | if (conn_idx == -1) |
---|
604 | { /* no connection, error */ |
---|
605 | DPRINTF(("wait_info_2_svc: msg from unknown debugger!\n")); |
---|
606 | out.wait_return = -1; |
---|
607 | out.errNo = ECHILD; /* closest error */ |
---|
608 | return(&out); |
---|
609 | } |
---|
610 | else |
---|
611 | { /* see if confirming message received */ |
---|
612 | if (conn_list[conn_idx].retry) |
---|
613 | TspMessageReceive(conn_idx, in->pid); |
---|
614 | } |
---|
615 | |
---|
616 | if (!in->pid) |
---|
617 | { /* warm test verify only */ |
---|
618 | /* this call (pid==0) is made to confirm that that connection is still |
---|
619 | active. */ |
---|
620 | /* we let it fall through as an error since any use other than connection |
---|
621 | reset would be an error (there is no pid0). */ |
---|
622 | } |
---|
623 | else |
---|
624 | { /* normal request */ |
---|
625 | idx = FindPidEntry (in->pid); |
---|
626 | if (idx >= 0) |
---|
627 | { /* found process they requested on */ |
---|
628 | plst = &pid_list[idx]; |
---|
629 | out.wait_return = plst->running ? 0 : in->pid; |
---|
630 | /* return: 0 is running, pid is stopped/term */ |
---|
631 | out.errNo = 0; |
---|
632 | out.status = plst->state; /* last stopped reason if stopped */ |
---|
633 | out.thread = plst->thread;/* current thread (or -1 if none) from stop */ |
---|
634 | if (!out.wait_return) |
---|
635 | out.reason = STOP_NONE; /* running, no action */ |
---|
636 | else if (STS_SIGNALLED (out.status)) |
---|
637 | { /* stopped on signal */ |
---|
638 | out.handle = STS_GETSIG (out.status); /* signal number */ |
---|
639 | if (out.handle == SIGTRAP) |
---|
640 | if (plst->is_step) |
---|
641 | { /* single step with hitting a break */ |
---|
642 | out.reason = STOP_STEP; |
---|
643 | out.handle = 0; /* no information */ |
---|
644 | } |
---|
645 | else |
---|
646 | { /* stopped on break */ |
---|
647 | out.reason = STOP_BREAK; |
---|
648 | if (plst->break_list) |
---|
649 | out.handle = ((BASE_BREAK*)plst->break_list)->last_break; |
---|
650 | else |
---|
651 | out.handle = 0; /* no break */ |
---|
652 | } |
---|
653 | else |
---|
654 | out.reason = STOP_SIGNAL; |
---|
655 | out.PC = plst->regs.REG_PC; /* copy standard regs */ |
---|
656 | out.SP = plst->regs.REG_SP; |
---|
657 | out.FP = plst->regs.REG_FP; |
---|
658 | } |
---|
659 | else |
---|
660 | { /* terminated, so lower use count */ |
---|
661 | if (plst->last_start == LAST_KILLED) |
---|
662 | out.reason = STOP_KILLED; |
---|
663 | else if (plst->last_start == LAST_DETACHED) |
---|
664 | out.reason = STOP_DETACHED; |
---|
665 | else if (plst->last_start == LAST_START) |
---|
666 | { /* failed in exec */ |
---|
667 | out.reason = STOP_SPAWN_FAILED; |
---|
668 | out.handle = STS_GETCODE (out.status); /* errno reason */ |
---|
669 | } |
---|
670 | else if (STS_TERMONSIG (out.status)) |
---|
671 | { /* terminated on signal */ |
---|
672 | out.reason = STOP_TERM_SIG; |
---|
673 | /* mask off the core-dumped bit 7 */ |
---|
674 | out.handle = (int)(unsigned)(u_char) STS_TERMGETSIG (out.status); |
---|
675 | } |
---|
676 | else |
---|
677 | { /* exit(2)ed */ |
---|
678 | out.reason = STOP_TERM_EXIT; |
---|
679 | out.handle = STS_GETCODE (out.status); /* code */ |
---|
680 | } |
---|
681 | } |
---|
682 | DPRINTF(("wait_info_2_svc: pid %d return %d status %x errNo %d" |
---|
683 | " reason %d handle %d pc %x sp %x fp %x thread %d\n", |
---|
684 | in->pid, out.wait_return, out.status, out.errNo, out.reason, |
---|
685 | out.handle, out.PC, out.SP, out.FP, out.thread)); |
---|
686 | return(&out); |
---|
687 | } |
---|
688 | } |
---|
689 | /* if not found in list, we return error: no such process */ |
---|
690 | out.wait_return = -1; |
---|
691 | out.errNo = ESRCH; /* no process */ |
---|
692 | out.status = 0; |
---|
693 | return(&out); |
---|
694 | } |
---|
695 | |
---|
696 | /* ----------------------------------------------------------------------- |
---|
697 | get_signal_names_2_svc - return names for signals |
---|
698 | ----------------------------------------------------------------------- */ |
---|
699 | |
---|
700 | static one_signal SignalNames[] = { |
---|
701 | {SIGILL, "SIGILL/EVT_ILL"}, |
---|
702 | {SIGTRAP, "SIGTRAP/EVT_BKPT"}, |
---|
703 | {SIGFPE, "SIGFPE/EVT_FPE"}, |
---|
704 | {SIGKILL, "SIGKILL/EVT_AKILL"}, |
---|
705 | {SIGSEGV, "SIGSEGV/EVT_SEGV"}, |
---|
706 | {17, "SIGSTOP"}, |
---|
707 | {23, "SIGSTOP"} |
---|
708 | }; |
---|
709 | |
---|
710 | get_signal_names_out* RPCGENSRVNAME(get_signal_names_2_svc) (in, rqstp) |
---|
711 | void* in; |
---|
712 | struct svc_req *rqstp; /* server info */ |
---|
713 | { |
---|
714 | static get_signal_names_out out; |
---|
715 | |
---|
716 | out.signals.all_signals_len = sizeof SignalNames / sizeof SignalNames[0]; |
---|
717 | out.signals.all_signals_val = SignalNames; |
---|
718 | |
---|
719 | return(&out); |
---|
720 | } |
---|