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 }