1 /* 2 * Copyright (c) 2002, 2013, 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.bsd; 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.x86.*; 32 import sun.jvm.hotspot.debugger.cdbg.*; 33 import sun.jvm.hotspot.utilities.*; 34 import sun.jvm.hotspot.runtime.VM; 35 import sun.jvm.hotspot.runtime.Threads; 36 import sun.jvm.hotspot.runtime.JavaThread; 37 import java.lang.reflect.*; 38 39 /** <P> An implementation of the JVMDebugger interface. The basic debug 40 facilities are implemented through ptrace interface in the JNI code 41 (libsaproc.so). Library maps and symbol table management are done in 42 JNI. </P> 43 44 <P> <B>NOTE</B> that since we have the notion of fetching "Java 45 primitive types" from the remote process (which might have 46 different sizes than we expect) we have a bootstrapping 47 problem. We need to know the sizes of these types before we can 48 fetch them. The current implementation solves this problem by 49 requiring that it be configured with these type sizes before they 50 can be fetched. The readJ(Type) routines here will throw a 51 RuntimeException if they are called before the debugger is 52 configured with the Java primitive type sizes. </P> */ 53 54 public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { 55 private boolean useGCC32ABI; 56 private boolean attached; 57 private long p_ps_prochandle; // native debugger handle 58 private long symbolicator; // macosx symbolicator handle 59 private long task; // macosx task handle 60 private boolean isCore; 61 private boolean isDarwin; // variant for bsd 62 63 // CDebugger support 64 private BsdCDebugger cdbg; 65 66 // threadList and loadObjectList are filled by attach0 method 67 private List threadList; 68 private List loadObjectList; 69 70 // called by native method lookupByAddress0 71 private ClosestSymbol createClosestSymbol(String name, long offset) { 72 return new ClosestSymbol(name, offset); 73 } 74 75 // called by native method attach0 76 private LoadObject createLoadObject(String fileName, long textsize, 77 long base) { 78 File f = new File(fileName); 79 Address baseAddr = newAddress(base); 80 return new SharedObject(this, fileName, f.length(), baseAddr); 81 } 82 83 // native methods 84 85 private native static void init0() 86 throws DebuggerException; 87 private native void attach0(int pid) 88 throws DebuggerException; 89 private native void attach0(String execName, String coreName) 90 throws DebuggerException; 91 private native void detach0() 92 throws DebuggerException; 93 private native long lookupByName0(String objectName, String symbol) 94 throws DebuggerException; 95 private native ClosestSymbol lookupByAddress0(long address) 96 throws DebuggerException; 97 private native long[] getThreadIntegerRegisterSet0(long unique_thread_id) 98 throws DebuggerException; 99 private native byte[] readBytesFromProcess0(long address, long numBytes) 100 throws DebuggerException; 101 public native static int getAddressSize() ; 102 103 // Note on Bsd threads are really processes. When target process is 104 // attached by a serviceability agent thread, only that thread can do 105 // ptrace operations on the target. This is because from kernel's point 106 // view, other threads are just separate processes and they are not 107 // attached to the target. When they attempt to make ptrace calls, 108 // an ESRCH error will be returned as kernel believes target is not 109 // being traced by the caller. 110 // To work around the problem, we use a worker thread here to handle 111 // all JNI functions that are making ptrace calls. 112 113 interface WorkerThreadTask { 114 public void doit(BsdDebuggerLocal debugger) throws DebuggerException; 115 } 116 117 class BsdDebuggerLocalWorkerThread extends Thread { 118 BsdDebuggerLocal debugger; 119 WorkerThreadTask task; 120 DebuggerException lastException; 121 122 public BsdDebuggerLocalWorkerThread(BsdDebuggerLocal debugger) { 123 this.debugger = debugger; 124 setDaemon(true); 125 } 126 127 public void run() { 128 synchronized (workerThread) { 129 for (;;) { 130 if (task != null) { 131 lastException = null; 132 try { 133 task.doit(debugger); 134 } catch (DebuggerException exp) { 135 lastException = exp; 136 } 137 task = null; 138 workerThread.notifyAll(); 139 } 140 141 try { 142 workerThread.wait(); 143 } catch (InterruptedException x) {} 144 } 145 } 146 } 147 148 public WorkerThreadTask execute(WorkerThreadTask task) throws DebuggerException { 149 synchronized (workerThread) { 150 this.task = task; 151 workerThread.notifyAll(); 152 while (this.task != null) { 153 try { 154 workerThread.wait(); 155 } catch (InterruptedException x) {} 156 } 157 if (lastException != null) { 158 throw new DebuggerException(lastException); 159 } else { 160 return task; 161 } 162 } 163 } 164 } 165 166 private BsdDebuggerLocalWorkerThread workerThread = null; 167 168 //---------------------------------------------------------------------- 169 // Implementation of Debugger interface 170 // 171 172 /** <P> machDesc may not be null. </P> 173 174 <P> useCache should be set to true if debugging is being done 175 locally, and to false if the debugger is being created for the 176 purpose of supporting remote debugging. </P> */ 177 public BsdDebuggerLocal(MachineDescription machDesc, 178 boolean useCache) throws DebuggerException { 179 this.machDesc = machDesc; 180 utils = new DebuggerUtilities(machDesc.getAddressSize(), 181 machDesc.isBigEndian()) { 182 public void checkAlignment(long address, long alignment) { 183 // Need to override default checkAlignment because we need to 184 // relax alignment constraints on Bsd/x86 185 if ( (address % alignment != 0) 186 &&(alignment != 8 || address % 4 != 0)) { 187 throw new UnalignedAddressException( 188 "Trying to read at address: " 189 + addressValueToString(address) 190 + " with alignment: " + alignment, 191 address); 192 } 193 } 194 }; 195 196 if (useCache) { 197 // FIXME: re-test necessity of cache on Bsd, where data 198 // fetching is faster 199 // Cache portion of the remote process's address space. 200 // Fetching data over the socket connection to dbx is slow. 201 // Might be faster if we were using a binary protocol to talk to 202 // dbx, but would have to test. For now, this cache works best 203 // if it covers the entire heap of the remote process. FIXME: at 204 // least should make this tunable from the outside, i.e., via 205 // the UI. This is a cache of 4096 4K pages, or 16 MB. The page 206 // size must be adjusted to be the hardware's page size. 207 // (FIXME: should pick this up from the debugger.) 208 if (getCPU().equals("ia64")) { 209 initCache(16384, parseCacheNumPagesProperty(1024)); 210 } else { 211 initCache(4096, parseCacheNumPagesProperty(4096)); 212 } 213 } 214 215 isDarwin = getOS().equals("darwin"); 216 workerThread = new BsdDebuggerLocalWorkerThread(this); 217 workerThread.start(); 218 } 219 220 /** From the Debugger interface via JVMDebugger */ 221 public boolean hasProcessList() throws DebuggerException { 222 return false; 223 } 224 225 /** From the Debugger interface via JVMDebugger */ 226 public List getProcessList() throws DebuggerException { 227 throw new DebuggerException("getProcessList not implemented yet"); 228 } 229 230 private void checkAttached() throws DebuggerException { 231 if (attached) { 232 if (isCore) { 233 throw new DebuggerException("attached to a core dump already"); 234 } else { 235 throw new DebuggerException("attached to a process already"); 236 } 237 } 238 } 239 240 private void requireAttach() { 241 if (! attached) { 242 throw new RuntimeException("not attached to a process or a core!"); 243 } 244 } 245 246 /* called from attach methods */ 247 private void findABIVersion() throws DebuggerException { 248 String libjvmName = isDarwin ? "libjvm.dylib" : "libjvm.so"; 249 String libjvm_gName = isDarwin? "libjvm_g.dylib" : "libjvm_g.so"; 250 String javaThreadVt = isDarwin ? "_vt_10JavaThread" : "__vt_10JavaThread"; 251 if (lookupByName0(libjvmName, javaThreadVt) != 0 || 252 lookupByName0(libjvm_gName, javaThreadVt) != 0) { 253 // old C++ ABI 254 useGCC32ABI = false; 255 } else { 256 // new C++ ABI 257 useGCC32ABI = true; 258 } 259 } 260 261 /** From the Debugger interface via JVMDebugger */ 262 public synchronized void attach(int processID) throws DebuggerException { 263 checkAttached(); 264 threadList = new ArrayList(); 265 loadObjectList = new ArrayList(); 266 class AttachTask implements WorkerThreadTask { 267 int pid; 268 public void doit(BsdDebuggerLocal debugger) { 269 debugger.attach0(pid); 270 debugger.attached = true; 271 debugger.isCore = false; 272 findABIVersion(); 273 } 274 } 275 276 AttachTask task = new AttachTask(); 277 task.pid = processID; 278 workerThread.execute(task); 279 } 280 281 /** From the Debugger interface via JVMDebugger */ 282 public synchronized void attach(String execName, String coreName) { 283 checkAttached(); 284 threadList = new ArrayList(); 285 loadObjectList = new ArrayList(); 286 attach0(execName, coreName); 287 attached = true; 288 isCore = true; 289 findABIVersion(); 290 } 291 292 /** From the Debugger interface via JVMDebugger */ 293 public synchronized boolean detach() { 294 if (!attached) { 295 return false; 296 } 297 298 threadList = null; 299 loadObjectList = null; 300 301 if (isCore) { 302 detach0(); 303 attached = false; 304 return true; 305 } else { 306 class DetachTask implements WorkerThreadTask { 307 boolean result = false; 308 309 public void doit(BsdDebuggerLocal debugger) { 310 debugger.detach0(); 311 debugger.attached = false; 312 result = true; 313 } 314 } 315 316 DetachTask task = new DetachTask(); 317 workerThread.execute(task); 318 return task.result; 319 } 320 } 321 322 /** From the Debugger interface via JVMDebugger */ 323 public Address parseAddress(String addressString) 324 throws NumberFormatException { 325 long addr = utils.scanAddress(addressString); 326 if (addr == 0) { 327 return null; 328 } 329 return new BsdAddress(this, addr); 330 } 331 332 /** From the Debugger interface via JVMDebugger */ 333 public String getOS() { 334 return PlatformInfo.getOS(); 335 } 336 337 /** From the Debugger interface via JVMDebugger */ 338 public String getCPU() { 339 return PlatformInfo.getCPU(); 340 } 341 342 public boolean hasConsole() throws DebuggerException { 343 return false; 344 } 345 346 public String consoleExecuteCommand(String cmd) throws DebuggerException { 347 throw new DebuggerException("No debugger console available on Bsd"); 348 } 349 350 public String getConsolePrompt() throws DebuggerException { 351 return null; 352 } 353 354 /* called from lookup */ 355 private long handleGCC32ABI(long addr, String symbol) throws DebuggerException { 356 if (useGCC32ABI && symbol.startsWith("_ZTV")) { 357 return addr + (2 * machDesc.getAddressSize()); 358 } else { 359 return addr; 360 } 361 } 362 363 /** From the SymbolLookup interface via Debugger and JVMDebugger */ 364 public synchronized Address lookup(String objectName, String symbol) { 365 requireAttach(); 366 if (!attached) { 367 return null; 368 } 369 370 if (isCore) { 371 // MacOSX symbol with "_" as leading 372 long addr = lookupByName0(objectName, isDarwin ? "_" + symbol : symbol); 373 return (addr == 0)? null : new BsdAddress(this, handleGCC32ABI(addr, symbol)); 374 } else { 375 class LookupByNameTask implements WorkerThreadTask { 376 String objectName, symbol; 377 Address result; 378 379 public void doit(BsdDebuggerLocal debugger) { 380 long addr = debugger.lookupByName0(objectName, symbol); 381 result = (addr == 0 ? null : new BsdAddress(debugger, handleGCC32ABI(addr, symbol))); 382 } 383 } 384 385 LookupByNameTask task = new LookupByNameTask(); 386 task.objectName = objectName; 387 task.symbol = symbol; 388 workerThread.execute(task); 389 return task.result; 390 } 391 } 392 393 /** From the SymbolLookup interface via Debugger and JVMDebugger */ 394 public synchronized OopHandle lookupOop(String objectName, String symbol) { 395 Address addr = lookup(objectName, symbol); 396 if (addr == null) { 397 return null; 398 } 399 return addr.addOffsetToAsOopHandle(0); 400 } 401 402 /** From the Debugger interface */ 403 public MachineDescription getMachineDescription() { 404 return machDesc; 405 } 406 407 //---------------------------------------------------------------------- 408 // Implementation of ThreadAccess interface 409 // 410 411 /** From the ThreadAccess interface via Debugger and JVMDebugger */ 412 public ThreadProxy getThreadForIdentifierAddress(Address threadIdAddr, Address uniqueThreadIdAddr) { 413 return new BsdThread(this, threadIdAddr, uniqueThreadIdAddr); 414 } 415 416 @Override 417 public ThreadProxy getThreadForIdentifierAddress(Address addr) { 418 throw new RuntimeException("unimplemented"); 419 } 420 421 /** From the ThreadAccess interface via Debugger and JVMDebugger */ 422 public ThreadProxy getThreadForThreadId(long id) { 423 return new BsdThread(this, id); 424 } 425 426 //---------------------------------------------------------------------- 427 // Internal routines (for implementation of BsdAddress). 428 // These must not be called until the MachineDescription has been set up. 429 // 430 431 /** From the BsdDebugger interface */ 432 public String addressValueToString(long address) { 433 return utils.addressValueToString(address); 434 } 435 436 /** From the BsdDebugger interface */ 437 public BsdAddress readAddress(long address) 438 throws UnmappedAddressException, UnalignedAddressException { 439 long value = readAddressValue(address); 440 return (value == 0 ? null : new BsdAddress(this, value)); 441 } 442 public BsdAddress readCompOopAddress(long address) 443 throws UnmappedAddressException, UnalignedAddressException { 444 long value = readCompOopAddressValue(address); 445 return (value == 0 ? null : new BsdAddress(this, value)); 446 } 447 448 public BsdAddress readCompKlassAddress(long address) 449 throws UnmappedAddressException, UnalignedAddressException { 450 long value = readCompKlassAddressValue(address); 451 return (value == 0 ? null : new BsdAddress(this, value)); 452 } 453 454 /** From the BsdDebugger interface */ 455 public BsdOopHandle readOopHandle(long address) 456 throws UnmappedAddressException, UnalignedAddressException, 457 NotInHeapException { 458 long value = readAddressValue(address); 459 return (value == 0 ? null : new BsdOopHandle(this, value)); 460 } 461 public BsdOopHandle readCompOopHandle(long address) 462 throws UnmappedAddressException, UnalignedAddressException, 463 NotInHeapException { 464 long value = readCompOopAddressValue(address); 465 return (value == 0 ? null : new BsdOopHandle(this, value)); 466 } 467 468 //---------------------------------------------------------------------- 469 // Thread context access 470 // 471 472 public synchronized long[] getThreadIntegerRegisterSet(long unique_thread_id) 473 throws DebuggerException { 474 requireAttach(); 475 if (isCore) { 476 return getThreadIntegerRegisterSet0(unique_thread_id); 477 } else { 478 class GetThreadIntegerRegisterSetTask implements WorkerThreadTask { 479 long unique_thread_id; 480 long[] result; 481 public void doit(BsdDebuggerLocal debugger) { 482 result = debugger.getThreadIntegerRegisterSet0(unique_thread_id); 483 } 484 } 485 486 GetThreadIntegerRegisterSetTask task = new GetThreadIntegerRegisterSetTask(); 487 task.unique_thread_id = unique_thread_id; 488 workerThread.execute(task); 489 return task.result; 490 } 491 } 492 493 /** Need to override this to relax alignment checks on x86. */ 494 public long readCInteger(long address, long numBytes, boolean isUnsigned) 495 throws UnmappedAddressException, UnalignedAddressException { 496 // Only slightly relaxed semantics -- this is a hack, but is 497 // necessary on x86 where it seems the compiler is 498 // putting some global 64-bit data on 32-bit boundaries 499 if (numBytes == 8) { 500 utils.checkAlignment(address, 4); 501 } else { 502 utils.checkAlignment(address, numBytes); 503 } 504 byte[] data = readBytes(address, numBytes); 505 return utils.dataToCInteger(data, isUnsigned); 506 } 507 508 // Overridden from DebuggerBase because we need to relax alignment 509 // constraints on x86 510 public long readJLong(long address) 511 throws UnmappedAddressException, UnalignedAddressException { 512 utils.checkAlignment(address, jintSize); 513 byte[] data = readBytes(address, jlongSize); 514 return utils.dataToJLong(data, jlongSize); 515 } 516 517 //---------------------------------------------------------------------- 518 // Address access. Can not be package private, but should only be 519 // accessed by the architecture-specific subpackages. 520 521 /** From the BsdDebugger interface */ 522 public long getAddressValue(Address addr) { 523 if (addr == null) return 0; 524 return ((BsdAddress) addr).getValue(); 525 } 526 527 /** From the BsdDebugger interface */ 528 public Address newAddress(long value) { 529 if (value == 0) return null; 530 return new BsdAddress(this, value); 531 } 532 533 /** From the BsdCDebugger interface */ 534 public List/*<ThreadProxy>*/ getThreadList() { 535 requireAttach(); 536 return threadList; 537 } 538 539 /** From the BsdCDebugger interface */ 540 public List/*<LoadObject>*/ getLoadObjectList() { 541 requireAttach(); 542 return loadObjectList; 543 } 544 545 /** From the BsdCDebugger interface */ 546 public synchronized ClosestSymbol lookup(long addr) { 547 requireAttach(); 548 if (isCore) { 549 return lookupByAddress0(addr); 550 } else { 551 class LookupByAddressTask implements WorkerThreadTask { 552 long addr; 553 ClosestSymbol result; 554 555 public void doit(BsdDebuggerLocal debugger) { 556 result = debugger.lookupByAddress0(addr); 557 } 558 } 559 560 LookupByAddressTask task = new LookupByAddressTask(); 561 task.addr = addr; 562 workerThread.execute(task); 563 return task.result; 564 } 565 } 566 567 public CDebugger getCDebugger() { 568 if (cdbg == null) { 569 String cpu = getCPU(); 570 if (cpu.equals("ia64") ) { 571 // IA-64 is not supported because of stack-walking issues 572 return null; 573 } 574 cdbg = new BsdCDebugger(this); 575 } 576 return cdbg; 577 } 578 579 /** This reads bytes from the remote process. */ 580 public synchronized ReadResult readBytesFromProcess(long address, 581 long numBytes) throws UnmappedAddressException, DebuggerException { 582 requireAttach(); 583 if (isCore) { 584 byte[] res = readBytesFromProcess0(address, numBytes); 585 return (res != null)? new ReadResult(res) : new ReadResult(address); 586 } else { 587 class ReadBytesFromProcessTask implements WorkerThreadTask { 588 long address, numBytes; 589 ReadResult result; 590 public void doit(BsdDebuggerLocal debugger) { 591 byte[] res = debugger.readBytesFromProcess0(address, numBytes); 592 if (res != null) 593 result = new ReadResult(res); 594 else 595 result = new ReadResult(address); 596 } 597 } 598 599 ReadBytesFromProcessTask task = new ReadBytesFromProcessTask(); 600 task.address = address; 601 task.numBytes = numBytes; 602 workerThread.execute(task); 603 return task.result; 604 } 605 } 606 607 public void writeBytesToProcess(long address, long numBytes, byte[] data) 608 throws UnmappedAddressException, DebuggerException { 609 // FIXME 610 throw new DebuggerException("Unimplemented"); 611 } 612 613 /** this functions used for core file reading and called from native attach0, 614 it returns an array of long integers as 615 [thread_id, stack_start, stack_end, thread_id, stack_start, stack_end, ....] for 616 all java threads recorded in Threads. Also adds the ThreadProxy to threadList */ 617 public long[] getJavaThreadsInfo() { 618 requireAttach(); 619 Threads threads = VM.getVM().getThreads(); 620 int len = threads.getNumberOfThreads(); 621 long[] result = new long[len * 3]; // triple 622 JavaThread t = threads.first(); 623 long beg, end; 624 int i = 0; 625 while (t != null) { 626 end = t.getStackBaseValue(); 627 beg = end - t.getStackSize(); 628 BsdThread bsdt = (BsdThread)t.getThreadProxy(); 629 long uid = bsdt.getUniqueThreadId(); 630 if (threadList != null) threadList.add(bsdt); 631 result[i] = uid; 632 result[i + 1] = beg; 633 result[i + 2] = end; 634 t = t.next(); 635 i += 3; 636 } 637 return result; 638 } 639 640 static { 641 System.loadLibrary("saproc"); 642 init0(); 643 } 644 }