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