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