/* * Copyright (c) 2007, 2011, 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 com.sun.max.tele.debug; import static com.sun.max.platform.Platform.*; import java.io.*; import java.util.*; import com.sun.cri.ci.*; import com.sun.max.jdwp.vm.data.*; import com.sun.max.lang.*; import com.sun.max.program.*; import com.sun.max.tele.*; import com.sun.max.tele.util.*; import com.sun.max.unsafe.*; /** * Abstract base class for caching the values of a set of ISA defined registers for a given thread. */ abstract class TeleRegisters extends AbstractVmHolder implements TeleVMCache { private static final int TRACE_VALUE = 2; private final TimedTrace updateTracer; private long lastUpdateEpoch = -1L; public final CiRegister[] registers; private final TeleRegisterSet teleRegisterSet; final Endianness endianness; private final Address[] registerValues; private final byte[] registerData; private final ByteArrayInputStream registerDataInputStream; protected TeleRegisters(TeleVM vm, TeleRegisterSet teleRegisterSet, CiRegister[] registers) { super(vm); final TimedTrace tracer = new TimedTrace(TRACE_VALUE, tracePrefix() + teleRegisterSet.thread().entityName() + " creating"); tracer.begin(); this.registers = registers; this.teleRegisterSet = teleRegisterSet; this.endianness = platform().endianness(); this.registerValues = new Address[registers.length]; this.registerData = new byte[registers.length * Address.size()]; this.registerDataInputStream = new ByteArrayInputStream(registerData); Arrays.fill(this.registerValues, Address.zero()); this.updateTracer = new TimedTrace(TRACE_VALUE, tracePrefix() + teleRegisterSet.thread().entityName() + " updating"); tracer.end(null); } public final void updateCache(long epoch) { if (epoch > lastUpdateEpoch) { updateTracer.begin(); // Refreshes the register values from the {@linkplain #registerData() raw buffer} holding the registers' values. // This method should be called whenever the raw buffer is updated. registerDataInputStream.reset(); for (int i = 0; i != registerValues.length; i++) { try { registerValues[i] = Word.read(registerDataInputStream, endianness).asAddress(); } catch (IOException ioException) { TeleError.unexpected(ioException); } } updateTracer.end(null); } else { Trace.line(TRACE_VALUE, tracePrefix() + "redundant update epoch=" + epoch + ": " + this); } } /** * Gets the value of a given register. * * @param register the register whose value is to be returned * @return the value of {@code register} */ final Address getValue(CiRegister register) { return registerValues[register.encoding]; } /** * Determines whether a particular register is the instruction pointer. * * @param register * @return whether the register is the instruction pointer */ boolean isInstructionPointerRegister(CiRegister register) { return false; } /** * Determines whether a particular register is a flags register. * * @param register * @return whether the register is a flags register */ boolean isFlagsRegister(CiRegister register) { return false; } /** * Gets the raw buffer into which the registers' values are read from the remote process. */ final byte[] registerData() { return registerData; } Address getValueAt(int index) { return registerValues[index]; } /** * Sets the value of a given register. * * Note: This call only updates the value of the register in this cache. The update to the actual register in the * remote process must be done by the caller of this method. * * @param register the register whose value is to be updated * @param value the new value of {@code register} */ protected final void setValue(CiRegister register, Address value) { registerValues[register.encoding] = value; } Registers getRegisters(String name) { final String[] registerNames = new String[registers.length]; final long[] values = new long[registerNames.length]; int z = 0; for (CiRegister reg : registers) { registerNames[z] = reg.name; values[z] = getValue(reg).toLong(); z++; } final Registers result = new Registers(name, registerNames, values); return result; } }