package sun.jvm.hotspot.debugger.linux.amd64;
import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.debugger.amd64.*;
import sun.jvm.hotspot.debugger.linux.*;
import sun.jvm.hotspot.debugger.cdbg.*;
import sun.jvm.hotspot.debugger.cdbg.basic.*;
final public class LinuxAMD64CFrame extends BasicCFrame {
public static LinuxAMD64CFrame getTopFrame(LinuxDebugger dbg, Address rip, ThreadContext context) {
Address libptr = dbg.findLibPtrByAddress(rip);
Address cfa = context.getRegisterAsAddress(AMD64ThreadContext.RBP);
DwarfParser dwarf = null;
if (libptr != null) {
dwarf = new DwarfParser(libptr);
try {
dwarf.processDwarf(rip);
} catch (DebuggerException e) {
return new LinuxAMD64CFrame(dbg, cfa, rip, dwarf, true);
}
cfa = ((dwarf.getCFARegister() == AMD64ThreadContext.RBP) &&
!dwarf.isBPOffsetAvailable())
? context.getRegisterAsAddress(AMD64ThreadContext.RBP)
: context.getRegisterAsAddress(dwarf.getCFARegister())
.addOffsetTo(dwarf.getCFAOffset());
}
return (cfa == null) ? null
: new LinuxAMD64CFrame(dbg, cfa, rip, dwarf);
}
private LinuxAMD64CFrame(LinuxDebugger dbg, Address cfa, Address rip, DwarfParser dwarf) {
this(dbg, cfa, rip, dwarf, false);
}
private LinuxAMD64CFrame(LinuxDebugger dbg, Address cfa, Address rip, DwarfParser dwarf, boolean finalFrame) {
super(dbg.getCDebugger());
this.cfa = cfa;
this.rip = rip;
this.dbg = dbg;
this.dwarf = dwarf;
this.finalFrame = finalFrame;
}
public ClosestSymbol closestSymbolToPC() {
return dbg.lookup(dbg.getAddressValue(pc()));
}
public Address pc() {
return rip;
}
public Address localVariableBase() {
return cfa;
}
private Address getNextPC(boolean useDwarf) {
try {
long offs = useDwarf ? dwarf.getReturnAddressOffsetFromCFA()
: ADDRESS_SIZE;
return cfa.getAddressAt(offs);
} catch (UnmappedAddressException | UnalignedAddressException e) {
return null;
}
}
private boolean isValidFrame(Address nextCFA, ThreadContext context) {
return (nextCFA != null) &&
!nextCFA.lessThan(context.getRegisterAsAddress(AMD64ThreadContext.RSP));
}
private Address getNextCFA(DwarfParser nextDwarf, ThreadContext context) {
Address nextCFA;
if (nextDwarf == null) {
nextCFA = (dwarf == null) ? cfa.getAddressAt(0)
: cfa.getAddressAt(dwarf.getBasePointerOffsetFromCFA());
} else {
if (dwarf == null) {
nextCFA = cfa.getAddressAt(0);
} else {
int nextCFAReg = nextDwarf.getCFARegister();
if (!dwarf.isBPOffsetAvailable() &&
(nextCFAReg == AMD64ThreadContext.RBP) &&
(nextCFAReg != dwarf.getCFARegister())) {
nextCFA = context.getRegisterAsAddress(AMD64ThreadContext.RBP);
if (nextCFA == null) {
return null;
}
nextCFA = nextCFA.getAddressAt(0);
} else {
nextCFA = cfa.getAddressAt(dwarf.getBasePointerOffsetFromCFA());
}
}
if (nextCFA != null) {
nextCFA = nextCFA.addOffsetTo(-nextDwarf.getBasePointerOffsetFromCFA());
}
}
return isValidFrame(nextCFA, context) ? nextCFA : null;
}
@Override
public CFrame sender(ThreadProxy thread) {
if (finalFrame) {
return null;
}
ThreadContext context = thread.getContext();
Address nextPC = getNextPC(dwarf != null);
if (nextPC == null) {
return null;
}
DwarfParser nextDwarf = null;
if ((dwarf != null) && dwarf.isIn(nextPC)) {
nextDwarf = dwarf;
} else {
Address libptr = dbg.findLibPtrByAddress(nextPC);
if (libptr != null) {
try {
nextDwarf = new DwarfParser(libptr);
} catch (DebuggerException e) {
}
}
}
if (nextDwarf != null) {
try {
nextDwarf.processDwarf(nextPC);
} catch (DebuggerException e) {
return new LinuxAMD64CFrame(dbg, null, nextPC, nextDwarf, true);
}
}
Address nextCFA = getNextCFA(nextDwarf, context);
return isValidFrame(nextCFA, context) ? new LinuxAMD64CFrame(dbg, nextCFA, nextPC, nextDwarf)
: null;
}
private static final int ADDRESS_SIZE = 8;
private Address rip;
private Address cfa;
private LinuxDebugger dbg;
private DwarfParser dwarf;
private boolean finalFrame;
}