| /* |
| * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| * |
| */ |
| |
| package sun.jvm.hotspot.debugger; |
| |
| /** A class representing an arbitrary-sized page which can be linked |
| into a list. Used by the PageCache. */ |
| |
| public class Page { |
| private long baseAddress; |
| private byte[] data; |
| private Page prev; |
| private Page next; |
| private long unmappedPageLength; |
| |
| /** The length of the data[] array implicitly defines the size of the |
| page. */ |
| public Page(long baseAddress, byte[] data) { |
| this.baseAddress = baseAddress; |
| this.data = data; |
| } |
| |
| /** This constructor creates an "unmapped" page of the specified |
| length. Fetches from this page will cause -1 to be inserted into |
| the destination buffer. */ |
| public Page(long baseAddress, long unmappedPageLength) { |
| this.baseAddress = baseAddress; |
| this.unmappedPageLength = unmappedPageLength; |
| } |
| |
| public long getBaseAddress() { |
| return baseAddress; |
| } |
| |
| public long getSize() { |
| if (data != null) { |
| return data.length; |
| } else { |
| return unmappedPageLength; |
| } |
| } |
| |
| /** Indicates whether this page is mapped in the remote process's |
| address space */ |
| public boolean isMapped() { |
| return (data != null); |
| } |
| |
| public Page getPrev() { |
| return prev; |
| } |
| |
| public void setPrev(Page prev) { |
| this.prev = prev; |
| } |
| |
| public Page getNext() { |
| return next; |
| } |
| |
| public void setNext(Page next) { |
| this.next = next; |
| } |
| |
| /** Throws IndexOutOfBoundsException if the number of bytes |
| requested is greater than the page size, or if the start address |
| doesn't fall within the page. There are no guarantees on whether |
| any data was actually fetched if an IndexOutOfBoundsException is |
| thrown. If this page is unmapped, -1 is returned for all |
| addresses on this page. */ |
| public void getData(long startAddress, long numBytes, |
| int[] destBuf, long destBufOffset) |
| throws IndexOutOfBoundsException { |
| int startOffset = (int) (startAddress - baseAddress); |
| if ((data == null) && |
| ((startOffset < 0) || ((startOffset + numBytes) > (baseAddress + unmappedPageLength)))) { |
| throw new IndexOutOfBoundsException("startAddress = " + startAddress + |
| ", baseAddress = " + baseAddress + |
| ", unmappedPageLength = " + unmappedPageLength); |
| } |
| for (int i = 0; i < (int) numBytes; ++i) { |
| if (data != null) { |
| destBuf[i + (int) destBufOffset] = ((int) (data[i + startOffset]) & 0x000000FF); |
| } else { |
| destBuf[i + (int) destBufOffset] = -1; |
| } |
| } |
| } |
| |
| /** Throws IndexOutOfBoundsException if the number of bytes |
| requested is greater than the page size, or if the start address |
| doesn't fall within the page. There are no guarantees on whether |
| any data was actually fetched if an IndexOutOfBoundsException is |
| thrown. If this page is unmapped, throws a RuntimeException; |
| this should be watched for at higher levels. */ |
| public void getDataAsBytes(long startAddress, long numBytes, |
| byte[] destBuf, long destBufOffset) |
| throws IndexOutOfBoundsException { |
| long startOffset = startAddress - baseAddress; |
| if (data == null) { |
| throw new RuntimeException("Bug in PageCache; should not fetch from unmapped pages using getDataAsBytes"); |
| } |
| System.arraycopy(data, (int) startOffset, destBuf, (int) destBufOffset, (int) numBytes); |
| } |
| |
| public boolean getBoolean(long address) { |
| return (getByte(address) != 0); |
| } |
| |
| public byte getByte(long address) { |
| return data[(int) address - (int) baseAddress]; |
| } |
| |
| public short getShort(long address, boolean bigEndian) { |
| int start = (int) address - (int) baseAddress; |
| if (bigEndian) { |
| return (short) |
| (((data[start + 1] & 0xFF)) | |
| ((data[start] & 0xFF) << 8)); |
| } else { |
| return (short) |
| (((data[start + 1] & 0xFF) << 8) | |
| ((data[start] & 0xFF))); |
| } |
| } |
| |
| public char getChar(long address, boolean bigEndian) { |
| return (char) getShort(address, bigEndian); |
| } |
| |
| public int getInt(long address, boolean bigEndian) { |
| int start = (int) address - (int) baseAddress; |
| if (bigEndian) { |
| return |
| ((data[start + 3] & 0xFF)) | |
| ((data[start + 2] & 0xFF) << 8) | |
| ((data[start + 1] & 0xFF) << 16) | |
| ((data[start] & 0xFF) << 24); |
| } else { |
| return |
| ((data[start + 3] & 0xFF) << 24) | |
| ((data[start + 2] & 0xFF) << 16) | |
| ((data[start + 1] & 0xFF) << 8) | |
| ((data[start] & 0xFF)); |
| } |
| } |
| |
| public long getLong(long address, boolean bigEndian) { |
| int start = (int) address - (int) baseAddress; |
| if (bigEndian) { |
| return |
| ((data[start + 7] & 0xFFL)) | |
| ((data[start + 6] & 0xFFL) << 8) | |
| ((data[start + 5] & 0xFFL) << 16) | |
| ((data[start + 4] & 0xFFL) << 24) | |
| ((data[start + 3] & 0xFFL) << 32) | |
| ((data[start + 2] & 0xFFL) << 40) | |
| ((data[start + 1] & 0xFFL) << 48) | |
| ((data[start] & 0xFFL) << 56); |
| } else { |
| return |
| ((data[start + 7] & 0xFFL) << 56) | |
| ((data[start + 6] & 0xFFL) << 48) | |
| ((data[start + 5] & 0xFFL) << 40) | |
| ((data[start + 4] & 0xFFL) << 32) | |
| ((data[start + 3] & 0xFFL) << 24) | |
| ((data[start + 2] & 0xFFL) << 16) | |
| ((data[start + 1] & 0xFFL) << 8) | |
| ((data[start] & 0xFFL)); |
| } |
| } |
| |
| public float getFloat(long address, boolean bigEndian) { |
| return Float.intBitsToFloat(getInt(address, bigEndian)); |
| } |
| |
| public double getDouble(long address, boolean bigEndian) { |
| return Double.longBitsToDouble(getLong(address, bigEndian)); |
| } |
| } |