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