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 }