1 /* 2 * Copyright (c) 2002, 2012, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 package sun.jvm.hotspot.debugger.proc; 26 27 import java.io.*; 28 import java.net.*; 29 import java.util.*; 30 import java.lang.reflect.*; 31 import sun.jvm.hotspot.debugger.*; 32 import sun.jvm.hotspot.debugger.cdbg.*; 33 import sun.jvm.hotspot.debugger.proc.amd64.*; 34 import sun.jvm.hotspot.debugger.proc.sparc.*; 35 import sun.jvm.hotspot.debugger.proc.x86.*; 36 import sun.jvm.hotspot.debugger.amd64.*; 37 import sun.jvm.hotspot.debugger.sparc.*; 38 import sun.jvm.hotspot.debugger.x86.*; 39 import sun.jvm.hotspot.utilities.*; 40 41 /** <P> An implementation of the JVMDebugger interface which sits on 42 * top of proc and relies on the SA's proc import module for 43 * communication with the debugger. </P> 44 * 45 * <P> <B>NOTE</B> that since we have the notion of fetching "Java 46 * primitive types" from the remote process (which might have 47 * different sizes than we expect) we have a bootstrapping 48 * problem. We need to know the sizes of these types before we can 49 * fetch them. The current implementation solves this problem by 50 * requiring that it be configured with these type sizes before they 51 * can be fetched. The readJ(Type) routines here will throw a 52 * RuntimeException if they are called before the debugger is 53 * configured with the Java primitive type sizes. </P> 54 */ 55 56 public class ProcDebuggerLocal extends DebuggerBase implements ProcDebugger { 57 protected static final int cacheSize = 16 * 1024 * 1024; // 16 MB 58 59 //------------------------------------------------------------------------ 60 // Implementation of Debugger interface 61 // 62 63 /** <P> machDesc may be null if it couldn't be determined yet; i.e., 64 * if we're on SPARC, we need to ask the remote process whether 65 * we're in 32- or 64-bit mode. </P> 66 * 67 * <P> useCache should be set to true if debugging is being done 68 * locally, and to false if the debugger is being created for the 69 * purpose of supporting remote debugging. </P> */ 70 public ProcDebuggerLocal(MachineDescription machDesc, boolean useCache) { 71 this.machDesc = machDesc; 72 int cacheNumPages; 73 int cachePageSize; 74 75 final String cpu = PlatformInfo.getCPU(); 76 if (cpu.equals("sparc")) { 77 threadFactory = new ProcSPARCThreadFactory(this); 78 pcRegIndex = SPARCThreadContext.R_PC; 79 fpRegIndex = SPARCThreadContext.R_I6; 80 } else if (cpu.equals("x86")) { 81 threadFactory = new ProcX86ThreadFactory(this); 82 pcRegIndex = X86ThreadContext.EIP; 83 fpRegIndex = X86ThreadContext.EBP; 84 unalignedAccessesOkay = true; 85 } else if (cpu.equals("amd64") || cpu.equals("x86_64")) { 86 threadFactory = new ProcAMD64ThreadFactory(this); 87 pcRegIndex = AMD64ThreadContext.RIP; 88 fpRegIndex = AMD64ThreadContext.RBP; 89 } else { 90 try { 91 Class tfc = Class.forName("sun.jvm.hotspot.debugger.proc." + 92 cpu.toLowerCase() + ".Proc" + cpu.toUpperCase() + 93 "ThreadFactory"); 94 Constructor[] ctfc = tfc.getConstructors(); 95 threadFactory = (ProcThreadFactory)ctfc[0].newInstance(this); 96 } catch (Exception e) { 97 throw new RuntimeException("Thread access for CPU architecture " + PlatformInfo.getCPU() + " not yet supported"); 98 // Note: pcRegIndex and fpRegIndex do not appear to be referenced 99 } 100 } 101 if (useCache) { 102 // Cache portion of the remote process's address space. 103 // For now, this cache works best if it covers the entire 104 // heap of the remote process. FIXME: at least should make this 105 // tunable from the outside, i.e., via the UI. This is a 16 MB 106 // cache divided on SPARC into 2048 8K pages and on x86 into 107 // 4096 4K pages; the page size must be adjusted to be the OS's 108 // page size. 109 110 cachePageSize = getPageSize(); 111 cacheNumPages = parseCacheNumPagesProperty(cacheSize / cachePageSize); 112 initCache(cachePageSize, cacheNumPages); 113 } 114 115 resetNativePointers(); 116 clearCacheFields(); 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 130 /** From the Debugger interface via JVMDebugger */ 131 public synchronized void attach(int processID) throws DebuggerException { 132 checkAttached(); 133 isCore = false; 134 attach0(new Integer(processID).toString()); 135 attached = true; 136 suspended = true; 137 } 138 139 /** From the Debugger interface via JVMDebugger */ 140 public synchronized void attach 141 (String executableName, String coreFileName) throws DebuggerException { 142 checkAttached(); 143 isCore = true; 144 topFrameCache = new HashMap(); 145 attach0(executableName, coreFileName); 146 attached = true; 147 suspended = true; 148 } 149 150 /** From the Debugger interface via JVMDebugger */ 151 public synchronized boolean detach() { 152 if (! attached) { 153 return false; 154 } 155 156 try { 157 if (p_ps_prochandle == 0L) { 158 return false; 159 } 160 detach0(); 161 clearCache(); 162 return true; 163 } catch (Exception e) { 164 e.printStackTrace(); 165 return false; 166 } finally { 167 resetNativePointers(); 168 clearCacheFields(); 169 suspended = false; 170 attached = false; 171 } 172 } 173 174 public synchronized void suspend() throws DebuggerException { 175 requireAttach(); 176 if (suspended) { 177 throw new DebuggerException("Process already suspended"); 178 } 179 suspend0(); 180 suspended = true; 181 enableCache(); 182 reresolveLoadObjects(); 183 } 184 185 public synchronized void resume() throws DebuggerException { 186 requireAttach(); 187 if (!suspended) { 188 throw new DebuggerException("Process not suspended"); 189 } 190 resume0(); 191 disableCache(); 192 suspended = false; 193 } 194 195 public synchronized boolean isSuspended() throws DebuggerException { 196 requireAttach(); 197 return suspended; 198 } 199 200 /** From the Debugger interface via JVMDebugger */ 201 public Address parseAddress(String addressString) throws NumberFormatException { 202 long addr = utils.scanAddress(addressString); 203 if (addr == 0) { 204 return null; 205 } 206 return new ProcAddress(this, addr); 207 } 208 209 /** From the Debugger interface via JVMDebugger */ 210 public String getOS() { 211 return PlatformInfo.getOS(); 212 } 213 214 /** From the Debugger interface via JVMDebugger */ 215 public String getCPU() { 216 return PlatformInfo.getCPU(); 217 } 218 219 public boolean hasConsole() throws DebuggerException { 220 return false; 221 } 222 223 public String consoleExecuteCommand(String cmd) throws DebuggerException { 224 throw new DebuggerException("Can't execute console commands"); 225 } 226 227 public String getConsolePrompt() throws DebuggerException { 228 return ""; 229 } 230 231 public CDebugger getCDebugger() throws DebuggerException { 232 if (cdbg == null) { 233 cdbg = new ProcCDebugger(this); 234 } 235 return cdbg; 236 } 237 238 /** From the SymbolLookup interface via Debugger and JVMDebugger */ 239 public synchronized Address lookup(String objectName, String symbol) { 240 requireAttach(); 241 long addr = lookupByName0(objectName, symbol); 242 if (addr == 0) { 243 return null; 244 } 245 return new ProcAddress(this, addr); 246 } 247 248 /** From the SymbolLookup interface via Debugger and JVMDebugger */ 249 public synchronized OopHandle lookupOop(String objectName, String symbol) { 250 Address addr = lookup(objectName, symbol); 251 if (addr == null) { 252 return null; 253 } 254 return addr.addOffsetToAsOopHandle(0); 255 } 256 257 /** From the ProcDebugger interface */ 258 public MachineDescription getMachineDescription() { 259 return machDesc; 260 } 261 262 /** Internal routine supporting lazy setting of MachineDescription, 263 * since on SPARC we will need to query the remote process to ask 264 * it what its data model is (32- or 64-bit). 265 */ 266 267 public void setMachineDescription(MachineDescription machDesc) { 268 this.machDesc = machDesc; 269 setBigEndian(machDesc.isBigEndian()); 270 utils = new DebuggerUtilities(machDesc.getAddressSize(), machDesc.isBigEndian()); 271 } 272 273 public synchronized int getRemoteProcessAddressSize() 274 throws DebuggerException { 275 requireAttach(); 276 return getRemoteProcessAddressSize0(); 277 } 278 279 //-------------------------------------------------------------------------------- 280 // Implementation of ThreadAccess interface 281 // 282 283 /** From the ThreadAccess interface via Debugger and JVMDebugger */ 284 public ThreadProxy getThreadForIdentifierAddress(Address addr) { 285 return threadFactory.createThreadWrapper(addr); 286 } 287 288 public ThreadProxy getThreadForThreadId(long id) { 289 return threadFactory.createThreadWrapper(id); 290 } 291 292 //---------------------------------------------------------------------- 293 // Overridden from DebuggerBase because we need to relax alignment 294 // constraints on x86 295 296 public long readJLong(long address) 297 throws UnmappedAddressException, UnalignedAddressException { 298 checkJavaConfigured(); 299 // FIXME: allow this to be configurable. Undesirable to add a 300 // dependency on the runtime package here, though, since this 301 // package should be strictly underneath it. 302 if (unalignedAccessesOkay) { 303 utils.checkAlignment(address, jintSize); 304 } else { 305 utils.checkAlignment(address, jlongSize); 306 } 307 byte[] data = readBytes(address, jlongSize); 308 return utils.dataToJLong(data, jlongSize); 309 } 310 311 //-------------------------------------------------------------------------------- 312 // Internal routines (for implementation of ProcAddress). 313 // These must not be called until the MachineDescription has been set up. 314 // 315 316 /** From the ProcDebugger interface */ 317 public String addressValueToString(long address) { 318 return utils.addressValueToString(address); 319 } 320 321 /** Need to override this to relax alignment checks on Solaris/x86. */ 322 public long readCInteger(long address, long numBytes, boolean isUnsigned) 323 throws UnmappedAddressException, UnalignedAddressException { 324 checkConfigured(); 325 if (!unalignedAccessesOkay) { 326 utils.checkAlignment(address, numBytes); 327 } else { 328 // Only slightly relaxed semantics -- this is a hack, but is 329 // necessary on Solaris/x86 where it seems the compiler is 330 // putting some global 64-bit data on 32-bit boundaries 331 if (numBytes == 8) { 332 utils.checkAlignment(address, 4); 333 } else { 334 utils.checkAlignment(address, numBytes); 335 } 336 } 337 byte[] data = readBytes(address, numBytes); 338 return utils.dataToCInteger(data, isUnsigned); 339 } 340 341 /** From the ProcDebugger interface */ 342 public ProcAddress readAddress(long address) 343 throws UnmappedAddressException, UnalignedAddressException { 344 long value = readAddressValue(address); 345 return (value == 0 ? null : new ProcAddress(this, value)); 346 } 347 348 public ProcAddress readCompOopAddress(long address) 349 throws UnmappedAddressException, UnalignedAddressException { 350 long value = readCompOopAddressValue(address); 351 return (value == 0 ? null : new ProcAddress(this, value)); 352 } 353 354 /** From the ProcDebugger interface */ 355 public ProcOopHandle readOopHandle(long address) 356 throws UnmappedAddressException, UnalignedAddressException, NotInHeapException { 357 long value = readAddressValue(address); 358 return (value == 0 ? null : new ProcOopHandle(this, value)); 359 } 360 361 public ProcOopHandle readCompOopHandle(long address) { 362 long value = readCompOopAddressValue(address); 363 return (value == 0 ? null : new ProcOopHandle(this, value)); 364 } 365 366 public void writeBytesToProcess(long address, long numBytes, byte[] data) 367 throws UnmappedAddressException, DebuggerException { 368 if (isCore) { 369 throw new DebuggerException("Attached to a core file!"); 370 } 371 writeBytesToProcess0(address, numBytes, data); 372 } 373 374 public synchronized ReadResult readBytesFromProcess(long address, long numBytes) 375 throws DebuggerException { 376 requireAttach(); 377 byte[] res = readBytesFromProcess0(address, numBytes); 378 if(res != null) 379 return new ReadResult(res); 380 else 381 return new ReadResult(address); 382 } 383 384 protected int getPageSize() { 385 int pagesize = getPageSize0(); 386 if (pagesize == -1) { 387 // return the hard coded default value. 388 if (PlatformInfo.getCPU().equals("sparc") || 389 PlatformInfo.getCPU().equals("amd64") ) 390 pagesize = 8196; 391 else 392 pagesize = 4096; 393 } 394 return pagesize; 395 } 396 397 //-------------------------------------------------------------------------------- 398 // Thread context access. Can not be package private, but should 399 // only be accessed by the architecture-specific subpackages. 400 401 /** From the ProcDebugger interface. May have to redefine this later. */ 402 public synchronized long[] getThreadIntegerRegisterSet(int tid) { 403 requireAttach(); 404 return getThreadIntegerRegisterSet0(tid); 405 } 406 407 //-------------------------------------------------------------------------------- 408 // Address access. Can not be package private, but should only be 409 // accessed by the architecture-specific subpackages. 410 411 /** From the ProcDebugger interface */ 412 public long getAddressValue(Address addr) { 413 if (addr == null) return 0; 414 return ((ProcAddress) addr).getValue(); 415 } 416 417 /** From the ProcDebugger interface */ 418 public Address newAddress(long value) { 419 if (value == 0) return null; 420 return new ProcAddress(this, value); 421 } 422 423 /** From the ProcDebugger interface */ 424 public synchronized List getThreadList() throws DebuggerException { 425 requireAttach(); 426 List res = null; 427 if (isCore && (threadListCache != null)) { 428 res = threadListCache; 429 } else { 430 res = new ArrayList(); 431 fillThreadList0(res); 432 if (isCore) { 433 threadListCache = res; 434 } 435 } 436 return res; 437 } 438 439 /** From the ProcDebugger interface */ 440 public synchronized List getLoadObjectList() throws DebuggerException { 441 requireAttach(); 442 if (!suspended) { 443 throw new DebuggerException("Process not suspended"); 444 } 445 446 if (loadObjectCache == null) { 447 updateLoadObjectCache(); 448 } 449 return loadObjectCache; 450 } 451 452 /** From the ProcDebugger interface */ 453 public synchronized CFrame topFrameForThread(ThreadProxy thread) 454 throws DebuggerException { 455 requireAttach(); 456 CFrame res = null; 457 if (isCore && ((res = (CFrame) topFrameCache.get(thread)) != null)) { 458 return res; 459 } else { 460 ThreadContext context = thread.getContext(); 461 int numRegs = context.getNumRegisters(); 462 long[] regs = new long[numRegs]; 463 for (int i = 0; i < numRegs; i++) { 464 regs[i] = context.getRegister(i); 465 } 466 res = fillCFrameList0(regs); 467 if (isCore) { 468 topFrameCache.put(thread, res); 469 } 470 return res; 471 } 472 } 473 474 /** From the ProcDebugger interface */ 475 public synchronized ClosestSymbol lookup(long address) { 476 requireAttach(); 477 return lookupByAddress0(address); 478 } 479 480 /** From the ProcDebugger interface */ 481 public String demangle(String name) { 482 return demangle0(name); 483 } 484 485 //------------- Internals only below this point -------------------- 486 // 487 // 488 489 private void updateLoadObjectCache() { 490 List res = new ArrayList(); 491 nameToDsoMap = new HashMap(); 492 fillLoadObjectList0(res); 493 loadObjectCache = sortLoadObjects(res); 494 } 495 496 // sort load objects by base address 497 private static List sortLoadObjects(List in) { 498 // sort the list by base address 499 Object[] arr = in.toArray(); 500 Arrays.sort(arr, loadObjectComparator); 501 return Arrays.asList(arr); 502 } 503 504 private long lookupByName(String objectName, String symbolName) 505 throws DebuggerException { 506 // NOTE: this assumes that process is suspended (which is probably 507 // necessary assumption given that DSOs can be loaded/unloaded as 508 // process runs). Should update documentation. 509 if (nameToDsoMap == null) { 510 getLoadObjectList(); 511 } 512 SharedObject dso = (SharedObject) nameToDsoMap.get(objectName); 513 // The DSO can be null because we use this to search through known 514 // DSOs in HotSpotTypeDataBase (for example) 515 if (dso != null) { 516 ProcAddress addr = (ProcAddress) dso.lookupSymbol(symbolName); 517 if (addr != null) { 518 return addr.getValue(); 519 } 520 } 521 return 0; 522 } 523 524 private SharedObject findDSOByName(String fullPathName) { 525 if (loadObjectCache == null) 526 return null; 527 for (Iterator iter = loadObjectCache.iterator(); iter.hasNext(); ) { 528 SharedObject dso = (SharedObject) iter.next(); 529 if (dso.getName().equals(fullPathName)) { 530 return dso; 531 } 532 } 533 return null; 534 } 535 536 private void reresolveLoadObjects() throws DebuggerException { 537 if (loadObjectCache == null) { 538 return; 539 } 540 updateLoadObjectCache(); 541 } 542 543 544 private void checkAttached() { 545 if (attached) { 546 if (isCore) { 547 throw new DebuggerException("already attached to a core file!"); 548 } else { 549 throw new DebuggerException("already attached to a process!"); 550 } 551 } 552 } 553 554 private void requireAttach() { 555 if (! attached) { 556 throw new RuntimeException("not attached to a process or core file!"); 557 } 558 } 559 560 private void clearCacheFields() { 561 loadObjectCache = null; 562 nameToDsoMap = null; 563 threadListCache = null; 564 topFrameCache = null; 565 } 566 567 private void resetNativePointers() { 568 p_ps_prochandle = 0L; 569 570 // reset thread_db pointers 571 libthread_db_handle = 0L; 572 p_td_thragent_t = 0L; 573 p_td_init = 0L; 574 p_td_ta_new = 0L; 575 p_td_ta_delete = 0L; 576 p_td_ta_thr_iter = 0L; 577 p_td_thr_get_info = 0L; 578 p_td_ta_map_id2thr = 0L; 579 p_td_thr_getgregs = 0L; 580 581 // part of class sharing workaround 582 classes_jsa_fd = -1; 583 p_file_map_header = 0L; 584 } 585 586 // native methods and native helpers 587 588 // attach, detach 589 private native void attach0(String pid) throws DebuggerException; 590 private native void attach0(String executableFile, String coreFileName) throws DebuggerException; 591 private native void detach0() throws DebuggerException; 592 593 // address size, page size 594 private native int getRemoteProcessAddressSize0() throws DebuggerException; 595 private native int getPageSize0() throws DebuggerException; 596 597 // threads, stacks 598 private native long[] getThreadIntegerRegisterSet0(long tid) throws DebuggerException; 599 private native void fillThreadList0(List l) throws DebuggerException; 600 601 // fills stack frame list given reg set of the top frame and top frame 602 private native ProcCFrame fillCFrameList0(long[] regs) throws DebuggerException; 603 604 // helper called by fillCFrameList0 605 private ProcCFrame createSenderFrame(ProcCFrame f, long pc, long fp) { 606 ProcCFrame sender = new ProcCFrame(this, newAddress(pc), newAddress(fp)); 607 if (f != null) { 608 f.setSender(sender); 609 } 610 return sender; 611 } 612 613 // shared objects 614 private native void fillLoadObjectList0(List l) throws DebuggerException; 615 616 // helper called by fillLoadObjectList0 617 private LoadObject createLoadObject(String fileName, long textsize, long base) { 618 File f = new File(fileName); 619 Address baseAddr = newAddress(base); 620 SharedObject res = findDSOByName(fileName); 621 if (res != null) { 622 // already in cache. just change the base, if needed 623 Address oldBase = res.getBase(); 624 if (! baseAddr.equals(oldBase)) { 625 res.setBase(baseAddr); 626 } 627 } else { 628 // new shared object. 629 res = new SharedObject(this, fileName, f.length(), baseAddr); 630 } 631 nameToDsoMap.put(f.getName(), res); 632 return res; 633 } 634 635 // symbol-to-pc 636 private native long lookupByName0(String objectName, String symbolName) throws DebuggerException; 637 private native ClosestSymbol lookupByAddress0(long address) throws DebuggerException; 638 639 // helper called by lookupByAddress0 640 private ClosestSymbol createClosestSymbol(String name, long offset) { 641 return new ClosestSymbol(name, offset); 642 } 643 644 // process read/write 645 private native byte[] readBytesFromProcess0(long address, long numBytes) throws DebuggerException; 646 private native void writeBytesToProcess0(long address, long numBytes, byte[] data) throws DebuggerException; 647 648 // process control 649 private native void suspend0() throws DebuggerException; 650 private native void resume0() throws DebuggerException; 651 652 // demangle a C++ name 653 private native String demangle0(String name); 654 655 // init JNI ids to fields, methods 656 private native static void initIDs() throws DebuggerException; 657 private static LoadObjectComparator loadObjectComparator; 658 659 static { 660 System.loadLibrary("saproc"); 661 initIDs(); 662 loadObjectComparator = new LoadObjectComparator(); 663 } 664 665 private boolean unalignedAccessesOkay; 666 private ProcThreadFactory threadFactory; 667 668 // indices of PC and FP registers in gregset 669 private int pcRegIndex; 670 private int fpRegIndex; 671 672 // Symbol lookup support 673 // This is a map of library names to DSOs 674 private Map nameToDsoMap; // Map<String, SharedObject> 675 676 // C/C++ debugging support 677 private List/*<LoadObject>*/ loadObjects; 678 private CDebugger cdbg; 679 680 // ProcessControl support 681 private boolean suspended; 682 683 // libproc handle 684 private long p_ps_prochandle; 685 686 // libthread.so's dlopen handle, thread agent 687 // and function pointers 688 private long libthread_db_handle; 689 private long p_td_thragent_t; 690 private long p_td_init; 691 private long p_td_ta_new; 692 private long p_td_ta_delete; 693 private long p_td_ta_thr_iter; 694 private long p_td_thr_get_info; 695 private long p_td_ta_map_id2thr; 696 private long p_td_thr_getgregs; 697 698 // part of class sharing workaround 699 private int classes_jsa_fd; 700 private long p_file_map_header; 701 702 private boolean attached = false; 703 private boolean isCore; 704 705 // for core files, we cache load object list, thread list, top frames etc. 706 // for processes we cache load object list and sync. it during suspend. 707 private List threadListCache; 708 private List loadObjectCache; 709 private Map topFrameCache; // Map<ThreadProxy, CFrame> 710 }