1 /* 2 * Copyright 2005-2006, Ingo Weinhold, bonefish@users.sf.net. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include <signal.h> 7 #include <stdlib.h> 8 #include <stdio.h> 9 #include <string.h> 10 11 #include <debugger.h> 12 #include <kernel.h> 13 #include <KernelExport.h> 14 #include <kscheduler.h> 15 #include <ksignal.h> 16 #include <ksyscalls.h> 17 #include <sem.h> 18 #include <team.h> 19 #include <thread.h> 20 #include <thread_types.h> 21 #include <user_debugger.h> 22 #include <vm.h> 23 #include <vm_types.h> 24 #include <arch/user_debugger.h> 25 26 //#define TRACE_USER_DEBUGGER 27 #ifdef TRACE_USER_DEBUGGER 28 # define TRACE(x) dprintf x 29 #else 30 # define TRACE(x) ; 31 #endif 32 33 34 static port_id sDefaultDebuggerPort = -1; 35 // accessed atomically 36 37 38 static status_t ensure_debugger_installed(team_id teamID, port_id *port = NULL); 39 static void get_team_debug_info(team_debug_info &teamDebugInfo); 40 41 42 static ssize_t 43 kill_interruptable_read_port(port_id port, int32 *code, void *buffer, 44 size_t bufferSize) 45 { 46 return read_port_etc(port, code, buffer, bufferSize, 47 B_KILL_CAN_INTERRUPT, 0); 48 } 49 50 51 static status_t 52 kill_interruptable_write_port(port_id port, int32 code, const void *buffer, 53 size_t bufferSize) 54 { 55 return write_port_etc(port, code, buffer, bufferSize, 56 B_KILL_CAN_INTERRUPT, 0); 57 } 58 59 60 static status_t 61 debugger_write(port_id port, int32 code, const void *buffer, size_t bufferSize, 62 bool dontWait) 63 { 64 TRACE(("debugger_write(): thread: %ld, team %ld, port: %ld, code: %lx, message: %p, " 65 "size: %lu, dontWait: %d\n", thread_get_current_thread()->id, 66 thread_get_current_thread()->team->id, port, code, buffer, bufferSize, 67 dontWait)); 68 69 status_t error = B_OK; 70 71 // get the team debug info 72 team_debug_info teamDebugInfo; 73 get_team_debug_info(teamDebugInfo); 74 sem_id writeLock = teamDebugInfo.debugger_write_lock; 75 76 // get the write lock 77 TRACE(("debugger_write(): acquiring write lock...\n")); 78 error = acquire_sem_etc(writeLock, 1, 79 dontWait ? (uint32)B_RELATIVE_TIMEOUT : (uint32)B_KILL_CAN_INTERRUPT, 0); 80 if (error != B_OK) { 81 TRACE(("debugger_write() done1: %lx\n", error)); 82 return error; 83 } 84 85 // re-get the team debug info 86 get_team_debug_info(teamDebugInfo); 87 88 if (teamDebugInfo.debugger_port != port 89 || (teamDebugInfo.flags & B_TEAM_DEBUG_DEBUGGER_HANDOVER)) { 90 // The debugger has changed in the meantime or we are about to be 91 // handed over to a new debugger. In either case we don't send the 92 // message. 93 TRACE(("debugger_write(): %s\n", 94 (teamDebugInfo.debugger_port != port ? "debugger port changed" 95 : "handover flag set"))); 96 } else { 97 TRACE(("debugger_write(): writing to port...\n")); 98 99 error = write_port_etc(port, code, buffer, bufferSize, 100 dontWait ? (uint32)B_RELATIVE_TIMEOUT : (uint32)B_KILL_CAN_INTERRUPT, 0); 101 } 102 103 // release the write lock 104 release_sem(writeLock); 105 106 TRACE(("debugger_write() done: %lx\n", error)); 107 108 return error; 109 } 110 111 112 /** 113 * For the first initialization the function must be called with \a initLock 114 * set to \c true. If it would be possible that another thread accesses the 115 * structure at the same time, `lock' must be held when calling the function. 116 */ 117 void 118 clear_team_debug_info(struct team_debug_info *info, bool initLock) 119 { 120 if (info) { 121 arch_clear_team_debug_info(&info->arch_info); 122 atomic_set(&info->flags, B_TEAM_DEBUG_DEFAULT_FLAGS); 123 info->debugger_team = -1; 124 info->debugger_port = -1; 125 info->nub_thread = -1; 126 info->nub_port = -1; 127 info->debugger_write_lock = -1; 128 129 if (initLock) 130 info->lock = 0; 131 } 132 } 133 134 /** 135 * `lock' must not be held nor may interrupts be disabled. 136 * \a info must not be a member of a team struct (or the team struct must no 137 * longer be accessible, i.e. the team should already be removed). 138 * 139 * In case the team is still accessible, the procedure is: 140 * 1. get `lock' 141 * 2. copy the team debug info on stack 142 * 3. call clear_team_debug_info() on the team debug info 143 * 4. release `lock' 144 * 5. call destroy_team_debug_info() on the copied team debug info 145 */ 146 void 147 destroy_team_debug_info(struct team_debug_info *info) 148 { 149 if (info) { 150 arch_destroy_team_debug_info(&info->arch_info); 151 152 // delete the debugger port write lock 153 if (info->debugger_write_lock >= 0) { 154 delete_sem(info->debugger_write_lock); 155 info->debugger_write_lock = -1; 156 } 157 158 // delete the nub port 159 if (info->nub_port >= 0) { 160 set_port_owner(info->nub_port, B_CURRENT_TEAM); 161 delete_port(info->nub_port); 162 info->nub_port = -1; 163 } 164 165 // wait for the nub thread 166 if (info->nub_thread >= 0) { 167 if (info->nub_thread != thread_get_current_thread()->id) { 168 int32 result; 169 wait_for_thread(info->nub_thread, &result); 170 } 171 172 info->nub_thread = -1; 173 } 174 175 atomic_set(&info->flags, 0); 176 info->debugger_team = -1; 177 info->debugger_port = -1; 178 } 179 } 180 181 182 void 183 clear_thread_debug_info(struct thread_debug_info *info, bool dying) 184 { 185 if (info) { 186 arch_clear_thread_debug_info(&info->arch_info); 187 atomic_set(&info->flags, 188 B_THREAD_DEBUG_DEFAULT_FLAGS | (dying ? B_THREAD_DEBUG_DYING : 0)); 189 info->debug_port = -1; 190 info->ignore_signals = 0; 191 info->ignore_signals_once = 0; 192 } 193 } 194 195 196 void 197 destroy_thread_debug_info(struct thread_debug_info *info) 198 { 199 if (info) { 200 arch_destroy_thread_debug_info(&info->arch_info); 201 202 if (info->debug_port >= 0) { 203 delete_port(info->debug_port); 204 info->debug_port = -1; 205 } 206 207 info->ignore_signals = 0; 208 info->ignore_signals_once = 0; 209 210 atomic_set(&info->flags, 0); 211 } 212 } 213 214 215 void 216 user_debug_prepare_for_exec() 217 { 218 struct thread *thread = thread_get_current_thread(); 219 struct team *team = thread->team; 220 221 // If a debugger is installed for the team and the thread debug stuff 222 // initialized, changed the ownership of the debug port for the thread 223 // to the kernel team, since exec_team() deletes all ports owned by this 224 // team. We change the ownership back later. 225 if (atomic_get(&team->debug_info.flags) & B_TEAM_DEBUG_DEBUGGER_INSTALLED) { 226 // get the port 227 port_id debugPort = -1; 228 229 cpu_status state = disable_interrupts(); 230 GRAB_THREAD_LOCK(); 231 232 if (thread->debug_info.flags & B_THREAD_DEBUG_INITIALIZED) 233 debugPort = thread->debug_info.debug_port; 234 235 RELEASE_THREAD_LOCK(); 236 restore_interrupts(state); 237 238 // set the new port ownership 239 if (debugPort >= 0) 240 set_port_owner(debugPort, team_get_kernel_team_id()); 241 } 242 } 243 244 245 void 246 user_debug_finish_after_exec() 247 { 248 struct thread *thread = thread_get_current_thread(); 249 struct team *team = thread->team; 250 251 // If a debugger is installed for the team and the thread debug stuff 252 // initialized for this thread, change the ownership of its debug port 253 // back to this team. 254 if (atomic_get(&team->debug_info.flags) & B_TEAM_DEBUG_DEBUGGER_INSTALLED) { 255 // get the port 256 port_id debugPort = -1; 257 258 cpu_status state = disable_interrupts(); 259 GRAB_THREAD_LOCK(); 260 261 if (thread->debug_info.flags & B_THREAD_DEBUG_INITIALIZED) 262 debugPort = thread->debug_info.debug_port; 263 264 RELEASE_THREAD_LOCK(); 265 restore_interrupts(state); 266 267 // set the new port ownership 268 if (debugPort >= 0) 269 set_port_owner(debugPort, team->id); 270 } 271 } 272 273 274 void 275 init_user_debug() 276 { 277 #ifdef ARCH_INIT_USER_DEBUG 278 ARCH_INIT_USER_DEBUG(); 279 #endif 280 } 281 282 283 static void 284 get_team_debug_info(team_debug_info &teamDebugInfo) 285 { 286 struct thread *thread = thread_get_current_thread(); 287 288 cpu_status state = disable_interrupts(); 289 GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 290 291 memcpy(&teamDebugInfo, &thread->team->debug_info, sizeof(team_debug_info)); 292 293 RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 294 restore_interrupts(state); 295 } 296 297 298 static status_t 299 thread_hit_debug_event_internal(debug_debugger_message event, 300 const void *message, int32 size, bool requireDebugger, bool &restart) 301 { 302 restart = false; 303 struct thread *thread = thread_get_current_thread(); 304 305 TRACE(("thread_hit_debug_event(): thread: %ld, event: %lu, message: %p, " 306 "size: %ld\n", thread->id, (uint32)event, message, size)); 307 308 // check, if there's a debug port already 309 bool setPort = !(atomic_get(&thread->debug_info.flags) 310 & B_THREAD_DEBUG_INITIALIZED); 311 312 // create a port, if there is none yet 313 port_id port = -1; 314 if (setPort) { 315 char nameBuffer[128]; 316 snprintf(nameBuffer, sizeof(nameBuffer), "nub to thread %ld", 317 thread->id); 318 319 port = create_port(1, nameBuffer); 320 if (port < 0) { 321 dprintf("thread_hit_debug_event(): Failed to create debug port: " 322 "%s\n", strerror(port)); 323 return port; 324 } 325 326 setPort = true; 327 } 328 329 // check the debug info structures once more: get the debugger port, set 330 // the thread's debug port, and update the thread's debug flags 331 port_id deletePort = port; 332 port_id debuggerPort = -1; 333 port_id nubPort = -1; 334 status_t error = B_OK; 335 cpu_status state = disable_interrupts(); 336 GRAB_THREAD_LOCK(); 337 GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 338 339 uint32 threadFlags = thread->debug_info.flags; 340 threadFlags &= ~B_THREAD_DEBUG_STOP; 341 bool debuggerInstalled 342 = (thread->team->debug_info.flags & B_TEAM_DEBUG_DEBUGGER_INSTALLED); 343 if (thread->id == thread->team->debug_info.nub_thread) { 344 // Ugh, we're the nub thread. We shouldn't be here. 345 TRACE(("thread_hit_debug_event(): Misdirected nub thread: %ld\n", 346 thread->id)); 347 348 error = B_ERROR; 349 350 } else if (debuggerInstalled || !requireDebugger) { 351 if (debuggerInstalled) { 352 debuggerPort = thread->team->debug_info.debugger_port; 353 nubPort = thread->team->debug_info.nub_port; 354 } 355 356 if (setPort) { 357 if (threadFlags & B_THREAD_DEBUG_INITIALIZED) { 358 // someone created a port for us (the port we've created will 359 // be deleted below) 360 port = thread->debug_info.debug_port; 361 } else { 362 thread->debug_info.debug_port = port; 363 deletePort = -1; // keep the port 364 threadFlags |= B_THREAD_DEBUG_INITIALIZED; 365 } 366 } else { 367 if (threadFlags & B_THREAD_DEBUG_INITIALIZED) { 368 port = thread->debug_info.debug_port; 369 } else { 370 // someone deleted our port 371 error = B_ERROR; 372 } 373 } 374 } else 375 error = B_ERROR; 376 377 // update the flags 378 if (error == B_OK) 379 threadFlags |= B_THREAD_DEBUG_STOPPED; 380 atomic_set(&thread->debug_info.flags, threadFlags); 381 382 RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 383 RELEASE_THREAD_LOCK(); 384 restore_interrupts(state); 385 386 // delete the superfluous port 387 if (deletePort >= 0) 388 delete_port(deletePort); 389 390 if (error != B_OK) { 391 TRACE(("thread_hit_debug_event() error: thread: %ld, error: %lx\n", 392 thread->id, error)); 393 return error; 394 } 395 396 // send a message to the debugger port 397 if (debuggerInstalled) { 398 // update the message's origin info first 399 debug_origin *origin = (debug_origin *)message; 400 origin->thread = thread->id; 401 origin->team = thread->team->id; 402 origin->nub_port = nubPort; 403 404 TRACE(("thread_hit_debug_event(): thread: %ld, sending message to " 405 "debugger port %ld\n", thread->id, debuggerPort)); 406 407 error = debugger_write(debuggerPort, event, message, size, false); 408 } 409 410 status_t result = B_THREAD_DEBUG_HANDLE_EVENT; 411 bool singleStep = false; 412 413 if (error == B_OK) { 414 bool done = false; 415 while (!done) { 416 // read a command from the debug port 417 int32 command; 418 debugged_thread_message_data commandMessage; 419 ssize_t commandMessageSize = kill_interruptable_read_port(port, 420 &command, &commandMessage, sizeof(commandMessage)); 421 if (commandMessageSize < 0) { 422 error = commandMessageSize; 423 TRACE(("thread_hit_debug_event(): thread: %ld, failed " 424 "to receive message from port %ld: %lx\n", 425 thread->id, port, error)); 426 break; 427 } 428 429 switch (command) { 430 case B_DEBUGGED_THREAD_MESSAGE_CONTINUE: 431 TRACE(("thread_hit_debug_event(): thread: %ld: " 432 "B_DEBUGGED_THREAD_MESSAGE_CONTINUE\n", 433 thread->id)); 434 result = commandMessage.continue_thread.handle_event; 435 436 singleStep = commandMessage.continue_thread.single_step; 437 done = true; 438 break; 439 440 case B_DEBUGGED_THREAD_SET_CPU_STATE: 441 { 442 TRACE(("thread_hit_debug_event(): thread: %ld: " 443 "B_DEBUGGED_THREAD_SET_CPU_STATE\n", 444 thread->id)); 445 arch_set_debug_cpu_state( 446 &commandMessage.set_cpu_state.cpu_state); 447 448 break; 449 } 450 451 case B_DEBUGGED_THREAD_GET_CPU_STATE: 452 { 453 port_id replyPort = commandMessage.get_cpu_state.reply_port; 454 455 // prepare the message 456 debug_nub_get_cpu_state_reply replyMessage; 457 replyMessage.error = B_OK; 458 replyMessage.message = event; 459 arch_get_debug_cpu_state(&replyMessage.cpu_state); 460 461 // send it 462 error = kill_interruptable_write_port(replyPort, event, 463 &replyMessage, sizeof(replyMessage)); 464 465 break; 466 } 467 468 case B_DEBUGGED_THREAD_DEBUGGER_CHANGED: 469 { 470 // Check, if the debugger really changed, i.e. is different 471 // than the one we know. 472 team_debug_info teamDebugInfo; 473 get_team_debug_info(teamDebugInfo); 474 475 if (teamDebugInfo.flags & B_TEAM_DEBUG_DEBUGGER_INSTALLED) { 476 if (!debuggerInstalled 477 || teamDebugInfo.debugger_port != debuggerPort) { 478 // debugger was installed or has changed: restart 479 // this function 480 restart = true; 481 done = true; 482 } 483 } else { 484 if (debuggerInstalled) { 485 // debugger is gone: continue the thread normally 486 done = true; 487 } 488 } 489 490 break; 491 } 492 } 493 } 494 } else { 495 TRACE(("thread_hit_debug_event(): thread: %ld, failed to send " 496 "message to debugger port %ld: %lx\n", thread->id, 497 debuggerPort, error)); 498 } 499 500 // update the thread debug info 501 bool destroyThreadInfo = false; 502 thread_debug_info threadDebugInfo; 503 504 state = disable_interrupts(); 505 GRAB_THREAD_LOCK(); 506 507 // check, if the team is still being debugged 508 int32 teamDebugFlags = atomic_get(&thread->team->debug_info.flags); 509 if (teamDebugFlags & B_TEAM_DEBUG_DEBUGGER_INSTALLED) { 510 // update the single-step flag 511 if (singleStep) { 512 atomic_or(&thread->debug_info.flags, 513 B_THREAD_DEBUG_SINGLE_STEP); 514 } else { 515 atomic_and(&thread->debug_info.flags, 516 ~B_THREAD_DEBUG_SINGLE_STEP); 517 } 518 519 // unset the "stopped" state 520 atomic_and(&thread->debug_info.flags, ~B_THREAD_DEBUG_STOPPED); 521 522 } else { 523 // the debugger is gone: cleanup our info completely 524 threadDebugInfo = thread->debug_info; 525 clear_thread_debug_info(&thread->debug_info, false); 526 destroyThreadInfo = true; 527 } 528 529 RELEASE_THREAD_LOCK(); 530 restore_interrupts(state); 531 532 if (destroyThreadInfo) 533 destroy_thread_debug_info(&threadDebugInfo); 534 535 return (error == B_OK ? result : error); 536 } 537 538 539 static status_t 540 thread_hit_debug_event(debug_debugger_message event, const void *message, 541 int32 size, bool requireDebugger) 542 { 543 status_t result; 544 bool restart; 545 do { 546 restart = false; 547 result = thread_hit_debug_event_internal(event, message, size, 548 requireDebugger, restart); 549 } while (result >= 0 && restart); 550 551 return result; 552 } 553 554 555 void 556 user_debug_pre_syscall(uint32 syscall, void *args) 557 { 558 // check whether a debugger is installed 559 struct thread *thread = thread_get_current_thread(); 560 int32 teamDebugFlags = atomic_get(&thread->team->debug_info.flags); 561 if (!(teamDebugFlags & B_TEAM_DEBUG_DEBUGGER_INSTALLED)) 562 return; 563 564 // check whether pre-syscall tracing is enabled for team or thread 565 int32 threadDebugFlags = atomic_get(&thread->debug_info.flags); 566 if (!(teamDebugFlags & B_TEAM_DEBUG_PRE_SYSCALL) 567 && !(threadDebugFlags & B_THREAD_DEBUG_PRE_SYSCALL)) { 568 return; 569 } 570 571 // prepare the message 572 debug_pre_syscall message; 573 message.syscall = syscall; 574 575 // copy the syscall args 576 if (syscall < (uint32)kSyscallCount) { 577 if (kSyscallInfos[syscall].parameter_size > 0) 578 memcpy(message.args, args, kSyscallInfos[syscall].parameter_size); 579 } 580 581 thread_hit_debug_event(B_DEBUGGER_MESSAGE_PRE_SYSCALL, &message, 582 sizeof(message), true); 583 } 584 585 586 void 587 user_debug_post_syscall(uint32 syscall, void *args, uint64 returnValue, 588 bigtime_t startTime) 589 { 590 // check whether a debugger is installed 591 struct thread *thread = thread_get_current_thread(); 592 int32 teamDebugFlags = atomic_get(&thread->team->debug_info.flags); 593 if (!(teamDebugFlags & B_TEAM_DEBUG_DEBUGGER_INSTALLED)) 594 return; 595 596 // check whether post-syscall tracing is enabled for team or thread 597 int32 threadDebugFlags = atomic_get(&thread->debug_info.flags); 598 if (!(teamDebugFlags & B_TEAM_DEBUG_POST_SYSCALL) 599 && !(threadDebugFlags & B_THREAD_DEBUG_POST_SYSCALL)) { 600 return; 601 } 602 603 // prepare the message 604 debug_post_syscall message; 605 message.start_time = startTime; 606 message.end_time = system_time(); 607 message.return_value = returnValue; 608 message.syscall = syscall; 609 610 // copy the syscall args 611 if (syscall < (uint32)kSyscallCount) { 612 if (kSyscallInfos[syscall].parameter_size > 0) 613 memcpy(message.args, args, kSyscallInfos[syscall].parameter_size); 614 } 615 616 thread_hit_debug_event(B_DEBUGGER_MESSAGE_POST_SYSCALL, &message, 617 sizeof(message), true); 618 } 619 620 621 /** \brief To be called when an unhandled processor exception (error/fault) 622 * occurred. 623 * \param exception The debug_why_stopped value identifying the kind of fault. 624 * \param singal The signal corresponding to the exception. 625 * \return \c true, if the caller shall continue normally, i.e. usually send 626 * a deadly signal. \c false, if the debugger insists to continue the 627 * program (e.g. because it has solved the removed the cause of the 628 * problem). 629 */ 630 bool 631 user_debug_exception_occurred(debug_exception_type exception, int signal) 632 { 633 // First check whether there's a signal handler installed for the signal. 634 // If so, we don't want to install a debugger for the team. We always send 635 // the signal instead. An already installed debugger will be notified, if 636 // it has requested notifications of signal. 637 struct sigaction signalAction; 638 if (sigaction(signal, NULL, &signalAction) == B_OK 639 && signalAction.sa_handler != SIG_DFL) { 640 return true; 641 } 642 643 // ensure that a debugger is installed for this team 644 struct thread *thread = thread_get_current_thread(); 645 port_id nubPort; 646 status_t error = ensure_debugger_installed(B_CURRENT_TEAM, &nubPort); 647 if (error != B_OK) { 648 dprintf("user_debug_exception_occurred(): Failed to install debugger: " 649 "thread: %ld: %s\n", thread->id, strerror(error)); 650 return true; 651 } 652 653 // prepare the message 654 debug_exception_occurred message; 655 message.exception = exception; 656 message.signal = signal; 657 658 status_t result = thread_hit_debug_event( 659 B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED, &message, sizeof(message), true); 660 return (result != B_THREAD_DEBUG_IGNORE_EVENT); 661 } 662 663 664 bool 665 user_debug_handle_signal(int signal, struct sigaction *handler, bool deadly) 666 { 667 // check, if a debugger is installed and is interested in signals 668 struct thread *thread = thread_get_current_thread(); 669 int32 teamDebugFlags = atomic_get(&thread->team->debug_info.flags); 670 if (~teamDebugFlags 671 & (B_TEAM_DEBUG_DEBUGGER_INSTALLED | B_TEAM_DEBUG_SIGNALS)) { 672 return true; 673 } 674 675 // prepare the message 676 debug_signal_received message; 677 message.signal = signal; 678 message.handler = *handler; 679 message.deadly = deadly; 680 681 status_t result = thread_hit_debug_event(B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED, 682 &message, sizeof(message), true); 683 return (result != B_THREAD_DEBUG_IGNORE_EVENT); 684 } 685 686 687 void 688 user_debug_stop_thread() 689 { 690 // ensure that a debugger is installed for this team 691 struct thread *thread = thread_get_current_thread(); 692 port_id nubPort; 693 status_t error = ensure_debugger_installed(B_CURRENT_TEAM, &nubPort); 694 if (error != B_OK) { 695 dprintf("user_debug_stop_thread(): Failed to install debugger: " 696 "thread: %ld: %s\n", thread->id, strerror(error)); 697 return; 698 } 699 700 // prepare the message 701 debug_thread_debugged message; 702 703 thread_hit_debug_event(B_DEBUGGER_MESSAGE_THREAD_DEBUGGED, &message, 704 sizeof(message), true); 705 } 706 707 708 void 709 user_debug_team_created(team_id teamID) 710 { 711 // check, if a debugger is installed and is interested in team creation 712 // events 713 struct thread *thread = thread_get_current_thread(); 714 int32 teamDebugFlags = atomic_get(&thread->team->debug_info.flags); 715 if (~teamDebugFlags 716 & (B_TEAM_DEBUG_DEBUGGER_INSTALLED | B_TEAM_DEBUG_TEAM_CREATION)) { 717 return; 718 } 719 720 // prepare the message 721 debug_team_created message; 722 message.new_team = teamID; 723 724 thread_hit_debug_event(B_DEBUGGER_MESSAGE_TEAM_CREATED, &message, 725 sizeof(message), true); 726 } 727 728 729 void 730 user_debug_team_deleted(team_id teamID, port_id debuggerPort) 731 { 732 if (debuggerPort >= 0) { 733 TRACE(("user_debug_team_deleted(team: %ld, debugger port: %ld)\n", 734 teamID, debuggerPort)); 735 736 debug_team_deleted message; 737 message.origin.thread = -1; 738 message.origin.team = teamID; 739 message.origin.nub_port = -1; 740 write_port_etc(debuggerPort, B_DEBUGGER_MESSAGE_TEAM_DELETED, &message, 741 sizeof(message), B_RELATIVE_TIMEOUT, 0); 742 // TODO: Would it be OK to wait here? 743 } 744 } 745 746 747 void 748 user_debug_thread_created(thread_id threadID) 749 { 750 // check, if a debugger is installed and is interested in thread events 751 struct thread *thread = thread_get_current_thread(); 752 int32 teamDebugFlags = atomic_get(&thread->team->debug_info.flags); 753 if (~teamDebugFlags 754 & (B_TEAM_DEBUG_DEBUGGER_INSTALLED | B_TEAM_DEBUG_THREADS)) { 755 return; 756 } 757 758 // prepare the message 759 debug_thread_created message; 760 message.new_thread = threadID; 761 762 thread_hit_debug_event(B_DEBUGGER_MESSAGE_THREAD_CREATED, &message, 763 sizeof(message), true); 764 } 765 766 767 void 768 user_debug_thread_deleted(team_id teamID, thread_id threadID) 769 { 770 // get the team debug flags and debugger port 771 cpu_status state = disable_interrupts(); 772 GRAB_TEAM_LOCK(); 773 774 struct team *team = team_get_team_struct_locked(teamID); 775 776 int32 teamDebugFlags = 0; 777 port_id debuggerPort = -1; 778 if (team) { 779 GRAB_TEAM_DEBUG_INFO_LOCK(team->debug_info); 780 781 teamDebugFlags = atomic_get(&team->debug_info.flags); 782 debuggerPort = team->debug_info.debugger_port; 783 784 RELEASE_TEAM_DEBUG_INFO_LOCK(team->debug_info); 785 } 786 787 RELEASE_TEAM_LOCK(); 788 restore_interrupts(state); 789 790 // check, if a debugger is installed and is interested in thread events 791 if (~teamDebugFlags 792 & (B_TEAM_DEBUG_DEBUGGER_INSTALLED | B_TEAM_DEBUG_THREADS)) { 793 return; 794 } 795 796 // notify the debugger 797 if (debuggerPort >= 0) { 798 debug_thread_deleted message; 799 message.origin.thread = threadID; 800 message.origin.team = teamID; 801 message.origin.nub_port = -1; 802 debugger_write(debuggerPort, B_DEBUGGER_MESSAGE_THREAD_DELETED, 803 &message, sizeof(message), true); 804 // TODO: Would it be OK to wait here? 805 } 806 } 807 808 809 void 810 user_debug_image_created(const image_info *imageInfo) 811 { 812 // check, if a debugger is installed and is interested in image events 813 struct thread *thread = thread_get_current_thread(); 814 int32 teamDebugFlags = atomic_get(&thread->team->debug_info.flags); 815 if (~teamDebugFlags 816 & (B_TEAM_DEBUG_DEBUGGER_INSTALLED | B_TEAM_DEBUG_IMAGES)) { 817 return; 818 } 819 820 // prepare the message 821 debug_image_created message; 822 memcpy(&message.info, imageInfo, sizeof(image_info)); 823 824 thread_hit_debug_event(B_DEBUGGER_MESSAGE_IMAGE_CREATED, &message, 825 sizeof(message), true); 826 } 827 828 829 void 830 user_debug_image_deleted(const image_info *imageInfo) 831 { 832 // check, if a debugger is installed and is interested in image events 833 struct thread *thread = thread_get_current_thread(); 834 int32 teamDebugFlags = atomic_get(&thread->team->debug_info.flags); 835 if (~teamDebugFlags 836 & (B_TEAM_DEBUG_DEBUGGER_INSTALLED | B_TEAM_DEBUG_IMAGES)) { 837 return; 838 } 839 840 // prepare the message 841 debug_image_deleted message; 842 memcpy(&message.info, imageInfo, sizeof(image_info)); 843 844 thread_hit_debug_event(B_DEBUGGER_MESSAGE_IMAGE_CREATED, &message, 845 sizeof(message), true); 846 } 847 848 849 void 850 user_debug_breakpoint_hit(bool software) 851 { 852 // ensure that a debugger is installed for this team 853 struct thread *thread = thread_get_current_thread(); 854 port_id nubPort; 855 status_t error = ensure_debugger_installed(B_CURRENT_TEAM, &nubPort); 856 if (error != B_OK) { 857 dprintf("user_debug_breakpoint_hit(): Failed to install debugger: " 858 "thread: %ld: %s\n", thread->id, strerror(error)); 859 return; 860 } 861 862 // prepare the message 863 debug_breakpoint_hit message; 864 message.software = software; 865 arch_get_debug_cpu_state(&message.cpu_state); 866 867 thread_hit_debug_event(B_DEBUGGER_MESSAGE_BREAKPOINT_HIT, &message, 868 sizeof(message), true); 869 } 870 871 872 void 873 user_debug_watchpoint_hit() 874 { 875 // ensure that a debugger is installed for this team 876 struct thread *thread = thread_get_current_thread(); 877 port_id nubPort; 878 status_t error = ensure_debugger_installed(B_CURRENT_TEAM, &nubPort); 879 if (error != B_OK) { 880 dprintf("user_debug_watchpoint_hit(): Failed to install debugger: " 881 "thread: %ld: %s\n", thread->id, strerror(error)); 882 return; 883 } 884 885 // prepare the message 886 debug_watchpoint_hit message; 887 arch_get_debug_cpu_state(&message.cpu_state); 888 889 thread_hit_debug_event(B_DEBUGGER_MESSAGE_WATCHPOINT_HIT, &message, 890 sizeof(message), true); 891 } 892 893 894 void 895 user_debug_single_stepped() 896 { 897 // ensure that a debugger is installed for this team 898 struct thread *thread = thread_get_current_thread(); 899 port_id nubPort; 900 status_t error = ensure_debugger_installed(B_CURRENT_TEAM, &nubPort); 901 if (error != B_OK) { 902 dprintf("user_debug_watchpoint_hit(): Failed to install debugger: " 903 "thread: %ld: %s\n", thread->id, strerror(error)); 904 return; 905 } 906 907 // prepare the message 908 debug_single_step message; 909 arch_get_debug_cpu_state(&message.cpu_state); 910 911 thread_hit_debug_event(B_DEBUGGER_MESSAGE_SINGLE_STEP, &message, 912 sizeof(message), true); 913 } 914 915 916 /** \brief Called by the debug nub thread of a team to broadcast a message 917 * that are initialized for debugging (and thus have a debug port). 918 */ 919 static void 920 broadcast_debugged_thread_message(struct thread *nubThread, int32 code, 921 const void *message, int32 size) 922 { 923 // iterate through the threads 924 thread_info threadInfo; 925 int32 cookie = 0; 926 while (get_next_thread_info(nubThread->team->id, &cookie, &threadInfo) 927 == B_OK) { 928 // find the thread and get its debug port 929 cpu_status state = disable_interrupts(); 930 GRAB_THREAD_LOCK(); 931 932 port_id threadDebugPort = -1; 933 thread_id threadID = -1; 934 struct thread *thread 935 = thread_get_thread_struct_locked(threadInfo.thread); 936 if (thread && thread != nubThread && thread->team == nubThread->team 937 && thread->debug_info.flags & B_THREAD_DEBUG_INITIALIZED) { 938 threadDebugPort = thread->debug_info.debug_port; 939 threadID = thread->id; 940 } 941 942 RELEASE_THREAD_LOCK(); 943 restore_interrupts(state); 944 945 // send the message to the thread 946 if (threadDebugPort >= 0) { 947 status_t error = kill_interruptable_write_port(threadDebugPort, 948 code, message, size); 949 if (error != B_OK) { 950 TRACE(("broadcast_debugged_thread_message(): Failed to send " 951 "message to thread %ld: %lx\n", threadID, error)); 952 } 953 } 954 } 955 } 956 957 958 static void 959 nub_thread_cleanup(struct thread *nubThread) 960 { 961 TRACE(("nub_thread_cleanup(%ld): debugger port: %ld\n", nubThread->id, 962 nubThread->team->debug_info.debugger_port)); 963 964 team_debug_info teamDebugInfo; 965 bool destroyDebugInfo = false; 966 967 cpu_status state = disable_interrupts(); 968 GRAB_TEAM_LOCK(); 969 GRAB_TEAM_DEBUG_INFO_LOCK(nubThread->team->debug_info); 970 971 team_debug_info &info = nubThread->team->debug_info; 972 if (info.flags & B_TEAM_DEBUG_DEBUGGER_INSTALLED 973 && info.nub_thread == nubThread->id) { 974 teamDebugInfo = info; 975 clear_team_debug_info(&info, false); 976 destroyDebugInfo = true; 977 } 978 979 RELEASE_TEAM_DEBUG_INFO_LOCK(nubThread->team->debug_info); 980 RELEASE_TEAM_LOCK(); 981 restore_interrupts(state); 982 983 if (destroyDebugInfo) 984 destroy_team_debug_info(&teamDebugInfo); 985 986 // notify all threads that the debugger is gone 987 broadcast_debugged_thread_message(nubThread, 988 B_DEBUGGED_THREAD_DEBUGGER_CHANGED, NULL, 0); 989 } 990 991 992 /** \brief Reads data from user memory. 993 * 994 * Tries to read \a size bytes of data from user memory address \a address 995 * into the supplied buffer \a buffer. If only a part could be read the 996 * function won't fail. The number of bytes actually read is return through 997 * \a bytesRead. 998 * 999 * \param address The user memory address from which to read. 1000 * \param buffer The buffer into which to write. 1001 * \param size The number of bytes to read. 1002 * \param bytesRead Will be set to the number of bytes actually read. 1003 * \return \c B_OK, if reading went fine. Then \a bytesRead will be set to 1004 * the amount of data actually read. An error indicates that nothing 1005 * has been read. 1006 */ 1007 static status_t 1008 read_user_memory(const void *_address, void *_buffer, int32 size, 1009 int32 &bytesRead) 1010 { 1011 const char *address = (const char*)_address; 1012 char *buffer = (char*)_buffer; 1013 1014 // check the parameters 1015 if (!IS_USER_ADDRESS(address)) 1016 return B_BAD_ADDRESS; 1017 if (size <= 0) 1018 return B_BAD_VALUE; 1019 1020 // If the region to be read crosses page boundaries, we split it up into 1021 // smaller chunks. 1022 status_t error = B_OK; 1023 bytesRead = 0; 1024 while (size > 0) { 1025 // check whether we're still in user address space 1026 if (!IS_USER_ADDRESS(address)) { 1027 error = B_BAD_ADDRESS; 1028 break; 1029 } 1030 1031 // don't cross page boundaries in a single read 1032 int32 toRead = size; 1033 int32 maxRead = B_PAGE_SIZE - (addr_t)address % B_PAGE_SIZE; 1034 if (toRead > maxRead) 1035 toRead = maxRead; 1036 1037 error = user_memcpy(buffer, address, toRead); 1038 if (error != B_OK) 1039 break; 1040 1041 bytesRead += toRead; 1042 address += toRead; 1043 buffer += toRead; 1044 size -= toRead; 1045 } 1046 1047 // If reading fails, we only fail, if we haven't read anything yet. 1048 if (error != B_OK) { 1049 if (bytesRead > 0) 1050 return B_OK; 1051 return error; 1052 } 1053 1054 return B_OK; 1055 } 1056 1057 1058 static status_t 1059 write_user_memory(void *_address, const void *_buffer, int32 size, 1060 int32 &bytesWritten) 1061 { 1062 char *address = (char*)_address; 1063 const char *buffer = (const char*)_buffer; 1064 1065 // check the parameters 1066 if (!IS_USER_ADDRESS(address)) 1067 return B_BAD_ADDRESS; 1068 if (size <= 0) 1069 return B_BAD_VALUE; 1070 1071 // If the region to be written crosses area boundaries, we split it up into 1072 // smaller chunks. 1073 status_t error = B_OK; 1074 bytesWritten = 0; 1075 while (size > 0) { 1076 // check whether we're still in user address space 1077 if (!IS_USER_ADDRESS(address)) { 1078 error = B_BAD_ADDRESS; 1079 break; 1080 } 1081 1082 // get the area for the address (we need to use _user_area_for(), since 1083 // we're looking for a user area) 1084 area_id area = _user_area_for((void*)address); 1085 if (area < 0) { 1086 TRACE(("write_user_memory(): area not found for address: %p: " 1087 "%lx\n", address, area)); 1088 error = area; 1089 break; 1090 } 1091 1092 area_info areaInfo; 1093 status_t error = get_area_info(area, &areaInfo); 1094 if (error != B_OK) { 1095 TRACE(("write_user_memory(): failed to get info for area %ld: " 1096 "%lx\n", area, error)); 1097 error = B_BAD_ADDRESS; 1098 break; 1099 } 1100 1101 // restrict this round of writing to the found area 1102 int32 toWrite = size; 1103 int32 maxWrite = (char*)areaInfo.address + areaInfo.size - address; 1104 if (toWrite > maxWrite) 1105 toWrite = maxWrite; 1106 1107 // if the area is read-only, we temporarily need to make it writable 1108 bool protectionChanged = false; 1109 if (!(areaInfo.protection & (B_WRITE_AREA | B_KERNEL_WRITE_AREA))) { 1110 error = set_area_protection(area, 1111 areaInfo.protection | B_WRITE_AREA); 1112 if (error != B_OK) { 1113 TRACE(("write_user_memory(): failed to set new protection for " 1114 "area %ld: %lx\n", area, error)); 1115 break; 1116 } 1117 protectionChanged = true; 1118 } 1119 1120 // copy the memory 1121 error = user_memcpy(address, buffer, toWrite); 1122 1123 // reset the area protection 1124 if (protectionChanged) 1125 set_area_protection(area, areaInfo.protection); 1126 1127 if (error != B_OK) { 1128 TRACE(("write_user_memory(): user_memcpy() failed: %lx\n", error)); 1129 break; 1130 } 1131 1132 bytesWritten += toWrite; 1133 address += toWrite; 1134 buffer += toWrite; 1135 size -= toWrite; 1136 } 1137 1138 // If writing fails, we only fail, if we haven't written anything yet. 1139 if (error != B_OK) { 1140 if (bytesWritten > 0) 1141 return B_OK; 1142 return error; 1143 } 1144 1145 return B_OK; 1146 } 1147 1148 1149 /** \brief Debug nub thread helper function that returns the debug port of 1150 * a thread of the same team. 1151 */ 1152 static status_t 1153 debug_nub_thread_get_thread_debug_port(struct thread *nubThread, 1154 thread_id threadID, port_id &threadDebugPort) 1155 { 1156 status_t result = B_OK; 1157 threadDebugPort = -1; 1158 1159 cpu_status state = disable_interrupts(); 1160 GRAB_THREAD_LOCK(); 1161 1162 struct thread *thread = thread_get_thread_struct_locked(threadID); 1163 if (thread) { 1164 if (thread->team != nubThread->team) 1165 result = B_BAD_VALUE; 1166 else if (thread->debug_info.flags & B_THREAD_DEBUG_STOPPED) 1167 threadDebugPort = thread->debug_info.debug_port; 1168 else 1169 result = B_BAD_VALUE; 1170 } else 1171 result = B_BAD_THREAD_ID; 1172 1173 RELEASE_THREAD_LOCK(); 1174 restore_interrupts(state); 1175 1176 if (result == B_OK && threadDebugPort < 0) 1177 result = B_ERROR; 1178 1179 return result; 1180 } 1181 1182 1183 static status_t 1184 debug_nub_thread(void *) 1185 { 1186 struct thread *nubThread = thread_get_current_thread(); 1187 1188 // check, if we're still the current nub thread and get our port 1189 cpu_status state = disable_interrupts(); 1190 1191 GRAB_TEAM_DEBUG_INFO_LOCK(nubThread->team->debug_info); 1192 1193 if (nubThread->team->debug_info.nub_thread != nubThread->id) 1194 return 0; 1195 1196 port_id port = nubThread->team->debug_info.nub_port; 1197 sem_id writeLock = nubThread->team->debug_info.debugger_write_lock; 1198 1199 RELEASE_TEAM_DEBUG_INFO_LOCK(nubThread->team->debug_info); 1200 restore_interrupts(state); 1201 1202 TRACE(("debug_nub_thread() thread: %ld, team %ld, nub port: %ld\n", 1203 nubThread->id, nubThread->team->id, port)); 1204 1205 // notify all threads that a debugger has been installed 1206 broadcast_debugged_thread_message(nubThread, 1207 B_DEBUGGED_THREAD_DEBUGGER_CHANGED, NULL, 0); 1208 1209 // command processing loop 1210 while (true) { 1211 int32 command; 1212 debug_nub_message_data message; 1213 ssize_t messageSize = kill_interruptable_read_port(port, &command, 1214 &message, sizeof(message)); 1215 1216 if (messageSize < 0) { 1217 // The port is not longer valid or we were interrupted by a kill 1218 // signal: If we are still listed in the team's debug info as nub 1219 // thread, we need to update that. 1220 nub_thread_cleanup(nubThread); 1221 1222 TRACE(("nub thread %ld: terminating: %lx\n", nubThread->id, 1223 messageSize)); 1224 1225 return messageSize; 1226 } 1227 1228 bool sendReply = false; 1229 union { 1230 debug_nub_read_memory_reply read_memory; 1231 debug_nub_write_memory_reply write_memory; 1232 debug_nub_get_cpu_state_reply get_cpu_state; 1233 debug_nub_set_breakpoint_reply set_breakpoint; 1234 debug_nub_set_watchpoint_reply set_watchpoint; 1235 debug_nub_get_signal_masks_reply get_signal_masks; 1236 debug_nub_get_signal_handler_reply get_signal_handler; 1237 } reply; 1238 int32 replySize = 0; 1239 port_id replyPort = -1; 1240 1241 // process the command 1242 switch (command) { 1243 case B_DEBUG_MESSAGE_READ_MEMORY: 1244 { 1245 // get the parameters 1246 replyPort = message.read_memory.reply_port; 1247 void *address = message.read_memory.address; 1248 int32 size = message.read_memory.size; 1249 status_t result = B_OK; 1250 1251 // check the parameters 1252 if (!IS_USER_ADDRESS(address)) 1253 result = B_BAD_ADDRESS; 1254 else if (size <= 0 || size > B_MAX_READ_WRITE_MEMORY_SIZE) 1255 result = B_BAD_VALUE; 1256 1257 // read the memory 1258 int32 bytesRead = 0; 1259 if (result == B_OK) { 1260 result = read_user_memory(address, reply.read_memory.data, 1261 size, bytesRead); 1262 } 1263 reply.read_memory.error = result; 1264 1265 TRACE(("nub thread %ld: B_DEBUG_MESSAGE_READ_MEMORY: " 1266 "reply port: %ld, address: %p, size: %ld, result: %lx, " 1267 "read: %ld\n", nubThread->id, replyPort, address, size, 1268 result, bytesRead)); 1269 1270 // send only as much data as necessary 1271 reply.read_memory.size = bytesRead; 1272 replySize = reply.read_memory.data + bytesRead - (char*)&reply; 1273 sendReply = true; 1274 break; 1275 } 1276 1277 case B_DEBUG_MESSAGE_WRITE_MEMORY: 1278 { 1279 // get the parameters 1280 replyPort = message.write_memory.reply_port; 1281 void *address = message.write_memory.address; 1282 int32 size = message.write_memory.size; 1283 const char *data = message.write_memory.data; 1284 int32 realSize = (char*)&message + messageSize - data; 1285 status_t result = B_OK; 1286 1287 // check the parameters 1288 if (!IS_USER_ADDRESS(address)) 1289 result = B_BAD_ADDRESS; 1290 else if (size <= 0 || size > realSize) 1291 result = B_BAD_VALUE; 1292 1293 // write the memory 1294 int32 bytesWritten = 0; 1295 if (result == B_OK) { 1296 result = write_user_memory(address, data, size, 1297 bytesWritten); 1298 } 1299 reply.write_memory.error = result; 1300 1301 TRACE(("nub thread %ld: B_DEBUG_MESSAGE_WRITE_MEMORY: " 1302 "reply port: %ld, address: %p, size: %ld, result: %lx, " 1303 "written: %ld\n", nubThread->id, replyPort, address, size, 1304 result, bytesWritten)); 1305 1306 reply.write_memory.size = bytesWritten; 1307 sendReply = true; 1308 replySize = sizeof(debug_nub_write_memory_reply); 1309 break; 1310 } 1311 1312 case B_DEBUG_MESSAGE_SET_TEAM_FLAGS: 1313 { 1314 // get the parameters 1315 int32 flags = message.set_team_flags.flags 1316 & B_TEAM_DEBUG_USER_FLAG_MASK; 1317 1318 TRACE(("nub thread %ld: B_DEBUG_MESSAGE_SET_TEAM_FLAGS: " 1319 "flags: %lx\n", nubThread->id, flags)); 1320 1321 struct team *team = thread_get_current_thread()->team; 1322 1323 // set the flags 1324 cpu_status state = disable_interrupts(); 1325 GRAB_TEAM_DEBUG_INFO_LOCK(team->debug_info); 1326 1327 flags |= team->debug_info.flags & B_TEAM_DEBUG_KERNEL_FLAG_MASK; 1328 atomic_set(&team->debug_info.flags, flags); 1329 1330 RELEASE_TEAM_DEBUG_INFO_LOCK(team->debug_info); 1331 restore_interrupts(state); 1332 1333 break; 1334 } 1335 1336 case B_DEBUG_MESSAGE_SET_THREAD_FLAGS: 1337 { 1338 // get the parameters 1339 thread_id threadID = message.set_thread_flags.thread; 1340 int32 flags = message.set_thread_flags.flags 1341 & B_THREAD_DEBUG_USER_FLAG_MASK; 1342 1343 TRACE(("nub thread %ld: B_DEBUG_MESSAGE_SET_THREAD_FLAGS: " 1344 "thread: %ld, flags: %lx\n", nubThread->id, threadID, 1345 flags)); 1346 1347 // set the flags 1348 cpu_status state = disable_interrupts(); 1349 GRAB_THREAD_LOCK(); 1350 1351 struct thread *thread 1352 = thread_get_thread_struct_locked(threadID); 1353 if (thread 1354 && thread->team == thread_get_current_thread()->team) { 1355 flags |= thread->debug_info.flags 1356 & B_THREAD_DEBUG_KERNEL_FLAG_MASK; 1357 atomic_set(&thread->debug_info.flags, flags); 1358 } 1359 1360 RELEASE_THREAD_LOCK(); 1361 restore_interrupts(state); 1362 1363 break; 1364 } 1365 1366 case B_DEBUG_MESSAGE_CONTINUE_THREAD: 1367 { 1368 // get the parameters 1369 thread_id threadID; 1370 uint32 handleEvent; 1371 bool singleStep; 1372 1373 threadID = message.continue_thread.thread; 1374 handleEvent = message.continue_thread.handle_event; 1375 singleStep = message.continue_thread.single_step; 1376 1377 TRACE(("nub thread %ld: B_DEBUG_MESSAGE_CONTINUE_THREAD: " 1378 "thread: %ld, handle event: %lu, single step: %d\n", 1379 nubThread->id, threadID, handleEvent, singleStep)); 1380 1381 // find the thread and get its debug port 1382 port_id threadDebugPort = -1; 1383 status_t result = debug_nub_thread_get_thread_debug_port( 1384 nubThread, threadID, threadDebugPort); 1385 1386 // send a message to the debugged thread 1387 if (result == B_OK) { 1388 debugged_thread_continue commandMessage; 1389 commandMessage.handle_event = handleEvent; 1390 commandMessage.single_step = singleStep; 1391 1392 result = write_port(threadDebugPort, 1393 B_DEBUGGED_THREAD_MESSAGE_CONTINUE, 1394 &commandMessage, sizeof(commandMessage)); 1395 } 1396 1397 break; 1398 } 1399 1400 case B_DEBUG_MESSAGE_SET_CPU_STATE: 1401 { 1402 // get the parameters 1403 thread_id threadID = message.set_cpu_state.thread; 1404 const debug_cpu_state &cpuState 1405 = message.set_cpu_state.cpu_state; 1406 1407 TRACE(("nub thread %ld: B_DEBUG_MESSAGE_SET_CPU_STATE: " 1408 "thread: %ld\n", nubThread->id, threadID)); 1409 1410 // find the thread and get its debug port 1411 port_id threadDebugPort = -1; 1412 status_t result = debug_nub_thread_get_thread_debug_port( 1413 nubThread, threadID, threadDebugPort); 1414 1415 // send a message to the debugged thread 1416 if (result == B_OK) { 1417 debugged_thread_set_cpu_state commandMessage; 1418 memcpy(&commandMessage.cpu_state, &cpuState, 1419 sizeof(debug_cpu_state)); 1420 write_port(threadDebugPort, 1421 B_DEBUGGED_THREAD_SET_CPU_STATE, 1422 &commandMessage, sizeof(commandMessage)); 1423 } 1424 1425 break; 1426 } 1427 1428 case B_DEBUG_MESSAGE_GET_CPU_STATE: 1429 { 1430 // get the parameters 1431 thread_id threadID = message.get_cpu_state.thread; 1432 replyPort = message.get_cpu_state.reply_port; 1433 1434 TRACE(("nub thread %ld: B_DEBUG_MESSAGE_GET_CPU_STATE: " 1435 "thread: %ld\n", nubThread->id, threadID)); 1436 1437 // find the thread and get its debug port 1438 port_id threadDebugPort = -1; 1439 status_t result = debug_nub_thread_get_thread_debug_port( 1440 nubThread, threadID, threadDebugPort); 1441 1442 // send a message to the debugged thread 1443 if (threadDebugPort >= 0) { 1444 debugged_thread_get_cpu_state commandMessage; 1445 commandMessage.reply_port = replyPort; 1446 result = write_port(threadDebugPort, 1447 B_DEBUGGED_THREAD_GET_CPU_STATE, &commandMessage, 1448 sizeof(commandMessage)); 1449 } 1450 1451 // send a reply to the debugger in case of error 1452 if (result != B_OK) { 1453 reply.get_cpu_state.error = result; 1454 sendReply = true; 1455 replySize = sizeof(reply.get_cpu_state); 1456 } 1457 1458 break; 1459 } 1460 1461 case B_DEBUG_MESSAGE_SET_BREAKPOINT: 1462 { 1463 // get the parameters 1464 replyPort = message.set_breakpoint.reply_port; 1465 void *address = message.set_breakpoint.address; 1466 1467 TRACE(("nub thread %ld: B_DEBUG_MESSAGE_SET_BREAKPOINT: " 1468 "address: %p\n", nubThread->id, address)); 1469 1470 // check the address 1471 status_t result = B_OK; 1472 if (address == NULL || !IS_USER_ADDRESS(address)) 1473 result = B_BAD_ADDRESS; 1474 1475 // set the breakpoint 1476 if (result == B_OK) 1477 result = arch_set_breakpoint(address); 1478 1479 // prepare the reply 1480 reply.set_breakpoint.error = result; 1481 replySize = sizeof(reply.set_breakpoint); 1482 sendReply = true; 1483 1484 break; 1485 } 1486 1487 case B_DEBUG_MESSAGE_CLEAR_BREAKPOINT: 1488 { 1489 // get the parameters 1490 void *address = message.clear_breakpoint.address; 1491 1492 TRACE(("nub thread %ld: B_DEBUG_MESSAGE_CLEAR_BREAKPOINT: " 1493 "address: %p\n", nubThread->id, address)); 1494 1495 // check the address 1496 status_t result = B_OK; 1497 if (address == NULL || !IS_USER_ADDRESS(address)) 1498 result = B_BAD_ADDRESS; 1499 1500 // clear the breakpoint 1501 if (result == B_OK) 1502 result = arch_clear_breakpoint(address); 1503 1504 break; 1505 } 1506 1507 case B_DEBUG_MESSAGE_SET_WATCHPOINT: 1508 { 1509 // get the parameters 1510 replyPort = message.set_watchpoint.reply_port; 1511 void *address = message.set_watchpoint.address; 1512 uint32 type = message.set_watchpoint.type; 1513 int32 length = message.set_watchpoint.length; 1514 1515 TRACE(("nub thread %ld: B_DEBUG_MESSAGE_SET_WATCHPOINT: " 1516 "address: %p, type: %lu, length: %ld\n", nubThread->id, 1517 address, type, length)); 1518 1519 // check the address and size 1520 status_t result = B_OK; 1521 if (address == NULL || !IS_USER_ADDRESS(address)) 1522 result = B_BAD_ADDRESS; 1523 if (length < 0) 1524 result = B_BAD_VALUE; 1525 1526 // set the watchpoint 1527 if (result == B_OK) 1528 result = arch_set_watchpoint(address, type, length); 1529 1530 // prepare the reply 1531 reply.set_watchpoint.error = result; 1532 replySize = sizeof(reply.set_watchpoint); 1533 sendReply = true; 1534 1535 break; 1536 } 1537 1538 case B_DEBUG_MESSAGE_CLEAR_WATCHPOINT: 1539 { 1540 // get the parameters 1541 void *address = message.clear_watchpoint.address; 1542 1543 TRACE(("nub thread %ld: B_DEBUG_MESSAGE_CLEAR_WATCHPOINT: " 1544 "address: %p\n", nubThread->id, address)); 1545 1546 // check the address 1547 status_t result = B_OK; 1548 if (address == NULL || !IS_USER_ADDRESS(address)) 1549 result = B_BAD_ADDRESS; 1550 1551 // clear the watchpoint 1552 if (result == B_OK) 1553 result = arch_clear_watchpoint(address); 1554 1555 break; 1556 } 1557 1558 case B_DEBUG_MESSAGE_SET_SIGNAL_MASKS: 1559 { 1560 // get the parameters 1561 thread_id threadID = message.set_signal_masks.thread; 1562 uint64 ignore = message.set_signal_masks.ignore_mask; 1563 uint64 ignoreOnce = message.set_signal_masks.ignore_once_mask; 1564 uint32 ignoreOp = message.set_signal_masks.ignore_op; 1565 uint32 ignoreOnceOp = message.set_signal_masks.ignore_once_op; 1566 1567 TRACE(("nub thread %ld: B_DEBUG_MESSAGE_SET_SIGNAL_MASKS: " 1568 "thread: %ld, ignore: %llx (op: %lu), ignore once: %llx " 1569 "(op: %lu)\n", nubThread->id, threadID, ignore, 1570 ignoreOp, ignoreOnce, ignoreOnceOp)); 1571 1572 // set the masks 1573 cpu_status state = disable_interrupts(); 1574 GRAB_THREAD_LOCK(); 1575 1576 struct thread *thread 1577 = thread_get_thread_struct_locked(threadID); 1578 if (thread 1579 && thread->team == thread_get_current_thread()->team) { 1580 thread_debug_info &threadDebugInfo = thread->debug_info; 1581 // set ignore mask 1582 switch (ignoreOp) { 1583 case B_DEBUG_SIGNAL_MASK_AND: 1584 threadDebugInfo.ignore_signals &= ignore; 1585 break; 1586 case B_DEBUG_SIGNAL_MASK_OR: 1587 threadDebugInfo.ignore_signals |= ignore; 1588 break; 1589 case B_DEBUG_SIGNAL_MASK_SET: 1590 threadDebugInfo.ignore_signals = ignore; 1591 break; 1592 } 1593 1594 // set ignore once mask 1595 switch (ignoreOnceOp) { 1596 case B_DEBUG_SIGNAL_MASK_AND: 1597 threadDebugInfo.ignore_signals_once &= ignoreOnce; 1598 break; 1599 case B_DEBUG_SIGNAL_MASK_OR: 1600 threadDebugInfo.ignore_signals_once |= ignoreOnce; 1601 break; 1602 case B_DEBUG_SIGNAL_MASK_SET: 1603 threadDebugInfo.ignore_signals_once = ignoreOnce; 1604 break; 1605 } 1606 } 1607 1608 RELEASE_THREAD_LOCK(); 1609 restore_interrupts(state); 1610 1611 break; 1612 } 1613 1614 case B_DEBUG_MESSAGE_GET_SIGNAL_MASKS: 1615 { 1616 // get the parameters 1617 replyPort = message.get_signal_masks.reply_port; 1618 thread_id threadID = message.get_signal_masks.thread; 1619 status_t result = B_OK; 1620 1621 // get the masks 1622 uint64 ignore = 0; 1623 uint64 ignoreOnce = 0; 1624 1625 cpu_status state = disable_interrupts(); 1626 GRAB_THREAD_LOCK(); 1627 1628 struct thread *thread 1629 = thread_get_thread_struct_locked(threadID); 1630 if (thread) { 1631 ignore = thread->debug_info.ignore_signals; 1632 ignoreOnce = thread->debug_info.ignore_signals_once; 1633 } else 1634 result = B_BAD_THREAD_ID; 1635 1636 RELEASE_THREAD_LOCK(); 1637 restore_interrupts(state); 1638 1639 TRACE(("nub thread %ld: B_DEBUG_MESSAGE_GET_SIGNAL_MASKS: " 1640 "reply port: %ld, thread: %ld, ignore: %llx, " 1641 "ignore once: %llx, result: %lx\n", nubThread->id, 1642 replyPort, threadID, ignore, ignoreOnce, result)); 1643 1644 // prepare the message 1645 reply.get_signal_masks.error = result; 1646 reply.get_signal_masks.ignore_mask = ignore; 1647 reply.get_signal_masks.ignore_once_mask = ignoreOnce; 1648 replySize = sizeof(reply.get_signal_masks); 1649 sendReply = true; 1650 break; 1651 } 1652 1653 case B_DEBUG_MESSAGE_SET_SIGNAL_HANDLER: 1654 { 1655 // get the parameters 1656 thread_id threadID = message.set_signal_handler.thread; 1657 int signal = message.set_signal_handler.signal; 1658 struct sigaction &handler = message.set_signal_handler.handler; 1659 1660 TRACE(("nub thread %ld: B_DEBUG_MESSAGE_SET_SIGNAL_HANDLER: " 1661 "thread: %ld, signal: %d, handler: %p\n", nubThread->id, 1662 threadID, signal, handler.sa_handler)); 1663 1664 // check, if the thread exists and is ours 1665 cpu_status state = disable_interrupts(); 1666 GRAB_THREAD_LOCK(); 1667 1668 struct thread *thread 1669 = thread_get_thread_struct_locked(threadID); 1670 if (thread 1671 && thread->team != thread_get_current_thread()->team) { 1672 thread = NULL; 1673 } 1674 1675 RELEASE_THREAD_LOCK(); 1676 restore_interrupts(state); 1677 1678 // set the handler 1679 if (thread) 1680 sigaction_etc(threadID, signal, &handler, NULL); 1681 1682 break; 1683 } 1684 1685 case B_DEBUG_MESSAGE_GET_SIGNAL_HANDLER: 1686 { 1687 // get the parameters 1688 replyPort = message.get_signal_handler.reply_port; 1689 thread_id threadID = message.get_signal_handler.thread; 1690 int signal = message.get_signal_handler.signal; 1691 status_t result = B_OK; 1692 1693 // check, if the thread exists and is ours 1694 cpu_status state = disable_interrupts(); 1695 GRAB_THREAD_LOCK(); 1696 1697 struct thread *thread 1698 = thread_get_thread_struct_locked(threadID); 1699 if (thread) { 1700 if (thread->team != thread_get_current_thread()->team) 1701 result = B_BAD_VALUE; 1702 } else 1703 result = B_BAD_THREAD_ID; 1704 1705 RELEASE_THREAD_LOCK(); 1706 restore_interrupts(state); 1707 1708 // get the handler 1709 if (result == B_OK) { 1710 result = sigaction_etc(threadID, signal, NULL, 1711 &reply.get_signal_handler.handler); 1712 } 1713 1714 TRACE(("nub thread %ld: B_DEBUG_MESSAGE_GET_SIGNAL_HANDLER: " 1715 "reply port: %ld, thread: %ld, signal: %d, " 1716 "handler: %p\n", nubThread->id, replyPort, 1717 threadID, signal, 1718 reply.get_signal_handler.handler.sa_handler)); 1719 1720 // prepare the message 1721 reply.get_signal_handler.error = result; 1722 replySize = sizeof(reply.get_signal_handler); 1723 sendReply = true; 1724 break; 1725 } 1726 1727 case B_DEBUG_MESSAGE_PREPARE_HANDOVER: 1728 { 1729 TRACE(("nub thread %ld: B_DEBUG_MESSAGE_PREPARE_HANDOVER\n", 1730 nubThread->id)); 1731 1732 struct team *team = nubThread->team; 1733 1734 // Acquire the debugger write lock. As soon as we have it and 1735 // have set the B_TEAM_DEBUG_DEBUGGER_HANDOVER flag, no thread 1736 // will write anything to the debugger port anymore. 1737 status_t result = acquire_sem_etc(writeLock, 1, 1738 B_KILL_CAN_INTERRUPT, 0); 1739 if (result == B_OK) { 1740 // set the respective team debug flag 1741 cpu_status state = disable_interrupts(); 1742 GRAB_TEAM_DEBUG_INFO_LOCK(team->debug_info); 1743 1744 atomic_or(&team->debug_info.flags, 1745 B_TEAM_DEBUG_DEBUGGER_HANDOVER); 1746 1747 RELEASE_TEAM_DEBUG_INFO_LOCK(team->debug_info); 1748 restore_interrupts(state); 1749 1750 release_sem(writeLock); 1751 } else { 1752 // We probably got a SIGKILL. If so, we will terminate when 1753 // reading the next message fails. 1754 } 1755 1756 break; 1757 } 1758 1759 case B_DEBUG_MESSAGE_HANDED_OVER: 1760 { 1761 // notify all threads that the debugger has changed 1762 broadcast_debugged_thread_message(nubThread, 1763 B_DEBUGGED_THREAD_DEBUGGER_CHANGED, NULL, 0); 1764 1765 break; 1766 } 1767 } 1768 1769 // send the reply, if necessary 1770 if (sendReply) { 1771 status_t error = kill_interruptable_write_port(replyPort, command, 1772 &reply, replySize); 1773 1774 if (error != B_OK) { 1775 // The debugger port is either not longer existing or we got 1776 // interrupted by a kill signal. In either case we terminate. 1777 TRACE(("nub thread %ld: failed to send reply to port %ld: %s\n", 1778 nubThread->id, replyPort, strerror(error))); 1779 1780 nub_thread_cleanup(nubThread); 1781 return error; 1782 } 1783 } 1784 } 1785 } 1786 1787 1788 /** \brief Helper function for install_team_debugger(), that sets up the team 1789 * and thread debug infos. 1790 * 1791 * Interrupts must be enabled and the team debug info lock of the team to be 1792 * debugged must be held. The function will release the lock, but leave 1793 * interrupts disabled. 1794 */ 1795 static void 1796 install_team_debugger_init_debug_infos(struct team *team, team_id debuggerTeam, 1797 port_id debuggerPort, port_id nubPort, thread_id nubThread, 1798 sem_id debuggerPortWriteLock) 1799 { 1800 atomic_set(&team->debug_info.flags, 1801 B_TEAM_DEBUG_DEFAULT_FLAGS | B_TEAM_DEBUG_DEBUGGER_INSTALLED); 1802 team->debug_info.nub_port = nubPort; 1803 team->debug_info.nub_thread = nubThread; 1804 team->debug_info.debugger_team = debuggerTeam; 1805 team->debug_info.debugger_port = debuggerPort; 1806 team->debug_info.debugger_write_lock = debuggerPortWriteLock; 1807 1808 RELEASE_TEAM_DEBUG_INFO_LOCK(team->debug_info); 1809 1810 // set the user debug flags and signal masks of all threads to the default 1811 GRAB_THREAD_LOCK(); 1812 1813 for (struct thread *thread = team->thread_list; 1814 thread; 1815 thread = thread->team_next) { 1816 if (thread->id == nubThread) { 1817 atomic_set(&thread->debug_info.flags, B_THREAD_DEBUG_NUB_THREAD); 1818 } else { 1819 int32 flags = thread->debug_info.flags 1820 & ~B_THREAD_DEBUG_USER_FLAG_MASK; 1821 atomic_set(&thread->debug_info.flags, 1822 flags | B_THREAD_DEBUG_DEFAULT_FLAGS); 1823 thread->debug_info.ignore_signals = 0; 1824 thread->debug_info.ignore_signals_once = 0; 1825 } 1826 } 1827 1828 RELEASE_THREAD_LOCK(); 1829 } 1830 1831 1832 static port_id 1833 install_team_debugger(team_id teamID, port_id debuggerPort, bool useDefault, 1834 bool dontFail) 1835 { 1836 TRACE(("install_team_debugger(team: %ld, port: %ld, default: %d, " 1837 "dontFail: %d)\n", teamID, debuggerPort, useDefault, dontFail)); 1838 1839 if (useDefault) 1840 debuggerPort = atomic_get(&sDefaultDebuggerPort); 1841 1842 // get the debugger team 1843 port_info debuggerPortInfo; 1844 status_t error = get_port_info(debuggerPort, &debuggerPortInfo); 1845 if (error != B_OK) { 1846 TRACE(("install_team_debugger(): Failed to get debugger port info: " 1847 "%lx\n", error)); 1848 return error; 1849 } 1850 team_id debuggerTeam = debuggerPortInfo.team; 1851 1852 // check the debugger team: It must neither be the kernel team nor the 1853 // debugged team 1854 if (debuggerTeam == team_get_kernel_team_id() || debuggerTeam == teamID) { 1855 TRACE(("install_team_debugger(): Can't debug kernel or debugger team. " 1856 "debugger: %ld, debugged: %ld\n", debuggerTeam, teamID)); 1857 return B_NOT_ALLOWED; 1858 } 1859 1860 // check, if a debugger is already installed 1861 1862 bool done = false; 1863 port_id result = B_ERROR; 1864 bool handOver = false; 1865 bool releaseDebugInfoLock = true; 1866 port_id oldDebuggerPort = -1; 1867 port_id nubPort = -1; 1868 1869 cpu_status state = disable_interrupts(); 1870 GRAB_TEAM_LOCK(); 1871 1872 // get a real team ID 1873 // We look up the team by ID, even in case of the current team, so we can be 1874 // sure, that the team is not already dying. 1875 if (teamID == B_CURRENT_TEAM) 1876 teamID = thread_get_current_thread()->team->id; 1877 1878 struct team *team = team_get_team_struct_locked(teamID); 1879 1880 if (team) { 1881 GRAB_TEAM_DEBUG_INFO_LOCK(team->debug_info); 1882 1883 int32 teamDebugFlags = team->debug_info.flags; 1884 1885 if (team == team_get_kernel_team()) { 1886 // don't allow to debug the kernel 1887 error = B_NOT_ALLOWED; 1888 } else if (teamDebugFlags & B_TEAM_DEBUG_DEBUGGER_INSTALLED) { 1889 if (teamDebugFlags & B_TEAM_DEBUG_DEBUGGER_HANDOVER) { 1890 // a handover to another debugger is requested 1891 // clear the flag 1892 atomic_and(& team->debug_info.flags, 1893 ~B_TEAM_DEBUG_DEBUGGER_HANDOVER); 1894 1895 oldDebuggerPort = team->debug_info.debugger_port; 1896 result = nubPort = team->debug_info.nub_port; 1897 1898 // set the new debugger 1899 install_team_debugger_init_debug_infos(team, debuggerTeam, 1900 debuggerPort, nubPort, team->debug_info.nub_thread, 1901 team->debug_info.debugger_write_lock); 1902 1903 releaseDebugInfoLock = false; 1904 handOver = true; 1905 done = true; 1906 1907 // finally set the new port owner 1908 if (set_port_owner(nubPort, debuggerTeam) != B_OK) { 1909 // The old debugger must just have died. Just proceed as 1910 // if there was no debugger installed. We may still be too 1911 // early, in which case we'll fail, but this race condition 1912 // should be unbelievably rare and relatively harmless. 1913 handOver = false; 1914 done = false; 1915 } 1916 1917 } else { 1918 // there's already a debugger installed 1919 error = (dontFail ? B_OK : B_BAD_VALUE); 1920 done = true; 1921 result = team->debug_info.nub_port; 1922 } 1923 } 1924 1925 // in case of a handover the lock has already been released 1926 if (releaseDebugInfoLock) 1927 RELEASE_TEAM_DEBUG_INFO_LOCK(team->debug_info); 1928 } else 1929 error = B_BAD_TEAM_ID; 1930 1931 RELEASE_TEAM_LOCK(); 1932 restore_interrupts(state); 1933 1934 if (handOver) { 1935 // notify the nub thread 1936 kill_interruptable_write_port(nubPort, B_DEBUG_MESSAGE_HANDED_OVER, 1937 NULL, 0); 1938 1939 // notify the old debugger 1940 debug_handed_over notification; 1941 notification.origin.thread = -1; 1942 notification.origin.team = teamID; 1943 notification.origin.nub_port = nubPort; 1944 notification.debugger = debuggerTeam; 1945 notification.debugger_port = debuggerPort; 1946 1947 error = write_port_etc(oldDebuggerPort, 1948 B_DEBUGGER_MESSAGE_HANDED_OVER, ¬ification, 1949 sizeof(notification), B_RELATIVE_TIMEOUT, 0); 1950 if (error != B_OK) { 1951 TRACE(("install_team_debugger(): Failed to send message to old " 1952 "debugger: %s\n", strerror(error))); 1953 } 1954 1955 TRACE(("install_team_debugger() done: handed over to debugger: team: " 1956 "%ld, port: %ld\n", debuggerTeam, debuggerPort)); 1957 1958 return result; 1959 } 1960 1961 if (done || error != B_OK) { 1962 TRACE(("install_team_debugger() done1: %ld\n", 1963 (error == B_OK ? result : error))); 1964 return (error == B_OK ? result : error); 1965 } 1966 1967 // create the debugger write lock semaphore 1968 char nameBuffer[B_OS_NAME_LENGTH]; 1969 snprintf(nameBuffer, sizeof(nameBuffer), "team %ld debugger port write", 1970 teamID); 1971 sem_id debuggerWriteLock = create_sem(1, nameBuffer); 1972 if (debuggerWriteLock < 0) 1973 error = debuggerWriteLock; 1974 1975 // create the nub port 1976 snprintf(nameBuffer, sizeof(nameBuffer), "team %ld debug", teamID); 1977 if (error == B_OK) { 1978 nubPort = create_port(1, nameBuffer); 1979 if (nubPort < 0) 1980 error = nubPort; 1981 else 1982 result = nubPort; 1983 } 1984 1985 // make the debugger team the port owner; thus we know, if the debugger is 1986 // gone and can cleanup 1987 if (error == B_OK) 1988 error = set_port_owner(nubPort, debuggerTeam); 1989 1990 // spawn the nub thread 1991 thread_id nubThread = -1; 1992 if (error == B_OK) { 1993 snprintf(nameBuffer, sizeof(nameBuffer), "team %ld debug task", teamID); 1994 nubThread = spawn_kernel_thread_etc(debug_nub_thread, nameBuffer, 1995 B_NORMAL_PRIORITY, NULL, teamID, -1); 1996 if (nubThread < 0) 1997 error = nubThread; 1998 } 1999 2000 // now adjust the debug info accordingly 2001 if (error == B_OK) { 2002 state = disable_interrupts(); 2003 GRAB_TEAM_LOCK(); 2004 2005 // look up again, to make sure the team isn't dying 2006 team = team_get_team_struct_locked(teamID); 2007 2008 if (team) { 2009 GRAB_TEAM_DEBUG_INFO_LOCK(team->debug_info); 2010 2011 if (team->debug_info.flags & B_TEAM_DEBUG_DEBUGGER_INSTALLED) { 2012 // there's already a debugger installed 2013 error = (dontFail ? B_OK : B_BAD_VALUE); 2014 done = true; 2015 result = team->debug_info.nub_port; 2016 2017 RELEASE_TEAM_DEBUG_INFO_LOCK(team->debug_info); 2018 } else { 2019 install_team_debugger_init_debug_infos(team, debuggerTeam, 2020 debuggerPort, nubPort, nubThread, debuggerWriteLock); 2021 } 2022 } else 2023 error = B_BAD_TEAM_ID; 2024 2025 RELEASE_TEAM_LOCK(); 2026 restore_interrupts(state); 2027 } 2028 2029 // if everything went fine, resume the nub thread, otherwise clean up 2030 if (error == B_OK && !done) { 2031 resume_thread(nubThread); 2032 } else { 2033 // delete port and terminate thread 2034 if (nubPort >= 0) { 2035 set_port_owner(nubPort, B_CURRENT_TEAM); 2036 delete_port(nubPort); 2037 } 2038 if (nubThread >= 0) { 2039 int32 result; 2040 wait_for_thread(nubThread, &result); 2041 } 2042 } 2043 2044 TRACE(("install_team_debugger() done2: %ld\n", 2045 (error == B_OK ? result : error))); 2046 return (error == B_OK ? result : error); 2047 } 2048 2049 2050 static status_t 2051 ensure_debugger_installed(team_id teamID, port_id *_port) 2052 { 2053 port_id port = install_team_debugger(teamID, -1, true, true); 2054 if (port < 0) 2055 return port; 2056 2057 if (_port) 2058 *_port = port; 2059 return B_OK; 2060 } 2061 2062 2063 // #pragma mark - 2064 2065 2066 void 2067 _user_debugger(const char *userMessage) 2068 { 2069 // install the default debugger, if there is none yet 2070 struct thread *thread = thread_get_current_thread(); 2071 port_id nubPort; 2072 status_t error = ensure_debugger_installed(B_CURRENT_TEAM, &nubPort); 2073 if (error != B_OK) { 2074 // time to commit suicide 2075 char buffer[128]; 2076 ssize_t length = user_strlcpy(buffer, userMessage, sizeof(buffer)); 2077 if (length >= 0) { 2078 dprintf("_user_debugger(): Failed to install debugger. Message is: " 2079 "`%s'\n", buffer); 2080 } else { 2081 dprintf("_user_debugger(): Failed to install debugger. Message is: " 2082 "%p (%s)\n", userMessage, strerror(length)); 2083 } 2084 _user_exit_team(1); 2085 } 2086 2087 // prepare the message 2088 debug_debugger_call message; 2089 message.message = (void*)userMessage; 2090 2091 thread_hit_debug_event(B_DEBUGGER_MESSAGE_DEBUGGER_CALL, &message, 2092 sizeof(message), true); 2093 } 2094 2095 2096 int 2097 _user_disable_debugger(int state) 2098 { 2099 struct team *team = thread_get_current_thread()->team; 2100 2101 cpu_status cpuState = disable_interrupts(); 2102 GRAB_TEAM_DEBUG_INFO_LOCK(team->debug_info); 2103 2104 int32 oldFlags; 2105 if (state) 2106 oldFlags = atomic_and(&team->debug_info.flags, ~B_TEAM_DEBUG_SIGNALS); 2107 else 2108 oldFlags = atomic_or(&team->debug_info.flags, B_TEAM_DEBUG_SIGNALS); 2109 2110 RELEASE_TEAM_DEBUG_INFO_LOCK(team->debug_info); 2111 restore_interrupts(cpuState); 2112 2113 // TODO: Check, if the return value is really the old state. 2114 return !(oldFlags & B_TEAM_DEBUG_SIGNALS); 2115 } 2116 2117 2118 status_t 2119 _user_install_default_debugger(port_id debuggerPort) 2120 { 2121 // if supplied, check whether the port is a valid port 2122 if (debuggerPort >= 0) { 2123 port_info portInfo; 2124 status_t error = get_port_info(debuggerPort, &portInfo); 2125 if (error != B_OK) 2126 return error; 2127 2128 // the debugger team must not be the kernel team 2129 if (portInfo.team == team_get_kernel_team_id()) 2130 return B_NOT_ALLOWED; 2131 } 2132 2133 atomic_set(&sDefaultDebuggerPort, debuggerPort); 2134 2135 return B_OK; 2136 } 2137 2138 2139 port_id 2140 _user_install_team_debugger(team_id teamID, port_id debuggerPort) 2141 { 2142 return install_team_debugger(teamID, debuggerPort, false, false); 2143 } 2144 2145 2146 status_t 2147 _user_remove_team_debugger(team_id teamID) 2148 { 2149 struct team_debug_info info; 2150 2151 status_t error = B_OK; 2152 2153 cpu_status state = disable_interrupts(); 2154 GRAB_TEAM_LOCK(); 2155 2156 struct team *team = (teamID == B_CURRENT_TEAM 2157 ? thread_get_current_thread()->team 2158 : team_get_team_struct_locked(teamID)); 2159 2160 if (team) { 2161 GRAB_TEAM_DEBUG_INFO_LOCK(team->debug_info); 2162 2163 if (team->debug_info.flags & B_TEAM_DEBUG_DEBUGGER_INSTALLED) { 2164 // there's a debugger installed 2165 info = team->debug_info; 2166 clear_team_debug_info(&team->debug_info, false); 2167 } else { 2168 // no debugger installed 2169 error = B_BAD_VALUE; 2170 } 2171 2172 RELEASE_TEAM_DEBUG_INFO_LOCK(team->debug_info); 2173 } else 2174 error = B_BAD_TEAM_ID; 2175 2176 RELEASE_TEAM_LOCK(); 2177 restore_interrupts(state); 2178 2179 // clean up the info, if there was a debugger installed 2180 if (error == B_OK) 2181 destroy_team_debug_info(&info); 2182 2183 return error; 2184 } 2185 2186 2187 status_t 2188 _user_debug_thread(thread_id threadID) 2189 { 2190 // tell the thread to stop as soon as possible 2191 status_t error = B_OK; 2192 cpu_status state = disable_interrupts(); 2193 GRAB_THREAD_LOCK(); 2194 2195 struct thread *thread = thread_get_thread_struct_locked(threadID); 2196 if (!thread) { 2197 // thread doesn't exist any longer 2198 error = B_BAD_THREAD_ID; 2199 } else if (thread->team == team_get_kernel_team()) { 2200 // we can't debug the kernel team 2201 error = B_NOT_ALLOWED; 2202 } else if (thread->debug_info.flags & B_THREAD_DEBUG_DYING) { 2203 // the thread is already dying -- too late to debug it 2204 error = B_BAD_THREAD_ID; 2205 } else if (thread->debug_info.flags & B_THREAD_DEBUG_NUB_THREAD) { 2206 // don't debug the nub thread 2207 error = B_NOT_ALLOWED; 2208 } else if (!(thread->debug_info.flags & B_THREAD_DEBUG_STOPPED)) { 2209 // set the flag that tells the thread to stop as soon as possible 2210 atomic_or(&thread->debug_info.flags, B_THREAD_DEBUG_STOP); 2211 2212 switch (thread->state) { 2213 case B_THREAD_SUSPENDED: 2214 // thread suspended: wake it up 2215 thread->state = thread->next_state = B_THREAD_READY; 2216 scheduler_enqueue_in_run_queue(thread); 2217 break; 2218 2219 case B_THREAD_WAITING: 2220 // thread waiting: interrupt it 2221 sem_interrupt_thread(thread); 2222 break; 2223 } 2224 } 2225 2226 RELEASE_THREAD_LOCK(); 2227 restore_interrupts(state); 2228 2229 return error; 2230 } 2231 2232 void 2233 _user_wait_for_debugger(void) 2234 { 2235 debug_thread_debugged message; 2236 thread_hit_debug_event(B_DEBUGGER_MESSAGE_THREAD_DEBUGGED, &message, 2237 sizeof(message), false); 2238 } 2239 2240 2241