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