1 /* 2 * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 // This is the source code for the subprocess forked by the Simple 26 // Windows Debug Server. It assumes most of the responsibility for the 27 // debug session, and processes all of the commands sent by clients. 28 29 // Disable too-long symbol warnings 30 #pragma warning ( disable : 4786 ) 31 32 #include <iostream> 33 #include <vector> 34 #include <stdlib.h> 35 #include <assert.h> 36 // Must come before windows.h 37 #include <winsock2.h> 38 #include <windows.h> 39 #include "IOBuf.hpp" 40 #include "libInfo.hpp" 41 #include "LockableList.hpp" 42 #include "Message.hpp" 43 #include "Monitor.hpp" 44 #include "nt4internals.hpp" 45 46 // Uncomment the #define below to get messages on stderr 47 // #define DEBUGGING 48 49 using namespace std; 50 51 DWORD pid; 52 HANDLE procHandle; 53 IOBuf* ioBuf; 54 55 // State flags indicating whether the attach to the remote process 56 // definitively succeeded or failed 57 volatile bool attachFailed = false; 58 volatile bool attachSucceeded = false; 59 60 // State flag indicating whether the target process is suspended. 61 // Modified by suspend()/resume(), viewed by debug thread, but only 62 // under cover of the threads lock. 63 volatile bool suspended = false; 64 65 // State flags indicating whether we are considered to be attached to 66 // the target process and are therefore queuing up events to be sent 67 // back to the debug server. These flags are only accessed and 68 // modified under the cover of the eventLock. 69 Monitor* eventLock; 70 // The following is set to true when a client is attached to this process 71 volatile bool generateDebugEvents = false; 72 // Pointer to current debug event; non-NULL indicates a debug event is 73 // waiting to be sent to the client. Main thread sets this to NULL to 74 // indicate that the event has been consumed; also sets 75 // passEventToClient, below. 76 volatile DEBUG_EVENT* curDebugEvent = NULL; 77 // Set by main thread to indicate whether the most recently posted 78 // debug event should be passed on to the target process. 79 volatile bool passEventToClient = true; 80 81 void conditionalPostDebugEvent(DEBUG_EVENT* ev, DWORD* continueOrNotHandledFlag) { 82 // FIXME: make it possible for the client to enable and disable 83 // certain types of events (have to do so in a platform-independent 84 // manner) 85 switch (ev->dwDebugEventCode) { 86 case EXCEPTION_DEBUG_EVENT: 87 switch (ev->u.Exception.ExceptionRecord.ExceptionCode) { 88 case EXCEPTION_BREAKPOINT: break; 89 case EXCEPTION_SINGLE_STEP: break; 90 case EXCEPTION_ACCESS_VIOLATION: break; 91 default: return; 92 } 93 } 94 eventLock->lock(); 95 if (generateDebugEvents) { 96 curDebugEvent = ev; 97 while (curDebugEvent != NULL) { 98 eventLock->wait(); 99 } 100 if (passEventToClient) { 101 *continueOrNotHandledFlag = DBG_EXCEPTION_NOT_HANDLED; 102 } else { 103 *continueOrNotHandledFlag = DBG_CONTINUE; 104 } 105 } 106 eventLock->unlock(); 107 } 108 109 110 //---------------------------------------------------------------------- 111 // Module list 112 // 113 114 vector<LibInfo> libs; 115 116 //---------------------------------------------------------------------- 117 // Thread list 118 // 119 120 struct ThreadInfo { 121 DWORD tid; 122 HANDLE thread; 123 124 ThreadInfo(DWORD tid, HANDLE thread) { 125 this->tid = tid; 126 this->thread = thread; 127 } 128 }; 129 130 class ThreadList : public LockableList<ThreadInfo> { 131 public: 132 bool removeByThreadID(DWORD tid) { 133 for (InternalListType::iterator iter = internalList.begin(); 134 iter != internalList.end(); iter++) { 135 if ((*iter).tid == tid) { 136 internalList.erase(iter); 137 return true; 138 } 139 } 140 return false; 141 } 142 HANDLE threadIDToHandle(DWORD tid) { 143 for (InternalListType::iterator iter = internalList.begin(); 144 iter != internalList.end(); iter++) { 145 if ((*iter).tid == tid) { 146 return (*iter).thread; 147 } 148 } 149 return NULL; 150 } 151 }; 152 153 ThreadList threads; 154 155 //---------------------------------------------------------------------- 156 // INITIALIZATION AND TERMINATION 157 // 158 159 void 160 printError(const char* prefix) { 161 DWORD detail = GetLastError(); 162 LPTSTR message; 163 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 164 FORMAT_MESSAGE_FROM_SYSTEM, 165 0, 166 detail, 167 0, 168 (LPTSTR) &message, 169 1, 170 NULL); 171 // FIXME: This is signaling an error: "The handle is invalid." ? 172 // Do I have to do all of my WaitForDebugEvent calls from the same thread? 173 cerr << prefix << ": " << message << endl; 174 LocalFree(message); 175 } 176 177 void 178 endProcess(bool waitForProcess = true) { 179 NT4::unloadNTDLL(); 180 if (waitForProcess) { 181 // Though we're exiting because of an error, do not tear down the 182 // target process. 183 WaitForSingleObject(procHandle, INFINITE); 184 } 185 CloseHandle(procHandle); 186 exit(0); 187 } 188 189 DWORD WINAPI 190 debugThreadEntry(void*) { 191 #ifdef DEBUGGING 192 DWORD lastMsgId = 0; 193 int count = 0; 194 #endif 195 196 if (!DebugActiveProcess(pid)) { 197 attachFailed = true; 198 return 0; 199 } 200 201 // Wait for debug events. We keep the information from some of these 202 // on the side in anticipation of later queries by the client. NOTE 203 // that we leave the process running. The main thread is responsible 204 // for suspending and resuming all currently-active threads upon 205 // client attach and detach. 206 207 while (true) { 208 DEBUG_EVENT ev; 209 if (!WaitForDebugEvent(&ev, INFINITE)) { 210 #ifdef DEBUGGING 211 if (++count < 10) { 212 // FIXME: This is signaling an error: "The handle is invalid." ? 213 // Do I have to do all of my WaitForDebugEvent calls from the same thread? 214 printError("WaitForDebugEvent failed"); 215 } 216 #endif 217 } else { 218 219 #ifdef DEBUGGING 220 if (ev.dwDebugEventCode != lastMsgId) { 221 lastMsgId = ev.dwDebugEventCode; 222 count = 0; 223 cerr << "Debug thread received event " << ev.dwDebugEventCode << endl; 224 } else { 225 if (++count < 10) { 226 cerr << "Debug thread received event " << ev.dwDebugEventCode << endl; 227 } 228 } 229 #endif 230 231 DWORD dbgContinueMode = DBG_CONTINUE; 232 233 switch (ev.dwDebugEventCode) { 234 case LOAD_DLL_DEBUG_EVENT: 235 conditionalPostDebugEvent(&ev, &dbgContinueMode); 236 break; 237 238 case UNLOAD_DLL_DEBUG_EVENT: 239 conditionalPostDebugEvent(&ev, &dbgContinueMode); 240 break; 241 242 case CREATE_PROCESS_DEBUG_EVENT: 243 threads.lock(); 244 // FIXME: will this deal properly with child processes? If 245 // not, is it possible to make it do so? 246 #ifdef DEBUGGING 247 cerr << "CREATE_PROCESS_DEBUG_EVENT " << ev.dwThreadId 248 << " " << ev.u.CreateProcessInfo.hThread << endl; 249 #endif 250 if (ev.u.CreateProcessInfo.hThread != NULL) { 251 threads.add(ThreadInfo(ev.dwThreadId, ev.u.CreateProcessInfo.hThread)); 252 } 253 threads.unlock(); 254 break; 255 256 case CREATE_THREAD_DEBUG_EVENT: 257 threads.lock(); 258 #ifdef DEBUGGING 259 cerr << "CREATE_THREAD_DEBUG_EVENT " << ev.dwThreadId 260 << " " << ev.u.CreateThread.hThread << endl; 261 #endif 262 if (suspended) { 263 // Suspend this thread before adding it to the thread list 264 SuspendThread(ev.u.CreateThread.hThread); 265 } 266 threads.add(ThreadInfo(ev.dwThreadId, ev.u.CreateThread.hThread)); 267 threads.unlock(); 268 break; 269 270 case EXIT_THREAD_DEBUG_EVENT: 271 threads.lock(); 272 #ifdef DEBUGGING 273 cerr << "EXIT_THREAD_DEBUG_EVENT " << ev.dwThreadId << endl; 274 #endif 275 threads.removeByThreadID(ev.dwThreadId); 276 threads.unlock(); 277 break; 278 279 case EXCEPTION_DEBUG_EVENT: 280 // cerr << "EXCEPTION_DEBUG_EVENT" << endl; 281 switch (ev.u.Exception.ExceptionRecord.ExceptionCode) { 282 case EXCEPTION_BREAKPOINT: 283 // cerr << "EXCEPTION_BREAKPOINT" << endl; 284 if (!attachSucceeded && !attachFailed) { 285 attachSucceeded = true; 286 } 287 break; 288 289 default: 290 dbgContinueMode = DBG_EXCEPTION_NOT_HANDLED; 291 break; 292 } 293 conditionalPostDebugEvent(&ev, &dbgContinueMode); 294 break; 295 296 case EXIT_PROCESS_DEBUG_EVENT: 297 endProcess(false); 298 // NOT REACHED 299 break; 300 301 default: 302 #ifdef DEBUGGING 303 cerr << "Received debug event " << ev.dwDebugEventCode << endl; 304 #endif 305 break; 306 } 307 308 ContinueDebugEvent(ev.dwProcessId, ev.dwThreadId, dbgContinueMode); 309 } 310 } 311 } 312 313 bool 314 attachToProcess() { 315 // Create event lock 316 eventLock = new Monitor(); 317 318 // Get a process handle for later 319 procHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); 320 if (procHandle == NULL) { 321 return false; 322 } 323 324 // Start up the debug thread 325 DWORD debugThreadId; 326 if (CreateThread(NULL, 0, &debugThreadEntry, NULL, 0, &debugThreadId) == NULL) { 327 // Failed to make background debug thread. Fail. 328 return false; 329 } 330 331 while ((!attachSucceeded) && (!attachFailed)) { 332 Sleep(1); 333 } 334 335 if (attachFailed) { 336 return false; 337 } 338 339 assert(attachSucceeded); 340 341 return true; 342 } 343 344 bool 345 readMessage(Message* msg) { 346 DWORD numRead; 347 if (!ReadFile(GetStdHandle(STD_INPUT_HANDLE), 348 msg, 349 sizeof(Message), 350 &numRead, 351 NULL)) { 352 return false; 353 } 354 if (numRead != sizeof(Message)) { 355 return false; 356 } 357 // For "poke" messages, must follow up by reading raw data 358 if (msg->type == Message::POKE) { 359 char* dataBuf = new char[msg->pokeArg.numBytes]; 360 if (dataBuf == NULL) { 361 return false; 362 } 363 if (!ReadFile(GetStdHandle(STD_INPUT_HANDLE), 364 dataBuf, 365 msg->pokeArg.numBytes, 366 &numRead, 367 NULL)) { 368 delete[] dataBuf; 369 return false; 370 } 371 if (numRead != msg->pokeArg.numBytes) { 372 delete[] dataBuf; 373 return false; 374 } 375 msg->pokeArg.data = (void *) dataBuf; 376 } 377 return true; 378 } 379 380 void 381 handlePeek(Message* msg) { 382 #ifdef DEBUGGING 383 cerr << "Entering handlePeek()" << endl; 384 #endif 385 386 char* memBuf = new char[msg->peekArg.numBytes]; 387 if (memBuf == NULL) { 388 ioBuf->writeString("B"); 389 ioBuf->writeBinChar(0); 390 ioBuf->flush(); 391 delete[] memBuf; 392 return; 393 } 394 395 // Try fast case first 396 DWORD numRead; 397 BOOL res = ReadProcessMemory(procHandle, 398 (LPCVOID) msg->peekArg.address, 399 memBuf, 400 msg->peekArg.numBytes, 401 &numRead); 402 if (res && (numRead == msg->peekArg.numBytes)) { 403 404 // OK, complete success. Phew. 405 #ifdef DEBUGGING 406 cerr << "Peek success case" << endl; 407 #endif 408 ioBuf->writeString("B"); 409 ioBuf->writeBinChar(1); 410 ioBuf->writeBinUnsignedInt(numRead); 411 ioBuf->writeBinChar(1); 412 ioBuf->writeBinBuf(memBuf, numRead); 413 } else { 414 #ifdef DEBUGGING 415 cerr << "*** Peek slow case ***" << endl; 416 #endif 417 418 ioBuf->writeString("B"); 419 ioBuf->writeBinChar(1); 420 421 // Use VirtualQuery to speed things up a bit 422 DWORD numLeft = msg->peekArg.numBytes; 423 char* curAddr = (char*) msg->peekArg.address; 424 while (numLeft > 0) { 425 MEMORY_BASIC_INFORMATION memInfo; 426 VirtualQueryEx(procHandle, curAddr, &memInfo, sizeof(memInfo)); 427 DWORD numToRead = memInfo.RegionSize; 428 if (numToRead > numLeft) { 429 numToRead = numLeft; 430 } 431 DWORD numRead; 432 if (memInfo.State == MEM_COMMIT) { 433 // Read the process memory at this address for this length 434 // FIXME: should check the result of this read 435 ReadProcessMemory(procHandle, curAddr, memBuf, 436 numToRead, &numRead); 437 // Write this out 438 #ifdef DEBUGGING 439 cerr << "*** Writing " << numToRead << " bytes as mapped ***" << endl; 440 #endif 441 ioBuf->writeBinUnsignedInt(numToRead); 442 ioBuf->writeBinChar(1); 443 ioBuf->writeBinBuf(memBuf, numToRead); 444 } else { 445 // Indicate region is free 446 #ifdef DEBUGGING 447 cerr << "*** Writing " << numToRead << " bytes as unmapped ***" << endl; 448 #endif 449 ioBuf->writeBinUnsignedInt(numToRead); 450 ioBuf->writeBinChar(0); 451 } 452 curAddr += numToRead; 453 numLeft -= numToRead; 454 } 455 } 456 457 ioBuf->flush(); 458 delete[] memBuf; 459 #ifdef DEBUGGING 460 cerr << "Exiting handlePeek()" << endl; 461 #endif 462 } 463 464 void 465 handlePoke(Message* msg) { 466 #ifdef DEBUGGING 467 cerr << "Entering handlePoke()" << endl; 468 #endif 469 DWORD numWritten; 470 BOOL res = WriteProcessMemory(procHandle, 471 (LPVOID) msg->pokeArg.address, 472 msg->pokeArg.data, 473 msg->pokeArg.numBytes, 474 &numWritten); 475 if (res && (numWritten == msg->pokeArg.numBytes)) { 476 // Success 477 ioBuf->writeBoolAsInt(true); 478 #ifdef DEBUGGING 479 cerr << " (Succeeded)" << endl; 480 #endif 481 } else { 482 // Failure 483 ioBuf->writeBoolAsInt(false); 484 #ifdef DEBUGGING 485 cerr << " (Failed)" << endl; 486 #endif 487 } 488 ioBuf->writeEOL(); 489 ioBuf->flush(); 490 // We clean up the data 491 char* dataBuf = (char*) msg->pokeArg.data; 492 delete[] dataBuf; 493 #ifdef DEBUGGING 494 cerr << "Exiting handlePoke()" << endl; 495 #endif 496 } 497 498 bool 499 suspend() { 500 if (suspended) { 501 return false; 502 } 503 // Before we suspend, we must take a snapshot of the loaded module 504 // names and base addresses, since acquiring this snapshot requires 505 // starting and exiting a thread in the remote process (at least on 506 // NT 4). 507 libs.clear(); 508 #ifdef DEBUGGING 509 cerr << "Starting suspension" << endl; 510 #endif 511 libInfo(pid, libs); 512 #ifdef DEBUGGING 513 cerr << " Got lib info" << endl; 514 #endif 515 threads.lock(); 516 #ifdef DEBUGGING 517 cerr << " Got thread lock" << endl; 518 #endif 519 suspended = true; 520 int j = 0; 521 for (int i = 0; i < threads.size(); i++) { 522 j++; 523 SuspendThread(threads.get(i).thread); 524 } 525 #ifdef DEBUGGING 526 cerr << "Suspended " << j << " threads" << endl; 527 #endif 528 threads.unlock(); 529 return true; 530 } 531 532 bool 533 resume() { 534 if (!suspended) { 535 return false; 536 } 537 threads.lock(); 538 suspended = false; 539 for (int i = 0; i < threads.size(); i++) { 540 ResumeThread(threads.get(i).thread); 541 } 542 threads.unlock(); 543 #ifdef DEBUGGING 544 cerr << "Resumed process" << endl; 545 #endif 546 return true; 547 } 548 549 int 550 main(int argc, char **argv) 551 { 552 if (argc != 2) { 553 // Should only be used by performing CreateProcess within SwDbgSrv 554 exit(1); 555 } 556 557 if (sscanf(argv[1], "%u", &pid) != 1) { 558 exit(1); 559 } 560 561 // Try to attach to process 562 if (!attachToProcess()) { 563 // Attach failed. Notify parent by writing result to stdout file 564 // handle. 565 char res = 0; 566 DWORD numBytes; 567 WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), &res, sizeof(res), 568 &numBytes, NULL); 569 exit(1); 570 } 571 572 // Server is expecting success result back. 573 char res = 1; 574 DWORD numBytes; 575 WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), &res, sizeof(res), 576 &numBytes, NULL); 577 578 // Initialize our I/O buffer 579 ioBuf = new IOBuf(32768, 131072); 580 ioBuf->setOutputFileHandle(GetStdHandle(STD_OUTPUT_HANDLE)); 581 582 // At this point we are attached. Enter our main loop which services 583 // requests from the server. Note that in order to handle attach/ 584 // detach properly (i.e., resumption of process upon "detach") we 585 // will need another thread which handles debug events. 586 while (true) { 587 // Read a message from the server 588 Message msg; 589 if (!readMessage(&msg)) { 590 endProcess(); 591 } 592 593 #ifdef DEBUGGING 594 cerr << "Main thread read message: " << msg.type << endl; 595 #endif 596 597 switch (msg.type) { 598 // ATTACH and DETACH messages MUST come in pairs 599 case Message::ATTACH: 600 suspend(); 601 eventLock->lock(); 602 generateDebugEvents = true; 603 eventLock->unlock(); 604 break; 605 606 case Message::DETACH: 607 eventLock->lock(); 608 generateDebugEvents = false; 609 // Flush remaining event if any 610 if (curDebugEvent != NULL) { 611 curDebugEvent = NULL; 612 eventLock->notifyAll(); 613 } 614 eventLock->unlock(); 615 resume(); 616 break; 617 618 case Message::LIBINFO: 619 { 620 if (!suspended) { 621 ioBuf->writeInt(0); 622 } else { 623 // Send back formatted text 624 ioBuf->writeInt(libs.size()); 625 for (int i = 0; i < libs.size(); i++) { 626 ioBuf->writeSpace(); 627 ioBuf->writeInt(1); 628 ioBuf->writeSpace(); 629 ioBuf->writeInt(libs[i].name.size()); 630 ioBuf->writeSpace(); 631 ioBuf->writeString(libs[i].name.c_str()); 632 ioBuf->writeSpace(); 633 ioBuf->writeAddress(libs[i].base); 634 } 635 } 636 ioBuf->writeEOL(); 637 ioBuf->flush(); 638 break; 639 } 640 641 case Message::PEEK: 642 handlePeek(&msg); 643 break; 644 645 case Message::POKE: 646 handlePoke(&msg); 647 break; 648 649 case Message::THREADLIST: 650 { 651 if (!suspended) { 652 ioBuf->writeInt(0); 653 } else { 654 threads.lock(); 655 ioBuf->writeInt(threads.size()); 656 for (int i = 0; i < threads.size(); i++) { 657 ioBuf->writeSpace(); 658 ioBuf->writeAddress((void*) threads.get(i).thread); 659 } 660 threads.unlock(); 661 } 662 ioBuf->writeEOL(); 663 ioBuf->flush(); 664 break; 665 } 666 667 case Message::DUPHANDLE: 668 { 669 HANDLE dup; 670 if (DuplicateHandle(procHandle, 671 msg.handleArg.handle, 672 GetCurrentProcess(), 673 &dup, 674 0, 675 FALSE, 676 DUPLICATE_SAME_ACCESS)) { 677 ioBuf->writeBoolAsInt(true); 678 ioBuf->writeSpace(); 679 ioBuf->writeAddress((void*) dup); 680 } else { 681 ioBuf->writeBoolAsInt(false); 682 } 683 ioBuf->writeEOL(); 684 ioBuf->flush(); 685 break; 686 } 687 688 case Message::CLOSEHANDLE: 689 { 690 CloseHandle(msg.handleArg.handle); 691 break; 692 } 693 694 case Message::GETCONTEXT: 695 { 696 if (!suspended) { 697 ioBuf->writeBoolAsInt(false); 698 } else { 699 CONTEXT context; 700 context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS; 701 if (GetThreadContext(msg.handleArg.handle, &context)) { 702 ioBuf->writeBoolAsInt(true); 703 // EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP, EIP, DS, ES, FS, GS, 704 // CS, SS, EFLAGS, DR0, DR1, DR2, DR3, DR6, DR7 705 // See README-commands.txt 706 ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Eax); 707 ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Ebx); 708 ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Ecx); 709 ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Edx); 710 ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Esi); 711 ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Edi); 712 ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Ebp); 713 ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Esp); 714 ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Eip); 715 ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.SegDs); 716 ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.SegEs); 717 ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.SegFs); 718 ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.SegGs); 719 ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.SegCs); 720 ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.SegSs); 721 ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.EFlags); 722 ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Dr0); 723 ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Dr1); 724 ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Dr2); 725 ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Dr3); 726 ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Dr6); 727 ioBuf->writeSpace(); ioBuf->writeAddress((void*) context.Dr7); 728 } else { 729 ioBuf->writeBoolAsInt(false); 730 } 731 } 732 ioBuf->writeEOL(); 733 ioBuf->flush(); 734 break; 735 } 736 737 case Message::SETCONTEXT: 738 { 739 if (!suspended) { 740 ioBuf->writeBoolAsInt(false); 741 } else { 742 CONTEXT context; 743 context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS; 744 context.Eax = msg.setContextArg.Eax; 745 context.Ebx = msg.setContextArg.Ebx; 746 context.Ecx = msg.setContextArg.Ecx; 747 context.Edx = msg.setContextArg.Edx; 748 context.Esi = msg.setContextArg.Esi; 749 context.Edi = msg.setContextArg.Edi; 750 context.Ebp = msg.setContextArg.Ebp; 751 context.Esp = msg.setContextArg.Esp; 752 context.Eip = msg.setContextArg.Eip; 753 context.SegDs = msg.setContextArg.Ds; 754 context.SegEs = msg.setContextArg.Es; 755 context.SegFs = msg.setContextArg.Fs; 756 context.SegGs = msg.setContextArg.Gs; 757 context.SegCs = msg.setContextArg.Cs; 758 context.SegSs = msg.setContextArg.Ss; 759 context.EFlags = msg.setContextArg.EFlags; 760 context.Dr0 = msg.setContextArg.Dr0; 761 context.Dr1 = msg.setContextArg.Dr1; 762 context.Dr2 = msg.setContextArg.Dr2; 763 context.Dr3 = msg.setContextArg.Dr3; 764 context.Dr6 = msg.setContextArg.Dr6; 765 context.Dr7 = msg.setContextArg.Dr7; 766 if (SetThreadContext(msg.setContextArg.handle, &context)) { 767 ioBuf->writeBoolAsInt(true); 768 } else { 769 ioBuf->writeBoolAsInt(false); 770 } 771 } 772 ioBuf->writeEOL(); 773 ioBuf->flush(); 774 break; 775 } 776 777 case Message::SELECTORENTRY: 778 { 779 LDT_ENTRY entry; 780 781 if (GetThreadSelectorEntry(msg.selectorArg.handle, 782 msg.selectorArg.selector, 783 &entry)) { 784 ioBuf->writeBoolAsInt(true); 785 ioBuf->writeSpace(); ioBuf->writeAddress((void*) entry.LimitLow); 786 ioBuf->writeSpace(); ioBuf->writeAddress((void*) entry.BaseLow); 787 ioBuf->writeSpace(); ioBuf->writeAddress((void*) entry.HighWord.Bytes.BaseMid); 788 ioBuf->writeSpace(); ioBuf->writeAddress((void*) entry.HighWord.Bytes.Flags1); 789 ioBuf->writeSpace(); ioBuf->writeAddress((void*) entry.HighWord.Bytes.Flags2); 790 ioBuf->writeSpace(); ioBuf->writeAddress((void*) entry.HighWord.Bytes.BaseHi); 791 } else { 792 ioBuf->writeBoolAsInt(false); 793 } 794 795 ioBuf->writeEOL(); 796 ioBuf->flush(); 797 break; 798 } 799 800 case Message::SUSPEND: 801 suspend(); 802 break; 803 804 case Message::RESUME: 805 resume(); 806 break; 807 808 case Message::POLLEVENT: 809 eventLock->lock(); 810 if (curDebugEvent == NULL) { 811 ioBuf->writeBoolAsInt(false); 812 } else { 813 ioBuf->writeBoolAsInt(true); 814 ioBuf->writeSpace(); 815 threads.lock(); 816 ioBuf->writeAddress((void*) threads.threadIDToHandle(curDebugEvent->dwThreadId)); 817 threads.unlock(); 818 ioBuf->writeSpace(); 819 ioBuf->writeUnsignedInt(curDebugEvent->dwDebugEventCode); 820 // Figure out what else to write 821 switch (curDebugEvent->dwDebugEventCode) { 822 case LOAD_DLL_DEBUG_EVENT: 823 ioBuf->writeSpace(); 824 ioBuf->writeAddress(curDebugEvent->u.LoadDll.lpBaseOfDll); 825 break; 826 827 case UNLOAD_DLL_DEBUG_EVENT: 828 ioBuf->writeSpace(); 829 ioBuf->writeAddress(curDebugEvent->u.UnloadDll.lpBaseOfDll); 830 break; 831 832 case EXCEPTION_DEBUG_EVENT: 833 { 834 DWORD code = curDebugEvent->u.Exception.ExceptionRecord.ExceptionCode; 835 ioBuf->writeSpace(); 836 ioBuf->writeUnsignedInt(code); 837 ioBuf->writeSpace(); 838 ioBuf->writeAddress(curDebugEvent->u.Exception.ExceptionRecord.ExceptionAddress); 839 switch (curDebugEvent->u.Exception.ExceptionRecord.ExceptionCode) { 840 case EXCEPTION_ACCESS_VIOLATION: 841 ioBuf->writeSpace(); 842 ioBuf->writeBoolAsInt(curDebugEvent->u.Exception.ExceptionRecord.ExceptionInformation[0] != 0); 843 ioBuf->writeSpace(); 844 ioBuf->writeAddress((void*) curDebugEvent->u.Exception.ExceptionRecord.ExceptionInformation[1]); 845 break; 846 847 default: 848 break; 849 } 850 break; 851 } 852 853 default: 854 break; 855 } 856 } 857 eventLock->unlock(); 858 ioBuf->writeEOL(); 859 ioBuf->flush(); 860 break; 861 862 case Message::CONTINUEEVENT: 863 eventLock->lock(); 864 if (curDebugEvent == NULL) { 865 ioBuf->writeBoolAsInt(false); 866 } else { 867 curDebugEvent = NULL; 868 passEventToClient = msg.boolArg.val; 869 ioBuf->writeBoolAsInt(true); 870 eventLock->notify(); 871 } 872 eventLock->unlock(); 873 ioBuf->writeEOL(); 874 ioBuf->flush(); 875 break; 876 } 877 } 878 879 endProcess(); 880 881 // NOT REACHED 882 return 0; 883 }