1 /*
2  * Copyright (c) 2001, 2009, 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;
26 
27 /** <P> DebuggerBase is a recommended base class for debugger
28     implementations. It can use a PageCache to cache data from the
29     target process. Note that this class would not be suitable if the
30     system were used to reflect upon itself; it would never be safe to
31     store the value in an OopHandle in anything but an OopHandle.
32     However, it provides a fair amount of code sharing to the current
33     dbx and win32 implementations. </P>
34 
35     <P> NOTE that much of the code sharing is achieved by having this
36     class implement many of the methods in the Win32Debugger and
37     DbxDebugger interfaces. </P> */
38 
39 public abstract class DebuggerBase implements Debugger {
40 
41   // May be set lazily, but must be set before calling any of the read
42   // routines below
43   protected MachineDescription machDesc;
44   protected DebuggerUtilities utils;
45   // Java primitive type sizes, set during bootstrapping. Do not call
46   // any of the Java read routines until these are set up.
47   protected long jbooleanSize;
48   protected long jbyteSize;
49   protected long jcharSize;
50   protected long jdoubleSize;
51   protected long jfloatSize;
52   protected long jintSize;
53   protected long jlongSize;
54   protected long jshortSize;
55   protected boolean javaPrimitiveTypesConfigured;
56   // heap data.
57   protected long oopSize;
58   protected long heapOopSize;
59   protected long narrowOopBase;  // heap base for compressed oops.
60   protected int  narrowOopShift; // shift to decode compressed oops.
61   // class metadata space
62   protected long klassPtrSize;
63   protected long narrowKlassBase;  // heap base for compressed klass ptrs.
64   protected int  narrowKlassShift; // shift to decode compressed klass ptrs.
65   // Should be initialized if desired by calling initCache()
66   private PageCache cache;
67 
68   // State for faster accessors that don't allocate memory on each read
69   private boolean useFastAccessors;
70   private boolean bigEndian;
71 
72   // Page-fetching functionality for LRU cache
73   class Fetcher implements PageFetcher {
fetchPage(long pageBaseAddress, long numBytes)74     public Page fetchPage(long pageBaseAddress, long numBytes) {
75       // This assumes that if any byte is unmapped, that the entire
76       // page is. The common case, however, is that the page is
77       // mapped, so we always fetch the entire thing all at once to
78       // avoid two round-trip communications per page fetch, even
79       // though fetching of unmapped pages will be slow.
80       ReadResult res = readBytesFromProcess(pageBaseAddress, numBytes);
81       if (res.getData() == null) {
82         return new Page(pageBaseAddress, numBytes);
83       }
84       return new Page(pageBaseAddress, res.getData());
85     }
86   }
87 
DebuggerBase()88   protected DebuggerBase() {
89   }
90 
91   /** From the JVMDebugger interface. This is the only public method
92       of this class. */
configureJavaPrimitiveTypeSizes(long jbooleanSize, long jbyteSize, long jcharSize, long jdoubleSize, long jfloatSize, long jintSize, long jlongSize, long jshortSize)93   public void configureJavaPrimitiveTypeSizes(long jbooleanSize,
94                                               long jbyteSize,
95                                               long jcharSize,
96                                               long jdoubleSize,
97                                               long jfloatSize,
98                                               long jintSize,
99                                               long jlongSize,
100                                               long jshortSize) {
101     this.jbooleanSize = jbooleanSize;
102     this.jbyteSize = jbyteSize;
103     this.jcharSize = jcharSize;
104     this.jdoubleSize = jdoubleSize;
105     this.jfloatSize = jfloatSize;
106     this.jintSize = jintSize;
107     this.jlongSize = jlongSize;
108     this.jshortSize = jshortSize;
109 
110     if (jbooleanSize < 1) {
111       throw new RuntimeException("jboolean size is too small");
112     }
113 
114     if (jbyteSize < 1) {
115       throw new RuntimeException("jbyte size is too small");
116     }
117 
118     if (jcharSize < 2) {
119       throw new RuntimeException("jchar size is too small");
120     }
121 
122     if (jdoubleSize < 8) {
123       throw new RuntimeException("jdouble size is too small");
124     }
125 
126     if (jfloatSize < 4) {
127       throw new RuntimeException("jfloat size is too small");
128     }
129 
130     if (jintSize < 4) {
131       throw new RuntimeException("jint size is too small");
132     }
133 
134     if (jlongSize < 8) {
135       throw new RuntimeException("jlong size is too small");
136     }
137 
138     if (jshortSize < 2) {
139       throw new RuntimeException("jshort size is too small");
140     }
141 
142     if (jintSize != jfloatSize) {
143       // If dataToJFloat were rewritten, this wouldn't be necessary
144       throw new RuntimeException("jint size and jfloat size must be equal");
145     }
146 
147     if (jlongSize != jdoubleSize) {
148       // If dataToJDouble were rewritten, this wouldn't be necessary
149       throw new RuntimeException("jlong size and jdouble size must be equal");
150     }
151 
152     useFastAccessors =
153       ((cache != null) &&
154        (jbooleanSize == 1) &&
155        (jbyteSize    == 1) &&
156        (jcharSize    == 2) &&
157        (jdoubleSize  == 8) &&
158        (jfloatSize   == 4) &&
159        (jintSize     == 4) &&
160        (jlongSize    == 8) &&
161        (jshortSize   == 2));
162 
163     javaPrimitiveTypesConfigured = true;
164   }
165 
putHeapConst(long heapOopSize, long klassPtrSize, long narrowOopBase, int narrowOopShift, long narrowKlassBase, int narrowKlassShift)166   public void putHeapConst(long heapOopSize, long klassPtrSize, long narrowOopBase, int narrowOopShift,
167                            long narrowKlassBase, int narrowKlassShift) {
168     this.heapOopSize = heapOopSize;
169     this.klassPtrSize = klassPtrSize;
170     this.narrowOopBase = narrowOopBase;
171     this.narrowOopShift = narrowOopShift;
172     this.narrowKlassBase = narrowKlassBase;
173     this.narrowKlassShift = narrowKlassShift;
174   }
175 
176   /** May be called by subclasses if desired to initialize the page
177       cache but may not be overridden */
initCache(long pageSize, long maxNumPages)178   protected final void initCache(long pageSize, long maxNumPages) {
179     cache = new PageCache(pageSize, maxNumPages, new Fetcher());
180     if (machDesc != null) {
181       bigEndian = machDesc.isBigEndian();
182     }
183   }
184 
185   /** May be called by subclasses if needed (if the machine
186       description is not available at the time of cache
187       initialization, as on Solaris) but may not be overridden */
setBigEndian(boolean bigEndian)188   protected final void setBigEndian(boolean bigEndian) {
189     this.bigEndian = bigEndian;
190   }
191 
192   /** May be called by subclasses to clear out the cache but may not
193       be overridden. For convenience, this can be called even if the
194       cache has not been initialized. */
clearCache()195   protected final void clearCache() {
196     if (cache != null) {
197       cache.clear();
198     }
199   }
200 
201   /** May be called by subclasses to disable the cache (for example,
202       when the target process has been resumed) but may not be
203       overridden. For convenience, this can be called even if the
204       cache has not been initialized. */
disableCache()205   protected final void disableCache() {
206     if (cache != null) {
207       cache.disable();
208     }
209   }
210 
211   /** May be called by subclasses to re-enable the cache (for example,
212       when the target process has been suspended) but may not be
213       overridden. For convenience, this can be called even if the
214       cache has not been initialized. */
enableCache()215   protected final void enableCache() {
216     if (cache != null) {
217       cache.enable();
218     }
219   }
220 
221   /** May be called by subclasses directly but may not be overridden */
readBytes(long address, long numBytes)222   protected final byte[] readBytes(long address, long numBytes)
223     throws UnmappedAddressException, DebuggerException {
224     if (cache != null) {
225       return cache.getData(address, numBytes);
226     } else {
227       ReadResult res = readBytesFromProcess(address, numBytes);
228       if (res.getData() != null) {
229         return res.getData();
230       }
231       throw new UnmappedAddressException(res.getFailureAddress());
232     }
233   }
234 
235   /** May be called by subclasses directly but may not be overridden */
writeBytes(long address, long numBytes, byte[] data)236   protected final void writeBytes(long address, long numBytes, byte[] data)
237     throws UnmappedAddressException, DebuggerException {
238     if (cache != null) {
239       cache.clear(address, numBytes);
240     }
241     writeBytesToProcess(address, numBytes, data);
242   }
243 
readJBoolean(long address)244   public boolean readJBoolean(long address)
245     throws UnmappedAddressException, UnalignedAddressException {
246     checkJavaConfigured();
247     utils.checkAlignment(address, jbooleanSize);
248     if (useFastAccessors) {
249       return (cache.getByte(address) != 0);
250     } else {
251       byte[] data = readBytes(address, jbooleanSize);
252       return utils.dataToJBoolean(data, jbooleanSize);
253     }
254   }
255 
readJByte(long address)256   public byte readJByte(long address)
257     throws UnmappedAddressException, UnalignedAddressException {
258     checkJavaConfigured();
259     utils.checkAlignment(address, jbyteSize);
260     if (useFastAccessors) {
261       return cache.getByte(address);
262     } else {
263       byte[] data = readBytes(address, jbyteSize);
264       return utils.dataToJByte(data, jbyteSize);
265     }
266   }
267 
268   // NOTE: assumes value does not span pages (may be bad assumption on
269   // Solaris/x86; see unalignedAccessesOkay in DbxDebugger hierarchy)
readJChar(long address)270   public char readJChar(long address)
271     throws UnmappedAddressException, UnalignedAddressException {
272     checkJavaConfigured();
273     utils.checkAlignment(address, jcharSize);
274     if (useFastAccessors) {
275       return cache.getChar(address, bigEndian);
276     } else {
277       byte[] data = readBytes(address, jcharSize);
278       return (char) utils.dataToJChar(data, jcharSize);
279     }
280   }
281 
282   // NOTE: assumes value does not span pages (may be bad assumption on
283   // Solaris/x86; see unalignedAccessesOkay in DbxDebugger hierarchy)
readJDouble(long address)284   public double readJDouble(long address)
285     throws UnmappedAddressException, UnalignedAddressException {
286     checkJavaConfigured();
287     utils.checkAlignment(address, jdoubleSize);
288     if (useFastAccessors) {
289       return cache.getDouble(address, bigEndian);
290     } else {
291       byte[] data = readBytes(address, jdoubleSize);
292       return utils.dataToJDouble(data, jdoubleSize);
293     }
294   }
295 
296   // NOTE: assumes value does not span pages (may be bad assumption on
297   // Solaris/x86; see unalignedAccessesOkay in DbxDebugger hierarchy)
readJFloat(long address)298   public float readJFloat(long address)
299     throws UnmappedAddressException, UnalignedAddressException {
300     checkJavaConfigured();
301     utils.checkAlignment(address, jfloatSize);
302     if (useFastAccessors) {
303       return cache.getFloat(address, bigEndian);
304     } else {
305       byte[] data = readBytes(address, jfloatSize);
306       return utils.dataToJFloat(data, jfloatSize);
307     }
308   }
309 
310   // NOTE: assumes value does not span pages (may be bad assumption on
311   // Solaris/x86; see unalignedAccessesOkay in DbxDebugger hierarchy)
readJInt(long address)312   public int readJInt(long address)
313     throws UnmappedAddressException, UnalignedAddressException {
314     checkJavaConfigured();
315     utils.checkAlignment(address, jintSize);
316     if (useFastAccessors) {
317       return cache.getInt(address, bigEndian);
318     } else {
319       byte[] data = readBytes(address, jintSize);
320       return utils.dataToJInt(data, jintSize);
321     }
322   }
323 
324   // NOTE: assumes value does not span pages (may be bad assumption on
325   // Solaris/x86; see unalignedAccessesOkay in DbxDebugger hierarchy)
readJLong(long address)326   public long readJLong(long address)
327     throws UnmappedAddressException, UnalignedAddressException {
328     checkJavaConfigured();
329     utils.checkAlignment(address, jlongSize);
330     if (useFastAccessors) {
331       return cache.getLong(address, bigEndian);
332     } else {
333       byte[] data = readBytes(address, jlongSize);
334       return utils.dataToJLong(data, jlongSize);
335     }
336   }
337 
338   // NOTE: assumes value does not span pages (may be bad assumption on
339   // Solaris/x86; see unalignedAccessesOkay in DbxDebugger hierarchy)
readJShort(long address)340   public short readJShort(long address)
341     throws UnmappedAddressException, UnalignedAddressException {
342     checkJavaConfigured();
343     utils.checkAlignment(address, jshortSize);
344     if (useFastAccessors) {
345       return cache.getShort(address, bigEndian);
346     } else {
347       byte[] data = readBytes(address, jshortSize);
348       return utils.dataToJShort(data, jshortSize);
349     }
350   }
351 
352   // NOTE: assumes value does not span pages (may be bad assumption on
353   // Solaris/x86; see unalignedAccessesOkay in DbxDebugger hierarchy)
readCInteger(long address, long numBytes, boolean isUnsigned)354   public long readCInteger(long address, long numBytes, boolean isUnsigned)
355     throws UnmappedAddressException, UnalignedAddressException {
356     checkConfigured();
357     utils.checkAlignment(address, numBytes);
358     if (useFastAccessors) {
359       if (isUnsigned) {
360         switch((int) numBytes) {
361         case 1: return cache.getByte(address) & 0xFF;
362         case 2: return cache.getShort(address, bigEndian) & 0xFFFF;
363         case 4: return cache.getInt(address, bigEndian) & 0xFFFFFFFFL;
364         case 8: return cache.getLong(address, bigEndian);
365         default: {
366           byte[] data = readBytes(address, numBytes);
367           return utils.dataToCInteger(data, isUnsigned);
368         }
369         }
370       } else {
371         switch((int) numBytes) {
372         case 1: return cache.getByte(address);
373         case 2: return cache.getShort(address, bigEndian);
374         case 4: return cache.getInt(address, bigEndian);
375         case 8: return cache.getLong(address, bigEndian);
376         default: {
377           byte[] data = readBytes(address, numBytes);
378           return utils.dataToCInteger(data, isUnsigned);
379         }
380         }
381       }
382     } else {
383       byte[] data = readBytes(address, numBytes);
384       return utils.dataToCInteger(data, isUnsigned);
385     }
386   }
387 
writeJBoolean(long address, boolean value)388   public void writeJBoolean(long address, boolean value)
389     throws UnmappedAddressException, UnalignedAddressException {
390     checkJavaConfigured();
391     utils.checkAlignment(address, jbooleanSize);
392     byte[] data = utils.jbooleanToData(value);
393     writeBytes(address, jbooleanSize, data);
394   }
395 
writeJByte(long address, byte value)396   public void writeJByte(long address, byte value)
397     throws UnmappedAddressException, UnalignedAddressException {
398     checkJavaConfigured();
399     utils.checkAlignment(address, jbyteSize);
400     byte[] data = utils.jbyteToData(value);
401     writeBytes(address, jbyteSize, data);
402   }
403 
writeJChar(long address, char value)404   public void writeJChar(long address, char value)
405     throws UnmappedAddressException, UnalignedAddressException {
406     checkJavaConfigured();
407     utils.checkAlignment(address, jcharSize);
408     byte[] data = utils.jcharToData(value);
409     writeBytes(address, jcharSize, data);
410   }
411 
writeJDouble(long address, double value)412   public void writeJDouble(long address, double value)
413     throws UnmappedAddressException, UnalignedAddressException {
414     checkJavaConfigured();
415     utils.checkAlignment(address, jdoubleSize);
416     byte[] data = utils.jdoubleToData(value);
417     writeBytes(address, jdoubleSize, data);
418   }
419 
writeJFloat(long address, float value)420   public void writeJFloat(long address, float value)
421     throws UnmappedAddressException, UnalignedAddressException {
422     checkJavaConfigured();
423     utils.checkAlignment(address, jfloatSize);
424     byte[] data = utils.jfloatToData(value);
425     writeBytes(address, jfloatSize, data);
426   }
427 
writeJInt(long address, int value)428   public void writeJInt(long address, int value)
429     throws UnmappedAddressException, UnalignedAddressException {
430     checkJavaConfigured();
431     utils.checkAlignment(address, jintSize);
432     byte[] data = utils.jintToData(value);
433     writeBytes(address, jintSize, data);
434   }
435 
writeJLong(long address, long value)436   public void writeJLong(long address, long value)
437     throws UnmappedAddressException, UnalignedAddressException {
438     checkJavaConfigured();
439     utils.checkAlignment(address, jlongSize);
440     byte[] data = utils.jlongToData(value);
441     writeBytes(address, jlongSize, data);
442   }
443 
writeJShort(long address, short value)444   public void writeJShort(long address, short value)
445     throws UnmappedAddressException, UnalignedAddressException {
446     checkJavaConfigured();
447     utils.checkAlignment(address, jshortSize);
448     byte[] data = utils.jshortToData(value);
449     writeBytes(address, jshortSize, data);
450   }
451 
writeCInteger(long address, long numBytes, long value)452   public void writeCInteger(long address, long numBytes, long value)
453     throws UnmappedAddressException, UnalignedAddressException {
454     checkConfigured();
455     utils.checkAlignment(address, numBytes);
456     byte[] data = utils.cIntegerToData(numBytes, value);
457     writeBytes(address, numBytes, data);
458   }
459 
readAddressValue(long address)460   protected long readAddressValue(long address)
461     throws UnmappedAddressException, UnalignedAddressException {
462     return readCInteger(address, machDesc.getAddressSize(), true);
463   }
464 
readCompOopAddressValue(long address)465   protected long readCompOopAddressValue(long address)
466     throws UnmappedAddressException, UnalignedAddressException {
467     long value = readCInteger(address, getHeapOopSize(), true);
468     if (value != 0) {
469       // See oop.inline.hpp decode_heap_oop
470       value = (long)(narrowOopBase + (long)(value << narrowOopShift));
471     }
472     return value;
473   }
474 
readCompKlassAddressValue(long address)475   protected long readCompKlassAddressValue(long address)
476     throws UnmappedAddressException, UnalignedAddressException {
477     long value = readCInteger(address, getKlassPtrSize(), true);
478     if (value != 0) {
479       value = (long)(narrowKlassBase + (long)(value << narrowKlassShift));
480     }
481     return value;
482   }
483 
writeAddressValue(long address, long value)484   protected void writeAddressValue(long address, long value)
485     throws UnmappedAddressException, UnalignedAddressException {
486     writeCInteger(address, machDesc.getAddressSize(), value);
487   }
488 
489   /** Can be called by subclasses but can not be overridden */
checkConfigured()490   protected final void checkConfigured() {
491     if (machDesc == null) {
492       throw new RuntimeException("MachineDescription must have been set by this point");
493     }
494     if (utils == null) {
495       throw new RuntimeException("DebuggerUtilities must have been set by this point");
496     }
497   }
498 
499   /** Can be called by subclasses but can not be overridden */
checkJavaConfigured()500   protected final void checkJavaConfigured() {
501     checkConfigured();
502 
503     if (!javaPrimitiveTypesConfigured) {
504       throw new RuntimeException("Java primitive type sizes have not yet been configured");
505     }
506   }
507 
508   /** Possibly override page cache size with user-specified property */
parseCacheNumPagesProperty(int defaultNum)509   protected int parseCacheNumPagesProperty(int defaultNum) {
510     String cacheNumPagesString = System.getProperty("cacheNumPages");
511     if (cacheNumPagesString != null) {
512       try {
513         return Integer.parseInt(cacheNumPagesString);
514       } catch (Exception e) {
515         System.err.println("Error parsing cacheNumPages property:");
516         e.printStackTrace();
517       }
518     }
519     return defaultNum;
520   }
521 
522   /** Interim solution for allowing subclasses to write bytes to
523       process until we make that functionality available in the basic
524       Address interface */
invalidatePageCache(long startAddress, long numBytes)525   protected void invalidatePageCache(long startAddress, long numBytes) {
526     cache.clear(startAddress, numBytes);
527   }
528 
getJBooleanSize()529   public long getJBooleanSize() {
530     return jbooleanSize;
531   }
532 
getJByteSize()533   public long getJByteSize() {
534     return jbyteSize;
535   }
536 
getJCharSize()537   public long getJCharSize() {
538     return jcharSize;
539   }
540 
getJDoubleSize()541   public long getJDoubleSize() {
542     return jdoubleSize;
543   }
544 
getJFloatSize()545   public long getJFloatSize() {
546     return jfloatSize;
547   }
548 
getJIntSize()549   public long getJIntSize() {
550     return jintSize;
551   }
552 
getJLongSize()553   public long getJLongSize() {
554     return jlongSize;
555   }
556 
getJShortSize()557   public long getJShortSize() {
558     return jshortSize;
559   }
560 
getHeapOopSize()561   public long getHeapOopSize() {
562     return heapOopSize;
563   }
564 
getNarrowOopBase()565   public long getNarrowOopBase() {
566     return narrowOopBase;
567   }
getNarrowOopShift()568   public int getNarrowOopShift() {
569     return narrowOopShift;
570   }
571 
getKlassPtrSize()572   public long getKlassPtrSize() {
573     return klassPtrSize;
574   }
575 
getNarrowKlassBase()576   public long getNarrowKlassBase() {
577     return narrowKlassBase;
578   }
getNarrowKlassShift()579   public int getNarrowKlassShift() {
580     return narrowKlassShift;
581   }
582 }
583