Mercurial > hg > truffle
annotate agent/src/os/win32/SwDbgSub.cpp @ 2183:eed52202caea
Added parameter to array store exception runtime call (new in HotSpot).
author | Thomas Wuerthinger <wuerthinger@ssw.jku.at> |
---|---|
date | Wed, 16 Feb 2011 15:13:34 +0100 |
parents | c18cbe5936b8 |
children |
rev | line source |
---|---|
0 | 1 /* |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
2 * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved. |
0 | 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 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
21 * questions. |
0 | 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 } |