1/* Low level interface for debugging HPUX/DCE threads for GDB, the GNU 2 debugger. 3 4 Copyright (C) 1996, 1998, 1999, 2000, 2001, 2004, 2007 5 Free Software Foundation, Inc. 6 7 This file is part of GDB. 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 3 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 21 22/* This module implements a sort of half target that sits between the 23 machine-independent parts of GDB and the ptrace interface (infptrace.c) to 24 provide access to the HPUX user-mode thread implementation. 25 26 HPUX threads are true user-mode threads, which are invoked via the cma_* 27 and pthread_* (DCE and Posix respectivly) interfaces. These are mostly 28 implemented in user-space, with all thread context kept in various 29 structures that live in the user's heap. For the most part, the kernel has 30 no knowlege of these threads. 31 32 */ 33 34#include "defs.h" 35 36#define _CMA_NOWRAPPERS_ 37 38#include <cma_tcb_defs.h> 39#include <cma_deb_core.h> 40#include "gdbthread.h" 41#include "target.h" 42#include "inferior.h" 43#include "regcache.h" 44#include <fcntl.h> 45#include <string.h> 46#include "gdb_stat.h" 47#include "gdbcore.h" 48#include "hppa-tdep.h" 49#include "observer.h" 50 51extern int child_suppress_run; 52 53extern void _initialize_hpux_thread (void); 54 55struct string_map 56 { 57 int num; 58 char *str; 59 }; 60 61static int hpux_thread_active = 0; 62 63static ptid_t main_ptid; /* Real process ID */ 64 65static CORE_ADDR P_cma__g_known_threads; 66static CORE_ADDR P_cma__g_current_thread; 67 68static void hpux_thread_resume (ptid_t ptid, int step, 69 enum target_signal signo); 70 71static void init_hpux_thread_ops (void); 72 73static struct target_ops hpux_thread_ops; 74 75static ptid_t find_active_thread (void); 76 77static int cached_thread; 78static cma__t_int_tcb cached_tcb; 79 80static ptid_t 81find_active_thread (void) 82{ 83 static cma__t_int_tcb tcb; 84 CORE_ADDR tcb_ptr; 85 86 read_memory ((CORE_ADDR) P_cma__g_current_thread, 87 (char *) &tcb_ptr, 88 sizeof tcb_ptr); 89 90 read_memory (tcb_ptr, (char *) &tcb, sizeof tcb); 91 92 return (ptid_build (PIDGET (main_ptid), 0, 93 cma_thread_get_unique (&tcb.prolog.client_thread))); 94} 95 96static cma__t_int_tcb *find_tcb (ptid_t ptid); 97 98static cma__t_int_tcb * 99find_tcb (ptid_t ptid) 100{ 101 cma__t_known_object queue_header; 102 cma__t_queue *queue_ptr; 103 int thread = ptid_get_tid (ptid); 104 105 if (thread == cached_thread) 106 return &cached_tcb; 107 108 read_memory ((CORE_ADDR) P_cma__g_known_threads, 109 (char *) &queue_header, 110 sizeof queue_header); 111 112 for (queue_ptr = queue_header.queue.flink; 113 queue_ptr != (cma__t_queue *) P_cma__g_known_threads; 114 queue_ptr = cached_tcb.threads.flink) 115 { 116 cma__t_int_tcb *tcb_ptr; 117 118 tcb_ptr = cma__base (queue_ptr, threads, cma__t_int_tcb); 119 120 read_memory ((CORE_ADDR) tcb_ptr, (char *) &cached_tcb, sizeof cached_tcb); 121 122 if (cached_tcb.header.type == cma__c_obj_tcb) 123 if (cma_thread_get_unique (&cached_tcb.prolog.client_thread) == thread) 124 { 125 cached_thread = thread; 126 return &cached_tcb; 127 } 128 } 129 130 error (_("Can't find TCB %d"), thread); 131 return NULL; 132} 133 134/* Most target vector functions from here on actually just pass through to 135 inftarg.c, as they don't need to do anything specific for threads. */ 136 137static void 138hpux_thread_open (char *arg, int from_tty) 139{ 140 deprecated_child_ops.to_open (arg, from_tty); 141} 142 143/* Attach to process PID, then initialize for debugging it 144 and wait for the trace-trap that results from attaching. */ 145 146static void 147hpux_thread_attach (char *args, int from_tty) 148{ 149 deprecated_child_ops.to_attach (args, from_tty); 150 151 /* XXX - might want to iterate over all the threads and register them. */ 152} 153 154/* Take a program previously attached to and detaches it. 155 The program resumes execution and will no longer stop 156 on signals, etc. We'd better not have left any breakpoints 157 in the program or it'll die when it hits one. For this 158 to work, it may be necessary for the process to have been 159 previously attached. It *might* work if the program was 160 started via the normal ptrace (PTRACE_TRACEME). */ 161 162static void 163hpux_thread_detach (char *args, int from_tty) 164{ 165 deprecated_child_ops.to_detach (args, from_tty); 166} 167 168/* Resume execution of process PID. If STEP is nozero, then 169 just single step it. If SIGNAL is nonzero, restart it with that 170 signal activated. We may have to convert pid from a thread-id to an LWP id 171 for procfs. */ 172 173static void 174hpux_thread_resume (ptid_t ptid, int step, enum target_signal signo) 175{ 176 struct cleanup *old_chain; 177 178 old_chain = save_inferior_ptid (); 179 180 ptid = main_ptid; 181 inferior_ptid = main_ptid; 182 183#if 0 184 if (pid != -1) 185 { 186 pid = thread_to_lwp (pid, -2); 187 if (pid == -2) /* Inactive thread */ 188 error (_("This version of Solaris can't start inactive threads.")); 189 } 190#endif 191 192 deprecated_child_ops.to_resume (ptid, step, signo); 193 194 cached_thread = 0; 195 196 do_cleanups (old_chain); 197} 198 199/* Wait for any threads to stop. We may have to convert PID from a thread id 200 to a LWP id, and vice versa on the way out. */ 201 202static ptid_t 203hpux_thread_wait (ptid_t ptid, struct target_waitstatus *ourstatus) 204{ 205 ptid_t rtnval; 206 struct cleanup *old_chain; 207 208 old_chain = save_inferior_ptid (); 209 210 inferior_ptid = main_ptid; 211 212 if (!ptid_equal (ptid, minus_one_ptid)) 213 ptid = main_ptid; 214 215 rtnval = deprecated_child_ops.to_wait (ptid, ourstatus); 216 217 rtnval = find_active_thread (); 218 219 do_cleanups (old_chain); 220 221 return rtnval; 222} 223 224static char regmap[] = 225{ 226 -2, -1, -1, 0, 4, 8, 12, 16, 20, 24, /* flags, r1 -> r9 */ 227 28, 32, 36, 40, 44, 48, 52, 56, 60, -1, /* r10 -> r19 */ 228 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* r20 -> r29 */ 229 230 /* r30, r31, sar, pcoqh, pcsqh, pcoqt, pcsqt, eiem, iir, isr */ 231 -2, -1, -1, -2, -1, -1, -1, -1, -1, -1, 232 233 /* ior, ipsw, goto, sr4, sr0, sr1, sr2, sr3, sr5, sr6 */ 234 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 235 236 /* sr7, cr0, cr8, cr9, ccr, cr12, cr13, cr24, cr25, cr26 */ 237 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 238 239 -1, -1, -1, -1, /* mpsfu_high, mpsfu_low, mpsfu_ovflo, pad */ 240 144, -1, -1, -1, -1, -1, -1, -1, /* fpsr, fpe1 -> fpe7 */ 241 -1, -1, -1, -1, -1, -1, -1, -1, /* fr4 -> fr7 */ 242 -1, -1, -1, -1, -1, -1, -1, -1, /* fr8 -> fr11 */ 243 136, -1, 128, -1, 120, -1, 112, -1, /* fr12 -> fr15 */ 244 104, -1, 96, -1, 88, -1, 80, -1, /* fr16 -> fr19 */ 245 72, -1, 64, -1, -1, -1, -1, -1, /* fr20 -> fr23 */ 246 -1, -1, -1, -1, -1, -1, -1, -1, /* fr24 -> fr27 */ 247 -1, -1, -1, -1, -1, -1, -1, -1, /* fr28 -> fr31 */ 248}; 249 250static void 251hpux_thread_fetch_registers (struct regcache *regcache, int regno) 252{ 253 cma__t_int_tcb tcb, *tcb_ptr; 254 struct cleanup *old_chain; 255 int i; 256 int first_regno, last_regno; 257 258 tcb_ptr = find_tcb (inferior_ptid); 259 260 old_chain = save_inferior_ptid (); 261 262 inferior_ptid = main_ptid; 263 264 if (tcb_ptr->state == cma__c_state_running) 265 { 266 deprecated_child_ops.to_fetch_registers (regcache, regno); 267 268 do_cleanups (old_chain); 269 270 return; 271 } 272 273 if (regno == -1) 274 { 275 first_regno = 0; 276 last_regno = gdbarch_num_regs (current_gdbarch) - 1; 277 } 278 else 279 { 280 first_regno = regno; 281 last_regno = regno; 282 } 283 284 for (regno = first_regno; regno <= last_regno; regno++) 285 { 286 if (regmap[regno] == -1) 287 deprecated_child_ops.to_fetch_registers (regcache, regno); 288 else 289 { 290 unsigned char buf[MAX_REGISTER_SIZE]; 291 CORE_ADDR sp; 292 293 sp = (CORE_ADDR) tcb_ptr->static_ctx.sp - 160; 294 295 if (regno == HPPA_FLAGS_REGNUM) 296 /* Flags must be 0 to avoid bogus value for SS_INSYSCALL */ 297 memset (buf, '\000', register_size (current_gdbarch, regno)); 298 else if (regno == HPPA_SP_REGNUM) 299 store_unsigned_integer (buf, sizeof sp, sp); 300 else if (regno == HPPA_PCOQ_HEAD_REGNUM) 301 read_memory (sp - 20, buf, register_size (current_gdbarch, regno)); 302 else 303 read_memory (sp + regmap[regno], buf, register_size (current_gdbarch, regno)); 304 305 regcache_raw_supply (regcache, regno, buf); 306 } 307 } 308 309 do_cleanups (old_chain); 310} 311 312static void 313hpux_thread_store_registers (struct regcache *regcache, int regno) 314{ 315 cma__t_int_tcb tcb, *tcb_ptr; 316 struct cleanup *old_chain; 317 int i; 318 int first_regno, last_regno; 319 320 tcb_ptr = find_tcb (inferior_ptid); 321 322 old_chain = save_inferior_ptid (); 323 324 inferior_ptid = main_ptid; 325 326 if (tcb_ptr->state == cma__c_state_running) 327 { 328 deprecated_child_ops.to_store_registers (regcache, regno); 329 330 do_cleanups (old_chain); 331 332 return; 333 } 334 335 if (regno == -1) 336 { 337 first_regno = 0; 338 last_regno = gdbarch_num_regs (current_gdbarch) - 1; 339 } 340 else 341 { 342 first_regno = regno; 343 last_regno = regno; 344 } 345 346 for (regno = first_regno; regno <= last_regno; regno++) 347 { 348 if (regmap[regno] == -1) 349 deprecated_child_ops.to_store_registers (regcache, regno); 350 else 351 { 352 unsigned char buf[MAX_REGISTER_SIZE]; 353 CORE_ADDR sp; 354 355 sp = (CORE_ADDR) tcb_ptr->static_ctx.sp - 160; 356 357 if (regno == HPPA_FLAGS_REGNUM) 358 deprecated_child_ops.to_store_registers (regcache, regno); /* Let lower layer handle this... */ 359 else if (regno == HPPA_SP_REGNUM) 360 { 361 regcache_raw_collect (regcache, regno, buf); 362 write_memory ((CORE_ADDR) &tcb_ptr->static_ctx.sp, buf, 363 register_size (current_gdbarch, regno)); 364 tcb_ptr->static_ctx.sp 365 = (cma__t_hppa_regs *) ((CORE_ADDR) buf + 160); 366 } 367 else if (regno == HPPA_PCOQ_HEAD_REGNUM) 368 { 369 regcache_raw_collect (regcache, regno, buf); 370 write_memory (sp - 20, buf, 371 register_size (current_gdbarch, regno)); 372 } 373 else 374 { 375 regcache_raw_collect (regcache, regno, buf); 376 write_memory (sp + regmap[regno], buf, 377 register_size (current_gdbarch, regno)); 378 } 379 } 380 } 381 382 do_cleanups (old_chain); 383} 384 385/* Get ready to modify the registers array. On machines which store 386 individual registers, this doesn't need to do anything. On machines 387 which store all the registers in one fell swoop, this makes sure 388 that registers contains all the registers from the program being 389 debugged. */ 390 391static void 392hpux_thread_prepare_to_store (struct regcache *regcache) 393{ 394 deprecated_child_ops.to_prepare_to_store (regcache); 395} 396 397static int 398hpux_thread_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, 399 int dowrite, struct mem_attrib *attribs, 400 struct target_ops *target) 401{ 402 int retval; 403 struct cleanup *old_chain; 404 405 old_chain = save_inferior_ptid (); 406 407 inferior_ptid = main_ptid; 408 409 retval = 410 deprecated_child_ops.deprecated_xfer_memory (memaddr, myaddr, len, dowrite, attribs, target); 411 412 do_cleanups (old_chain); 413 414 return retval; 415} 416 417/* Print status information about what we're accessing. */ 418 419static void 420hpux_thread_files_info (struct target_ops *ignore) 421{ 422 deprecated_child_ops.to_files_info (ignore); 423} 424 425static void 426hpux_thread_kill_inferior (void) 427{ 428 deprecated_child_ops.to_kill (); 429} 430 431static void 432hpux_thread_notice_signals (ptid_t ptid) 433{ 434 deprecated_child_ops.to_notice_signals (ptid); 435} 436 437/* Fork an inferior process, and start debugging it with /proc. */ 438 439static void 440hpux_thread_create_inferior (char *exec_file, char *allargs, char **env, 441 int from_tty) 442{ 443 deprecated_child_ops.to_create_inferior (exec_file, allargs, env, from_tty); 444 445 if (hpux_thread_active) 446 { 447 main_ptid = inferior_ptid; 448 449 push_target (&hpux_thread_ops); 450 451 inferior_ptid = find_active_thread (); 452 453 add_thread (inferior_ptid); 454 } 455} 456 457/* This routine is called whenever a new symbol table is read in, or when all 458 symbol tables are removed. libthread_db can only be initialized when it 459 finds the right variables in libthread.so. Since it's a shared library, 460 those variables don't show up until the library gets mapped and the symbol 461 table is read in. */ 462 463static void 464hpux_thread_new_objfile (struct objfile *objfile) 465{ 466 struct minimal_symbol *ms; 467 468 if (!objfile) 469 { 470 hpux_thread_active = 0; 471 return; 472 } 473 474 ms = lookup_minimal_symbol ("cma__g_known_threads", NULL, objfile); 475 476 if (!ms) 477 return; 478 479 P_cma__g_known_threads = SYMBOL_VALUE_ADDRESS (ms); 480 481 ms = lookup_minimal_symbol ("cma__g_current_thread", NULL, objfile); 482 483 if (!ms) 484 return; 485 486 P_cma__g_current_thread = SYMBOL_VALUE_ADDRESS (ms); 487 488 hpux_thread_active = 1; 489} 490 491/* Clean up after the inferior dies. */ 492 493static void 494hpux_thread_mourn_inferior (void) 495{ 496 deprecated_child_ops.to_mourn_inferior (); 497} 498 499/* Mark our target-struct as eligible for stray "run" and "attach" commands. */ 500 501static int 502hpux_thread_can_run (void) 503{ 504 return child_suppress_run; 505} 506 507static int 508hpux_thread_alive (ptid_t ptid) 509{ 510 return 1; 511} 512 513static void 514hpux_thread_stop (void) 515{ 516 deprecated_child_ops.to_stop (); 517} 518 519/* Convert a pid to printable form. */ 520 521char * 522hpux_pid_to_str (ptid_t ptid) 523{ 524 static char buf[100]; 525 int pid = PIDGET (ptid); 526 527 sprintf (buf, "Thread %ld", ptid_get_tid (ptid)); 528 529 return buf; 530} 531 532static void 533init_hpux_thread_ops (void) 534{ 535 hpux_thread_ops.to_shortname = "hpux-threads"; 536 hpux_thread_ops.to_longname = "HPUX threads and pthread."; 537 hpux_thread_ops.to_doc = "HPUX threads and pthread support."; 538 hpux_thread_ops.to_open = hpux_thread_open; 539 hpux_thread_ops.to_attach = hpux_thread_attach; 540 hpux_thread_ops.to_detach = hpux_thread_detach; 541 hpux_thread_ops.to_resume = hpux_thread_resume; 542 hpux_thread_ops.to_wait = hpux_thread_wait; 543 hpux_thread_ops.to_fetch_registers = hpux_thread_fetch_registers; 544 hpux_thread_ops.to_store_registers = hpux_thread_store_registers; 545 hpux_thread_ops.to_prepare_to_store = hpux_thread_prepare_to_store; 546 hpux_thread_ops.deprecated_xfer_memory = hpux_thread_xfer_memory; 547 hpux_thread_ops.to_files_info = hpux_thread_files_info; 548 hpux_thread_ops.to_insert_breakpoint = memory_insert_breakpoint; 549 hpux_thread_ops.to_remove_breakpoint = memory_remove_breakpoint; 550 hpux_thread_ops.to_terminal_init = terminal_init_inferior; 551 hpux_thread_ops.to_terminal_inferior = terminal_inferior; 552 hpux_thread_ops.to_terminal_ours_for_output = terminal_ours_for_output; 553 hpux_thread_ops.to_terminal_save_ours = terminal_save_ours; 554 hpux_thread_ops.to_terminal_ours = terminal_ours; 555 hpux_thread_ops.to_terminal_info = child_terminal_info; 556 hpux_thread_ops.to_kill = hpux_thread_kill_inferior; 557 hpux_thread_ops.to_create_inferior = hpux_thread_create_inferior; 558 hpux_thread_ops.to_mourn_inferior = hpux_thread_mourn_inferior; 559 hpux_thread_ops.to_can_run = hpux_thread_can_run; 560 hpux_thread_ops.to_notice_signals = hpux_thread_notice_signals; 561 hpux_thread_ops.to_thread_alive = hpux_thread_alive; 562 hpux_thread_ops.to_stop = hpux_thread_stop; 563 hpux_thread_ops.to_stratum = process_stratum; 564 hpux_thread_ops.to_has_all_memory = 1; 565 hpux_thread_ops.to_has_memory = 1; 566 hpux_thread_ops.to_has_stack = 1; 567 hpux_thread_ops.to_has_registers = 1; 568 hpux_thread_ops.to_has_execution = 1; 569 hpux_thread_ops.to_magic = OPS_MAGIC; 570} 571 572void 573_initialize_hpux_thread (void) 574{ 575 init_hpux_thread_ops (); 576 add_target (&hpux_thread_ops); 577 578 child_suppress_run = 1; 579 /* Hook into new_objfile notification. */ 580 observer_attach_new_objfile (hpux_thread_new_objfile); 581} 582