1 /* 2 * Copyright 2000-2008 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 public DbxAddress readCompOopAddress(long address) 464 throws UnmappedAddressException, UnalignedAddressException { 465 long value = readCompOopAddressValue(address); 466 return (value == 0 ? null : new DbxAddress(this, value)); 467 } 468 469 /** From the DbxDebugger interface */ 470 public DbxOopHandle readOopHandle(long address) 471 throws UnmappedAddressException, UnalignedAddressException, NotInHeapException { 472 long value = readAddressValue(address); 473 return (value == 0 ? null : new DbxOopHandle(this, value)); 474 } 475 public DbxOopHandle readCompOopHandle(long address) 476 throws UnmappedAddressException, UnalignedAddressException, NotInHeapException { 477 long value = readCompOopAddressValue(address); 478 return (value == 0 ? null : new DbxOopHandle(this, value)); 479 } 480 481 //-------------------------------------------------------------------------------- 482 // Thread context access. Can not be package private, but should 483 // only be accessed by the architecture-specific subpackages. 484 485 /** From the DbxDebugger interface. May have to redefine this later. */ 486 public synchronized long[] getThreadIntegerRegisterSet(int tid) { 487 try { 488 printlnToOutput("thr_gregs " + tid); 489 int num = in.parseInt(); 490 long[] res = new long[num]; 491 for (int i = 0; i < num; i++) { 492 res[i] = in.parseAddress(); 493 } 494 return res; 495 } 496 catch (Exception e) { 497 e.printStackTrace(); 498 return null; 499 } 500 } 501 502 //-------------------------------------------------------------------------------- 503 // Address access. Can not be package private, but should only be 504 // accessed by the architecture-specific subpackages. 505 506 /** From the Debugger interface */ 507 public long getAddressValue(Address addr) { 508 if (addr == null) return 0; 509 return ((DbxAddress) addr).getValue(); 510 } 511 512 /** From the DbxDebugger interface */ 513 public Address newAddress(long value) { 514 if (value == 0) return null; 515 return new DbxAddress(this, value); 516 } 517 518 //-------------------------------------------------------------------------------- 519 // Internals only below this point 520 // 521 522 private void launchProcess() throws IOException { 523 dbxProcess = Runtime.getRuntime().exec(dbxPathName); 524 // dbxOutStreamMonitor = new StreamMonitor(dbxProcess.getInputStream()); 525 // dbxErrStreamMonitor = new StreamMonitor(dbxProcess.getErrorStream()); 526 dbxOutStreamMonitor = new StreamMonitor(dbxProcess.getInputStream(), "dbx stdout", true); 527 dbxErrStreamMonitor = new StreamMonitor(dbxProcess.getErrorStream(), "dbx stderr", true); 528 } 529 530 /** Requires that dbxErrStreamMonitor has a trigger on "dbx: Cannot 531 find" with number DBX_MODULE_NOT_FOUND as well as one on "dbx: 532 warning:" (plus the serviceability agent's dbx module path name, 533 to avoid conflation with inability to load individual object 534 files) with number DBX_MODULE_FAILED_TO_LOAD. The former 535 indicates an absence of libsvc_agent_dbx.so, while the latter 536 indicates that the module failed to load, specifically because 537 the architecture was mismatched. (I don't see a way to detect 538 from the dbx command prompt whether it's running the v8 or v9 539 executbale, so we try to import both flavors of the import 540 module; the "v8" file name convention doesn't actually include 541 the v8 prefix, so this code should work for Intel as well.) */ 542 private void importDbxModule() throws DebuggerException { 543 // Trigger for a successful load 544 dbxOutStreamMonitor.addTrigger("Defining svc_agent_run", DBX_MODULE_LOADED); 545 for (int i = 0; i < dbxSvcAgentDSOPathNames.length; i++) { 546 dbxOstr.println("import " + dbxSvcAgentDSOPathNames[i]); 547 dbxOstr.println("kprint -u2 \\(Ready\\)"); 548 boolean seen = dbxErrStreamMonitor.waitFor("(Ready)", LONG_TIMEOUT); 549 if (!seen) { 550 detach(); 551 throw new DebuggerException("Timed out while importing dbx module from file\n" + dbxSvcAgentDSOPathNames[i]); 552 } 553 List retVals = dbxErrStreamMonitor.getTriggersSeen(); 554 if (retVals.contains(new Integer(DBX_MODULE_NOT_FOUND))) { 555 detach(); 556 throw new DebuggerException("Unable to find the Serviceability Agent's dbx import module at pathname \"" + 557 dbxSvcAgentDSOPathNames[i] + "\""); 558 } else { 559 retVals = dbxOutStreamMonitor.getTriggersSeen(); 560 if (retVals.contains(new Integer(DBX_MODULE_LOADED))) { 561 System.out.println("importDbxModule: imported " + dbxSvcAgentDSOPathNames[i]); 562 return; 563 } 564 } 565 } 566 567 // Failed to load all flavors 568 detach(); 569 String errMsg = ("Unable to find a version of the Serviceability Agent's dbx import module\n" + 570 "matching the architecture of dbx at any of the following locations:"); 571 for (int i = 0; i < dbxSvcAgentDSOPathNames.length; i++) { 572 errMsg = errMsg + "\n" + dbxSvcAgentDSOPathNames[i]; 573 } 574 throw new DebuggerException(errMsg); 575 } 576 577 /** Terminate the debugger forcibly */ 578 private void shutdown() { 579 580 if (dbxProcess != null) { 581 // See whether the process has exited and, if not, terminate it 582 // forcibly 583 try { 584 dbxProcess.exitValue(); 585 } 586 catch (IllegalThreadStateException e) { 587 dbxProcess.destroy(); 588 } 589 } 590 591 try { 592 if (importModuleSocket != null) { 593 importModuleSocket.close(); 594 } 595 } 596 catch (IOException e) { 597 } 598 599 // Release references to all objects 600 clear(); 601 clearCache(); 602 } 603 604 /** Looks up an address in the remote process's address space. 605 Returns 0 if symbol not found or upon error. Package private to 606 allow DbxDebuggerRemoteIntfImpl access. */ 607 synchronized long lookupInProcess(String objectName, String symbol) { 608 try { 609 printlnToOutput("lookup " + objectName + " " + symbol); 610 return in.parseAddress(); 611 } 612 catch (Exception e) { 613 return 0; 614 } 615 } 616 617 /** This reads bytes from the remote process. */ 618 public synchronized ReadResult readBytesFromProcess(long address, long numBytes) 619 throws DebuggerException { 620 if (numBytes < 0) { 621 throw new DebuggerException("Can not read negative number (" + numBytes + ") of bytes from process"); 622 } 623 try { 624 String cmd = "peek " + utils.addressValueToString(address) + " " + numBytes; 625 printlnToOutput(cmd); 626 while (in.readByte() != 'B') { 627 } 628 byte res = in.readByte(); 629 if (res == 0) { 630 System.err.println("Failing command: " + cmd); 631 throw new DebuggerException("Read of remote process address space failed"); 632 } 633 // NOTE: must read ALL of the data regardless of whether we need 634 // to throw an UnmappedAddressException. Otherwise will corrupt 635 // the input stream each time we have a failure. Not good. Do 636 // not want to risk "flushing" the input stream in case a huge 637 // read has a hangup in the middle and we leave data on the 638 // stream. 639 byte[] buf = new byte[(int) numBytes]; 640 boolean bailOut = false; 641 long failureAddress = 0; 642 int numReads = 0; 643 while (numBytes > 0) { 644 long len = in.readUnsignedInt(); 645 boolean isMapped = ((in.readByte() == 0) ? false : true); 646 if (!isMapped) { 647 if (!bailOut) { 648 bailOut = true; 649 failureAddress = address; 650 } 651 } else { 652 // This won't work if we have unmapped regions, but if we do 653 // then we're going to throw an exception anyway 654 655 // NOTE: there is a factor of 20 speed difference between 656 // these two ways of doing this read. 657 in.readBytes(buf, 0, (int) len); 658 } 659 660 // Do NOT do this: 661 // for (int i = 0; i < (int) len; i++) { 662 // buf[i] = in.readByte(); 663 // } 664 665 numBytes -= len; 666 address += len; 667 ++numReads; 668 } 669 if (Assert.ASSERTS_ENABLED) { 670 Assert.that(numBytes == 0, "Bug in debug server's implementation of peek: numBytesLeft == " + 671 numBytes + ", should be 0 (did " + numReads + " reads)"); 672 } 673 if (bailOut) { 674 return new ReadResult(failureAddress); 675 } 676 return new ReadResult(buf); 677 } 678 catch (IOException e) { 679 throw new DebuggerException(e); 680 } 681 } 682 683 public void writeBytesToProcess(long address, long numBytes, byte[] data) 684 throws UnmappedAddressException, DebuggerException { 685 // FIXME 686 throw new DebuggerException("Unimplemented"); 687 } 688 689 /** This provides DbxDebuggerRemoteIntfImpl access to readBytesFromProcess */ 690 ReadResult readBytesFromProcessInternal(long address, long numBytes) 691 throws DebuggerException { 692 return readBytesFromProcess(address, numBytes); 693 } 694 695 /** Convenience routine */ 696 private void printlnToOutput(String s) throws IOException { 697 out.println(s); 698 if (out.checkError()) { 699 throw new IOException("Error occurred while writing to debug server"); 700 } 701 } 702 703 private void clear() { 704 dbxProcess = null; 705 dbxOstr = null; 706 out = null; 707 in = null; 708 importModuleSocket = null; 709 } 710 711 /** Connects to the dbx import module, setting up out and in 712 streams. Factored out to allow access to the dbx console. */ 713 private void connectToImportModule() throws IOException { 714 // Try for 20 seconds to connect to dbx import module; time out 715 // with failure if didn't succeed 716 importModuleSocket = null; 717 long endTime = System.currentTimeMillis() + LONG_TIMEOUT; 718 719 while ((importModuleSocket == null) && (System.currentTimeMillis() < endTime)) { 720 try { 721 importModuleSocket = new Socket(InetAddress.getLocalHost(), PORT); 722 importModuleSocket.setTcpNoDelay(true); 723 } 724 catch (IOException e) { 725 // Swallow IO exceptions while attempting connection 726 try { 727 // Don't swamp the CPU 728 Thread.sleep(1000); 729 } 730 catch (InterruptedException ex) { 731 } 732 } 733 } 734 735 if (importModuleSocket == null) { 736 // Failed to connect because of timeout 737 detach(); 738 throw new DebuggerException("Timed out while attempting to connect to remote dbx process"); 739 } 740 741 out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(importModuleSocket.getOutputStream(), "US-ASCII")), true); 742 in = new InputLexer(new BufferedInputStream(importModuleSocket.getInputStream())); 743 } 744 }