1 /*
  2  * Copyright (c) 2001, 2021, 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 {
 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 
 88   protected DebuggerBase() {
 89   }
 90 
 91   /** From the JVMDebugger interface. This is the only public method
 92       of this class. */
 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 
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 */
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 */
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. */
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. */
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. */
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 */
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 */
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 
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 
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)
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)
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)
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)
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)
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)
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)
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
460   protected long readAddressValue(long address)
461     throws UnmappedAddressException, UnalignedAddressException {
462     return readCInteger(address, machDesc.getAddressSize(), true);
463   }
464 
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 
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 
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 */
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 */
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 */
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 */
525   protected void invalidatePageCache(long startAddress, long numBytes) {
526     cache.clear(startAddress, numBytes);
527   }
528 
529   @Override
530   public String findSymbol(String symbol) {
531     Address addr = lookup(null, symbol);
532     if (addr == null && getOS().equals("win32")) {
533       // On win32 symbols are prefixed with the dll name. Do the user
534       // a favor and see if this is a symbol in jvm.dll or java.dll.
535       addr = lookup(null, "jvm!" + symbol);
536       if (addr == null) {
537         addr = lookup(null, "java!" + symbol);
538       }
539     }
540     if (addr == null) {
541       return null;
542     }
543     var builder = new StringBuilder(addr.toString());
544     var cdbg = getCDebugger();
545     var loadObject = cdbg.loadObjectContainingPC(addr);
546     // Print the shared library path and the offset of the symbol
547     if (loadObject != null) {
548       builder.append(": ").append(loadObject.getName());
549       long diff = addr.minus(loadObject.getBase());
550       if (diff != 0L) {
551         builder.append(" + 0x").append(Long.toHexString(diff));
552       }
553     }
554     return builder.toString();
555   }
556 
557   public long getJBooleanSize() {
558     return jbooleanSize;
559   }
560 
561   public long getJByteSize() {
562     return jbyteSize;
563   }
564 
565   public long getJCharSize() {
566     return jcharSize;
567   }
568 
569   public long getJDoubleSize() {
570     return jdoubleSize;
571   }
572 
573   public long getJFloatSize() {
574     return jfloatSize;
575   }
576 
577   public long getJIntSize() {
578     return jintSize;
579   }
580 
581   public long getJLongSize() {
582     return jlongSize;
583   }
584 
585   public long getJShortSize() {
586     return jshortSize;
587   }
588 
589   public long getHeapOopSize() {
590     return heapOopSize;
591   }
592 
593   public long getNarrowOopBase() {
594     return narrowOopBase;
595   }
596   public int getNarrowOopShift() {
597     return narrowOopShift;
598   }
599 
600   public long getKlassPtrSize() {
601     return klassPtrSize;
602   }
603 
604   public long getNarrowKlassBase() {
605     return narrowKlassBase;
606   }
607   public int getNarrowKlassShift() {
608     return narrowKlassShift;
609   }
610 }