package xtc.lang.blink; import java.io.IOException; import java.util.LinkedList; import java.util.List; import xtc.lang.blink.CallStack.ICallFrame; import xtc.lang.blink.CallStack.JavaCallFrame; import xtc.lang.blink.CallStack.JeannieCallFrame; import xtc.lang.blink.CallStack.NativeCallFrame; import xtc.lang.blink.SymbolMapper.SourceFileAndLine; import xtc.lang.blink.SymbolMapper.TargetSourceLanguage; import xtc.lang.blink.SymbolMapper.VariableRemapEntry; import xtc.lang.blink.CallStack.MicroCallFrame; import xtc.lang.blink.CallStack.LocalVariable; /** * The debugger calling context. * * @author Byeongcheol Lee */ public class DebuggerContext { /** The mixed call stack. */ private final CallStack callStack; /** The currently chosen call frame number. */ private int currentFrameNumber; /** * @param callStack The call stack. * @param where The source code location. */ DebuggerContext(CallStack callStack) { this.callStack = callStack; this.currentFrameNumber = 0; } /** * Obtain the name and value pairs for the Jeannie frame. * * @param jframe The Jeannie frame. * @param dbg The Blink debugger. * @param remapper The Jeannie Symbol remapper. * @return The list. */ private List<LocalVariable> getJeannieLocals(JeannieCallFrame jframe, Blink dbg, SymbolMapper remapper) { LinkedList<LocalVariable> localList = new LinkedList<LocalVariable>(); // Obtain symbol remap information. String sourceFile = jframe.getSourceFile(); int line = jframe.getLineNumber(); if (sourceFile == null || line <= 0) { dbg.err("no source file and info avaiable.\n"); } assert sourceFile != null && line > 0; List<VariableRemapEntry> list = remapper.lookup(sourceFile, line); // Obtain values from Java side. dbg.ensureJDBContext(); for(VariableRemapEntry v: list) { if (v.targetLanguage == TargetSourceLanguage.JAVA) { String name = v.sourceVariableName; String val = dbg.jdb.print(getCurrentJavaFrame(), v.targetLanguageExpression()); localList.add(new LocalVariable(name, val)); } } //obtain values from native side. dbg.ensureGDBContext(); for(VariableRemapEntry v: list) { if (v.targetLanguage == TargetSourceLanguage.C) { String name = v.sourceVariableName; String val = dbg.ndb.eval(getCurrentNativeFrame(), v.targetLanguageExpression()); localList.add(new LocalVariable(name, val)); } } return localList; } /** * Present the current calling context to the user. * * @param dbg The debugger. */ public void showWhere(Blink dbg) { StringBuffer sb = new StringBuffer(); int nsize = callStack.size(); for(int i = currentFrameNumber;i < nsize;i++) { CallStack.ICallFrame f = callStack.getCallFrame(i); if (f.getSourceFile() != null) { dbg.out(" [%d] %s at %s:%d\n", i, f.getName(), f.getSourceFile(), f.getLineNumber()); } else { dbg.out(" [%d] %s\n", i, f.getName()); } } } /** * Unwind the current call stack n steps. If this n steps unwinding exceed the * bottom of the stack, this unwinding stops at the bottom of the stack.. * * @param dbg The debugger. * @param nSteps The number of steps to unwind. */ public void unWindStack(Blink dbg, int nSteps) { int maxPosition = callStack.size() - 1; int expectedPosition = currentFrameNumber + nSteps; if (expectedPosition > maxPosition ) { int modifiedStep = maxPosition - currentFrameNumber; dbg.err("can not unwind the stack more than " + modifiedStep +"\n"); currentFrameNumber = maxPosition; } else { currentFrameNumber = expectedPosition; } assert currentFrameNumber >= 0 && currentFrameNumber < callStack.size(); } /** * Wind the current call stack n steps. If this n steps exceeds the top of the * stack, this winding stops at the top of the stack. * * @param dbg The debugger. * @param nSteps The number of steps to wind. */ public void windStack(Blink dbg, int nSteps) { int minPosition = 0; int expectedPosition = currentFrameNumber - nSteps; if (expectedPosition < minPosition ) { int modifiedStep = currentFrameNumber; dbg.err("can not wind stack more than " + modifiedStep + "\n"); currentFrameNumber = minPosition; } else { currentFrameNumber = expectedPosition; } assert currentFrameNumber >= 0 && currentFrameNumber < callStack.size(); } /** * Show local variables in the currently chosen call stack. * * @param dbg The debugger. * @param remapper The symbol remapper. */ public void showLocals(Blink dbg, SymbolMapper remapper) { //obtain a list of local variable info. List<LocalVariable> l = null; ICallFrame f = callStack.getCallFrame(currentFrameNumber); if (f instanceof JavaCallFrame) { JavaCallFrame jframe = (JavaCallFrame)f; dbg.ensureJDBContext(); l = dbg.jdb.getLocals(jframe); } else if (f instanceof NativeCallFrame) { NativeCallFrame nframe = (NativeCallFrame)f; dbg.ensureGDBContext(); l = dbg.ndb.getLocals(nframe); } else if ( f instanceof JeannieCallFrame) { l = getJeannieLocals((JeannieCallFrame)f, dbg, remapper); } else { assert false : "can not deal with this call frame: " + f + "\n"; } // show the result. if (l.size() == 0) { dbg.out("No Locals\n"); } else { for(final LocalVariable lv : l) { dbg.out(lv.getName() + " = " + lv.getValue() + "\n"); } } } /** * The source code for the currently chosen frame. * * @param dbg The debugger. */ public void showSourceCode(Blink dbg) { MicroCallFrame frame = callStack.getCallFrame(currentFrameNumber).getTopMicroFrame(); if (frame instanceof JavaCallFrame) { JavaCallFrame jframe = (JavaCallFrame)frame; dbg.ensureJDBContext(); String msg = dbg.jdb.list(jframe); dbg.out("%s", msg); } else { assert frame instanceof NativeCallFrame; dbg.ensureGDBContext(); NativeCallFrame nframe = (NativeCallFrame)frame; String sourceFile = nframe.getSourceFile(); int line = nframe.getLineNumber(); if (sourceFile != null && line > 0) { String lines = dbg.ndb.getSourceLines(sourceFile, line, 10); dbg.out("%s", lines); } else { dbg.err("line number is not availble.\n"); } } } /** Find the current Java frame. */ public JavaCallFrame getCurrentJavaFrame() { return callStack.getJavaCallFrame(currentFrameNumber); } /** Find the current native frame. */ public NativeCallFrame getCurrentNativeFrame() { return callStack.getNativeCallFrame(currentFrameNumber); } /** Getter method for the user readable location. */ public SourceFileAndLine getCurrentLocation() { ICallFrame f = callStack.getCallFrame(currentFrameNumber); if (f != null) { return new SourceFileAndLine(f.getSourceFile(), f.getLineNumber()); } else { return null; } } }