]>
Commit | Line | Data |
---|---|---|
8fc2b417 SG |
1 | /* Low level interface for debugging Solaris threads for GDB, the GNU debugger. |
2 | Copyright 1996 Free Software Foundation, Inc. | |
3 | ||
4 | This file is part of GDB. | |
5 | ||
6 | This program is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
8 | the Free Software Foundation; either version 2 of the License, or | |
9 | (at your option) any later version. | |
10 | ||
11 | This program is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with this program; if not, write to the Free Software | |
18 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |
19 | ||
20 | ||
21 | #include "defs.h" | |
22 | ||
23 | #ifdef gregset_t | |
24 | #undef gregset_t | |
25 | #endif | |
26 | ||
27 | #ifdef fpregset_t | |
28 | #undef fpregset_t | |
29 | #endif | |
30 | ||
31 | #include "/usr/include/thread.h" | |
32 | #include <proc_service.h> | |
33 | #include <thread_db.h> | |
34 | #include "thread.h" | |
35 | #include "target.h" | |
36 | #include "inferior.h" | |
37 | #include <fcntl.h> | |
38 | #include <unistd.h> | |
39 | #include <sys/stat.h> | |
40 | ||
41 | static void sol_thread_resume PARAMS ((int pid, int step, | |
42 | enum target_signal signo)); | |
43 | ||
44 | extern struct target_ops sol_thread_ops; /* Forward declaration */ | |
45 | ||
46 | extern int procfs_suppress_run; | |
47 | ||
48 | struct ps_prochandle | |
49 | { | |
50 | pid_t pid; | |
51 | }; | |
52 | ||
53 | static struct ps_prochandle main_ph; | |
54 | static td_thragent_t *main_ta; | |
55 | ||
56 | static int sol_thread_active = 0; | |
57 | ||
58 | \f | |
59 | ||
60 | extern struct target_ops procfs_ops; | |
61 | ||
62 | /* Convert thread_id to an LWP id. */ | |
63 | ||
64 | static int thread_to_lwp PARAMS ((int thread_id, int default_lwp)); | |
65 | ||
66 | static int | |
67 | thread_to_lwp (thread_id, default_lwp) | |
68 | int thread_id; | |
69 | int default_lwp; | |
70 | { | |
71 | td_thrinfo_t ti; | |
72 | td_thrhandle_t th; | |
73 | td_err_e val; | |
74 | int pid; | |
75 | int lwp; | |
76 | ||
77 | if (!(thread_id & 0x80000000)) | |
78 | return thread_id; /* It's already an LWP id */ | |
79 | ||
80 | /* It's a thread. Convert to lwp */ | |
81 | ||
82 | pid = thread_id & 0xffff; | |
83 | thread_id = (thread_id >> 16) & 0x7fff; | |
84 | ||
85 | val = td_ta_map_id2thr (main_ta, thread_id, &th); | |
86 | if (val != TD_OK) | |
87 | error ("thread_to_lwp: td_ta_map_id2thr %d", val); | |
88 | ||
89 | val = td_thr_get_info (&th, &ti); | |
90 | ||
91 | if (val != TD_OK) | |
92 | error ("thread_to_lwp: td_thr_get_info: %d", val); | |
93 | ||
94 | if (ti.ti_state != TD_THR_ACTIVE) | |
95 | { | |
96 | if (default_lwp != -1) | |
97 | return default_lwp; | |
98 | error ("thread_to_lwp: thread state not active: %d", ti.ti_state); | |
99 | } | |
100 | ||
101 | lwp = (ti.ti_lid << 16) | pid; | |
102 | ||
103 | return lwp; | |
104 | } | |
105 | ||
106 | /* Convert an LWP id to a thread. */ | |
107 | ||
108 | static int lwp_to_thread PARAMS ((int lwp)); | |
109 | ||
110 | static int | |
111 | lwp_to_thread (lwp) | |
112 | int lwp; | |
113 | { | |
114 | td_thrinfo_t ti; | |
115 | td_thrhandle_t th; | |
116 | td_err_e val; | |
117 | int pid; | |
118 | int thread_id; | |
119 | ||
120 | if (lwp & 0x80000000) | |
121 | return lwp; /* It's already a thread id */ | |
122 | ||
123 | /* It's an lwp. Convert it to a thread id. */ | |
124 | ||
125 | pid = lwp & 0xffff; | |
126 | lwp = (lwp >> 16) & 0xffff; | |
127 | ||
128 | val = td_ta_map_lwp2thr (main_ta, lwp, &th); | |
129 | if (val != TD_OK) | |
130 | error ("lwp_to_thread: td_thr_get_info: %d.", val); | |
131 | ||
132 | val = td_thr_get_info (&th, &ti); | |
133 | ||
134 | if (val != TD_OK) | |
135 | error ("lwp_to_thread: td_thr_get_info: %d.", val); | |
136 | ||
137 | thread_id = (ti.ti_tid << 16) | pid | 0x80000000; | |
138 | ||
139 | return thread_id; | |
140 | } | |
141 | ||
142 | ||
143 | /* ARGSUSED */ | |
144 | static void | |
145 | sol_thread_open (arg, from_tty) | |
146 | char *arg; | |
147 | int from_tty; | |
148 | { | |
149 | procfs_ops.to_open (arg, from_tty); | |
150 | } | |
151 | ||
152 | /* Attach to process PID, then initialize for debugging it | |
153 | and wait for the trace-trap that results from attaching. */ | |
154 | ||
155 | static void | |
156 | sol_thread_attach (args, from_tty) | |
157 | char *args; | |
158 | int from_tty; | |
159 | { | |
160 | procfs_ops.to_attach (args, from_tty); | |
161 | ||
162 | /* XXX - might want to iterate over all the threads and register them. */ | |
163 | } | |
164 | ||
165 | /* Take a program previously attached to and detaches it. | |
166 | The program resumes execution and will no longer stop | |
167 | on signals, etc. We'd better not have left any breakpoints | |
168 | in the program or it'll die when it hits one. For this | |
169 | to work, it may be necessary for the process to have been | |
170 | previously attached. It *might* work if the program was | |
171 | started via the normal ptrace (PTRACE_TRACEME). */ | |
172 | ||
173 | static void | |
174 | sol_thread_detach (args, from_tty) | |
175 | char *args; | |
176 | int from_tty; | |
177 | { | |
178 | procfs_ops.to_detach (args, from_tty); | |
179 | } | |
180 | ||
181 | /* Resume execution of process PID. If STEP is nozero, then | |
182 | just single step it. If SIGNAL is nonzero, restart it with that | |
183 | signal activated. */ | |
184 | ||
185 | static void | |
186 | sol_thread_resume (pid, step, signo) | |
187 | int pid; | |
188 | int step; | |
189 | enum target_signal signo; | |
190 | { | |
191 | int save_pid; | |
192 | ||
193 | save_pid = inferior_pid; | |
194 | ||
195 | inferior_pid = thread_to_lwp (inferior_pid, main_ph.pid); | |
196 | ||
197 | if (pid != -1) | |
198 | pid = thread_to_lwp (pid, -1); | |
199 | ||
200 | procfs_ops.to_resume (pid, step, signo); | |
201 | ||
202 | inferior_pid = save_pid; | |
203 | } | |
204 | ||
205 | /* Wait for any LWPs to stop */ | |
206 | ||
207 | static int | |
208 | sol_thread_wait (pid, ourstatus) | |
209 | int pid; | |
210 | struct target_waitstatus *ourstatus; | |
211 | { | |
212 | int statval; | |
213 | int rtnval; | |
214 | int save_pid; | |
215 | ||
216 | if (!sol_thread_active) | |
217 | return procfs_ops.to_wait (pid, ourstatus); | |
218 | ||
219 | save_pid = inferior_pid; | |
220 | ||
221 | inferior_pid = thread_to_lwp (inferior_pid, main_ph.pid); | |
222 | ||
223 | if (pid != -1) | |
224 | pid = thread_to_lwp (pid, -1); | |
225 | ||
226 | rtnval = procfs_ops.to_wait (pid, ourstatus); | |
227 | ||
228 | if (rtnval != save_pid | |
229 | && !in_thread_list (rtnval)) | |
230 | { | |
231 | fprintf_unfiltered (gdb_stderr, "[New %s]\n", | |
232 | target_pid_to_str (rtnval)); | |
233 | add_thread (rtnval); | |
234 | } | |
235 | ||
236 | inferior_pid = save_pid; /* XXX need to make a cleanup for this in case of error */ | |
237 | ||
238 | /* During process initialization, we may get here without the thread package | |
239 | being initialized, since that can only happen after we've found the shared | |
240 | libs. */ | |
241 | ||
242 | /* Map the LWP of interest back to the appropriate thread ID */ | |
243 | ||
244 | rtnval = lwp_to_thread (rtnval); | |
245 | ||
246 | return rtnval; | |
247 | } | |
248 | ||
249 | static void | |
250 | sol_thread_fetch_registers (regno) | |
251 | int regno; | |
252 | { | |
253 | thread_t thread; | |
254 | td_thrhandle_t thandle; | |
255 | td_err_e val; | |
256 | prgregset_t regset; | |
257 | prfpregset_t fpregset; | |
258 | int xregsize; | |
259 | caddr_t xregset; | |
260 | ||
261 | if (!sol_thread_active | |
262 | || !(inferior_pid & 0x80000000)) | |
263 | { | |
264 | procfs_ops.to_fetch_registers (regno); | |
265 | return; | |
266 | } | |
267 | ||
268 | /* Convert inferior_pid into a td_thrhandle_t */ | |
269 | ||
270 | thread = (inferior_pid >> 16) & 0x7fff; | |
271 | ||
272 | if (thread == 0) | |
273 | error ("sol_thread_fetch_registers: thread == 0"); | |
274 | ||
275 | val = td_ta_map_id2thr (main_ta, thread, &thandle); | |
276 | if (val != TD_OK) | |
277 | error ("sol_thread_fetch_registers: td_ta_map_id2thr: %d", val); | |
278 | ||
279 | /* Get the integer regs */ | |
280 | ||
281 | val = td_thr_getgregs (&thandle, regset); | |
282 | if (val == TD_OK) | |
283 | supply_gregset (regset); | |
284 | else if (val == TD_PARTIALREG) | |
285 | { | |
286 | /* For the sparc, only i0->i7, l0->l7, pc and sp are saved by a thread | |
287 | context switch. */ | |
288 | ||
289 | supply_gregset (regset); /* This is not entirely correct, as it sets | |
290 | the valid bits for the o, g, ps, y, npc, | |
291 | wim and tbr. That should be harmless | |
292 | though, as the context switch routine | |
293 | doesn't need to save them. */ | |
294 | } | |
295 | else | |
296 | error ("sol_thread_fetch_registers: td_thr_getgregs %d", val); | |
297 | ||
298 | /* And, now the fp regs */ | |
299 | ||
300 | val = td_thr_getfpregs (&thandle, &fpregset); | |
301 | if (val == TD_OK) | |
302 | supply_fpregset (&fpregset); | |
303 | else if (val != TD_NOFPREGS) | |
304 | error ("sol_thread_fetch_registers: td_thr_getfpregs %d", val); | |
305 | ||
306 | #if 0 | |
307 | /* thread_db doesn't seem to handle this right */ | |
308 | val = td_thr_getxregsize (&thandle, &xregsize); | |
309 | if (val != TD_OK && val != TD_NOXREGS) | |
310 | error ("sol_thread_fetch_registers: td_thr_getxregsize %d", val); | |
311 | ||
312 | if (val == TD_OK) | |
313 | { | |
314 | xregset = alloca (xregsize); | |
315 | val = td_thr_getxregs (&thandle, xregset); | |
316 | if (val != TD_OK) | |
317 | error ("sol_thread_fetch_registers: td_thr_getxregs %d", val); | |
318 | } | |
319 | #endif | |
320 | } | |
321 | ||
322 | static void | |
323 | sol_thread_store_registers (regno) | |
324 | int regno; | |
325 | { | |
326 | thread_t thread; | |
327 | td_thrhandle_t thandle; | |
328 | td_err_e val; | |
329 | prgregset_t regset; | |
330 | prfpregset_t fpregset; | |
331 | int xregsize; | |
332 | caddr_t xregset; | |
333 | ||
334 | if (!sol_thread_active | |
335 | || !(inferior_pid & 0x80000000)) | |
336 | { | |
337 | procfs_ops.to_store_registers (regno); | |
338 | return; | |
339 | } | |
340 | ||
341 | /* Convert inferior_pid into a td_thrhandle_t */ | |
342 | ||
343 | thread = (inferior_pid >> 16) & 0x7fff; | |
344 | ||
345 | val = td_ta_map_id2thr (main_ta, thread, &thandle); | |
346 | if (val != TD_OK) | |
347 | error ("sol_thread_store_registers: td_ta_map_id2thr %d", val); | |
348 | ||
349 | if (regno != -1) | |
350 | { /* Not writing all the regs */ | |
351 | val = td_thr_getgregs (&thandle, regset); | |
352 | if (val != TD_OK) | |
353 | error ("sol_thread_store_registers: td_thr_getgregs %d", val); | |
354 | val = td_thr_getfpregs (&thandle, &fpregset); | |
355 | if (val != TD_OK) | |
356 | error ("sol_thread_store_registers: td_thr_getfpregs %d", val); | |
357 | ||
358 | #if 0 | |
359 | /* thread_db doesn't seem to handle this right */ | |
360 | val = td_thr_getxregsize (&thandle, &xregsize); | |
361 | if (val != TD_OK && val != TD_NOXREGS) | |
362 | error ("sol_thread_store_registers: td_thr_getxregsize %d", val); | |
363 | ||
364 | if (val == TD_OK) | |
365 | { | |
366 | xregset = alloca (xregsize); | |
367 | val = td_thr_getxregs (&thandle, xregset); | |
368 | if (val != TD_OK) | |
369 | error ("sol_thread_store_registers: td_thr_getxregs %d", val); | |
370 | } | |
371 | #endif | |
372 | } | |
373 | ||
374 | fill_gregset (regset, regno); | |
375 | fill_fpregset (&fpregset, regno); | |
376 | ||
377 | val = td_thr_setgregs (&thandle, regset); | |
378 | if (val != TD_OK) | |
379 | error ("sol_thread_store_registers: td_thr_setgregs %d", val); | |
380 | val = td_thr_setfpregs (&thandle, &fpregset); | |
381 | if (val != TD_OK) | |
382 | error ("sol_thread_store_registers: td_thr_setfpregs %d", val); | |
383 | ||
384 | #if 0 | |
385 | /* thread_db doesn't seem to handle this right */ | |
386 | val = td_thr_getxregsize (&thandle, &xregsize); | |
387 | if (val != TD_OK && val != TD_NOXREGS) | |
388 | error ("sol_thread_store_registers: td_thr_getxregsize %d", val); | |
389 | ||
390 | /* Should probably do something about writing the xregs here, but what are | |
391 | they? */ | |
392 | #endif | |
393 | } | |
394 | ||
395 | /* Get ready to modify the registers array. On machines which store | |
396 | individual registers, this doesn't need to do anything. On machines | |
397 | which store all the registers in one fell swoop, this makes sure | |
398 | that registers contains all the registers from the program being | |
399 | debugged. */ | |
400 | ||
401 | static void | |
402 | sol_thread_prepare_to_store () | |
403 | { | |
404 | procfs_ops.to_prepare_to_store (); | |
405 | } | |
406 | ||
407 | static int | |
408 | sol_thread_xfer_memory (memaddr, myaddr, len, dowrite, target) | |
409 | CORE_ADDR memaddr; | |
410 | char *myaddr; | |
411 | int len; | |
412 | int dowrite; | |
413 | struct target_ops *target; /* ignored */ | |
414 | { | |
415 | int retval; | |
416 | int save_pid; | |
417 | ||
418 | save_pid = inferior_pid; | |
419 | ||
420 | if (inferior_pid & 0x80000000) | |
421 | inferior_pid = main_ph.pid; /* It's a thread. Convert to lwp */ | |
422 | ||
423 | retval = procfs_ops.to_xfer_memory (memaddr, myaddr, len, dowrite, target); | |
424 | ||
425 | inferior_pid = save_pid; | |
426 | ||
427 | return retval; | |
428 | } | |
429 | ||
430 | /* Print status information about what we're accessing. */ | |
431 | ||
432 | static void | |
433 | sol_thread_files_info (ignore) | |
434 | struct target_ops *ignore; | |
435 | { | |
436 | procfs_ops.to_files_info (ignore); | |
437 | } | |
438 | ||
439 | static void | |
440 | sol_thread_kill_inferior () | |
441 | { | |
442 | procfs_ops.to_kill (); | |
443 | } | |
444 | ||
445 | static void | |
446 | sol_thread_notice_signals (pid) | |
447 | int pid; | |
448 | { | |
449 | procfs_ops.to_notice_signals (pid); | |
450 | } | |
451 | ||
452 | void target_new_objfile PARAMS ((struct objfile *objfile)); | |
453 | ||
454 | /* Fork an inferior process, and start debugging it with /proc. */ | |
455 | ||
456 | static void | |
457 | sol_thread_create_inferior (exec_file, allargs, env) | |
458 | char *exec_file; | |
459 | char *allargs; | |
460 | char **env; | |
461 | { | |
462 | procfs_ops.to_create_inferior (exec_file, allargs, env); | |
463 | ||
464 | if (sol_thread_active) | |
465 | { | |
466 | td_thrhandle_t thandle; | |
467 | td_err_e val; | |
468 | td_thrinfo_t ti; | |
469 | ||
470 | main_ph.pid = inferior_pid; /* Save for xfer_memory */ | |
471 | ||
472 | push_target (&sol_thread_ops); | |
473 | ||
474 | inferior_pid = lwp_to_thread (inferior_pid); | |
475 | ||
476 | add_thread (inferior_pid); | |
477 | } | |
478 | } | |
479 | ||
480 | /* This routine is called whenever a new symbol table is read in, or when all | |
481 | symbol tables are removed. */ | |
482 | ||
483 | void | |
484 | sol_thread_new_objfile (objfile) | |
485 | struct objfile *objfile; | |
486 | { | |
487 | td_err_e val; | |
488 | ||
489 | if (!objfile) | |
490 | { | |
491 | sol_thread_active = 0; | |
492 | ||
493 | return; | |
494 | } | |
495 | ||
496 | /* Now, initialize the thread debugging library. This needs to be done after | |
497 | the shared libraries are located because it needs information from the | |
498 | user's thread library. */ | |
499 | ||
500 | val = td_init (); | |
501 | if (val != TD_OK) | |
502 | error ("target_new_objfile: td_init: %d", val); | |
503 | ||
504 | val = td_ta_new (&main_ph, &main_ta); | |
505 | if (val == TD_NOLIBTHREAD) | |
506 | return; | |
507 | else if (val != TD_OK) | |
508 | error ("target_new_objfile: td_ta_new: %d", val); | |
509 | ||
510 | sol_thread_active = 1; | |
511 | } | |
512 | ||
513 | /* Clean up after the inferior dies. */ | |
514 | ||
515 | static void | |
516 | sol_thread_mourn_inferior () | |
517 | { | |
518 | procfs_ops.to_mourn_inferior (); | |
519 | } | |
520 | ||
521 | /* Mark our target-struct as eligible for stray "run" and "attach" commands. */ | |
522 | static int | |
523 | sol_thread_can_run () | |
524 | { | |
525 | return procfs_suppress_run; | |
526 | } | |
527 | ||
528 | int | |
529 | sol_thread_alive (pid) | |
530 | int pid; | |
531 | { | |
532 | return 1; | |
533 | } | |
534 | ||
535 | void | |
536 | sol_thread_stop () | |
537 | { | |
538 | procfs_ops.to_stop (); | |
539 | } | |
540 | ||
541 | /* Service routines we must supply to libthread_db */ | |
542 | ||
543 | struct lwp_map | |
544 | { | |
545 | struct lwp_map *next; | |
546 | pid_t pid; | |
547 | lwpid_t lwp; | |
548 | int lwpfd; | |
549 | }; | |
550 | ||
551 | #if 0 | |
552 | struct lwp_map *lwp_map; | |
553 | ||
554 | /* Create a /proc file descriptor for the given LWPID */ | |
555 | ||
556 | static ps_err_e | |
557 | get_lwp_fd (const struct ps_prochandle *ph, const lwpid_t lwpid, int *fd) | |
558 | { | |
559 | struct lwp_map *lp; | |
560 | ||
561 | for (lp = lwp_map; lp; lp = lp->next) | |
562 | if (lp->pid = ph->pid | |
563 | && lp->lwp == lwpid) | |
564 | { | |
565 | *fd = lp->lwpfd; | |
566 | ||
567 | return PS_OK; | |
568 | } | |
569 | ||
570 | lp = xmalloc (sizeof (struct lwp_map)); | |
571 | ||
572 | if ((lp->lwpfd = ioctl (ph->fd, PIOCOPENLWP, &lwpid)) < 0) | |
573 | { | |
574 | print_sys_errmsg ("get_lwp_fd (): PIOCOPENLWP", errno); | |
575 | return PS_BADLID; | |
576 | } | |
577 | ||
578 | lp->pid = ph->pid; | |
579 | lp->lwp = lwpid; | |
580 | lp->next = lwp_map; | |
581 | lwp_map = lp; | |
582 | ||
583 | *fd = lp->lwpfd; | |
584 | ||
585 | return PS_OK; | |
586 | } | |
587 | #endif | |
588 | ||
589 | ps_err_e | |
590 | ps_pstop (const struct ps_prochandle *ph) | |
591 | { | |
592 | #if 0 | |
593 | if (ioctl (ph->fd, PIOCSTOP, NULL)) | |
594 | { | |
595 | print_sys_errmsg ("ps_pstop (): PIOCSTOP", errno); | |
596 | return PS_ERR; | |
597 | } | |
598 | #endif | |
599 | return PS_OK; | |
600 | } | |
601 | ||
602 | ps_err_e | |
603 | ps_pcontinue (const struct ps_prochandle *ph) | |
604 | { | |
605 | #if 0 | |
606 | if (ioctl (ph->fd, PIOCRUN, NULL)) | |
607 | { | |
608 | print_sys_errmsg ("ps_pcontinue (): PIOCRUN", errno); | |
609 | return PS_ERR; | |
610 | } | |
611 | #endif | |
612 | return PS_OK; | |
613 | } | |
614 | ||
615 | ps_err_e | |
616 | ps_lstop (const struct ps_prochandle *ph, lwpid_t lwpid) | |
617 | { | |
618 | int lwp_fd; | |
619 | ps_err_e val; | |
620 | ||
621 | #if 0 | |
622 | val = get_lwp_fd (ph, lwpid, &lwp_fd); | |
623 | if (val != PS_OK) | |
624 | return val; | |
625 | ||
626 | if (ioctl (lwp_fd, PIOCSTOP, NULL)) | |
627 | { | |
628 | print_sys_errmsg ("ps_lstop (): PIOCSTOP", errno); | |
629 | return PS_ERR; | |
630 | } | |
631 | #endif | |
632 | ||
633 | return PS_OK; | |
634 | } | |
635 | ||
636 | ps_err_e | |
637 | ps_lcontinue (const struct ps_prochandle *ph, lwpid_t lwpid) | |
638 | { | |
639 | int lwp_fd; | |
640 | ps_err_e val; | |
641 | ||
642 | #if 0 | |
643 | val = get_lwp_fd (ph, lwpid, &lwp_fd); | |
644 | if (val != PS_OK) | |
645 | return val; | |
646 | ||
647 | if (ioctl (lwp_fd, PIOCRUN, NULL)) | |
648 | { | |
649 | print_sys_errmsg ("ps_lcontinue (): PIOCRUN", errno); | |
650 | return PS_ERR; | |
651 | } | |
652 | #endif | |
653 | ||
654 | return PS_OK; | |
655 | } | |
656 | ||
657 | ps_err_e | |
658 | ps_pglobal_lookup (const struct ps_prochandle *ph, const char *ld_object_name, | |
659 | const char *ld_symbol_name, paddr_t *ld_symbol_addr) | |
660 | { | |
661 | struct minimal_symbol *ms; | |
662 | ||
663 | ms = lookup_minimal_symbol (ld_symbol_name, NULL, NULL); | |
664 | ||
665 | if (!ms) | |
666 | return PS_NOSYM; | |
667 | ||
668 | *ld_symbol_addr = SYMBOL_VALUE_ADDRESS (ms); | |
669 | ||
670 | return PS_OK; | |
671 | } | |
672 | ||
673 | static ps_err_e | |
674 | rw_common (int dowrite, const struct ps_prochandle *ph, paddr_t addr, | |
675 | char *buf, int size) | |
676 | { | |
677 | int save_pid; | |
678 | ||
679 | save_pid = inferior_pid; | |
680 | ||
681 | if (inferior_pid & 0x80000000) | |
682 | inferior_pid = main_ph.pid; /* It's a thread. Convert to lwp */ | |
683 | ||
684 | while (size > 0) | |
685 | { | |
686 | int cc; | |
687 | ||
688 | cc = procfs_ops.to_xfer_memory (addr, buf, size, dowrite, &procfs_ops); | |
689 | ||
690 | if (cc < 0) | |
691 | { | |
692 | if (dowrite == 0) | |
693 | print_sys_errmsg ("ps_pdread (): read", errno); | |
694 | else | |
695 | print_sys_errmsg ("ps_pdread (): write", errno); | |
696 | ||
697 | inferior_pid = save_pid; | |
698 | ||
699 | return PS_ERR; | |
700 | } | |
701 | size -= cc; | |
702 | buf += cc; | |
703 | } | |
704 | ||
705 | inferior_pid = save_pid; | |
706 | ||
707 | return PS_OK; | |
708 | } | |
709 | ||
710 | ps_err_e | |
711 | ps_pdread (const struct ps_prochandle *ph, paddr_t addr, char *buf, int size) | |
712 | { | |
713 | return rw_common (0, ph, addr, buf, size); | |
714 | } | |
715 | ||
716 | ps_err_e | |
717 | ps_pdwrite (const struct ps_prochandle *ph, paddr_t addr, char *buf, int size) | |
718 | { | |
719 | return rw_common (1, ph, addr, buf, size); | |
720 | } | |
721 | ||
722 | ps_err_e | |
723 | ps_ptread (const struct ps_prochandle *ph, paddr_t addr, char *buf, int size) | |
724 | { | |
725 | return rw_common (0, ph, addr, buf, size); | |
726 | } | |
727 | ||
728 | ps_err_e | |
729 | ps_ptwrite (const struct ps_prochandle *ph, paddr_t addr, char *buf, int size) | |
730 | { | |
731 | return rw_common (1, ph, addr, buf, size); | |
732 | } | |
733 | ||
734 | ps_err_e | |
735 | ps_lgetregs (const struct ps_prochandle *ph, lwpid_t lwpid, | |
736 | prgregset_t gregset) | |
737 | { | |
738 | int save_pid; | |
739 | ||
740 | save_pid = inferior_pid; | |
741 | ||
742 | inferior_pid = (lwpid << 16) | (inferior_pid & 0xffff); | |
743 | ||
744 | procfs_ops.to_fetch_registers (-1); | |
745 | fill_gregset (gregset, -1); | |
746 | ||
747 | inferior_pid = save_pid; | |
748 | ||
749 | return PS_OK; | |
750 | } | |
751 | ||
752 | ps_err_e | |
753 | ps_lsetregs (const struct ps_prochandle *ph, lwpid_t lwpid, | |
754 | const prgregset_t gregset) | |
755 | { | |
756 | int save_pid; | |
757 | ||
758 | save_pid = inferior_pid; | |
759 | ||
760 | inferior_pid = (lwpid << 16) | (inferior_pid & 0xffff); | |
761 | ||
762 | supply_gregset (gregset); | |
763 | procfs_ops.to_store_registers (-1); | |
764 | ||
765 | inferior_pid = save_pid; | |
766 | ||
767 | return PS_OK; | |
768 | } | |
769 | ||
770 | void | |
771 | ps_plog (const char *fmt, ...) | |
772 | { | |
773 | va_list args; | |
774 | ||
775 | va_start (args, fmt); | |
776 | ||
777 | vfprintf_filtered (gdb_stderr, fmt, args); | |
778 | } | |
779 | ||
780 | ps_err_e | |
781 | ps_lgetxregsize (const struct ps_prochandle *ph, lwpid_t lwpid, int *xregsize) | |
782 | { | |
783 | int lwp_fd; | |
784 | int regsize; | |
785 | ps_err_e val; | |
786 | ||
787 | #if 0 | |
788 | val = get_lwp_fd (ph, lwpid, &lwp_fd); | |
789 | if (val != PS_OK) | |
790 | return val; | |
791 | ||
792 | if (ioctl (lwp_fd, PIOCGXREGSIZE, ®size)) | |
793 | { | |
794 | if (errno == EINVAL) | |
795 | return PS_NOFREGS; /* XXX Wrong code, but this is the closest | |
796 | thing in proc_service.h */ | |
797 | ||
798 | print_sys_errmsg ("ps_lgetxregsize (): PIOCGXREGSIZE", errno); | |
799 | return PS_ERR; | |
800 | } | |
801 | #endif | |
802 | ||
803 | return PS_OK; | |
804 | } | |
805 | ||
806 | ps_err_e | |
807 | ps_lgetxregs (const struct ps_prochandle *ph, lwpid_t lwpid, caddr_t xregset) | |
808 | { | |
809 | int lwp_fd; | |
810 | ps_err_e val; | |
811 | ||
812 | #if 0 | |
813 | val = get_lwp_fd (ph, lwpid, &lwp_fd); | |
814 | if (val != PS_OK) | |
815 | return val; | |
816 | ||
817 | if (ioctl (lwp_fd, PIOCGXREG, xregset)) | |
818 | { | |
819 | print_sys_errmsg ("ps_lgetxregs (): PIOCGXREG", errno); | |
820 | return PS_ERR; | |
821 | } | |
822 | #endif | |
823 | ||
824 | return PS_OK; | |
825 | } | |
826 | ||
827 | ps_err_e | |
828 | ps_lsetxregs (const struct ps_prochandle *ph, lwpid_t lwpid, caddr_t xregset) | |
829 | { | |
830 | int lwp_fd; | |
831 | ps_err_e val; | |
832 | ||
833 | #if 0 | |
834 | val = get_lwp_fd (ph, lwpid, &lwp_fd); | |
835 | if (val != PS_OK) | |
836 | return val; | |
837 | ||
838 | if (ioctl (lwp_fd, PIOCSXREG, xregset)) | |
839 | { | |
840 | print_sys_errmsg ("ps_lsetxregs (): PIOCSXREG", errno); | |
841 | return PS_ERR; | |
842 | } | |
843 | #endif | |
844 | ||
845 | return PS_OK; | |
846 | } | |
847 | ||
848 | ps_err_e | |
849 | ps_lgetfpregs (const struct ps_prochandle *ph, lwpid_t lwpid, | |
850 | prfpregset_t *fpregset) | |
851 | { | |
852 | int save_pid; | |
853 | ||
854 | save_pid = inferior_pid; | |
855 | ||
856 | inferior_pid = (lwpid << 16) | (inferior_pid & 0xffff); | |
857 | ||
858 | procfs_ops.to_fetch_registers (-1); | |
859 | fill_fpregset (fpregset, -1); | |
860 | ||
861 | inferior_pid = save_pid; | |
862 | ||
863 | return PS_OK; | |
864 | } | |
865 | ||
866 | ps_err_e | |
867 | ps_lsetfpregs (const struct ps_prochandle *ph, lwpid_t lwpid, | |
868 | const prfpregset_t *fpregset) | |
869 | { | |
870 | int save_pid; | |
871 | ||
872 | save_pid = inferior_pid; | |
873 | ||
874 | inferior_pid = (lwpid << 16) | (inferior_pid & 0xffff); | |
875 | ||
876 | supply_gregset (fpregset); | |
877 | procfs_ops.to_store_registers (-1); | |
878 | ||
879 | inferior_pid = save_pid; | |
880 | ||
881 | return PS_OK; | |
882 | } | |
883 | \f | |
884 | char * | |
885 | solaris_pid_to_str (pid) | |
886 | int pid; | |
887 | { | |
888 | static char buf[100]; | |
889 | ||
890 | if (pid & 0x80000000) | |
891 | { | |
892 | int lwp; | |
893 | ||
894 | lwp = thread_to_lwp (pid, -2); | |
895 | ||
896 | if (lwp != -2) | |
897 | sprintf (buf, "Thread %d (LWP %d)", (pid >> 16) & 0x7fff, | |
898 | (lwp >> 16) & 0xffff); | |
899 | else | |
900 | sprintf (buf, "Thread %d ", (pid >> 16) & 0x7fff); | |
901 | } | |
902 | else | |
903 | sprintf (buf, "LWP %d ", (pid >> 16) & 0xffff); | |
904 | ||
905 | return buf; | |
906 | } | |
907 | \f | |
908 | struct target_ops sol_thread_ops = { | |
909 | "solaris-threads", /* to_shortname */ | |
910 | "Solaris threads and pthread.", /* to_longname */ | |
911 | "Solaris threads and pthread support.", /* to_doc */ | |
912 | sol_thread_open, /* to_open */ | |
913 | 0, /* to_close */ | |
914 | sol_thread_attach, /* to_attach */ | |
915 | sol_thread_detach, /* to_detach */ | |
916 | sol_thread_resume, /* to_resume */ | |
917 | sol_thread_wait, /* to_wait */ | |
918 | sol_thread_fetch_registers, /* to_fetch_registers */ | |
919 | sol_thread_store_registers, /* to_store_registers */ | |
920 | sol_thread_prepare_to_store, /* to_prepare_to_store */ | |
921 | sol_thread_xfer_memory, /* to_xfer_memory */ | |
922 | sol_thread_files_info, /* to_files_info */ | |
923 | memory_insert_breakpoint, /* to_insert_breakpoint */ | |
924 | memory_remove_breakpoint, /* to_remove_breakpoint */ | |
925 | terminal_init_inferior, /* to_terminal_init */ | |
926 | terminal_inferior, /* to_terminal_inferior */ | |
927 | terminal_ours_for_output, /* to_terminal_ours_for_output */ | |
928 | terminal_ours, /* to_terminal_ours */ | |
929 | child_terminal_info, /* to_terminal_info */ | |
930 | sol_thread_kill_inferior, /* to_kill */ | |
931 | 0, /* to_load */ | |
932 | 0, /* to_lookup_symbol */ | |
933 | sol_thread_create_inferior, /* to_create_inferior */ | |
934 | sol_thread_mourn_inferior, /* to_mourn_inferior */ | |
935 | sol_thread_can_run, /* to_can_run */ | |
936 | sol_thread_notice_signals, /* to_notice_signals */ | |
937 | sol_thread_alive, /* to_thread_alive */ | |
938 | sol_thread_stop, /* to_stop */ | |
939 | process_stratum, /* to_stratum */ | |
940 | 0, /* to_next */ | |
941 | 1, /* to_has_all_memory */ | |
942 | 1, /* to_has_memory */ | |
943 | 1, /* to_has_stack */ | |
944 | 1, /* to_has_registers */ | |
945 | 1, /* to_has_execution */ | |
946 | 0, /* sections */ | |
947 | 0, /* sections_end */ | |
948 | OPS_MAGIC /* to_magic */ | |
949 | }; | |
950 | ||
951 | void | |
952 | _initialize_sol_thread () | |
953 | { | |
954 | add_target (&sol_thread_ops); | |
955 | ||
956 | procfs_suppress_run = 1; | |
957 | } |