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
25package 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
39public 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  public long getJBooleanSize() {
530    return jbooleanSize;
531  }
532
533  public long getJByteSize() {
534    return jbyteSize;
535  }
536
537  public long getJCharSize() {
538    return jcharSize;
539  }
540
541  public long getJDoubleSize() {
542    return jdoubleSize;
543  }
544
545  public long getJFloatSize() {
546    return jfloatSize;
547  }
548
549  public long getJIntSize() {
550    return jintSize;
551  }
552
553  public long getJLongSize() {
554    return jlongSize;
555  }
556
557  public long getJShortSize() {
558    return jshortSize;
559  }
560
561  public long getHeapOopSize() {
562    return heapOopSize;
563  }
564
565  public long getNarrowOopBase() {
566    return narrowOopBase;
567  }
568  public int getNarrowOopShift() {
569    return narrowOopShift;
570  }
571
572  public long getKlassPtrSize() {
573    return klassPtrSize;
574  }
575
576  public long getNarrowKlassBase() {
577    return narrowKlassBase;
578  }
579  public int getNarrowKlassShift() {
580    return narrowKlassShift;
581  }
582}
583