/*
* Copyright (c) 2009, 2012, 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.vm.runtime.amd64;
import static com.oracle.max.asm.target.amd64.AMD64.*;
import static com.sun.max.vm.MaxineVM.*;
import static com.sun.max.vm.runtime.amd64.AMD64SafepointPoll.*;
import com.sun.cri.ci.*;
import com.sun.max.unsafe.*;
import com.sun.max.vm.*;
import com.sun.max.vm.runtime.*;
/**
* The trap frame on AMD64 contains the {@linkplain com.sun.max.vm.runtime.Trap.Number trap number} and the values of the
* processor's registers when a trap occurs. The trap frame is as follows:
*
* <pre>
* Base Contents
*
* : :
* | | Trapped frame
* -------+--------------------------------+----------
* | trapped PC | Trap frame
* +--------------------------------+ ---
* | flags register | ^
* +--------------------------------+ |
* | trap number | |
* +--------------------------------+ |
* | | frame
* : XMM0 - XMM15 save area : size
* | | |
* +--------------------------------+ |
* | | |
* : GPR (rax - r15) save area : |
* %sp | | v
* -------+--------------------------------+----------
* </pre>
*
* Or, alternatively, the trap frame is described by the following C-like struct declaration:
*
* <pre>
* trap_state {
* Word generalPurposeRegisters[16];
* Word xmmRegisters[16];
* Word trapNumber;
* Word flagsRegister;
* }
* </pre>
*
* The fault address (i.e. trapped PC) is stored in the return address slot, making the
* trap frame appear as if the trapped method called the trap stub directly.
*/
public final class AMD64TrapFrameAccess extends TrapFrameAccess {
public static final int TRAP_NUMBER_OFFSET;
public static final int FLAGS_OFFSET;
public static final CiCalleeSaveLayout CSL;
static {
CiRegister[] csaRegs = {
rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi,
r8, r9, r10, r11, r12, r13, r14, r15,
xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15
};
int size = (16 * 8) + (16 * 16);
TRAP_NUMBER_OFFSET = size;
size += 8;
FLAGS_OFFSET = size;
size += 8;
CSL = new CiCalleeSaveLayout(0, size, 8, csaRegs);
}
@Override
public Pointer getPCPointer(Pointer trapFrame) {
return trapFrame.plus(vm().stubs.trapStub().frameSize());
}
@Override
public Pointer getSP(Pointer trapFrame) {
return trapFrame.plus(vm().stubs.trapStub().frameSize() + 8);
}
@Override
public Pointer getFP(Pointer trapFrame) {
return trapFrame.readWord(CSL.offsetOf(rbp)).asPointer();
}
@Override
public Pointer getSafepointLatch(Pointer trapFrame) {
Pointer csa = getCalleeSaveArea(trapFrame);
int offset = CSL.offsetOf(LATCH_REGISTER);
return csa.readWord(offset).asPointer();
}
@Override
public void setSafepointLatch(Pointer trapFrame, Pointer value) {
Pointer csa = getCalleeSaveArea(trapFrame);
int offset = CSL.offsetOf(LATCH_REGISTER);
csa.writeWord(offset, value);
}
@Override
public Pointer getCalleeSaveArea(Pointer trapFrame) {
return trapFrame.plus(CSL.frameOffsetToCSA);
}
@Override
public int getTrapNumber(Pointer trapFrame) {
return trapFrame.readWord(TRAP_NUMBER_OFFSET).asAddress().toInt();
}
@Override
public void setTrapNumber(Pointer trapFrame, int trapNumber) {
trapFrame.writeWord(TRAP_NUMBER_OFFSET, Address.fromInt(trapNumber));
}
@Override
public void logTrapFrame(Pointer trapFrame) {
final Pointer csa = getCalleeSaveArea(trapFrame);
Log.println("Non-zero registers:");
for (CiRegister reg : CSL.registers) {
if (reg.isCpu()) {
int offset = CSL.offsetOf(reg);
final Word value = csa.readWord(offset);
if (!value.isZero()) {
Log.print(" ");
Log.print(reg.name);
Log.print("=");
Log.println(value);
}
}
}
Log.print(" rip=");
Log.println(getPC(trapFrame));
Log.print(" rflags=");
final Word flags = csa.readWord(FLAGS_OFFSET);
Log.print(flags);
Log.print(' ');
logFlags(flags.asAddress().toInt());
Log.println();
if (false) {
boolean seenNonZeroXMM = false;
for (CiRegister reg : CSL.registers) {
if (reg.isFpu()) {
int offset = CSL.offsetOf(reg);
final double value = csa.readDouble(offset);
if (value != 0) {
if (!seenNonZeroXMM) {
Log.println("Non-zero XMM registers:");
seenNonZeroXMM = true;
}
Log.print(" ");
Log.print(reg.name);
Log.print("=");
Log.print(value);
Log.print(" {bits: ");
Log.print(Address.fromLong(Double.doubleToRawLongBits(value)));
Log.println("}");
}
}
}
}
final int trapNumber = getTrapNumber(trapFrame);
Log.print("Trap number: ");
Log.print(trapNumber);
Log.print(" == ");
Log.println(Trap.Number.toExceptionName(trapNumber));
}
private static final String[] rflags = {
"CF", // 0
null, // 1
"PF", // 2
null, // 3
"AF", // 4
null, // 5
"ZF", // 6
"SF", // 7
"TF", // 8
"IF", // 9
"DF", // 10
"OF", // 11
"IO", // 12
"PL", // 13
"NT", // 14
null, // 15
"RF", // 16
"VM", // 17
"AC", // 18
"VIF", // 19
"VIP", // 20
"ID" // 21
};
private static void logFlags(int flags) {
Log.print('{');
boolean first = true;
for (int i = rflags.length - 1; i >= 0; i--) {
int mask = 1 << i;
if ((flags & mask) != 0) {
final String flag = rflags[i];
if (flag != null) {
if (!first) {
Log.print(", ");
} else {
first = false;
}
Log.print(flag);
}
}
}
Log.print('}');
}
}