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 public ProcAddress readCompKlassAddress(long address) 355 throws UnmappedAddressException, UnalignedAddressException { 356 long value = readCompKlassAddressValue(address); 357 return (value == 0 ? null : new ProcAddress(this, value)); 358 } 359 360 /** From the ProcDebugger interface */ 361 public ProcOopHandle readOopHandle(long address) 362 throws UnmappedAddressException, UnalignedAddressException, NotInHeapException { 363 long value = readAddressValue(address); 364 return (value == 0 ? null : new ProcOopHandle(this, value)); 365 } 366 367 public ProcOopHandle readCompOopHandle(long address) { 368 long value = readCompOopAddressValue(address); 369 return (value == 0 ? null : new ProcOopHandle(this, value)); 370 } 371 372 public void writeBytesToProcess(long address, long numBytes, byte[] data) 373 throws UnmappedAddressException, DebuggerException { 374 if (isCore) { 375 throw new DebuggerException("Attached to a core file!"); 376 } 377 writeBytesToProcess0(address, numBytes, data); 378 } 379 380 public synchronized ReadResult readBytesFromProcess(long address, long numBytes) 381 throws DebuggerException { 382 requireAttach(); 383 byte[] res = readBytesFromProcess0(address, numBytes); 384 if(res != null) 385 return new ReadResult(res); 386 else 387 return new ReadResult(address); 388 } 389 390 protected int getPageSize() { 391 int pagesize = getPageSize0(); 392 if (pagesize == -1) { 393 // return the hard coded default value. 394 if (PlatformInfo.getCPU().equals("sparc") || 395 PlatformInfo.getCPU().equals("amd64") ) 396 pagesize = 8196; 397 else 398 pagesize = 4096; 399 } 400 return pagesize; 401 } 402 403 //-------------------------------------------------------------------------------- 404 // Thread context access. Can not be package private, but should 405 // only be accessed by the architecture-specific subpackages. 406 407 /** From the ProcDebugger interface. May have to redefine this later. */ 408 public synchronized long[] getThreadIntegerRegisterSet(int tid) { 409 requireAttach(); 410 return getThreadIntegerRegisterSet0(tid); 411 } 412 413 //-------------------------------------------------------------------------------- 414 // Address access. Can not be package private, but should only be 415 // accessed by the architecture-specific subpackages. 416 417 /** From the ProcDebugger interface */ 418 public long getAddressValue(Address addr) { 419 if (addr == null) return 0; 420 return ((ProcAddress) addr).getValue(); 421 } 422 423 /** From the ProcDebugger interface */ 424 public Address newAddress(long value) { 425 if (value == 0) return null; 426 return new ProcAddress(this, value); 427 } 428 429 /** From the ProcDebugger interface */ 430 public synchronized List getThreadList() throws DebuggerException { 431 requireAttach(); 432 List res = null; 433 if (isCore && (threadListCache != null)) { 434 res = threadListCache; 435 } else { 436 res = new ArrayList(); 437 fillThreadList0(res); 438 if (isCore) { 439 threadListCache = res; 440 } 441 } 442 return res; 443 } 444 445 /** From the ProcDebugger interface */ 446 public synchronized List getLoadObjectList() throws DebuggerException { 447 requireAttach(); 448 if (!suspended) { 449 throw new DebuggerException("Process not suspended"); 450 } 451 452 if (loadObjectCache == null) { 453 updateLoadObjectCache(); 454 } 455 return loadObjectCache; 456 } 457 458 /** From the ProcDebugger interface */ 459 public synchronized CFrame topFrameForThread(ThreadProxy thread) 460 throws DebuggerException { 461 requireAttach(); 462 CFrame res = null; 463 if (isCore && ((res = (CFrame) topFrameCache.get(thread)) != null)) { 464 return res; 465 } else { 466 ThreadContext context = thread.getContext(); 467 int numRegs = context.getNumRegisters(); 468 long[] regs = new long[numRegs]; 469 for (int i = 0; i < numRegs; i++) { 470 regs[i] = context.getRegister(i); 471 } 472 res = fillCFrameList0(regs); 473 if (isCore) { 474 topFrameCache.put(thread, res); 475 } 476 return res; 477 } 478 } 479 480 /** From the ProcDebugger interface */ 481 public synchronized ClosestSymbol lookup(long address) { 482 requireAttach(); 483 return lookupByAddress0(address); 484 } 485 486 /** From the ProcDebugger interface */ 487 public String demangle(String name) { 488 return demangle0(name); 489 } 490 491 //------------- Internals only below this point -------------------- 492 // 493 // 494 495 private void updateLoadObjectCache() { 496 List res = new ArrayList(); 497 nameToDsoMap = new HashMap(); 498 fillLoadObjectList0(res); 499 loadObjectCache = sortLoadObjects(res); 500 } 501 502 // sort load objects by base address 503 private static List sortLoadObjects(List in) { 504 // sort the list by base address 505 Object[] arr = in.toArray(); 506 Arrays.sort(arr, loadObjectComparator); 507 return Arrays.asList(arr); 508 } 509 510 private long lookupByName(String objectName, String symbolName) 511 throws DebuggerException { 512 // NOTE: this assumes that process is suspended (which is probably 513 // necessary assumption given that DSOs can be loaded/unloaded as 514 // process runs). Should update documentation. 515 if (nameToDsoMap == null) { 516 getLoadObjectList(); 517 } 518 SharedObject dso = (SharedObject) nameToDsoMap.get(objectName); 519 // The DSO can be null because we use this to search through known 520 // DSOs in HotSpotTypeDataBase (for example) 521 if (dso != null) { 522 ProcAddress addr = (ProcAddress) dso.lookupSymbol(symbolName); 523 if (addr != null) { 524 return addr.getValue(); 525 } 526 } 527 return 0; 528 } 529 530 private SharedObject findDSOByName(String fullPathName) { 531 if (loadObjectCache == null) 532 return null; 533 for (Iterator iter = loadObjectCache.iterator(); iter.hasNext(); ) { 534 SharedObject dso = (SharedObject) iter.next(); 535 if (dso.getName().equals(fullPathName)) { 536 return dso; 537 } 538 } 539 return null; 540 } 541 542 private void reresolveLoadObjects() throws DebuggerException { 543 if (loadObjectCache == null) { 544 return; 545 } 546 updateLoadObjectCache(); 547 } 548 549 550 private void checkAttached() { 551 if (attached) { 552 if (isCore) { 553 throw new DebuggerException("already attached to a core file!"); 554 } else { 555 throw new DebuggerException("already attached to a process!"); 556 } 557 } 558 } 559 560 private void requireAttach() { 561 if (! attached) { 562 throw new RuntimeException("not attached to a process or core file!"); 563 } 564 } 565 566 private void clearCacheFields() { 567 loadObjectCache = null; 568 nameToDsoMap = null; 569 threadListCache = null; 570 topFrameCache = null; 571 } 572 573 private void resetNativePointers() { 574 p_ps_prochandle = 0L; 575 576 // reset thread_db pointers 577 libthread_db_handle = 0L; 578 p_td_thragent_t = 0L; 579 p_td_init = 0L; 580 p_td_ta_new = 0L; 581 p_td_ta_delete = 0L; 582 p_td_ta_thr_iter = 0L; 583 p_td_thr_get_info = 0L; 584 p_td_ta_map_id2thr = 0L; 585 p_td_thr_getgregs = 0L; 586 587 // part of class sharing workaround 588 classes_jsa_fd = -1; 589 p_file_map_header = 0L; 590 } 591 592 // native methods and native helpers 593 594 // attach, detach 595 private native void attach0(String pid) throws DebuggerException; 596 private native void attach0(String executableFile, String coreFileName) throws DebuggerException; 597 private native void detach0() throws DebuggerException; 598 599 // address size, page size 600 private native int getRemoteProcessAddressSize0() throws DebuggerException; 601 private native int getPageSize0() throws DebuggerException; 602 603 // threads, stacks 604 private native long[] getThreadIntegerRegisterSet0(long tid) throws DebuggerException; 605 private native void fillThreadList0(List l) throws DebuggerException; 606 607 // fills stack frame list given reg set of the top frame and top frame 608 private native ProcCFrame fillCFrameList0(long[] regs) throws DebuggerException; 609 610 // helper called by fillCFrameList0 611 private ProcCFrame createSenderFrame(ProcCFrame f, long pc, long fp) { 612 ProcCFrame sender = new ProcCFrame(this, newAddress(pc), newAddress(fp)); 613 if (f != null) { 614 f.setSender(sender); 615 } 616 return sender; 617 } 618 619 // shared objects 620 private native void fillLoadObjectList0(List l) throws DebuggerException; 621 622 // helper called by fillLoadObjectList0 623 private LoadObject createLoadObject(String fileName, long textsize, long base) { 624 File f = new File(fileName); 625 Address baseAddr = newAddress(base); 626 SharedObject res = findDSOByName(fileName); 627 if (res != null) { 628 // already in cache. just change the base, if needed 629 Address oldBase = res.getBase(); 630 if (! baseAddr.equals(oldBase)) { 631 res.setBase(baseAddr); 632 } 633 } else { 634 // new shared object. 635 res = new SharedObject(this, fileName, f.length(), baseAddr); 636 } 637 nameToDsoMap.put(f.getName(), res); 638 return res; 639 } 640 641 // symbol-to-pc 642 private native long lookupByName0(String objectName, String symbolName) throws DebuggerException; 643 private native ClosestSymbol lookupByAddress0(long address) throws DebuggerException; 644 645 // helper called by lookupByAddress0 646 private ClosestSymbol createClosestSymbol(String name, long offset) { 647 return new ClosestSymbol(name, offset); 648 } 649 650 // process read/write 651 private native byte[] readBytesFromProcess0(long address, long numBytes) throws DebuggerException; 652 private native void writeBytesToProcess0(long address, long numBytes, byte[] data) throws DebuggerException; 653 654 // process control 655 private native void suspend0() throws DebuggerException; 656 private native void resume0() throws DebuggerException; 657 658 // demangle a C++ name 659 private native String demangle0(String name); 660 661 // init JNI ids to fields, methods 662 private native static void initIDs() throws DebuggerException; 663 private static LoadObjectComparator loadObjectComparator; 664 665 static { 666 System.loadLibrary("saproc"); 667 initIDs(); 668 loadObjectComparator = new LoadObjectComparator(); 669 } 670 671 private boolean unalignedAccessesOkay; 672 private ProcThreadFactory threadFactory; 673 674 // indices of PC and FP registers in gregset 675 private int pcRegIndex; 676 private int fpRegIndex; 677 678 // Symbol lookup support 679 // This is a map of library names to DSOs 680 private Map nameToDsoMap; // Map<String, SharedObject> 681 682 // C/C++ debugging support 683 private List/*<LoadObject>*/ loadObjects; 684 private CDebugger cdbg; 685 686 // ProcessControl support 687 private boolean suspended; 688 689 // libproc handle 690 private long p_ps_prochandle; 691 692 // libthread.so's dlopen handle, thread agent 693 // and function pointers 694 private long libthread_db_handle; 695 private long p_td_thragent_t; 696 private long p_td_init; 697 private long p_td_ta_new; 698 private long p_td_ta_delete; 699 private long p_td_ta_thr_iter; 700 private long p_td_thr_get_info; 701 private long p_td_ta_map_id2thr; 702 private long p_td_thr_getgregs; 703 704 // part of class sharing workaround 705 private int classes_jsa_fd; 706 private long p_file_map_header; 707 708 private boolean attached = false; 709 private boolean isCore; 710 711 // for core files, we cache load object list, thread list, top frames etc. 712 // for processes we cache load object list and sync. it during suspend. 713 private List threadListCache; 714 private List loadObjectCache; 715 private Map topFrameCache; // Map<ThreadProxy, CFrame> 716 }