1 /*
   2  * Copyright (c) 2014, 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.aarch64.*;
  35 import sun.jvm.hotspot.debugger.proc.sparc.*;
  36 import sun.jvm.hotspot.debugger.proc.ppc64.*;
  37 import sun.jvm.hotspot.debugger.proc.x86.*;
  38 import sun.jvm.hotspot.debugger.ppc64.*;
  39 import sun.jvm.hotspot.debugger.amd64.*;
  40 import sun.jvm.hotspot.debugger.aarch64.*;
  41 import sun.jvm.hotspot.debugger.sparc.*;
  42 import sun.jvm.hotspot.debugger.x86.*;
  43 import sun.jvm.hotspot.utilities.*;
  44 
  45 /** <P> An implementation of the JVMDebugger interface which sits on
  46  * top of proc and relies on the SA's proc import module for
  47  * communication with the debugger. </P>
  48  *
  49  * <P> <B>NOTE</B> that since we have the notion of fetching "Java
  50  * primitive types" from the remote process (which might have
  51  * different sizes than we expect) we have a bootstrapping
  52  * problem. We need to know the sizes of these types before we can
  53  * fetch them. The current implementation solves this problem by
  54  * requiring that it be configured with these type sizes before they
  55  * can be fetched. The readJ(Type) routines here will throw a
  56  * RuntimeException if they are called before the debugger is
  57  * configured with the Java primitive type sizes. </P>
  58  */
  59 
  60 public class ProcDebuggerLocal extends DebuggerBase implements ProcDebugger {
  61     protected static final int cacheSize = 16 * 1024 * 1024; // 16 MB
  62 
  63     //------------------------------------------------------------------------
  64     // Implementation of Debugger interface
  65     //
  66 
  67     /** <P> machDesc may be null if it couldn't be determined yet; i.e.,
  68      * if we're on SPARC, we need to ask the remote process whether
  69      * we're in 32- or 64-bit mode. </P>
  70      *
  71      * <P> useCache should be set to true if debugging is being done
  72      * locally, and to false if the debugger is being created for the
  73      * purpose of supporting remote debugging. </P> */
  74     public ProcDebuggerLocal(MachineDescription machDesc, boolean useCache) {
  75         this.machDesc = machDesc;
  76         int cacheNumPages;
  77         int cachePageSize;
  78 
  79         final String cpu = PlatformInfo.getCPU();
  80         if (cpu.equals("sparc")) {
  81             threadFactory = new ProcSPARCThreadFactory(this);
  82             pcRegIndex = SPARCThreadContext.R_PC;
  83             fpRegIndex = SPARCThreadContext.R_I6;
  84         } else if (cpu.equals("x86")) {
  85             threadFactory = new ProcX86ThreadFactory(this);
  86             pcRegIndex = X86ThreadContext.EIP;
  87             fpRegIndex = X86ThreadContext.EBP;
  88             unalignedAccessesOkay = true;
  89         } else if (cpu.equals("amd64") || cpu.equals("x86_64")) {
  90             threadFactory = new ProcAMD64ThreadFactory(this);
  91             pcRegIndex = AMD64ThreadContext.RIP;
  92             fpRegIndex = AMD64ThreadContext.RBP;
  93         } else if (cpu.equals("aarch64")) {
  94             threadFactory = new ProcAARCH64ThreadFactory(this);
  95             pcRegIndex = AARCH64ThreadContext.PC;
  96             fpRegIndex = AARCH64ThreadContext.FP;
  97         } else if (cpu.equals("ppc64")) {
  98             threadFactory = new ProcPPC64ThreadFactory(this);
  99             pcRegIndex = PPC64ThreadContext.PC;
 100             fpRegIndex = PPC64ThreadContext.SP;
 101         } else {
 102           try {
 103             Class tfc = Class.forName("sun.jvm.hotspot.debugger.proc." +
 104                cpu.toLowerCase() + ".Proc" + cpu.toUpperCase() +
 105                "ThreadFactory");
 106             Constructor[] ctfc = tfc.getConstructors();
 107             threadFactory = (ProcThreadFactory)ctfc[0].newInstance(this);
 108           } catch (Exception e) {
 109             throw new RuntimeException("Thread access for CPU architecture " + PlatformInfo.getCPU() + " not yet supported");
 110             // Note: pcRegIndex and fpRegIndex do not appear to be referenced
 111           }
 112         }
 113         if (useCache) {
 114             // Cache portion of the remote process's address space.
 115             // For now, this cache works best if it covers the entire
 116             // heap of the remote process. FIXME: at least should make this
 117             // tunable from the outside, i.e., via the UI. This is a 16 MB
 118             // cache divided on SPARC into 2048 8K pages and on x86 into
 119             // 4096 4K pages; the page size must be adjusted to be the OS's
 120             // page size.
 121 
 122             cachePageSize = getPageSize();
 123             cacheNumPages = parseCacheNumPagesProperty(cacheSize / cachePageSize);
 124             initCache(cachePageSize, cacheNumPages);
 125         }
 126 
 127         resetNativePointers();
 128         clearCacheFields();
 129     }
 130 
 131     /** FIXME: implement this with a Runtime.exec() of ps followed by
 132      * parsing of its output */
 133     public boolean hasProcessList() throws DebuggerException {
 134         return false;
 135     }
 136 
 137     public List getProcessList() throws DebuggerException {
 138         throw new DebuggerException("Not yet supported");
 139     }
 140 
 141 
 142     /** From the Debugger interface via JVMDebugger */
 143     public synchronized void attach(int processID) throws DebuggerException {
 144         checkAttached();
 145         isCore = false;
 146         attach0(new Integer(processID).toString());
 147         attached = true;
 148         suspended = true;
 149     }
 150 
 151     /** From the Debugger interface via JVMDebugger */
 152     public synchronized void attach
 153     (String executableName, String coreFileName) throws DebuggerException {
 154         checkAttached();
 155         isCore = true;
 156         topFrameCache = new HashMap();
 157         attach0(executableName, coreFileName);
 158         attached = true;
 159         suspended = true;
 160     }
 161 
 162     /** From the Debugger interface via JVMDebugger */
 163     public synchronized boolean detach() {
 164         if (! attached) {
 165             return false;
 166         }
 167 
 168         try {
 169             if (p_ps_prochandle == 0L) {
 170                 return false;
 171             }
 172             detach0();
 173             clearCache();
 174             return true;
 175         } catch (Exception e) {
 176             e.printStackTrace();
 177             return false;
 178         } finally {
 179             resetNativePointers();
 180             clearCacheFields();
 181             suspended = false;
 182             attached = false;
 183         }
 184     }
 185 
 186     public synchronized void suspend() throws DebuggerException {
 187         requireAttach();
 188         if (suspended) {
 189             throw new DebuggerException("Process already suspended");
 190         }
 191         suspend0();
 192         suspended = true;
 193         enableCache();
 194         reresolveLoadObjects();
 195     }
 196 
 197     public synchronized void resume() throws DebuggerException {
 198         requireAttach();
 199         if (!suspended) {
 200             throw new DebuggerException("Process not suspended");
 201         }
 202         resume0();
 203         disableCache();
 204         suspended = false;
 205     }
 206 
 207     public synchronized boolean isSuspended() throws DebuggerException {
 208         requireAttach();
 209         return suspended;
 210     }
 211 
 212     /** From the Debugger interface via JVMDebugger */
 213     public Address parseAddress(String addressString) throws NumberFormatException {
 214         long addr = utils.scanAddress(addressString);
 215         if (addr == 0) {
 216             return null;
 217         }
 218         return new ProcAddress(this, addr);
 219     }
 220 
 221     /** From the Debugger interface via JVMDebugger */
 222     public String getOS() {
 223         return PlatformInfo.getOS();
 224     }
 225 
 226     /** From the Debugger interface via JVMDebugger */
 227     public String getCPU() {
 228         return PlatformInfo.getCPU();
 229     }
 230 
 231     public boolean hasConsole() throws DebuggerException {
 232         return false;
 233     }
 234 
 235     public String consoleExecuteCommand(String cmd) throws DebuggerException {
 236         throw new DebuggerException("Can't execute console commands");
 237     }
 238 
 239     public String getConsolePrompt() throws DebuggerException {
 240         return "";
 241     }
 242 
 243     public CDebugger getCDebugger() throws DebuggerException {
 244         if (cdbg == null) {
 245             cdbg = new ProcCDebugger(this);
 246         }
 247         return cdbg;
 248     }
 249 
 250     /** From the SymbolLookup interface via Debugger and JVMDebugger */
 251     public synchronized Address lookup(String objectName, String symbol) {
 252         requireAttach();
 253         long addr = lookupByName0(objectName, symbol);
 254         if (addr == 0) {
 255             return null;
 256         }
 257         return new ProcAddress(this, addr);
 258     }
 259 
 260     /** From the SymbolLookup interface via Debugger and JVMDebugger */
 261     public synchronized OopHandle lookupOop(String objectName, String symbol) {
 262         Address addr = lookup(objectName, symbol);
 263         if (addr == null) {
 264             return null;
 265         }
 266         return addr.addOffsetToAsOopHandle(0);
 267     }
 268 
 269     /** From the ProcDebugger interface */
 270     public MachineDescription getMachineDescription() {
 271         return machDesc;
 272     }
 273 
 274     /** Internal routine supporting lazy setting of MachineDescription,
 275      * since on SPARC we will need to query the remote process to ask
 276      * it what its data model is (32- or 64-bit).
 277      */
 278 
 279     public void setMachineDescription(MachineDescription machDesc) {
 280         this.machDesc = machDesc;
 281         setBigEndian(machDesc.isBigEndian());
 282         utils = new DebuggerUtilities(machDesc.getAddressSize(), machDesc.isBigEndian());
 283     }
 284 
 285     public synchronized int getRemoteProcessAddressSize()
 286     throws DebuggerException {
 287         requireAttach();
 288         return getRemoteProcessAddressSize0();
 289     }
 290 
 291     //--------------------------------------------------------------------------------
 292     // Implementation of ThreadAccess interface
 293     //
 294 
 295     /** From the ThreadAccess interface via Debugger and JVMDebugger */
 296     public ThreadProxy getThreadForIdentifierAddress(Address addr) {
 297         return threadFactory.createThreadWrapper(addr);
 298     }
 299 
 300     public ThreadProxy getThreadForThreadId(long id) {
 301         return threadFactory.createThreadWrapper(id);
 302     }
 303 
 304     //----------------------------------------------------------------------
 305     // Overridden from DebuggerBase because we need to relax alignment
 306     // constraints on x86
 307 
 308     public long readJLong(long address)
 309     throws UnmappedAddressException, UnalignedAddressException {
 310         checkJavaConfigured();
 311         // FIXME: allow this to be configurable. Undesirable to add a
 312         // dependency on the runtime package here, though, since this
 313         // package should be strictly underneath it.
 314         if (unalignedAccessesOkay) {
 315             utils.checkAlignment(address, jintSize);
 316         } else {
 317             utils.checkAlignment(address, jlongSize);
 318         }
 319         byte[] data = readBytes(address, jlongSize);
 320         return utils.dataToJLong(data, jlongSize);
 321     }
 322 
 323     //--------------------------------------------------------------------------------
 324     // Internal routines (for implementation of ProcAddress).
 325     // These must not be called until the MachineDescription has been set up.
 326     //
 327 
 328     /** From the ProcDebugger interface */
 329     public String addressValueToString(long address) {
 330         return utils.addressValueToString(address);
 331     }
 332 
 333     /** Need to override this to relax alignment checks on Solaris/x86. */
 334     public long readCInteger(long address, long numBytes, boolean isUnsigned)
 335     throws UnmappedAddressException, UnalignedAddressException {
 336         checkConfigured();
 337         if (!unalignedAccessesOkay) {
 338             utils.checkAlignment(address, numBytes);
 339         } else {
 340             // Only slightly relaxed semantics -- this is a hack, but is
 341             // necessary on Solaris/x86 where it seems the compiler is
 342             // putting some global 64-bit data on 32-bit boundaries
 343             if (numBytes == 8) {
 344                 utils.checkAlignment(address, 4);
 345             } else {
 346                 utils.checkAlignment(address, numBytes);
 347             }
 348         }
 349         byte[] data = readBytes(address, numBytes);
 350         return utils.dataToCInteger(data, isUnsigned);
 351     }
 352 
 353     /** From the ProcDebugger interface */
 354     public ProcAddress readAddress(long address)
 355     throws UnmappedAddressException, UnalignedAddressException {
 356         long value = readAddressValue(address);
 357         return (value == 0 ? null : new ProcAddress(this, value));
 358     }
 359 
 360     public ProcAddress readCompOopAddress(long address)
 361     throws UnmappedAddressException, UnalignedAddressException {
 362         long value = readCompOopAddressValue(address);
 363         return (value == 0 ? null : new ProcAddress(this, value));
 364     }
 365 
 366     public ProcAddress readCompKlassAddress(long address)
 367     throws UnmappedAddressException, UnalignedAddressException {
 368         long value = readCompKlassAddressValue(address);
 369         return (value == 0 ? null : new ProcAddress(this, value));
 370     }
 371 
 372     /** From the ProcDebugger interface */
 373     public ProcOopHandle readOopHandle(long address)
 374     throws UnmappedAddressException, UnalignedAddressException, NotInHeapException {
 375         long   value = readAddressValue(address);
 376         return (value == 0 ? null : new ProcOopHandle(this, value));
 377     }
 378 
 379     public ProcOopHandle readCompOopHandle(long address) {
 380         long value = readCompOopAddressValue(address);
 381         return (value == 0 ? null : new ProcOopHandle(this, value));
 382     }
 383 
 384     public void writeBytesToProcess(long address, long numBytes, byte[] data)
 385     throws UnmappedAddressException, DebuggerException {
 386         if (isCore) {
 387             throw new DebuggerException("Attached to a core file!");
 388         }
 389         writeBytesToProcess0(address, numBytes, data);
 390     }
 391 
 392     public synchronized ReadResult readBytesFromProcess(long address, long numBytes)
 393     throws DebuggerException {
 394         requireAttach();
 395         byte[] res = readBytesFromProcess0(address, numBytes);
 396         if(res != null)
 397             return new ReadResult(res);
 398         else
 399             return new ReadResult(address);
 400     }
 401 
 402     protected int getPageSize() {
 403         int pagesize = getPageSize0();
 404         if (pagesize == -1) {
 405             // return the hard coded default value.
 406             if (PlatformInfo.getCPU().equals("sparc") ||
 407                 PlatformInfo.getCPU().equals("amd64") )
 408                pagesize = 8196;
 409             else
 410                pagesize = 4096;
 411         }
 412         return pagesize;
 413     }
 414 
 415     //--------------------------------------------------------------------------------
 416     // Thread context access. Can not be package private, but should
 417     // only be accessed by the architecture-specific subpackages.
 418 
 419     /** From the ProcDebugger interface. May have to redefine this later. */
 420     public synchronized long[] getThreadIntegerRegisterSet(int tid) {
 421         requireAttach();
 422         return getThreadIntegerRegisterSet0(tid);
 423     }
 424 
 425     //--------------------------------------------------------------------------------
 426     // Address access. Can not be package private, but should only be
 427     // accessed by the architecture-specific subpackages.
 428 
 429     /** From the ProcDebugger interface */
 430     public long getAddressValue(Address addr) {
 431         if (addr == null) return 0;
 432         return ((ProcAddress) addr).getValue();
 433     }
 434 
 435     /** From the ProcDebugger interface */
 436     public Address newAddress(long value) {
 437         if (value == 0) return null;
 438         return new ProcAddress(this, value);
 439     }
 440 
 441     /** From the ProcDebugger interface */
 442     public synchronized List getThreadList() throws DebuggerException {
 443         requireAttach();
 444         List res = null;
 445         if (isCore && (threadListCache != null)) {
 446             res = threadListCache;
 447         } else {
 448             res = new ArrayList();
 449             fillThreadList0(res);
 450             if (isCore) {
 451                 threadListCache = res;
 452             }
 453         }
 454         return res;
 455     }
 456 
 457     /** From the ProcDebugger interface */
 458     public synchronized List getLoadObjectList() throws DebuggerException {
 459         requireAttach();
 460         if (!suspended) {
 461             throw new DebuggerException("Process not suspended");
 462         }
 463 
 464         if (loadObjectCache == null) {
 465             updateLoadObjectCache();
 466         }
 467         return loadObjectCache;
 468     }
 469 
 470     /** From the ProcDebugger interface */
 471     public synchronized CFrame topFrameForThread(ThreadProxy thread)
 472     throws DebuggerException {
 473         requireAttach();
 474         CFrame res = null;
 475         if (isCore && ((res = (CFrame) topFrameCache.get(thread)) != null)) {
 476             return res;
 477         } else {
 478             ThreadContext context = thread.getContext();
 479             int numRegs = context.getNumRegisters();
 480             long[] regs = new long[numRegs];
 481             for (int i = 0; i < numRegs; i++) {
 482                 regs[i] = context.getRegister(i);
 483             }
 484             res = fillCFrameList0(regs);
 485             if (isCore) {
 486                 topFrameCache.put(thread, res);
 487             }
 488             return res;
 489         }
 490     }
 491 
 492     /** From the ProcDebugger interface */
 493     public synchronized ClosestSymbol lookup(long address) {
 494         requireAttach();
 495         return lookupByAddress0(address);
 496     }
 497 
 498     /** From the ProcDebugger interface */
 499     public String demangle(String name) {
 500         return demangle0(name);
 501     }
 502 
 503     //------------- Internals only below this point --------------------
 504     //
 505     //
 506 
 507     private void updateLoadObjectCache() {
 508         List res = new ArrayList();
 509         nameToDsoMap = new HashMap();
 510         fillLoadObjectList0(res);
 511         loadObjectCache = sortLoadObjects(res);
 512     }
 513 
 514     // sort load objects by base address
 515     private static List sortLoadObjects(List in) {
 516         // sort the list by base address
 517         Object[] arr = in.toArray();
 518         Arrays.sort(arr, loadObjectComparator);
 519         return Arrays.asList(arr);
 520     }
 521 
 522     private long lookupByName(String objectName, String symbolName)
 523     throws DebuggerException {
 524         // NOTE: this assumes that process is suspended (which is probably
 525         // necessary assumption given that DSOs can be loaded/unloaded as
 526         // process runs). Should update documentation.
 527         if (nameToDsoMap == null) {
 528             getLoadObjectList();
 529         }
 530         SharedObject dso = (SharedObject) nameToDsoMap.get(objectName);
 531         // The DSO can be null because we use this to search through known
 532         // DSOs in HotSpotTypeDataBase (for example)
 533         if (dso != null) {
 534             ProcAddress addr = (ProcAddress) dso.lookupSymbol(symbolName);
 535             if (addr != null) {
 536                 return addr.getValue();
 537             }
 538         }
 539         return 0;
 540     }
 541 
 542     private SharedObject findDSOByName(String fullPathName) {
 543         if (loadObjectCache == null)
 544             return null;
 545         for (Iterator iter = loadObjectCache.iterator(); iter.hasNext(); ) {
 546             SharedObject dso = (SharedObject) iter.next();
 547             if (dso.getName().equals(fullPathName)) {
 548                 return dso;
 549             }
 550         }
 551         return null;
 552     }
 553 
 554     private void reresolveLoadObjects() throws DebuggerException {
 555         if (loadObjectCache == null) {
 556             return;
 557         }
 558         updateLoadObjectCache();
 559     }
 560 
 561 
 562     private void checkAttached() {
 563         if (attached) {
 564             if (isCore) {
 565                 throw new DebuggerException("already attached to a core file!");
 566             } else {
 567                 throw new DebuggerException("already attached to a process!");
 568             }
 569         }
 570     }
 571 
 572     private void requireAttach() {
 573         if (! attached) {
 574             throw new RuntimeException("not attached to a process or core file!");
 575         }
 576     }
 577 
 578     private void clearCacheFields() {
 579         loadObjectCache = null;
 580         nameToDsoMap    = null;
 581         threadListCache = null;
 582         topFrameCache   = null;
 583     }
 584 
 585     private void resetNativePointers() {
 586         p_ps_prochandle          = 0L;
 587 
 588         // reset thread_db pointers
 589         libthread_db_handle    = 0L;
 590         p_td_thragent_t        = 0L;
 591         p_td_init              = 0L;
 592         p_td_ta_new            = 0L;
 593         p_td_ta_delete         = 0L;
 594         p_td_ta_thr_iter       = 0L;
 595         p_td_thr_get_info      = 0L;
 596         p_td_ta_map_id2thr     = 0L;
 597         p_td_thr_getgregs      = 0L;
 598 
 599         // part of class sharing workaround
 600         classes_jsa_fd         = -1;
 601         p_file_map_header      = 0L;
 602     }
 603 
 604     // native methods and native helpers
 605 
 606     // attach, detach
 607     private native void attach0(String pid) throws DebuggerException;
 608     private native void attach0(String executableFile, String coreFileName) throws DebuggerException;
 609     private native void detach0() throws DebuggerException;
 610 
 611     // address size, page size
 612     private native int getRemoteProcessAddressSize0() throws DebuggerException;
 613     private native int getPageSize0() throws DebuggerException;
 614 
 615     // threads, stacks
 616     private native long[] getThreadIntegerRegisterSet0(long tid) throws DebuggerException;
 617     private native void   fillThreadList0(List l) throws DebuggerException;
 618 
 619     // fills stack frame list given reg set of the top frame and top frame
 620     private native ProcCFrame fillCFrameList0(long[] regs) throws DebuggerException;
 621 
 622     // helper called by fillCFrameList0
 623     private ProcCFrame createSenderFrame(ProcCFrame f, long pc, long fp) {
 624         ProcCFrame sender = new ProcCFrame(this, newAddress(pc), newAddress(fp));
 625         if (f != null) {
 626             f.setSender(sender);
 627         }
 628         return sender;
 629     }
 630 
 631     // shared objects
 632     private native void fillLoadObjectList0(List l) throws DebuggerException;
 633 
 634     // helper called by fillLoadObjectList0
 635     private LoadObject createLoadObject(String fileName, long textsize, long base) {
 636         File f = new File(fileName);
 637         Address baseAddr = newAddress(base);
 638         SharedObject res = findDSOByName(fileName);
 639         if (res != null) {
 640             // already in cache. just change the base, if needed
 641             Address oldBase = res.getBase();
 642             if (! baseAddr.equals(oldBase)) {
 643                 res.setBase(baseAddr);
 644             }
 645         } else {
 646             // new shared object.
 647             res = new SharedObject(this, fileName, f.length(), baseAddr);
 648         }
 649         nameToDsoMap.put(f.getName(), res);
 650         return res;
 651     }
 652 
 653     // symbol-to-pc
 654     private native long lookupByName0(String objectName, String symbolName) throws DebuggerException;
 655     private native ClosestSymbol lookupByAddress0(long address) throws DebuggerException;
 656 
 657     // helper called by lookupByAddress0
 658     private ClosestSymbol createClosestSymbol(String name, long offset) {
 659         return new ClosestSymbol(name, offset);
 660     }
 661 
 662     // process read/write
 663     private native byte[] readBytesFromProcess0(long address, long numBytes) throws DebuggerException;
 664     private native void writeBytesToProcess0(long address, long numBytes, byte[] data) throws DebuggerException;
 665 
 666     // process control
 667     private native void suspend0() throws DebuggerException;
 668     private native void resume0() throws DebuggerException;
 669 
 670     // demangle a C++ name
 671     private native String demangle0(String name);
 672 
 673     // init JNI ids to fields, methods
 674     private native static void initIDs() throws DebuggerException;
 675     private static LoadObjectComparator loadObjectComparator;
 676 
 677     static {
 678         System.loadLibrary("saproc");
 679         initIDs();
 680         loadObjectComparator = new LoadObjectComparator();
 681     }
 682 
 683     private boolean unalignedAccessesOkay;
 684     private ProcThreadFactory threadFactory;
 685 
 686     // indices of PC and FP registers in gregset
 687     private int pcRegIndex;
 688     private int fpRegIndex;
 689 
 690     // Symbol lookup support
 691     // This is a map of library names to DSOs
 692     private Map nameToDsoMap;  // Map<String, SharedObject>
 693 
 694     // C/C++ debugging support
 695     private List/*<LoadObject>*/ loadObjects;
 696     private CDebugger cdbg;
 697 
 698     // ProcessControl support
 699     private boolean suspended;
 700 
 701     // libproc handle
 702     private long p_ps_prochandle;
 703 
 704     // libthread.so's dlopen handle, thread agent
 705     // and function pointers
 706     private long libthread_db_handle;
 707     private long p_td_thragent_t;
 708     private long p_td_init;
 709     private long p_td_ta_new;
 710     private long p_td_ta_delete;
 711     private long p_td_ta_thr_iter;
 712     private long p_td_thr_get_info;
 713     private long p_td_ta_map_id2thr;
 714     private long p_td_thr_getgregs;
 715 
 716     // part of class sharing workaround
 717     private int classes_jsa_fd;
 718     private long p_file_map_header;
 719 
 720     private boolean attached = false;
 721     private boolean isCore;
 722 
 723     // for core files, we cache load object list, thread list, top frames etc.
 724     // for processes we cache load object list and sync. it during suspend.
 725     private List threadListCache;
 726     private List loadObjectCache;
 727     private Map  topFrameCache;      // Map<ThreadProxy, CFrame>
 728 }