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