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> */
ProcDebuggerLocal(MachineDescription machDesc, boolean useCache)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 */
hasProcessList()133     public boolean hasProcessList() throws DebuggerException {
134         return false;
135     }
136 
getProcessList()137     public List getProcessList() throws DebuggerException {
138         throw new DebuggerException("Not yet supported");
139     }
140 
141 
142     /** From the Debugger interface via JVMDebugger */
attach(int processID)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 */
attach(String executableName, String coreFileName)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 */
detach()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 
suspend()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 
resume()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 
isSuspended()207     public synchronized boolean isSuspended() throws DebuggerException {
208         requireAttach();
209         return suspended;
210     }
211 
212     /** From the Debugger interface via JVMDebugger */
parseAddress(String addressString)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 */
getOS()222     public String getOS() {
223         return PlatformInfo.getOS();
224     }
225 
226     /** From the Debugger interface via JVMDebugger */
getCPU()227     public String getCPU() {
228         return PlatformInfo.getCPU();
229     }
230 
hasConsole()231     public boolean hasConsole() throws DebuggerException {
232         return false;
233     }
234 
consoleExecuteCommand(String cmd)235     public String consoleExecuteCommand(String cmd) throws DebuggerException {
236         throw new DebuggerException("Can't execute console commands");
237     }
238 
getConsolePrompt()239     public String getConsolePrompt() throws DebuggerException {
240         return "";
241     }
242 
getCDebugger()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 */
lookup(String objectName, String symbol)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 */
lookupOop(String objectName, String symbol)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 */
getMachineDescription()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 
setMachineDescription(MachineDescription machDesc)279     public void setMachineDescription(MachineDescription machDesc) {
280         this.machDesc = machDesc;
281         setBigEndian(machDesc.isBigEndian());
282         utils = new DebuggerUtilities(machDesc.getAddressSize(), machDesc.isBigEndian());
283     }
284 
getRemoteProcessAddressSize()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 */
getThreadForIdentifierAddress(Address addr)296     public ThreadProxy getThreadForIdentifierAddress(Address addr) {
297         return threadFactory.createThreadWrapper(addr);
298     }
299 
getThreadForThreadId(long id)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 
readJLong(long address)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 */
addressValueToString(long address)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. */
readCInteger(long address, long numBytes, boolean isUnsigned)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 */
readAddress(long address)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 
readCompOopAddress(long address)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 
readCompKlassAddress(long address)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 */
readOopHandle(long address)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 
readCompOopHandle(long address)379     public ProcOopHandle readCompOopHandle(long address) {
380         long value = readCompOopAddressValue(address);
381         return (value == 0 ? null : new ProcOopHandle(this, value));
382     }
383 
writeBytesToProcess(long address, long numBytes, byte[] data)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 
readBytesFromProcess(long address, long numBytes)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 
getPageSize()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. */
getThreadIntegerRegisterSet(int tid)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 */
getAddressValue(Address addr)430     public long getAddressValue(Address addr) {
431         if (addr == null) return 0;
432         return ((ProcAddress) addr).getValue();
433     }
434 
435     /** From the ProcDebugger interface */
newAddress(long value)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 */
getThreadList()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 */
getLoadObjectList()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 */
topFrameForThread(ThreadProxy thread)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 */
lookup(long address)493     public synchronized ClosestSymbol lookup(long address) {
494         requireAttach();
495         return lookupByAddress0(address);
496     }
497 
498     /** From the ProcDebugger interface */
demangle(String name)499     public String demangle(String name) {
500         return demangle0(name);
501     }
502 
503     //------------- Internals only below this point --------------------
504     //
505     //
506 
updateLoadObjectCache()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
sortLoadObjects(List in)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 
lookupByName(String objectName, String symbolName)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 
findDSOByName(String fullPathName)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 
reresolveLoadObjects()554     private void reresolveLoadObjects() throws DebuggerException {
555         if (loadObjectCache == null) {
556             return;
557         }
558         updateLoadObjectCache();
559     }
560 
561 
checkAttached()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 
requireAttach()572     private void requireAttach() {
573         if (! attached) {
574             throw new RuntimeException("not attached to a process or core file!");
575         }
576     }
577 
clearCacheFields()578     private void clearCacheFields() {
579         loadObjectCache = null;
580         nameToDsoMap    = null;
581         threadListCache = null;
582         topFrameCache   = null;
583     }
584 
resetNativePointers()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
attach0(String pid)607     private native void attach0(String pid) throws DebuggerException;
attach0(String executableFile, String coreFileName)608     private native void attach0(String executableFile, String coreFileName) throws DebuggerException;
detach0()609     private native void detach0() throws DebuggerException;
610 
611     // address size, page size
getRemoteProcessAddressSize0()612     private native int getRemoteProcessAddressSize0() throws DebuggerException;
getPageSize0()613     private native int getPageSize0() throws DebuggerException;
614 
615     // threads, stacks
getThreadIntegerRegisterSet0(long tid)616     private native long[] getThreadIntegerRegisterSet0(long tid) throws DebuggerException;
fillThreadList0(List l)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
fillCFrameList0(long[] regs)620     private native ProcCFrame fillCFrameList0(long[] regs) throws DebuggerException;
621 
622     // helper called by fillCFrameList0
createSenderFrame(ProcCFrame f, long pc, long fp)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
fillLoadObjectList0(List l)632     private native void fillLoadObjectList0(List l) throws DebuggerException;
633 
634     // helper called by fillLoadObjectList0
createLoadObject(String fileName, long textsize, long base)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
lookupByName0(String objectName, String symbolName)654     private native long lookupByName0(String objectName, String symbolName) throws DebuggerException;
lookupByAddress0(long address)655     private native ClosestSymbol lookupByAddress0(long address) throws DebuggerException;
656 
657     // helper called by lookupByAddress0
createClosestSymbol(String name, long offset)658     private ClosestSymbol createClosestSymbol(String name, long offset) {
659         return new ClosestSymbol(name, offset);
660     }
661 
662     // process read/write
readBytesFromProcess0(long address, long numBytes)663     private native byte[] readBytesFromProcess0(long address, long numBytes) throws DebuggerException;
writeBytesToProcess0(long address, long numBytes, byte[] data)664     private native void writeBytesToProcess0(long address, long numBytes, byte[] data) throws DebuggerException;
665 
666     // process control
suspend0()667     private native void suspend0() throws DebuggerException;
resume0()668     private native void resume0() throws DebuggerException;
669 
670     // demangle a C++ name
demangle0(String name)671     private native String demangle0(String name);
672 
673     // init JNI ids to fields, methods
initIDs()674     private native static void initIDs() throws DebuggerException;
675     private static LoadObjectComparator loadObjectComparator;
676 
677     static {
678         System.loadLibrary("saproc");
initIDs()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 }
729