Mercurial > hg > truffle
annotate agent/src/os/win32/SwDbgSrv.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 // A Simple Windows Debug Server. | |
26 // | |
27 // This software provides a socket-based debug server which uses | |
28 // mostly ASCII protocols to communicate with its clients. Since the | |
29 // Windows security model is largely based around being able to run | |
30 // programs on the machine, this server only accepts connections | |
31 // coming from localhost. | |
32 // | |
33 // When run as a service (under Windows NT), this software provides | |
34 // clients the ability to attach to and detach from processes without | |
35 // killing those processes. Ordinarily this is forbidden by the | |
36 // Windows debugging APIs (although more recent debugging environments | |
37 // from Microsoft seem to have circumvented this restriction, perhaps | |
38 // in a different way). This is achieved by forking a persistent | |
39 // subprocess for each debugging session which remains alive as long | |
40 // as the target process is. | |
41 // | |
42 // At this point the client can read information out of the target | |
43 // process's address space. Future work includes exposing more | |
44 // functionality like writing to the remote address space and | |
45 // suspending and resuming threads. | |
46 | |
47 #include <iostream> | |
48 #include <vector> | |
49 #include <stdlib.h> | |
50 // Must come before everything else | |
51 #include <winsock2.h> | |
52 #include <assert.h> | |
53 #include "Dispatcher.hpp" | |
54 #include "Handler.hpp" | |
55 #include "initWinsock.hpp" | |
56 #include "ioUtils.hpp" | |
57 #include "isNT4.hpp" | |
58 #include "Message.hpp" | |
59 #include "nt4internals.hpp" | |
60 #include "ports.h" | |
61 #include "procList.hpp" | |
62 #include "serverLists.hpp" | |
63 #include "Reaper.hpp" | |
64 | |
65 // Uncomment the #define below to get messages on stderr | |
66 // #define DEBUGGING | |
67 | |
68 using namespace std; | |
69 | |
70 static ChildList childList; | |
71 static ClientList clientList; | |
72 static Reaper* reaper = NULL; | |
73 | |
74 // Needed prototypes | |
75 void shutdownChild(ChildInfo* childInfo); | |
76 void detachClient(ClientInfo* clientInfo); | |
77 void shutdownClient(ClientInfo* clientInfo); | |
78 | |
79 char * | |
80 longToDotFormat(long addr) | |
81 { | |
82 char *temp_s = new char[20]; | |
83 | |
84 sprintf(temp_s, "%d.%d.%d.%d", ((addr & 0xff000000) >> 24), | |
85 ((addr & 0x00ff0000) >> 16), ((addr & 0x0000ff00) >> 8), | |
86 (addr & 0x000000ff)); | |
87 | |
88 return temp_s; | |
89 } | |
90 | |
91 // NOTE that we do this query every time. It is a bad idea to cache IP | |
92 // addresses. For example, we might be hosted on a machine using DHCP | |
93 // and the connection addresses might change over time. (Yes, this | |
94 // actually happened.) | |
95 bool | |
96 isConnectionOkay(ULONG connAddr) { | |
97 if (connAddr == INADDR_LOOPBACK) { | |
98 return true; | |
99 } | |
100 | |
101 const int MAXNAME = 1024; | |
102 char myname[MAXNAME]; | |
103 gethostname(myname, MAXNAME); | |
104 struct hostent* myInfo = gethostbyname(myname); | |
105 if (myInfo == NULL) { | |
106 #ifdef DEBUGGING | |
107 cerr << "My host information was null" << endl; | |
108 #endif | |
109 } else { | |
110 // Run down the list of IP addresses for myself | |
111 assert(myInfo->h_length == sizeof(ULONG)); | |
112 #ifdef DEBUGGING | |
113 cerr << "My known IP addresses: " << endl; | |
114 #endif | |
115 for (char** pp = myInfo->h_addr_list; *pp != NULL; pp++) { | |
116 char* p = *pp; | |
117 ULONG altAddr = ntohl(*((ULONG*) p)); | |
118 #ifdef DEBUGGING | |
119 char* name = longToDotFormat(altAddr); | |
120 cerr << name << endl; | |
121 delete[] name; | |
122 #endif | |
123 if (altAddr == connAddr) { | |
124 #ifdef DEBUGGING | |
125 cerr << "FOUND" << endl; | |
126 #endif | |
127 return true; | |
128 } | |
129 } | |
130 #ifdef DEBUGGING | |
131 cerr << "Done." << endl; | |
132 #endif | |
133 } | |
134 | |
135 return false; | |
136 } | |
137 | |
138 SOCKET | |
139 setupListeningSocket(short port) { | |
140 SOCKET listening = socket(AF_INET, SOCK_STREAM, 0); | |
141 if (listening == INVALID_SOCKET) { | |
142 cerr << "Error creating listening socket" << endl; | |
143 exit(1); | |
144 } | |
145 | |
146 int reuseAddress = 1; | |
147 if (setsockopt(listening, SOL_SOCKET, SO_REUSEADDR, | |
148 (char *)&reuseAddress, sizeof(reuseAddress)) == -1) { | |
149 cerr << "Error reusing address" << endl; | |
150 exit(1); | |
151 } | |
152 | |
153 struct sockaddr_in serverInfo; | |
154 | |
155 memset((char *)&serverInfo, 0, sizeof(serverInfo)); | |
156 serverInfo.sin_addr.s_addr = INADDR_ANY; | |
157 serverInfo.sin_family = AF_INET; | |
158 serverInfo.sin_port = htons(port); | |
159 | |
160 if (bind(listening, (struct sockaddr *) &serverInfo, sizeof(serverInfo)) < 0) { | |
161 cerr << "Error binding socket" << endl; | |
162 exit(1); | |
163 } | |
164 | |
165 if (listen(listening, 5) < 0) { | |
166 cerr << "Error listening" << endl; | |
167 exit(1); | |
168 } | |
169 | |
170 return listening; | |
171 } | |
172 | |
173 /** Accepts a connection from the given listening socket, but only if | |
174 the connection came from localhost. Returns INVALID_SOCKET if the | |
175 connection came from any other IP address or if an error occurred | |
176 during the call to accept(). */ | |
177 SOCKET | |
178 acceptFromLocalhost(SOCKET listening) { | |
179 struct sockaddr_in peerAddr; | |
180 int peerAddrLen = sizeof(peerAddr); | |
181 SOCKET fd = accept(listening, (sockaddr*) &peerAddr, &peerAddrLen); | |
182 if (fd == INVALID_SOCKET) { | |
183 return fd; | |
184 } | |
185 | |
186 if (!isConnectionOkay(ntohl(peerAddr.sin_addr.s_addr))) { | |
187 // Reject connections from other machines for security purposes. | |
188 // The Windows security model seems to assume one user per | |
189 // machine, and that security is compromised if another user is | |
190 // able to run executables on the given host. (If these | |
191 // assumptions are not strict enough, we will have to change | |
192 // this.) | |
193 shutdown(fd, SD_BOTH); | |
194 closesocket(fd); | |
195 return INVALID_SOCKET; | |
196 } | |
197 | |
198 // Disable TCP buffering on all sockets. We send small amounts of | |
199 // data back and forth and don't want buffering. | |
200 int buffer_val = 1; | |
201 if (setsockopt(fd, IPPROTO_IP, TCP_NODELAY, | |
202 (char *) &buffer_val, sizeof(buffer_val)) < 0) { | |
203 shutdown(fd, SD_BOTH); | |
204 closesocket(fd); | |
205 } | |
206 | |
207 return fd; | |
208 } | |
209 | |
210 void | |
211 reapCB(void* arg) { | |
212 ChildInfo* info = (ChildInfo*) arg; | |
213 ListsLocker ll; | |
214 DWORD pid = info->getPid(); | |
215 shutdownChild(info); | |
216 #ifdef DEBUGGING | |
217 cerr << "Reaped child for process " << pid << endl; | |
218 #endif | |
219 } | |
220 | |
221 /** Starts a child process with stdin and stdout redirected to pipes, | |
222 handles to which are returned. auxHandle1 and auxHandle2 should be | |
223 closed as well when the child process exits. Returns false if | |
224 process creation failed. */ | |
225 bool | |
226 startChildProcess(DWORD pidToDebug, | |
227 DWORD childStdinBufSize, | |
228 DWORD childStdoutBufSize, | |
229 LPHANDLE childProcessHandle, | |
230 LPHANDLE writeToStdinHandle, | |
231 LPHANDLE readFromStdoutHandle, | |
232 LPHANDLE auxHandle1, | |
233 LPHANDLE auxHandle2) { | |
234 // Code adapted from Microsoft example | |
235 // "Creating a Child Process with Redirected Input and Output" | |
236 | |
237 SECURITY_ATTRIBUTES saAttr; | |
238 BOOL fSuccess; | |
239 | |
240 HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup, | |
241 hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup, | |
242 hSaveStdin, hSaveStdout; | |
243 | |
244 // Set the bInheritHandle flag so pipe handles are inherited. | |
245 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); | |
246 saAttr.bInheritHandle = TRUE; | |
247 saAttr.lpSecurityDescriptor = NULL; | |
248 | |
249 // The steps for redirecting child process's STDOUT: | |
250 // 1. Save current STDOUT, to be restored later. | |
251 // 2. Create anonymous pipe to be STDOUT for child process. | |
252 // 3. Set STDOUT of the parent process to be write handle to | |
253 // the pipe, so it is inherited by the child process. | |
254 // 4. Create a noninheritable duplicate of the read handle and | |
255 // close the inheritable read handle. | |
256 | |
257 // Save the handle to the current STDOUT. | |
258 hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE); | |
259 // Create a pipe for the child process's STDOUT. | |
260 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, childStdoutBufSize)) { | |
261 return false; | |
262 } | |
263 // Set a write handle to the pipe to be STDOUT. | |
264 if (! SetStdHandle(STD_OUTPUT_HANDLE, hChildStdoutWr)) { | |
265 return false; | |
266 } | |
267 // Create noninheritable read handle and close the inheritable read | |
268 // handle. | |
269 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd, | |
270 GetCurrentProcess(), &hChildStdoutRdDup, | |
271 0, FALSE, | |
272 DUPLICATE_SAME_ACCESS); | |
273 if( !fSuccess ) { | |
274 return false; | |
275 } | |
276 CloseHandle(hChildStdoutRd); | |
277 | |
278 // The steps for redirecting child process's STDIN: | |
279 // 1. Save current STDIN, to be restored later. | |
280 // 2. Create anonymous pipe to be STDIN for child process. | |
281 // 3. Set STDIN of the parent to be the read handle to the | |
282 // pipe, so it is inherited by the child process. | |
283 // 4. Create a noninheritable duplicate of the write handle, | |
284 // and close the inheritable write handle. | |
285 // Save the handle to the current STDIN. | |
286 hSaveStdin = GetStdHandle(STD_INPUT_HANDLE); | |
287 // Create a pipe for the child process's STDIN. | |
288 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, childStdinBufSize)) { | |
289 return false; | |
290 } | |
291 // Set a read handle to the pipe to be STDIN. | |
292 if (! SetStdHandle(STD_INPUT_HANDLE, hChildStdinRd)) { | |
293 return false; | |
294 } | |
295 // Duplicate the write handle to the pipe so it is not inherited. | |
296 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr, | |
297 GetCurrentProcess(), &hChildStdinWrDup, 0, | |
298 FALSE, // not inherited | |
299 DUPLICATE_SAME_ACCESS); | |
300 if (! fSuccess) { | |
301 return false; | |
302 } | |
303 CloseHandle(hChildStdinWr); | |
304 | |
305 // Create the child process | |
306 char cmdLine[256]; | |
307 sprintf(cmdLine, "SwDbgSub.exe %u", pidToDebug); | |
308 PROCESS_INFORMATION procInfo; | |
309 STARTUPINFO startInfo; | |
310 memset((char*) &startInfo, 0, sizeof(startInfo)); | |
311 startInfo.cb = sizeof(startInfo); | |
312 BOOL res = CreateProcess(NULL, | |
313 cmdLine, | |
314 NULL, | |
315 NULL, | |
316 TRUE, // inherit handles: important | |
317 0, | |
318 NULL, | |
319 NULL, | |
320 &startInfo, | |
321 &procInfo); | |
322 if (!res) { | |
323 return false; | |
324 } | |
325 // After process creation, restore the saved STDIN and STDOUT. | |
326 if (! SetStdHandle(STD_INPUT_HANDLE, hSaveStdin)) { | |
327 return false; | |
328 } | |
329 if (! SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout)) { | |
330 return false; | |
331 } | |
332 | |
333 // hChildStdinWrDup can be used to write to the child's stdin | |
334 // hChildStdoutRdDup can be used to read from the child's stdout | |
335 | |
336 // NOTE: example code closes hChildStdoutWr before reading from | |
337 // hChildStdoutRdDup. "Close the write end of the pipe before | |
338 // reading from the read end of the pipe"??? Looks like this is | |
339 // example-specific. | |
340 | |
341 // Set up return arguments | |
342 // hChildStdoutRd and hChildStdinWr are already closed at this point | |
343 *childProcessHandle = procInfo.hProcess; | |
344 *writeToStdinHandle = hChildStdinWrDup; | |
345 *readFromStdoutHandle = hChildStdoutRdDup; | |
346 *auxHandle1 = hChildStdinRd; | |
347 *auxHandle2 = hChildStdoutWr; | |
348 return true; | |
349 } | |
350 | |
351 /** Clears the event and writes the message to the child process */ | |
352 bool | |
353 sendMessage(ChildInfo* child, Message* message) { | |
354 DWORD numBytesWritten; | |
355 if (!WriteFile(child->getWriteToStdinHandle(), | |
356 message, sizeof(Message), &numBytesWritten, NULL)) { | |
357 return false; | |
358 } | |
359 if (numBytesWritten != sizeof(Message)) { | |
360 return false; | |
361 } | |
362 // Follow up "poke" messages with the raw data | |
363 if (message->type == Message::POKE) { | |
364 if (!WriteFile(child->getWriteToStdinHandle(), | |
365 message->pokeArg.data, message->pokeArg.numBytes, &numBytesWritten, NULL)) { | |
366 return false; | |
367 } | |
368 if (numBytesWritten != message->pokeArg.numBytes) { | |
369 return false; | |
370 } | |
371 } | |
372 return true; | |
373 } | |
374 | |
375 /** Copies data from child's stdout to the client's IOBuf and sends it | |
376 along */ | |
377 bool | |
378 forwardReplyToClient(ChildInfo* child, ClientInfo* client) { | |
379 DWORD total = 0; | |
380 IOBuf::FillState ret; | |
381 | |
382 do { | |
383 DWORD temp; | |
384 ret = client->getIOBuf()->fillFromFileHandle(child->getReadFromStdoutHandle(), | |
385 &temp); | |
386 if (ret == IOBuf::DONE || ret == IOBuf::MORE_DATA_PENDING) { | |
387 if (!client->getIOBuf()->flush()) { | |
388 #ifdef DEBUGGING | |
389 cerr << "Forward failed because flush failed" << endl; | |
390 #endif | |
391 return false; | |
392 } | |
393 total += temp; | |
394 } | |
395 } while (ret == IOBuf::MORE_DATA_PENDING); | |
396 | |
397 return (ret == IOBuf::FAILED) ? false : true; | |
398 } | |
399 | |
400 //---------------------------------------------------------------------- | |
401 // Server Handler | |
402 // | |
403 | |
404 class ServerHandler : public Handler { | |
405 public: | |
406 ServerHandler(); | |
407 | |
408 // Starts up in Unicode mode by default | |
409 bool getASCII(); | |
410 | |
411 void setIOBuf(IOBuf* ioBuf); | |
412 | |
413 void procList(char* arg); | |
414 | |
415 // Must be called before calling one of the routines below | |
416 void setClientInfo(ClientInfo* info); | |
417 | |
418 // Indicates to outer loop that exit was called or that an error | |
419 // occurred and that the client exited. | |
420 bool exited(); | |
421 // Clears this state | |
422 void clearExited(); | |
423 | |
424 void ascii(char* arg); | |
425 void unicode(char* arg); | |
426 void attach(char* arg); | |
427 void detach(char* arg); | |
428 void libInfo(char* arg); | |
429 void peek(char* arg); | |
430 void poke(char* arg); | |
431 void threadList(char* arg); | |
432 void dupHandle(char* arg); | |
433 void closeHandle(char* arg); | |
434 void getContext(char* arg); | |
435 void setContext(char* arg); | |
436 void selectorEntry(char* arg); | |
437 void suspend(char* arg); | |
438 void resume(char* arg); | |
439 void pollEvent(char* arg); | |
440 void continueEvent(char* arg); | |
441 void exit(char* arg); | |
442 | |
443 // This is pretty gross. Needed to make the target process know | |
444 // about clients that have disconnected unexpectedly while attached. | |
445 friend void shutdownClient(ClientInfo*); | |
446 private: | |
447 // Writes: charSize <space> numChars <space> <binary string> | |
448 // Handles both ASCII and UNICODE modes | |
449 void writeString(USHORT len, WCHAR* str); | |
450 | |
451 // Handles only ASCII mode | |
452 void writeString(USHORT len, char* str); | |
453 | |
454 ClientInfo* clientInfo; | |
455 IOBuf* ioBuf; | |
456 bool _exited; | |
457 bool _ascii; | |
458 }; | |
459 | |
460 static ServerHandler* handler; | |
461 | |
462 ServerHandler::ServerHandler() { | |
463 _exited = false; | |
464 _ascii = false; | |
465 ioBuf = NULL; | |
466 } | |
467 | |
468 bool | |
469 ServerHandler::getASCII() { | |
470 return _ascii; | |
471 } | |
472 | |
473 void | |
474 ServerHandler::setIOBuf(IOBuf* buf) { | |
475 ioBuf = buf; | |
476 } | |
477 | |
478 void | |
479 ServerHandler::setClientInfo(ClientInfo* info) { | |
480 clientInfo = info; | |
481 } | |
482 | |
483 bool | |
484 ServerHandler::exited() { | |
485 return _exited; | |
486 } | |
487 | |
488 void | |
489 ServerHandler::clearExited() { | |
490 _exited = false; | |
491 } | |
492 | |
493 void | |
494 ServerHandler::ascii(char* arg) { | |
495 _ascii = true; | |
496 } | |
497 | |
498 void | |
499 ServerHandler::unicode(char* arg) { | |
500 _ascii = false; | |
501 } | |
502 | |
503 void | |
504 ServerHandler::procList(char* arg) { | |
505 #ifdef DEBUGGING | |
506 cerr << "proclist" << endl; | |
507 #endif | |
508 | |
509 ProcEntryList processes; | |
510 ::procList(processes); | |
511 | |
512 ioBuf->writeInt(processes.size()); | |
513 | |
514 for (ProcEntryList::iterator iter = processes.begin(); | |
515 iter != processes.end(); iter++) { | |
516 ProcEntry& entry = *iter; | |
517 ioBuf->writeSpace(); | |
518 ioBuf->writeUnsignedInt(entry.getPid()); | |
519 ioBuf->writeSpace(); | |
520 writeString(entry.getNameLength(), entry.getName()); | |
521 } | |
522 | |
523 ioBuf->writeEOL(); | |
524 ioBuf->flush(); | |
525 } | |
526 | |
527 void | |
528 ServerHandler::attach(char* arg) { | |
529 // If the client is already attached to a process, fail. | |
530 if (clientInfo->getTarget() != NULL) { | |
531 ioBuf->writeBoolAsInt(false); | |
532 ioBuf->writeEOL(); | |
533 ioBuf->flush(); | |
534 return; | |
535 } | |
536 | |
537 // Try to get pid | |
538 DWORD pid; | |
539 if (!scanUnsignedLong(&arg, &pid)) { | |
540 ioBuf->writeBoolAsInt(false); | |
541 ioBuf->writeEOL(); | |
542 ioBuf->flush(); | |
543 return; | |
544 } | |
545 | |
546 // See whether this pid is already forked | |
547 ListsLocker ll; | |
548 ChildInfo* childInfo = childList.getChildByPid(pid); | |
549 if (childInfo != NULL) { | |
550 // If this child already has a client, return false | |
551 if (childInfo->getClient() != NULL) { | |
552 ioBuf->writeBoolAsInt(false); | |
553 ioBuf->writeEOL(); | |
554 ioBuf->flush(); | |
555 return; | |
556 } | |
557 | |
558 // Otherwise, can associate this client with this child process | |
559 childInfo->setClient(clientInfo); | |
560 clientInfo->setTarget(childInfo); | |
561 | |
562 // Tell the child we are attaching so it can suspend the target | |
563 // process | |
564 Message msg; | |
565 msg.type = Message::ATTACH; | |
566 sendMessage(childInfo, &msg); | |
567 | |
568 ioBuf->writeBoolAsInt(true); | |
569 ioBuf->writeEOL(); | |
570 ioBuf->flush(); | |
571 return; | |
572 } else { | |
573 // Have to fork a new child subprocess | |
574 HANDLE childProcessHandle; | |
575 HANDLE writeToStdinHandle; | |
576 HANDLE readFromStdoutHandle; | |
577 HANDLE auxHandle1; | |
578 HANDLE auxHandle2; | |
579 if (!startChildProcess(pid, | |
580 32768, | |
581 131072, | |
582 &childProcessHandle, | |
583 &writeToStdinHandle, | |
584 &readFromStdoutHandle, | |
585 &auxHandle1, | |
586 &auxHandle2)) { | |
587 ioBuf->writeBoolAsInt(false); | |
588 ioBuf->writeEOL(); | |
589 ioBuf->flush(); | |
590 return; | |
591 } | |
592 | |
593 // See whether the child succeeded in attaching to the process | |
594 char res; | |
595 DWORD numRead; | |
596 if (!ReadFile(readFromStdoutHandle, | |
597 &res, | |
598 sizeof(char), | |
599 &numRead, | |
600 NULL)) { | |
601 ioBuf->writeBoolAsInt(false); | |
602 ioBuf->writeEOL(); | |
603 ioBuf->flush(); | |
604 return; | |
605 } | |
606 | |
607 if (!res) { | |
608 ioBuf->writeBoolAsInt(false); | |
609 ioBuf->writeEOL(); | |
610 ioBuf->flush(); | |
611 return; | |
612 } | |
613 | |
614 // OK, success. | |
615 childInfo = new ChildInfo(pid, childProcessHandle, | |
616 writeToStdinHandle, readFromStdoutHandle, | |
617 auxHandle1, auxHandle2); | |
618 childList.addChild(childInfo); | |
619 reaper->registerProcess(childProcessHandle, childInfo); | |
620 // Associate this client with this child process | |
621 childInfo->setClient(clientInfo); | |
622 clientInfo->setTarget(childInfo); | |
623 | |
624 // Tell the child process to actually suspend the target process | |
625 Message msg; | |
626 msg.type = Message::ATTACH; | |
627 sendMessage(childInfo, &msg); | |
628 | |
629 // Write result to client | |
630 ioBuf->writeBoolAsInt(true); | |
631 ioBuf->writeEOL(); | |
632 ioBuf->flush(); | |
633 return; | |
634 } | |
635 } | |
636 | |
637 void | |
638 ServerHandler::detach(char* arg) { | |
639 // If the client is not attached, fail. | |
640 if (clientInfo->getTarget() == NULL) { | |
641 ioBuf->writeBoolAsInt(false); | |
642 ioBuf->writeEOL(); | |
643 ioBuf->flush(); | |
644 return; | |
645 } | |
646 | |
647 detachClient(clientInfo); | |
648 | |
649 ioBuf->writeBoolAsInt(true); | |
650 ioBuf->writeEOL(); | |
651 ioBuf->flush(); | |
652 } | |
653 | |
654 void | |
655 ServerHandler::libInfo(char* arg) { | |
656 ListsLocker ll; | |
657 ChildInfo* child = clientInfo->getTarget(); | |
658 if (child == NULL) { | |
659 ioBuf->writeInt(0); | |
660 ioBuf->writeEOL(); | |
661 ioBuf->flush(); | |
662 return; | |
663 } | |
664 | |
665 // Send message to child | |
666 Message msg; | |
667 msg.type = Message::LIBINFO; | |
668 sendMessage(child, &msg); | |
669 | |
670 // Forward reply to client | |
671 forwardReplyToClient(child, clientInfo); | |
672 } | |
673 | |
674 void | |
675 ServerHandler::peek(char* arg) { | |
676 ListsLocker ll; | |
677 ChildInfo* child = clientInfo->getTarget(); | |
678 if (child == NULL) { | |
679 ioBuf->writeString("B"); | |
680 ioBuf->writeBinChar(0); | |
681 ioBuf->flush(); | |
682 return; | |
683 } | |
684 | |
685 // Try to get address | |
686 DWORD address; | |
687 if (!scanAddress(&arg, &address)) { | |
688 ioBuf->writeString("B"); | |
689 ioBuf->writeBinChar(0); | |
690 ioBuf->flush(); | |
691 return; | |
692 } | |
693 | |
694 // Try to get number of bytes | |
695 DWORD numBytes; | |
696 if (!scanUnsignedLong(&arg, &numBytes)) { | |
697 ioBuf->writeString("B"); | |
698 ioBuf->writeBinChar(0); | |
699 ioBuf->flush(); | |
700 return; | |
701 } | |
702 | |
703 // Send message to child | |
704 Message msg; | |
705 msg.type = Message::PEEK; | |
706 msg.peekArg.address = address; | |
707 msg.peekArg.numBytes = numBytes; | |
708 sendMessage(child, &msg); | |
709 | |
710 // Forward reply to client | |
711 forwardReplyToClient(child, clientInfo); | |
712 } | |
713 | |
714 void | |
715 ServerHandler::poke(char* arg) { | |
716 #ifdef DEBUGGING | |
717 cerr << "ServerHandler::poke" << endl; | |
718 #endif | |
719 ListsLocker ll; | |
720 ChildInfo* child = clientInfo->getTarget(); | |
721 if (child == NULL) { | |
722 ioBuf->writeBoolAsInt(false); | |
723 ioBuf->flush(); | |
724 return; | |
725 } | |
726 | |
727 // Try to get address | |
728 DWORD address; | |
729 if (!scanAddress(&arg, &address)) { | |
730 ioBuf->writeBoolAsInt(false); | |
731 ioBuf->flush(); | |
732 return; | |
733 } | |
734 | |
735 // Try to get number of bytes | |
736 if (!scanAndSkipBinEscapeChar(&arg)) { | |
737 ioBuf->writeBoolAsInt(false); | |
738 ioBuf->flush(); | |
739 return; | |
740 } | |
741 DWORD numBytes; | |
742 if (!scanBinUnsignedLong(&arg, &numBytes)) { | |
743 ioBuf->writeBoolAsInt(false); | |
744 ioBuf->flush(); | |
745 return; | |
746 } | |
747 | |
748 // Raw data is now in "arg" | |
749 // Send message to child | |
750 Message msg; | |
751 msg.type = Message::POKE; | |
752 msg.pokeArg.address = address; | |
753 msg.pokeArg.numBytes = numBytes; | |
754 msg.pokeArg.data = arg; | |
755 sendMessage(child, &msg); | |
756 | |
757 // Forward reply to client | |
758 forwardReplyToClient(child, clientInfo); | |
759 } | |
760 | |
761 void | |
762 ServerHandler::threadList(char* arg) { | |
763 ListsLocker ll; | |
764 ChildInfo* child = clientInfo->getTarget(); | |
765 if (child == NULL) { | |
766 ioBuf->writeBoolAsInt(false); | |
767 ioBuf->flush(); | |
768 return; | |
769 } | |
770 | |
771 // Send message to child | |
772 Message msg; | |
773 msg.type = Message::THREADLIST; | |
774 sendMessage(child, &msg); | |
775 | |
776 // Forward reply to client | |
777 forwardReplyToClient(child, clientInfo); | |
778 } | |
779 | |
780 void | |
781 ServerHandler::dupHandle(char* arg) { | |
782 ListsLocker ll; | |
783 ChildInfo* child = clientInfo->getTarget(); | |
784 if (child == NULL) { | |
785 ioBuf->writeBoolAsInt(false); | |
786 ioBuf->flush(); | |
787 return; | |
788 } | |
789 | |
790 // Try to get handle | |
791 DWORD address; | |
792 if (!scanAddress(&arg, &address)) { | |
793 ioBuf->writeBoolAsInt(false); | |
794 ioBuf->flush(); | |
795 } | |
796 | |
797 // Send message to child | |
798 Message msg; | |
799 msg.type = Message::DUPHANDLE; | |
800 msg.handleArg.handle = (HANDLE) address; | |
801 sendMessage(child, &msg); | |
802 | |
803 // Forward reply to client | |
804 forwardReplyToClient(child, clientInfo); | |
805 } | |
806 | |
807 void | |
808 ServerHandler::closeHandle(char* arg) { | |
809 ListsLocker ll; | |
810 ChildInfo* child = clientInfo->getTarget(); | |
811 if (child == NULL) { | |
812 return; | |
813 } | |
814 | |
815 // Try to get handle | |
816 DWORD address; | |
817 if (!scanAddress(&arg, &address)) { | |
818 return; | |
819 } | |
820 | |
821 // Send message to child | |
822 Message msg; | |
823 msg.type = Message::CLOSEHANDLE; | |
824 msg.handleArg.handle = (HANDLE) address; | |
825 sendMessage(child, &msg); | |
826 | |
827 // No reply | |
828 } | |
829 | |
830 void | |
831 ServerHandler::getContext(char* arg) { | |
832 ListsLocker ll; | |
833 ChildInfo* child = clientInfo->getTarget(); | |
834 if (child == NULL) { | |
835 ioBuf->writeBoolAsInt(false); | |
836 ioBuf->flush(); | |
837 return; | |
838 } | |
839 | |
840 // Try to get handle | |
841 DWORD address; | |
842 if (!scanAddress(&arg, &address)) { | |
843 ioBuf->writeBoolAsInt(false); | |
844 ioBuf->flush(); | |
845 return; | |
846 } | |
847 | |
848 // Send message to child | |
849 Message msg; | |
850 msg.type = Message::GETCONTEXT; | |
851 msg.handleArg.handle = (HANDLE) address; | |
852 sendMessage(child, &msg); | |
853 | |
854 // Forward reply to client | |
855 forwardReplyToClient(child, clientInfo); | |
856 } | |
857 | |
858 void | |
859 ServerHandler::setContext(char* arg) { | |
860 ListsLocker ll; | |
861 ChildInfo* child = clientInfo->getTarget(); | |
862 if (child == NULL) { | |
863 ioBuf->writeBoolAsInt(false); | |
864 ioBuf->flush(); | |
865 return; | |
866 } | |
867 | |
868 // Try to get handle | |
869 DWORD address; | |
870 if (!scanAddress(&arg, &address)) { | |
871 ioBuf->writeBoolAsInt(false); | |
872 ioBuf->flush(); | |
873 return; | |
874 } | |
875 | |
876 // Try to get context | |
877 DWORD regs[NUM_REGS_IN_CONTEXT]; | |
878 for (int i = 0; i < NUM_REGS_IN_CONTEXT; i++) { | |
879 if (!scanAddress(&arg, ®s[i])) { | |
880 ioBuf->writeBoolAsInt(false); | |
881 ioBuf->flush(); | |
882 return; | |
883 } | |
884 } | |
885 | |
886 // Send message to child | |
887 Message msg; | |
888 msg.type = Message::SETCONTEXT; | |
889 msg.setContextArg.handle = (HANDLE) address; | |
890 msg.setContextArg.Eax = regs[0]; | |
891 msg.setContextArg.Ebx = regs[1]; | |
892 msg.setContextArg.Ecx = regs[2]; | |
893 msg.setContextArg.Edx = regs[3]; | |
894 msg.setContextArg.Esi = regs[4]; | |
895 msg.setContextArg.Edi = regs[5]; | |
896 msg.setContextArg.Ebp = regs[6]; | |
897 msg.setContextArg.Esp = regs[7]; | |
898 msg.setContextArg.Eip = regs[8]; | |
899 msg.setContextArg.Ds = regs[9]; | |
900 msg.setContextArg.Es = regs[10]; | |
901 msg.setContextArg.Fs = regs[11]; | |
902 msg.setContextArg.Gs = regs[12]; | |
903 msg.setContextArg.Cs = regs[13]; | |
904 msg.setContextArg.Ss = regs[14]; | |
905 msg.setContextArg.EFlags = regs[15]; | |
906 msg.setContextArg.Dr0 = regs[16]; | |
907 msg.setContextArg.Dr1 = regs[17]; | |
908 msg.setContextArg.Dr2 = regs[18]; | |
909 msg.setContextArg.Dr3 = regs[19]; | |
910 msg.setContextArg.Dr6 = regs[20]; | |
911 msg.setContextArg.Dr7 = regs[21]; | |
912 sendMessage(child, &msg); | |
913 | |
914 // Forward reply to client | |
915 forwardReplyToClient(child, clientInfo); | |
916 } | |
917 | |
918 void | |
919 ServerHandler::selectorEntry(char* arg) { | |
920 ListsLocker ll; | |
921 ChildInfo* child = clientInfo->getTarget(); | |
922 if (child == NULL) { | |
923 ioBuf->writeBoolAsInt(false); | |
924 ioBuf->flush(); | |
925 return; | |
926 } | |
927 | |
928 // Try to get thread handle | |
929 DWORD address; | |
930 if (!scanAddress(&arg, &address)) { | |
931 ioBuf->writeBoolAsInt(false); | |
932 ioBuf->flush(); | |
933 return; | |
934 } | |
935 | |
936 // Try to get selector | |
937 DWORD selector; | |
938 if (!scanUnsignedLong(&arg, &selector)) { | |
939 ioBuf->writeBoolAsInt(false); | |
940 ioBuf->flush(); | |
941 return; | |
942 } | |
943 | |
944 // Send message to child | |
945 Message msg; | |
946 msg.type = Message::SELECTORENTRY; | |
947 msg.selectorArg.handle = (HANDLE) address; | |
948 msg.selectorArg.selector = selector; | |
949 sendMessage(child, &msg); | |
950 | |
951 // Forward reply to client | |
952 forwardReplyToClient(child, clientInfo); | |
953 } | |
954 | |
955 void | |
956 ServerHandler::suspend(char* arg) { | |
957 ListsLocker ll; | |
958 ChildInfo* child = clientInfo->getTarget(); | |
959 if (child == NULL) { | |
960 return; | |
961 } | |
962 | |
963 // Send message to child | |
964 Message msg; | |
965 msg.type = Message::SUSPEND; | |
966 sendMessage(child, &msg); | |
967 | |
968 // No reply | |
969 } | |
970 | |
971 void | |
972 ServerHandler::resume(char* arg) { | |
973 ListsLocker ll; | |
974 ChildInfo* child = clientInfo->getTarget(); | |
975 if (child == NULL) { | |
976 return; | |
977 } | |
978 | |
979 // Send message to child | |
980 Message msg; | |
981 msg.type = Message::RESUME; | |
982 sendMessage(child, &msg); | |
983 | |
984 // No reply | |
985 } | |
986 | |
987 void | |
988 ServerHandler::pollEvent(char* arg) { | |
989 ListsLocker ll; | |
990 ChildInfo* child = clientInfo->getTarget(); | |
991 if (child == NULL) { | |
992 ioBuf->writeBoolAsInt(false); | |
993 ioBuf->flush(); | |
994 return; | |
995 } | |
996 | |
997 // Send message to child | |
998 Message msg; | |
999 msg.type = Message::POLLEVENT; | |
1000 sendMessage(child, &msg); | |
1001 | |
1002 // Forward reply to client | |
1003 forwardReplyToClient(child, clientInfo); | |
1004 } | |
1005 | |
1006 void | |
1007 ServerHandler::continueEvent(char* arg) { | |
1008 ListsLocker ll; | |
1009 ChildInfo* child = clientInfo->getTarget(); | |
1010 if (child == NULL) { | |
1011 ioBuf->writeBoolAsInt(false); | |
1012 ioBuf->flush(); | |
1013 return; | |
1014 } | |
1015 | |
1016 // Try to get bool arg | |
1017 int passEventToClient; | |
1018 if (!scanInt(&arg, &passEventToClient)) { | |
1019 ioBuf->writeBoolAsInt(false); | |
1020 ioBuf->flush(); | |
1021 return; | |
1022 } | |
1023 | |
1024 // Send message to child | |
1025 Message msg; | |
1026 msg.type = Message::CONTINUEEVENT; | |
1027 msg.boolArg.val = ((passEventToClient != 0) ? true : false); | |
1028 sendMessage(child, &msg); | |
1029 | |
1030 // Forward reply to client | |
1031 forwardReplyToClient(child, clientInfo); | |
1032 } | |
1033 | |
1034 void | |
1035 ServerHandler::exit(char* arg) { | |
1036 shutdownClient(clientInfo); | |
1037 _exited = true; | |
1038 } | |
1039 | |
1040 void | |
1041 ServerHandler::writeString(USHORT len, WCHAR* str) { | |
1042 if (_ascii) { | |
1043 char* cStr = new char[len + 1]; | |
1044 sprintf(cStr, "%.*ls", len, str); | |
1045 writeString(len, cStr); | |
1046 delete[] cStr; | |
1047 } else { | |
1048 ioBuf->writeInt(sizeof(unsigned short)); | |
1049 ioBuf->writeSpace(); | |
1050 ioBuf->writeInt(len); | |
1051 ioBuf->writeSpace(); | |
1052 for (int i = 0; i < len; i++) { | |
1053 ioBuf->writeBinUnsignedShort(str[i]); | |
1054 } | |
1055 } | |
1056 } | |
1057 | |
1058 void | |
1059 ServerHandler::writeString(USHORT len, char* str) { | |
1060 ioBuf->writeInt(1); | |
1061 ioBuf->writeSpace(); | |
1062 ioBuf->writeInt(len); | |
1063 ioBuf->writeSpace(); | |
1064 ioBuf->writeString(str); | |
1065 } | |
1066 | |
1067 // | |
1068 //---------------------------------------------------------------------- | |
1069 | |
1070 //---------------------------------------------------------------------- | |
1071 // Shutdown routines | |
1072 // | |
1073 | |
1074 void | |
1075 shutdownChild(ChildInfo* childInfo) { | |
1076 childList.removeChild(childInfo); | |
1077 childInfo->closeAll(); | |
1078 if (childInfo->getClient() != NULL) { | |
1079 shutdownClient(childInfo->getClient()); | |
1080 } | |
1081 delete childInfo; | |
1082 } | |
1083 | |
1084 void | |
1085 detachClient(ClientInfo* info) { | |
1086 ListsLocker ll; | |
1087 // May have been dissociated while not under cover of lock | |
1088 if (info->getTarget() == NULL) { | |
1089 return; | |
1090 } | |
1091 | |
1092 // Tell the child that we have detached to let the target process | |
1093 // continue running | |
1094 Message msg; | |
1095 msg.type = Message::DETACH; | |
1096 sendMessage(info->getTarget(), &msg); | |
1097 | |
1098 // Dissociate the client and the target | |
1099 info->getTarget()->setClient(NULL); | |
1100 info->setTarget(NULL); | |
1101 } | |
1102 | |
1103 void | |
1104 shutdownClient(ClientInfo* clientInfo) { | |
1105 #ifdef DEBUGGING | |
1106 cerr << "Shutting down client" << endl; | |
1107 #endif | |
1108 | |
1109 // If we're connected, inform the target process that we're | |
1110 // disconnecting | |
1111 detachClient(clientInfo); | |
1112 | |
1113 // Remove this client from the list and delete it | |
1114 clientList.removeClient(clientInfo); | |
1115 if (clientInfo->getTarget() != NULL) { | |
1116 clientInfo->getTarget()->setClient(NULL); | |
1117 } | |
1118 clientInfo->closeAll(); | |
1119 delete clientInfo; | |
1120 } | |
1121 | |
1122 // | |
1123 //---------------------------------------------------------------------- | |
1124 | |
1125 | |
1126 /** Main dispatcher for client commands. NOTE: do not refer to this | |
1127 clientInfo data structure after calling this routine, as it may be | |
1128 deleted internally. */ | |
1129 void | |
1130 readAndDispatch(ClientInfo* clientInfo) { | |
1131 IOBuf::ReadLineResult res; | |
1132 IOBuf* ioBuf = clientInfo->getIOBuf(); | |
1133 unsigned long howMany; | |
1134 ioctlsocket(clientInfo->getDataSocket(), FIONREAD, &howMany); | |
1135 if (howMany == 0) { | |
1136 // Client closed down. | |
1137 shutdownClient(clientInfo); | |
1138 return; | |
1139 } | |
1140 // Read and process as much data as possible | |
1141 do { | |
1142 res = ioBuf->tryReadLine(); | |
1143 if (res == IOBuf::RL_ERROR) { | |
1144 #ifdef DEBUGGING | |
1145 cerr << "Error while reading line" << endl; | |
1146 #endif | |
1147 shutdownClient(clientInfo); | |
1148 return; | |
1149 } else if (res == IOBuf::RL_GOT_DATA) { | |
1150 #ifdef DEBUGGING | |
1151 cerr << "Got data: \"" << ioBuf->getLine() << "\"" << endl; | |
1152 #endif | |
1153 handler->setIOBuf(ioBuf); | |
1154 handler->setClientInfo(clientInfo); | |
1155 handler->clearExited(); | |
1156 Dispatcher::dispatch(ioBuf->getLine(), handler); | |
1157 } | |
1158 } while (res == IOBuf::RL_GOT_DATA && (!handler->exited())); | |
1159 #ifdef DEBUGGING | |
1160 cerr << "Exiting readAndDispatch" << endl; | |
1161 #endif | |
1162 } | |
1163 | |
1164 int | |
1165 main(int argc, char **argv) | |
1166 { | |
1167 initWinsock(); | |
1168 | |
1169 if (isNT4()) { | |
1170 loadPSAPIDLL(); // Will exit if not present | |
1171 } | |
1172 | |
1173 SOCKET clientListeningSock = setupListeningSocket(CLIENT_PORT); | |
1174 | |
1175 handler = new ServerHandler(); | |
1176 Lists::init(); | |
1177 | |
1178 reaper = new Reaper(&reapCB); | |
1179 if (!reaper->start()) { | |
1180 exit(1); | |
1181 } | |
1182 | |
1183 while (true) { | |
1184 // Select on all sockets: | |
1185 // - client listening socket | |
1186 // - sockets for all client connections | |
1187 | |
1188 // When one of the client connections closes, close its socket | |
1189 // handles. | |
1190 | |
1191 fd_set set; | |
1192 SOCKET maxSock = 0; | |
1193 | |
1194 // Set up fd_set | |
1195 { | |
1196 int i; | |
1197 FD_ZERO(&set); | |
1198 FD_SET(clientListeningSock, &set); | |
1199 if (clientListeningSock > maxSock) { | |
1200 maxSock = clientListeningSock; | |
1201 } | |
1202 for (i = 0; i < clientList.size(); i++) { | |
1203 ClientInfo* info = clientList.get(i); | |
1204 if (info->getDataSocket() > maxSock) { | |
1205 maxSock = info->getDataSocket(); | |
1206 } | |
1207 FD_SET(info->getDataSocket(), &set); | |
1208 } | |
1209 } | |
1210 struct timeval timeout; | |
1211 timeout.tv_sec = 300; // 5 minutes | |
1212 timeout.tv_usec = 0; | |
1213 int res = select(maxSock, &set, NULL, NULL, &timeout); | |
1214 if (res > 0) { | |
1215 | |
1216 //////////////// | |
1217 // New client // | |
1218 //////////////// | |
1219 if (FD_ISSET(clientListeningSock, &set)) { | |
1220 SOCKET fd = acceptFromLocalhost(clientListeningSock); | |
1221 if (fd != INVALID_SOCKET) { | |
1222 // Create new client information object | |
1223 ClientInfo* info = new ClientInfo(fd); | |
1224 // Add to list of clients | |
1225 clientList.addClient(info); | |
1226 #ifdef DEBUGGING | |
1227 cerr << "New client" << endl; | |
1228 #endif | |
1229 } | |
1230 } | |
1231 | |
1232 /////////////////////////// | |
1233 // Commands from clients // | |
1234 /////////////////////////// | |
1235 ClientInfo* clientInfo; | |
1236 if (clientList.isAnyDataSocketSet(&set, &clientInfo)) { | |
1237 readAndDispatch(clientInfo); | |
1238 } | |
1239 } else if (res < 0) { | |
1240 // Looks like one of the clients was killed. Try to figure out which one. | |
1241 bool found = false; | |
1242 fd_set set; | |
1243 struct timeval timeout; | |
1244 timeout.tv_sec = 0; | |
1245 timeout.tv_usec = 0; | |
1246 for (int i = 0; i < clientList.size(); i++) { | |
1247 ClientInfo* info = clientList.get(i); | |
1248 FD_ZERO(&set); | |
1249 FD_SET(info->getDataSocket(), &set); | |
1250 if (select(1 + info->getDataSocket(), &set, NULL, NULL, &timeout) < 0) { | |
1251 found = true; | |
1252 clientList.removeClient(info); | |
1253 info->closeAll(); | |
1254 delete info; | |
1255 break; | |
1256 } | |
1257 } | |
1258 if (!found) { | |
1259 // This indicates trouble -- one of our listening sockets died. | |
1260 exit(1); | |
1261 } | |
1262 } | |
1263 } | |
1264 | |
1265 return 0; | |
1266 } |