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