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