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 }