View Javadoc
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 }