Mercurial > hg > truffle
annotate agent/src/os/win32/SwDbgSub.cpp @ 1994:6cd6d394f280
7001033: assert(gch->gc_cause() == GCCause::_scavenge_alot || !gch->incremental_collection_failed())
7002546: regression on SpecJbb2005 on 7b118 comparing to 7b117 on small heaps
Summary: Relaxed assertion checking related to incremental_collection_failed flag to allow for ExplicitGCInvokesConcurrent behaviour where we do not want a failing scavenge to bail to a stop-world collection. Parameterized incremental_collection_will_fail() so we can selectively use, or not use, as appropriate, the statistical prediction at specific use sites. This essentially reverts the scavenge bail-out logic to what it was prior to some recent changes that had inadvertently started using the statistical prediction which can be noisy in the presence of bursty loads. Added some associated verbose non-product debugging messages.
Reviewed-by: johnc, tonyp
author | ysr |
---|---|
date | Tue, 07 Dec 2010 21:55:53 -0800 |
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 } |