comparison agent/src/share/classes/sun/jvm/hotspot/debugger/dbx/DbxDebuggerLocal.java @ 0:a61af66fc99e jdk7-b24

Initial load
author duke
date Sat, 01 Dec 2007 00:00:00 +0000
parents
children ba764ed4b6f2
comparison
equal deleted inserted replaced
-1:000000000000 0:a61af66fc99e
1 /*
2 * Copyright 2000-2004 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any questions.
22 *
23 */
24
25 package sun.jvm.hotspot.debugger.dbx;
26
27 import java.io.*;
28 import java.net.*;
29 import java.util.*;
30 import sun.jvm.hotspot.debugger.*;
31 import sun.jvm.hotspot.debugger.dbx.sparc.*;
32 import sun.jvm.hotspot.debugger.dbx.x86.*;
33 import sun.jvm.hotspot.debugger.cdbg.CDebugger;
34 import sun.jvm.hotspot.utilities.*;
35
36 /** <P> An implementation of the JVMDebugger interface which sits on
37 top of dbx and relies on the SA's dbx import module for
38 communication with the debugger. </P>
39
40 <P> <B>NOTE</B> that since we have the notion of fetching "Java
41 primitive types" from the remote process (which might have
42 different sizes than we expect) we have a bootstrapping
43 problem. We need to know the sizes of these types before we can
44 fetch them. The current implementation solves this problem by
45 requiring that it be configured with these type sizes before they
46 can be fetched. The readJ(Type) routines here will throw a
47 RuntimeException if they are called before the debugger is
48 configured with the Java primitive type sizes. </P>
49 */
50
51 public class DbxDebuggerLocal extends DebuggerBase implements DbxDebugger {
52 // These may be set by DbxDebuggerRemote
53 protected boolean unalignedAccessesOkay;
54 protected DbxThreadFactory threadFactory;
55
56 private String dbxPathName;
57 private String[] dbxSvcAgentDSOPathNames;
58 private Process dbxProcess;
59 private StreamMonitor dbxOutStreamMonitor;
60 private StreamMonitor dbxErrStreamMonitor;
61 private PrintWriter dbxOstr;
62 private PrintWriter out;
63 private InputLexer in;
64 private Socket importModuleSocket;
65 private static final int PORT = 21928;
66 private static final int LONG_TIMEOUT = 60000;
67 private static final int DBX_MODULE_NOT_FOUND = 101;
68 private static final int DBX_MODULE_LOADED = 102;
69
70 //--------------------------------------------------------------------------------
71 // Implementation of Debugger interface
72 //
73
74 /** <P> machDesc may be null if it couldn't be determined yet; i.e.,
75 if we're on SPARC, we need to ask the remote process whether
76 we're in 32- or 64-bit mode. </P>
77
78 <P> useCache should be set to true if debugging is being done
79 locally, and to false if the debugger is being created for the
80 purpose of supporting remote debugging. </P> */
81 public DbxDebuggerLocal(MachineDescription machDesc,
82 String dbxPathName,
83 String[] dbxSvcAgentDSOPathNames,
84 boolean useCache) {
85 this.machDesc = machDesc;
86 this.dbxPathName = dbxPathName;
87 this.dbxSvcAgentDSOPathNames = dbxSvcAgentDSOPathNames;
88 int cacheNumPages;
89 int cachePageSize;
90 if (PlatformInfo.getCPU().equals("sparc")) {
91 cacheNumPages = parseCacheNumPagesProperty(2048);
92 cachePageSize = 8192;
93 threadFactory = new DbxSPARCThreadFactory(this);
94 } else if (PlatformInfo.getCPU().equals("x86")) {
95 cacheNumPages = 4096;
96 cachePageSize = 4096;
97 threadFactory = new DbxX86ThreadFactory(this);
98 unalignedAccessesOkay = true;
99 } else {
100 throw new RuntimeException("Thread access for CPU architecture " + PlatformInfo.getCPU() + " not yet supported");
101 }
102 if (useCache) {
103 // Cache portion of the remote process's address space.
104 // Fetching data over the socket connection to dbx is relatively
105 // slow. For now, this cache works best if it covers the entire
106 // heap of the remote process. FIXME: at least should make this
107 // tunable from the outside, i.e., via the UI. This is a 16 MB
108 // cache divided on SPARC into 2048 8K pages and on x86 into
109 // 4096 4K pages; the page size must be adjusted to be the OS's
110 // page size. (FIXME: should pick this up from the debugger.)
111 initCache(cachePageSize, cacheNumPages);
112 }
113 }
114
115 /** Only called by DbxDebuggerRemote */
116 protected DbxDebuggerLocal() {
117 }
118
119 /** FIXME: implement this with a Runtime.exec() of ps followed by
120 parsing of its output */
121 public boolean hasProcessList() throws DebuggerException {
122 return false;
123 }
124
125 public List getProcessList() throws DebuggerException {
126 throw new DebuggerException("Not yet supported");
127 }
128
129 /** From the Debugger interface via JVMDebugger */
130 public synchronized void attach(int processID) throws DebuggerException {
131 try {
132 launchProcess();
133 dbxErrStreamMonitor.addTrigger("dbx: no process", 1);
134 dbxErrStreamMonitor.addTrigger("dbx: Cannot open", 1);
135 dbxErrStreamMonitor.addTrigger("dbx: Cannot find", DBX_MODULE_NOT_FOUND);
136 dbxOstr = new PrintWriter(dbxProcess.getOutputStream(), true);
137 dbxOstr.println("debug - " + processID);
138 dbxOstr.println("kprint -u2 \\(ready\\)");
139 boolean seen = dbxErrStreamMonitor.waitFor("(ready)", LONG_TIMEOUT);
140 if (!seen) {
141 detach();
142 throw new DebuggerException("Timed out while connecting to process " + processID);
143 }
144 List retVals = dbxErrStreamMonitor.getTriggersSeen();
145 if (retVals.contains(new Integer(1))) {
146 detach();
147 throw new DebuggerException("No such process " + processID);
148 }
149
150 // Throws DebuggerException upon failure
151 importDbxModule();
152
153 dbxOstr.println("svc_agent_run");
154
155 connectToImportModule();
156
157 // Set "fail fast" mode on process memory reads
158 printlnToOutput("peek_fail_fast 1");
159 }
160 catch (IOException e) {
161 detach();
162 throw new DebuggerException("Error while connecting to dbx process", e);
163 }
164 }
165
166 /** From the Debugger interface via JVMDebugger */
167 public synchronized void attach(String executableName, String coreFileName) throws DebuggerException {
168 try {
169 launchProcess();
170 // Missing executable
171 dbxErrStreamMonitor.addTrigger("dbx: Cannot open", 1);
172 // Missing core file
173 dbxErrStreamMonitor.addTrigger("dbx: can't read", 2);
174 // Corrupt executable
175 dbxErrStreamMonitor.addTrigger("dbx: File", 3);
176 // Corrupt core file
177 dbxErrStreamMonitor.addTrigger("dbx: Unable to read", 4);
178 // Mismatched core and executable
179 dbxErrStreamMonitor.addTrigger("dbx: core object name", 5);
180 // Missing loadobject
181 dbxErrStreamMonitor.addTrigger("dbx: can't stat", 6);
182 // Successful load of svc module
183 dbxOstr = new PrintWriter(dbxProcess.getOutputStream(), true);
184 dbxOstr.println("debug " + executableName + " " + coreFileName);
185 dbxOstr.println("kprint -u2 \\(ready\\)");
186 boolean seen = dbxErrStreamMonitor.waitFor("(ready)", LONG_TIMEOUT);
187 if (!seen) {
188 detach();
189 throw new DebuggerException("Timed out while attaching to core file");
190 }
191 List retVals = dbxErrStreamMonitor.getTriggersSeen();
192 if (retVals.size() > 0) {
193 detach();
194
195 if (retVals.contains(new Integer(1))) {
196 throw new DebuggerException("Can not find executable \"" + executableName + "\"");
197 } else if (retVals.contains(new Integer(2))) {
198 throw new DebuggerException("Can not find core file \"" + coreFileName + "\"");
199 } else if (retVals.contains(new Integer(3))) {
200 throw new DebuggerException("Corrupt executable \"" + executableName + "\"");
201 } else if (retVals.contains(new Integer(4))) {
202 throw new DebuggerException("Corrupt core file \"" + coreFileName + "\"");
203 } else if (retVals.contains(new Integer(5))) {
204 throw new DebuggerException("Mismatched core file/executable \"" + coreFileName + "\"/\"" + executableName + "\"");
205 } else {
206 throw new DebuggerException("Couldn't find all loaded libraries for executable \"" + executableName + "\"");
207 }
208 }
209
210 // Throws DebuggerException upon failure
211 importDbxModule();
212
213 dbxOstr.println("svc_agent_run");
214
215 connectToImportModule();
216
217 // Set "fail fast" mode on process memory reads
218 printlnToOutput("peek_fail_fast 1");
219 }
220 catch (IOException e) {
221 detach();
222 throw new DebuggerException("Error while connecting to dbx process", e);
223 }
224 }
225
226 /** From the Debugger interface via JVMDebugger */
227 public synchronized boolean detach() {
228 try {
229 if (dbxProcess == null) {
230 return false;
231 }
232
233 if (out != null && dbxOstr != null) {
234 printlnToOutput("exit");
235 dbxOstr.println("exit");
236
237 // Wait briefly for the process to exit (FIXME: should make this
238 // nicer)
239 try {
240 Thread.sleep(500);
241 }
242 catch (InterruptedException e) {
243 }
244 }
245
246 shutdown();
247
248 return true;
249 } catch (IOException e) {
250 e.printStackTrace();
251 return false;
252 }
253 }
254
255 /** From the Debugger interface via JVMDebugger */
256 public Address parseAddress(String addressString) throws NumberFormatException {
257 long addr = utils.scanAddress(addressString);
258 if (addr == 0) {
259 return null;
260 }
261 return new DbxAddress(this, addr);
262 }
263
264 /** From the Debugger interface via JVMDebugger */
265 public String getOS() {
266 return PlatformInfo.getOS();
267 }
268
269 /** From the Debugger interface via JVMDebugger */
270 public String getCPU() {
271 return PlatformInfo.getCPU();
272 }
273
274 public boolean hasConsole() throws DebuggerException {
275 return true;
276 }
277
278 public synchronized String consoleExecuteCommand(String cmd) throws DebuggerException {
279 try {
280 // A little tricky. We need to cause the dbx import module to
281 // exit, then print our command on dbx's stdin along with a
282 // command which will allow our StreamMonitors to
283 // resynchronize. We need save the output from the StreamMonitors
284 // along the way.
285 printlnToOutput("exit");
286 importModuleSocket.close();
287 importModuleSocket = null;
288 out = null;
289 in = null;
290 dbxOstr.println("kprint \\(ready\\)");
291 dbxOstr.flush();
292 dbxOutStreamMonitor.waitFor("(ready)", LONG_TIMEOUT);
293
294 dbxOutStreamMonitor.startCapture();
295 dbxErrStreamMonitor.startCapture();
296 dbxOstr.println(cmd);
297 dbxOstr.println("kprint \\(ready\\)");
298 dbxOutStreamMonitor.waitFor("(ready)", LONG_TIMEOUT);
299 String result = dbxOutStreamMonitor.stopCapture();
300 String result2 = dbxErrStreamMonitor.stopCapture();
301 result = result + result2;
302 // Cut out the "(ready)" string
303 StringBuffer outBuf = new StringBuffer(result.length());
304 BufferedReader reader = new BufferedReader(new StringReader(result));
305 // FIXME: bug in BufferedReader? readLine returns null when
306 // ready() returns true.
307 String line = null;
308 do {
309 line = reader.readLine();
310 if ((line != null) && (!line.equals("(ready)"))) {
311 outBuf.append(line);
312 outBuf.append("\n");
313 }
314 } while (line != null);
315 dbxOstr.println("svc_agent_run");
316 dbxOstr.flush();
317
318 connectToImportModule();
319
320 return outBuf.toString();
321 }
322 catch (IOException e) {
323 detach();
324 throw new DebuggerException("Error while executing command on dbx console", e);
325 }
326 }
327
328 public String getConsolePrompt() throws DebuggerException {
329 return "(dbx) ";
330 }
331
332 public CDebugger getCDebugger() throws DebuggerException {
333 return null;
334 }
335
336 /** From the SymbolLookup interface via Debugger and JVMDebugger */
337 public synchronized Address lookup(String objectName, String symbol) {
338 long addr = lookupInProcess(objectName, symbol);
339 if (addr == 0) {
340 return null;
341 }
342 return new DbxAddress(this, addr);
343 }
344
345 /** From the SymbolLookup interface via Debugger and JVMDebugger */
346 public synchronized OopHandle lookupOop(String objectName, String symbol) {
347 long addr = lookupInProcess(objectName, symbol);
348 if (addr == 0) {
349 return null;
350 }
351 return new DbxOopHandle(this, addr);
352 }
353
354 /** From the Debugger interface */
355 public MachineDescription getMachineDescription() {
356 return machDesc;
357 }
358
359 /** Internal routine supporting lazy setting of MachineDescription,
360 since on SPARC we will need to query the remote process to ask
361 it what its data model is (32- or 64-bit). NOTE that this is NOT
362 present in the DbxDebugger interface because it should not be
363 called across the wire (until we support attaching to multiple
364 remote processes via RMI -- see the documentation for
365 DbxDebuggerRemoteIntf.) */
366 public void setMachineDescription(MachineDescription machDesc) {
367 this.machDesc = machDesc;
368 setBigEndian(machDesc.isBigEndian());
369 utils = new DebuggerUtilities(machDesc.getAddressSize(), machDesc.isBigEndian());
370 }
371
372 /** Internal routine which queries the remote process about its data
373 model -- i.e., size of addresses. Returns -1 upon error.
374 Currently supported return values are 32 and 64. NOTE that this
375 is NOT present in the DbxDebugger interface because it should
376 not be called across the wire (until we support attaching to
377 multiple remote processes via RMI -- see the documentation for
378 DbxDebuggerRemoteIntf.) */
379 public int getRemoteProcessAddressSize() {
380 if (dbxProcess == null) {
381 throw new RuntimeException("Not attached to remote process");
382 }
383
384 try {
385 printlnToOutput("address_size");
386 int i = in.parseInt();
387 return i;
388 }
389 catch (IOException e) {
390 return -1;
391 }
392 }
393
394 //--------------------------------------------------------------------------------
395 // Implementation of ThreadAccess interface
396 //
397
398 /** From the ThreadAccess interface via Debugger and JVMDebugger */
399 public ThreadProxy getThreadForIdentifierAddress(Address addr) {
400 return threadFactory.createThreadWrapper(addr);
401 }
402
403 public ThreadProxy getThreadForThreadId(long id) {
404 return threadFactory.createThreadWrapper(id);
405 }
406
407 //----------------------------------------------------------------------
408 // Overridden from DebuggerBase because we need to relax alignment
409 // constraints on x86
410
411 public long readJLong(long address)
412 throws UnmappedAddressException, UnalignedAddressException {
413 checkJavaConfigured();
414 // FIXME: allow this to be configurable. Undesirable to add a
415 // dependency on the runtime package here, though, since this
416 // package should be strictly underneath it.
417 if (unalignedAccessesOkay) {
418 utils.checkAlignment(address, jintSize);
419 } else {
420 utils.checkAlignment(address, jlongSize);
421 }
422 byte[] data = readBytes(address, jlongSize);
423 return utils.dataToJLong(data, jlongSize);
424 }
425
426 //--------------------------------------------------------------------------------
427 // Internal routines (for implementation of DbxAddress).
428 // These must not be called until the MachineDescription has been set up.
429 //
430
431 /** From the DbxDebugger interface */
432 public String addressValueToString(long address) {
433 return utils.addressValueToString(address);
434 }
435
436 /** Need to override this to relax alignment checks on Solaris/x86. */
437 public long readCInteger(long address, long numBytes, boolean isUnsigned)
438 throws UnmappedAddressException, UnalignedAddressException {
439 checkConfigured();
440 if (!unalignedAccessesOkay) {
441 utils.checkAlignment(address, numBytes);
442 } else {
443 // Only slightly relaxed semantics -- this is a hack, but is
444 // necessary on Solaris/x86 where it seems the compiler is
445 // putting some global 64-bit data on 32-bit boundaries
446 if (numBytes == 8) {
447 utils.checkAlignment(address, 4);
448 } else {
449 utils.checkAlignment(address, numBytes);
450 }
451 }
452 byte[] data = readBytes(address, numBytes);
453 return utils.dataToCInteger(data, isUnsigned);
454 }
455
456 /** From the DbxDebugger interface */
457 public DbxAddress readAddress(long address)
458 throws UnmappedAddressException, UnalignedAddressException {
459 long value = readAddressValue(address);
460 return (value == 0 ? null : new DbxAddress(this, value));
461 }
462
463 /** From the DbxDebugger interface */
464 public DbxOopHandle readOopHandle(long address)
465 throws UnmappedAddressException, UnalignedAddressException, NotInHeapException {
466 long value = readAddressValue(address);
467 return (value == 0 ? null : new DbxOopHandle(this, value));
468 }
469
470 //--------------------------------------------------------------------------------
471 // Thread context access. Can not be package private, but should
472 // only be accessed by the architecture-specific subpackages.
473
474 /** From the DbxDebugger interface. May have to redefine this later. */
475 public synchronized long[] getThreadIntegerRegisterSet(int tid) {
476 try {
477 printlnToOutput("thr_gregs " + tid);
478 int num = in.parseInt();
479 long[] res = new long[num];
480 for (int i = 0; i < num; i++) {
481 res[i] = in.parseAddress();
482 }
483 return res;
484 }
485 catch (Exception e) {
486 e.printStackTrace();
487 return null;
488 }
489 }
490
491 //--------------------------------------------------------------------------------
492 // Address access. Can not be package private, but should only be
493 // accessed by the architecture-specific subpackages.
494
495 /** From the Debugger interface */
496 public long getAddressValue(Address addr) {
497 if (addr == null) return 0;
498 return ((DbxAddress) addr).getValue();
499 }
500
501 /** From the DbxDebugger interface */
502 public Address newAddress(long value) {
503 if (value == 0) return null;
504 return new DbxAddress(this, value);
505 }
506
507 //--------------------------------------------------------------------------------
508 // Internals only below this point
509 //
510
511 private void launchProcess() throws IOException {
512 dbxProcess = Runtime.getRuntime().exec(dbxPathName);
513 // dbxOutStreamMonitor = new StreamMonitor(dbxProcess.getInputStream());
514 // dbxErrStreamMonitor = new StreamMonitor(dbxProcess.getErrorStream());
515 dbxOutStreamMonitor = new StreamMonitor(dbxProcess.getInputStream(), "dbx stdout", true);
516 dbxErrStreamMonitor = new StreamMonitor(dbxProcess.getErrorStream(), "dbx stderr", true);
517 }
518
519 /** Requires that dbxErrStreamMonitor has a trigger on "dbx: Cannot
520 find" with number DBX_MODULE_NOT_FOUND as well as one on "dbx:
521 warning:" (plus the serviceability agent's dbx module path name,
522 to avoid conflation with inability to load individual object
523 files) with number DBX_MODULE_FAILED_TO_LOAD. The former
524 indicates an absence of libsvc_agent_dbx.so, while the latter
525 indicates that the module failed to load, specifically because
526 the architecture was mismatched. (I don't see a way to detect
527 from the dbx command prompt whether it's running the v8 or v9
528 executbale, so we try to import both flavors of the import
529 module; the "v8" file name convention doesn't actually include
530 the v8 prefix, so this code should work for Intel as well.) */
531 private void importDbxModule() throws DebuggerException {
532 // Trigger for a successful load
533 dbxOutStreamMonitor.addTrigger("Defining svc_agent_run", DBX_MODULE_LOADED);
534 for (int i = 0; i < dbxSvcAgentDSOPathNames.length; i++) {
535 dbxOstr.println("import " + dbxSvcAgentDSOPathNames[i]);
536 dbxOstr.println("kprint -u2 \\(Ready\\)");
537 boolean seen = dbxErrStreamMonitor.waitFor("(Ready)", LONG_TIMEOUT);
538 if (!seen) {
539 detach();
540 throw new DebuggerException("Timed out while importing dbx module from file\n" + dbxSvcAgentDSOPathNames[i]);
541 }
542 List retVals = dbxErrStreamMonitor.getTriggersSeen();
543 if (retVals.contains(new Integer(DBX_MODULE_NOT_FOUND))) {
544 detach();
545 throw new DebuggerException("Unable to find the Serviceability Agent's dbx import module at pathname \"" +
546 dbxSvcAgentDSOPathNames[i] + "\"");
547 } else {
548 retVals = dbxOutStreamMonitor.getTriggersSeen();
549 if (retVals.contains(new Integer(DBX_MODULE_LOADED))) {
550 System.out.println("importDbxModule: imported " + dbxSvcAgentDSOPathNames[i]);
551 return;
552 }
553 }
554 }
555
556 // Failed to load all flavors
557 detach();
558 String errMsg = ("Unable to find a version of the Serviceability Agent's dbx import module\n" +
559 "matching the architecture of dbx at any of the following locations:");
560 for (int i = 0; i < dbxSvcAgentDSOPathNames.length; i++) {
561 errMsg = errMsg + "\n" + dbxSvcAgentDSOPathNames[i];
562 }
563 throw new DebuggerException(errMsg);
564 }
565
566 /** Terminate the debugger forcibly */
567 private void shutdown() {
568
569 if (dbxProcess != null) {
570 // See whether the process has exited and, if not, terminate it
571 // forcibly
572 try {
573 dbxProcess.exitValue();
574 }
575 catch (IllegalThreadStateException e) {
576 dbxProcess.destroy();
577 }
578 }
579
580 try {
581 if (importModuleSocket != null) {
582 importModuleSocket.close();
583 }
584 }
585 catch (IOException e) {
586 }
587
588 // Release references to all objects
589 clear();
590 clearCache();
591 }
592
593 /** Looks up an address in the remote process's address space.
594 Returns 0 if symbol not found or upon error. Package private to
595 allow DbxDebuggerRemoteIntfImpl access. */
596 synchronized long lookupInProcess(String objectName, String symbol) {
597 try {
598 printlnToOutput("lookup " + objectName + " " + symbol);
599 return in.parseAddress();
600 }
601 catch (Exception e) {
602 return 0;
603 }
604 }
605
606 /** This reads bytes from the remote process. */
607 public synchronized ReadResult readBytesFromProcess(long address, long numBytes)
608 throws DebuggerException {
609 if (numBytes < 0) {
610 throw new DebuggerException("Can not read negative number (" + numBytes + ") of bytes from process");
611 }
612 try {
613 String cmd = "peek " + utils.addressValueToString(address) + " " + numBytes;
614 printlnToOutput(cmd);
615 while (in.readByte() != 'B') {
616 }
617 byte res = in.readByte();
618 if (res == 0) {
619 System.err.println("Failing command: " + cmd);
620 throw new DebuggerException("Read of remote process address space failed");
621 }
622 // NOTE: must read ALL of the data regardless of whether we need
623 // to throw an UnmappedAddressException. Otherwise will corrupt
624 // the input stream each time we have a failure. Not good. Do
625 // not want to risk "flushing" the input stream in case a huge
626 // read has a hangup in the middle and we leave data on the
627 // stream.
628 byte[] buf = new byte[(int) numBytes];
629 boolean bailOut = false;
630 long failureAddress = 0;
631 int numReads = 0;
632 while (numBytes > 0) {
633 long len = in.readUnsignedInt();
634 boolean isMapped = ((in.readByte() == 0) ? false : true);
635 if (!isMapped) {
636 if (!bailOut) {
637 bailOut = true;
638 failureAddress = address;
639 }
640 } else {
641 // This won't work if we have unmapped regions, but if we do
642 // then we're going to throw an exception anyway
643
644 // NOTE: there is a factor of 20 speed difference between
645 // these two ways of doing this read.
646 in.readBytes(buf, 0, (int) len);
647 }
648
649 // Do NOT do this:
650 // for (int i = 0; i < (int) len; i++) {
651 // buf[i] = in.readByte();
652 // }
653
654 numBytes -= len;
655 address += len;
656 ++numReads;
657 }
658 if (Assert.ASSERTS_ENABLED) {
659 Assert.that(numBytes == 0, "Bug in debug server's implementation of peek: numBytesLeft == " +
660 numBytes + ", should be 0 (did " + numReads + " reads)");
661 }
662 if (bailOut) {
663 return new ReadResult(failureAddress);
664 }
665 return new ReadResult(buf);
666 }
667 catch (IOException e) {
668 throw new DebuggerException(e);
669 }
670 }
671
672 public void writeBytesToProcess(long address, long numBytes, byte[] data)
673 throws UnmappedAddressException, DebuggerException {
674 // FIXME
675 throw new DebuggerException("Unimplemented");
676 }
677
678 /** This provides DbxDebuggerRemoteIntfImpl access to readBytesFromProcess */
679 ReadResult readBytesFromProcessInternal(long address, long numBytes)
680 throws DebuggerException {
681 return readBytesFromProcess(address, numBytes);
682 }
683
684 /** Convenience routine */
685 private void printlnToOutput(String s) throws IOException {
686 out.println(s);
687 if (out.checkError()) {
688 throw new IOException("Error occurred while writing to debug server");
689 }
690 }
691
692 private void clear() {
693 dbxProcess = null;
694 dbxOstr = null;
695 out = null;
696 in = null;
697 importModuleSocket = null;
698 }
699
700 /** Connects to the dbx import module, setting up out and in
701 streams. Factored out to allow access to the dbx console. */
702 private void connectToImportModule() throws IOException {
703 // Try for 20 seconds to connect to dbx import module; time out
704 // with failure if didn't succeed
705 importModuleSocket = null;
706 long endTime = System.currentTimeMillis() + LONG_TIMEOUT;
707
708 while ((importModuleSocket == null) && (System.currentTimeMillis() < endTime)) {
709 try {
710 importModuleSocket = new Socket(InetAddress.getLocalHost(), PORT);
711 importModuleSocket.setTcpNoDelay(true);
712 }
713 catch (IOException e) {
714 // Swallow IO exceptions while attempting connection
715 try {
716 // Don't swamp the CPU
717 Thread.sleep(1000);
718 }
719 catch (InterruptedException ex) {
720 }
721 }
722 }
723
724 if (importModuleSocket == null) {
725 // Failed to connect because of timeout
726 detach();
727 throw new DebuggerException("Timed out while attempting to connect to remote dbx process");
728 }
729
730 out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(importModuleSocket.getOutputStream(), "US-ASCII")), true);
731 in = new InputLexer(new BufferedInputStream(importModuleSocket.getInputStream()));
732 }
733 }