package com.siberika.idea.pascal.debugger.gdb;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.ui.MessageType;
import com.intellij.xdebugger.frame.XStackFrame;
import com.siberika.idea.pascal.PascalBundle;
import com.siberika.idea.pascal.debugger.gdb.parser.GdbMiLine;
import com.siberika.idea.pascal.debugger.gdb.parser.GdbMiParser;
import com.siberika.idea.pascal.debugger.gdb.parser.GdbMiResults;
import com.siberika.idea.pascal.debugger.gdb.parser.GdbStopReason;
import com.siberika.idea.pascal.jps.util.PascalConsoleProcessAdapter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Author: George Bakhtadze
* Date: 28/03/2017
*/
public class GdbProcessAdapter extends PascalConsoleProcessAdapter {
private static final Logger LOG = Logger.getInstance(GdbProcessAdapter.class);
private final GdbXDebugProcess process;
private GdbSuspendContext suspendContext;
GdbProcessAdapter(GdbXDebugProcess xDebugProcess) {
this.process = xDebugProcess;
}
@Override
public boolean onLine(String text) {
GdbMiLine res = GdbMiParser.parseLine(text);
if (GdbMiLine.Type.EXEC_ASYNC.equals(res.getType())) {
if ("stopped".equals(res.getRecClass())) {
handleStop(res);
} else if ("running".equals(res.getRecClass())) {
process.setInferiorRunning(true);
}
} else if (GdbMiLine.Type.RESULT_RECORD.equals(res.getType())) {
if ("done".equals(res.getRecClass())) {
if (res.getResults().getValue("stack") != null) {
addStackFramesToContainer(res.getResults().getList("stack"));
} else if (res.getResults().getValue("bkpt") != null) {
process.getBreakpointHandler().handleBreakpointResult(res.getResults().getTuple("bkpt"));
} else if (res.getResults().getValue("variables") != null) {
process.handleVariablesResponse(res.getResults().getList("variables"));
} else if (isCreateVarResult(res.getResults())) {
process.handleVarResult(res.getResults());
} else if (res.getResults().getValue("changelist") != null) {
process.handleVarUpdate(res.getResults());
} else if (res.getResults().getValue("children") != null) {
process.handleChildrenResult(res.getResults().getList("children"));
} else if ("0".equals(res.getResults().getString("numchild"))) {
process.handleChildrenResult(Collections.emptyList());
}
} else if ("error".equals(res.getRecClass())) {
String msg = res.getResults().getString("msg");
if (msg != null) {
process.getSession().reportMessage(PascalBundle.message("debug.error.response",
msg.replace("\\n", "\n")), MessageType.ERROR);
}
}
}
return true;
}
private boolean isCreateVarResult(GdbMiResults results) {
return (results.getValue("name") != null) && (results.getValue("value") != null);
}
private void handleStop(GdbMiLine res) {
suspendContext = new GdbSuspendContext(process, res);
process.setInferiorRunning(false);
process.getSession().positionReached(suspendContext);
GdbStopReason reason = GdbStopReason.fromUid(res.getResults().getString("reason"));
String msg = null;
if (reason != null) {
switch (reason) {
case SIGNAL_RECEIVED: {
String detail = res.getResults().getString("signal-name");
msg = detail != null ? String.format(", %s (%s)", res.getResults().getValue("signal-name"), res.getResults().getValue("signal-meaning")) : "";
break;
}
case BREAKPOINT_HIT:
case WATCHPOINT_TRIGGER:
case READ_WATCHPOINT_TRIGGER:
case ACCESS_WATCHPOINT_TRIGGER:
case LOCATION_REACHED:
case FUNCTION_FINISHED: {
msg = reason.getUid();
break;
}
case EXITED:
case EXITED_SIGNALLED:
case EXITED_NORMALLY: {
msg = reason.getUid();
process.sendCommand("-gdb-exit");
}
}
if (msg != null) {
process.getSession().reportMessage(PascalBundle.message("debug.notify.stopped", msg), MessageType.INFO);
}
}
}
private void addStackFramesToContainer(List<Object> stack) {
List<XStackFrame> frames = new ArrayList<XStackFrame>();
for (Object o : stack) {
if (o instanceof GdbMiResults) {
GdbMiResults res = (GdbMiResults) o;
frames.add(new GdbStackFrame((GdbExecutionStack) suspendContext.getActiveExecutionStack(), res.getTuple("frame")));
} else {
reportError("Invalid stack frames list entry");
return;
}
}
suspendContext.getStackFrameContainer().addStackFrames(frames, true);
}
private void reportError(String msg) {
LOG.warn("ERROR: " + msg);
}
}