package com.oracle.objectfile.elf.dwarf;
import com.oracle.objectfile.LayoutDecision;
import com.oracle.objectfile.debugentry.ClassEntry;
import com.oracle.objectfile.debugentry.PrimaryEntry;
import com.oracle.objectfile.debugentry.Range;
import com.oracle.objectfile.debuginfo.DebugInfoProvider;
import org.graalvm.compiler.debug.DebugContext;
import java.util.List;
import static com.oracle.objectfile.elf.dwarf.DwarfDebugInfo.DW_CFA_CIE_id;
import static com.oracle.objectfile.elf.dwarf.DwarfDebugInfo.DW_CFA_CIE_version;
import static com.oracle.objectfile.elf.dwarf.DwarfDebugInfo.DW_CFA_advance_loc;
import static com.oracle.objectfile.elf.dwarf.DwarfDebugInfo.DW_CFA_advance_loc1;
import static com.oracle.objectfile.elf.dwarf.DwarfDebugInfo.DW_CFA_advance_loc2;
import static com.oracle.objectfile.elf.dwarf.DwarfDebugInfo.DW_CFA_advance_loc4;
import static com.oracle.objectfile.elf.dwarf.DwarfDebugInfo.DW_CFA_def_cfa;
import static com.oracle.objectfile.elf.dwarf.DwarfDebugInfo.DW_CFA_def_cfa_offset;
import static com.oracle.objectfile.elf.dwarf.DwarfDebugInfo.DW_CFA_nop;
import static com.oracle.objectfile.elf.dwarf.DwarfDebugInfo.DW_CFA_offset;
import static com.oracle.objectfile.elf.dwarf.DwarfDebugInfo.DW_CFA_register;
import static com.oracle.objectfile.elf.dwarf.DwarfDebugInfo.DW_CFA_restore;
import static com.oracle.objectfile.elf.dwarf.DwarfDebugInfo.DW_FRAME_SECTION_NAME;
import static com.oracle.objectfile.elf.dwarf.DwarfDebugInfo.DW_LINE_SECTION_NAME;
public abstract class DwarfFrameSectionImpl extends DwarfSectionImpl {
private static final int PADDING_NOPS_ALIGNMENT = 8;
public DwarfFrameSectionImpl(DwarfDebugInfo dwarfSections) {
super(dwarfSections);
}
@Override
public String getSectionName() {
return DW_FRAME_SECTION_NAME;
}
@Override
public void createContent() {
int pos = 0;
pos = writeCIE(null, pos);
pos = writeMethodFrames(null, pos);
byte[] buffer = new byte[pos];
super.setContent(buffer);
}
@Override
public void writeContent(DebugContext context) {
byte[] buffer = getContent();
int size = buffer.length;
int pos = 0;
enableLog(context, pos);
pos = writeCIE(buffer, pos);
pos = writeMethodFrames(buffer, pos);
if (pos != size) {
System.out.format("pos = 0x%x size = 0x%x", pos, size);
}
assert pos == size;
}
private int writeCIE(byte[] buffer, int p) {
int pos = p;
if (buffer == null) {
pos += putInt(0, scratch, 0);
pos += putInt(DW_CFA_CIE_id, scratch, 0);
pos += putByte(DW_CFA_CIE_version, scratch, 0);
pos += putAsciiStringBytes("", scratch, 0);
pos += putULEB(1, scratch, 0);
pos += putSLEB(-8, scratch, 0);
pos += putByte((byte) getReturnPCIdx(), scratch, 0);
pos = writeInitialInstructions(buffer, pos);
pos = writePaddingNops(buffer, pos);
return pos;
} else {
int lengthPos = pos;
pos = putInt(0, buffer, pos);
pos = putInt(DW_CFA_CIE_id, buffer, pos);
pos = putByte(DW_CFA_CIE_version, buffer, pos);
pos = putAsciiStringBytes("", buffer, pos);
pos = putULEB(1, buffer, pos);
pos = putSLEB(-8, buffer, pos);
pos = putByte((byte) getReturnPCIdx(), buffer, pos);
pos = writeInitialInstructions(buffer, pos);
pos = writePaddingNops(buffer, pos);
patchLength(lengthPos, buffer, pos);
return pos;
}
}
private int writeMethodFrames(byte[] buffer, int p) {
int pos = p;
for (ClassEntry classEntry : getPrimaryClasses()) {
for (PrimaryEntry primaryEntry : classEntry.getPrimaryEntries()) {
Range range = primaryEntry.getPrimary();
if (!range.isDeoptTarget()) {
long lo = range.getLo();
long hi = range.getHi();
int lengthPos = pos;
pos = writeFDEHeader((int) lo, (int) hi, buffer, pos);
pos = writeFDEs(primaryEntry.getFrameSize(), primaryEntry.getFrameSizeInfos(), buffer, pos);
pos = writePaddingNops(buffer, pos);
patchLength(lengthPos, buffer, pos);
}
}
}
for (ClassEntry classEntry : getPrimaryClasses()) {
for (PrimaryEntry primaryEntry : classEntry.getPrimaryEntries()) {
Range range = primaryEntry.getPrimary();
if (range.isDeoptTarget()) {
long lo = range.getLo();
long hi = range.getHi();
int lengthPos = pos;
pos = writeFDEHeader((int) lo, (int) hi, buffer, pos);
pos = writeFDEs(primaryEntry.getFrameSize(), primaryEntry.getFrameSizeInfos(), buffer, pos);
pos = writePaddingNops(buffer, pos);
patchLength(lengthPos, buffer, pos);
}
}
}
return pos;
}
protected abstract int writeFDEs(int frameSize, List<DebugInfoProvider.DebugFrameSizeChange> frameSizeInfos, byte[] buffer, int pos);
private int (int lo, int hi, byte[] buffer, int p) {
int pos = p;
if (buffer == null) {
pos += putInt(0, scratch, 0);
pos += putInt(0, scratch, 0);
pos += putLong(lo, scratch, 0);
return pos + putLong(hi - lo, scratch, 0);
} else {
pos = putInt(0, buffer, pos);
pos = putInt(0, buffer, pos);
pos = putRelocatableCodeOffset(lo, buffer, pos);
return putLong(hi - lo, buffer, pos);
}
}
private int writePaddingNops(byte[] buffer, int p) {
int pos = p;
while ((pos & (PADDING_NOPS_ALIGNMENT - 1)) != 0) {
if (buffer == null) {
pos++;
} else {
pos = putByte(DW_CFA_nop, buffer, pos);
}
}
return pos;
}
protected int writeDefCFA(int register, int offset, byte[] buffer, int p) {
int pos = p;
if (buffer == null) {
pos += putByte(DW_CFA_def_cfa, scratch, 0);
pos += putSLEB(register, scratch, 0);
return pos + putULEB(offset, scratch, 0);
} else {
pos = putByte(DW_CFA_def_cfa, buffer, pos);
pos = putULEB(register, buffer, pos);
return putULEB(offset, buffer, pos);
}
}
protected int writeDefCFAOffset(int offset, byte[] buffer, int p) {
int pos = p;
if (buffer == null) {
pos += putByte(DW_CFA_def_cfa_offset, scratch, 0);
return pos + putULEB(offset, scratch, 0);
} else {
pos = putByte(DW_CFA_def_cfa_offset, buffer, pos);
return putULEB(offset, buffer, pos);
}
}
protected int writeAdvanceLoc(int offset, byte[] buffer, int pos) {
if (offset <= 0x3f) {
return writeAdvanceLoc0((byte) offset, buffer, pos);
} else if (offset <= 0xff) {
return writeAdvanceLoc1((byte) offset, buffer, pos);
} else if (offset <= 0xffff) {
return writeAdvanceLoc2((short) offset, buffer, pos);
} else {
return writeAdvanceLoc4(offset, buffer, pos);
}
}
protected int writeAdvanceLoc0(byte offset, byte[] buffer, int pos) {
byte op = advanceLoc0Op(offset);
if (buffer == null) {
return pos + putByte(op, scratch, 0);
} else {
return putByte(op, buffer, pos);
}
}
protected int writeAdvanceLoc1(byte offset, byte[] buffer, int p) {
int pos = p;
byte op = DW_CFA_advance_loc1;
if (buffer == null) {
pos += putByte(op, scratch, 0);
return pos + putByte(offset, scratch, 0);
} else {
pos = putByte(op, buffer, pos);
return putByte(offset, buffer, pos);
}
}
protected int writeAdvanceLoc2(short offset, byte[] buffer, int p) {
byte op = DW_CFA_advance_loc2;
int pos = p;
if (buffer == null) {
pos += putByte(op, scratch, 0);
return pos + putShort(offset, scratch, 0);
} else {
pos = putByte(op, buffer, pos);
return putShort(offset, buffer, pos);
}
}
protected int writeAdvanceLoc4(int offset, byte[] buffer, int p) {
byte op = DW_CFA_advance_loc4;
int pos = p;
if (buffer == null) {
pos += putByte(op, scratch, 0);
return pos + putInt(offset, scratch, 0);
} else {
pos = putByte(op, buffer, pos);
return putInt(offset, buffer, pos);
}
}
protected int writeOffset(int register, int offset, byte[] buffer, int p) {
byte op = offsetOp(register);
int pos = p;
if (buffer == null) {
pos += putByte(op, scratch, 0);
return pos + putULEB(offset, scratch, 0);
} else {
pos = putByte(op, buffer, pos);
return putULEB(offset, buffer, pos);
}
}
protected int writeRestore(int register, byte[] buffer, int p) {
byte op = restoreOp(register);
int pos = p;
if (buffer == null) {
return pos + putByte(op, scratch, 0);
} else {
return putByte(op, buffer, pos);
}
}
@SuppressWarnings("unused")
protected int writeRegister(int savedReg, int savedToReg, byte[] buffer, int p) {
int pos = p;
if (buffer == null) {
pos += putByte(DW_CFA_register, scratch, 0);
pos += putULEB(savedReg, scratch, 0);
return pos + putULEB(savedToReg, scratch, 0);
} else {
pos = putByte(DW_CFA_register, buffer, pos);
pos = putULEB(savedReg, buffer, pos);
return putULEB(savedToReg, buffer, pos);
}
}
protected abstract int getReturnPCIdx();
@SuppressWarnings("unused")
protected abstract int getSPIdx();
protected abstract int writeInitialInstructions(byte[] buffer, int pos);
private static final String TARGET_SECTION_NAME = DW_LINE_SECTION_NAME;
@Override
public String targetSectionName() {
return TARGET_SECTION_NAME;
}
private final LayoutDecision.Kind[] targetSectionKinds = {
LayoutDecision.Kind.CONTENT,
LayoutDecision.Kind.OFFSET
};
@Override
public LayoutDecision.Kind[] targetSectionKinds() {
return targetSectionKinds;
}
private static byte offsetOp(int register) {
assert (register >> 6) == 0;
return (byte) ((DW_CFA_offset << 6) | register);
}
private static byte restoreOp(int register) {
assert (register >> 6) == 0;
return (byte) ((DW_CFA_restore << 6) | register);
}
private static byte advanceLoc0Op(int offset) {
assert (offset >= 0 && offset <= 0x3f);
return (byte) ((DW_CFA_advance_loc << 6) | offset);
}
}