blob: e67d08371eb3dee045a64248eeff428d254db0a6 [file] [log] [blame]
/*
* (c) Copyright QNX Software Systems Ltd. 2002.
* All Rights Reserved.
*
*/
package org.eclipse.cdt.debug.mi.core.cdi.model;
import org.eclipse.cdt.debug.core.cdi.CDIException;
import org.eclipse.cdt.debug.core.cdi.ICDIExpressionManager;
import org.eclipse.cdt.debug.core.cdi.ICDIRegisterManager;
import org.eclipse.cdt.debug.core.cdi.ICDIVariableManager;
import org.eclipse.cdt.debug.core.cdi.model.ICDIStackFrame;
import org.eclipse.cdt.debug.core.cdi.model.ICDITarget;
import org.eclipse.cdt.debug.core.cdi.model.ICDIValue;
import org.eclipse.cdt.debug.core.cdi.model.ICDIVariable;
import org.eclipse.cdt.debug.core.cdi.model.type.ICDIArrayType;
import org.eclipse.cdt.debug.core.cdi.model.type.ICDIBoolType;
import org.eclipse.cdt.debug.core.cdi.model.type.ICDICharType;
import org.eclipse.cdt.debug.core.cdi.model.type.ICDIDoubleType;
import org.eclipse.cdt.debug.core.cdi.model.type.ICDIEnumType;
import org.eclipse.cdt.debug.core.cdi.model.type.ICDIFloatType;
import org.eclipse.cdt.debug.core.cdi.model.type.ICDIFunctionType;
import org.eclipse.cdt.debug.core.cdi.model.type.ICDIIntType;
import org.eclipse.cdt.debug.core.cdi.model.type.ICDILongLongType;
import org.eclipse.cdt.debug.core.cdi.model.type.ICDILongType;
import org.eclipse.cdt.debug.core.cdi.model.type.ICDIPointerType;
import org.eclipse.cdt.debug.core.cdi.model.type.ICDIReferenceType;
import org.eclipse.cdt.debug.core.cdi.model.type.ICDIShortType;
import org.eclipse.cdt.debug.core.cdi.model.type.ICDIStructType;
import org.eclipse.cdt.debug.core.cdi.model.type.ICDIType;
import org.eclipse.cdt.debug.core.cdi.model.type.ICDIWCharType;
import org.eclipse.cdt.debug.mi.core.MIException;
import org.eclipse.cdt.debug.mi.core.MISession;
import org.eclipse.cdt.debug.mi.core.cdi.Format;
import org.eclipse.cdt.debug.mi.core.cdi.MI2CDIException;
import org.eclipse.cdt.debug.mi.core.cdi.Session;
import org.eclipse.cdt.debug.mi.core.cdi.model.type.ArrayValue;
import org.eclipse.cdt.debug.mi.core.cdi.model.type.BoolValue;
import org.eclipse.cdt.debug.mi.core.cdi.model.type.CharValue;
import org.eclipse.cdt.debug.mi.core.cdi.model.type.DoubleValue;
import org.eclipse.cdt.debug.mi.core.cdi.model.type.EnumValue;
import org.eclipse.cdt.debug.mi.core.cdi.model.type.FloatValue;
import org.eclipse.cdt.debug.mi.core.cdi.model.type.FunctionValue;
import org.eclipse.cdt.debug.mi.core.cdi.model.type.IntValue;
import org.eclipse.cdt.debug.mi.core.cdi.model.type.LongLongValue;
import org.eclipse.cdt.debug.mi.core.cdi.model.type.LongValue;
import org.eclipse.cdt.debug.mi.core.cdi.model.type.PointerValue;
import org.eclipse.cdt.debug.mi.core.cdi.model.type.ReferenceValue;
import org.eclipse.cdt.debug.mi.core.cdi.model.type.ShortValue;
import org.eclipse.cdt.debug.mi.core.cdi.model.type.StructValue;
import org.eclipse.cdt.debug.mi.core.cdi.model.type.WCharValue;
import org.eclipse.cdt.debug.mi.core.command.CommandFactory;
import org.eclipse.cdt.debug.mi.core.command.MIVarAssign;
import org.eclipse.cdt.debug.mi.core.command.MIVarInfoExpression;
import org.eclipse.cdt.debug.mi.core.command.MIVarListChildren;
import org.eclipse.cdt.debug.mi.core.command.MIVarSetFormat;
import org.eclipse.cdt.debug.mi.core.command.MIVarShowAttributes;
import org.eclipse.cdt.debug.mi.core.event.MIVarChangedEvent;
import org.eclipse.cdt.debug.mi.core.output.MIInfo;
import org.eclipse.cdt.debug.mi.core.output.MIVar;
import org.eclipse.cdt.debug.mi.core.output.MIVarInfoExpressionInfo;
import org.eclipse.cdt.debug.mi.core.output.MIVarListChildrenInfo;
import org.eclipse.cdt.debug.mi.core.output.MIVarShowAttributesInfo;
/**
*/
public class Variable extends VariableObject implements ICDIVariable {
MIVar miVar;
Value value;
ICDIVariable[] children = new ICDIVariable[0];
String editable = null;
String language;
boolean isFake = false;
public Variable(VariableObject obj, MIVar v) {
super(obj);
miVar = v;
}
public Variable(ICDITarget target, String n, String q, ICDIStackFrame stack, int pos, int depth, MIVar v) {
super(target, n, q, stack, pos, depth);
miVar = v;
}
public MIVar getMIVar() {
return miVar;
}
public Variable getChild(String name) {
for (int i = 0; i < children.length; i++) {
Variable variable = (Variable) children[i];
if (name.equals(variable.getMIVar().getVarName())) {
return variable;
} else {
// Look also in the grandchildren.
Variable grandChild = variable.getChild(name);
if (grandChild != null) {
return grandChild;
}
}
}
return null;
}
String getLanguage() throws CDIException {
if (language == null) {
Session session = (Session) (getTarget().getSession());
MISession mi = session.getMISession();
CommandFactory factory = mi.getCommandFactory();
MIVarInfoExpression var = factory.createMIVarInfoExpression(getMIVar().getVarName());
try {
mi.postCommand(var);
MIVarInfoExpressionInfo info = var.getMIVarInfoExpressionInfo();
if (info == null) {
throw new CDIException("No answer");
}
language = info.getLanguage();
} catch (MIException e) {
throw new MI2CDIException(e);
}
}
return (language == null) ? "" : language;
}
boolean isCPPLanguage() throws CDIException {
return getLanguage().equalsIgnoreCase("C++");
}
void setIsFake(boolean f) {
isFake = f;
}
boolean isFake() {
return isFake;
}
public ICDIVariable[] getChildren() throws CDIException {
// Use the default timeout.
return getChildren(-1);
}
/**
* This can be a potentially long operation for GDB.
* allow the override of the timeout.
*/
public ICDIVariable[] getChildren(int timeout) throws CDIException {
Session session = (Session) (getTarget().getSession());
MISession mi = session.getMISession();
CommandFactory factory = mi.getCommandFactory();
MIVarListChildren var = factory.createMIVarListChildren(getMIVar().getVarName());
try {
if (timeout >= 0) {
mi.postCommand(var, timeout);
} else {
mi.postCommand(var);
}
MIVarListChildrenInfo info = var.getMIVarListChildrenInfo();
if (info == null) {
throw new CDIException("No answer");
}
MIVar[] vars = info.getMIVars();
children = new Variable[vars.length];
for (int i = 0; i < vars.length; i++) {
String fn= getFullName();
String childName = vars[i].getExp();
String childTypename = null;
boolean childFake = false;
ICDIType t = getType();
if (t instanceof ICDIArrayType) {
fn = "(" + fn + ")[" + i + "]";
// For Array gdb varobj only return the index, override here.
int index = castingIndex + i;
childName = getName() + "[" + index + "]";
} else if (t instanceof ICDIPointerType) {
fn = "*(" + fn + ")";
} else if (t instanceof ICDIStructType) {
if (isCPPLanguage()) {
// For C++ in GDB the children of the
// the struture are the scope and the inherited classes.
// For example:
// class foo: public bar {
// int x;
// public: int y;
// } foobar;
// This will map to
// - foobar
// + bar
// - private
// - x
// - public
// - y
// So we choose to ignore the first set of children
// but carry over to those "fake" variables the typename and the qualified name
if (!isFake()
|| (isFake() && !(name.equals("private") || name.equals("public") || name.equals("protected")))) {
childFake = true;
childTypename = getTypeName();
} else {
fn = "(" + fn + ")." + vars[i].getExp();
}
} else { // If not C++ language
fn = "(" + fn + ")." + vars[i].getExp();
}
}
Variable v = new Variable(getTarget(), childName, fn, getStackFrame(), getPosition(), getStackDepth(), vars[i]);
if (childTypename != null) {
// Hack to reset the typename to a known value
v.typename = childTypename;
}
v.setIsFake(childFake);
children[i] = v;
}
} catch (MIException e) {
throw new MI2CDIException(e);
}
return children;
}
public int getChildrenNumber() throws CDIException {
return miVar.getNumChild();
}
/**
* We overload the VariableObject since the gdb-varobject already knows
* the type and its probably more accurate.
*
* @see org.eclipse.cdt.debug.core.cdi.model.ICDIVariableObject#getTypeName()
*/
public String getTypeName() throws CDIException {
// We overload here not to use the whatis command.
if (typename == null) {
typename = miVar.getType();
}
return typename;
}
/**
* @see org.eclipse.cdt.debug.core.cdi.model.ICDIVariable#getValue()
*/
public ICDIValue getValue() throws CDIException {
if (value == null) {
ICDIType t = getType();
if (t instanceof ICDIBoolType) {
value = new BoolValue(this);
} else if (t instanceof ICDICharType) {
value = new CharValue(this);
} else if (t instanceof ICDIWCharType) {
value = new WCharValue(this);
} else if (t instanceof ICDIShortType) {
value = new ShortValue(this);
} else if (t instanceof ICDIIntType) {
value = new IntValue(this);
} else if (t instanceof ICDILongType) {
value = new LongValue(this);
} else if (t instanceof ICDILongLongType) {
value = new LongLongValue(this);
} else if (t instanceof ICDIEnumType) {
value = new EnumValue(this);
} else if (t instanceof ICDIFloatType) {
value = new FloatValue(this);
} else if (t instanceof ICDIDoubleType) {
value = new DoubleValue(this);
} else if (t instanceof ICDIFunctionType) {
value = new FunctionValue(this);
} else if (t instanceof ICDIPointerType) {
value = new PointerValue(this);
} else if (t instanceof ICDIReferenceType) {
value = new ReferenceValue(this);
} else if (t instanceof ICDIArrayType) {
value = new ArrayValue(this);
} else if (t instanceof ICDIStructType) {
value = new StructValue(this);
} else {
value = new Value(this);
}
}
return value;
}
/**
* @see org.eclipse.cdt.debug.core.cdi.model.ICDIVariable#setValue(ICDIValue)
*/
public void setValue(ICDIValue value) throws CDIException {
setValue(value.getValueString());
}
/**
* @see org.eclipse.cdt.debug.core.cdi.model.ICDIVariable#setValue(String)
*/
public void setValue(String expression) throws CDIException {
Session session = (Session) (getTarget().getSession());
MISession mi = session.getMISession();
CommandFactory factory = mi.getCommandFactory();
MIVarAssign var = factory.createMIVarAssign(miVar.getVarName(), expression);
try {
mi.postCommand(var);
MIInfo info = var.getMIInfo();
if (info == null) {
throw new CDIException("No answer");
}
} catch (MIException e) {
throw new MI2CDIException(e);
}
// If the assign was succesfull fire a MIVarChangedEvent() for the variable
// Note GDB will not fire an event for the changed variable we have to do it manually.
MIVarChangedEvent change = new MIVarChangedEvent(var.getToken(), miVar.getVarName());
mi.fireEvent(change);
// Changing values may have side effects i.e. affecting other variables
// if the manager is on autoupdate check all the other variables.
// Note: This maybe very costly.
if (this instanceof Register) {
// If register was on autoupdate, update all the other registers
// assigning may have side effects i.e. affecting other registers.
ICDIRegisterManager mgr = session.getRegisterManager();
if (mgr.isAutoUpdate()) {
mgr.update();
}
} else if (this instanceof Expression) {
// If expression was on autoupdate, update all the other expression
// assigning may have side effects i.e. affecting other expressions.
ICDIExpressionManager mgr = session.getExpressionManager();
if (mgr.isAutoUpdate()) {
mgr.update();
}
} else {
// FIXME: Should we always call the Variable Manager ?
ICDIVariableManager mgr = session.getVariableManager();
if (mgr.isAutoUpdate()) {
mgr.update();
}
}
}
/**
* Overload the implementation of VariableObject and let gdb
* handle it.
* @see org.eclipse.cdt.debug.core.cdi.model.ICDIVariable#isEditable()
*/
public boolean isEditable() throws CDIException {
if (editable == null) {
MISession mi = ((Session) (getTarget().getSession())).getMISession();
CommandFactory factory = mi.getCommandFactory();
MIVarShowAttributes var = factory.createMIVarShowAttributes(miVar.getVarName());
try {
mi.postCommand(var);
MIVarShowAttributesInfo info = var.getMIVarShowAttributesInfo();
if (info == null) {
throw new CDIException("No answer");
}
editable = String.valueOf(info.isEditable());
} catch (MIException e) {
throw new MI2CDIException(e);
}
}
return (editable == null) ? false : editable.equalsIgnoreCase("true");
}
/**
* @see org.eclipse.cdt.debug.core.cdi.model.ICDIVariable#setFormat()
*/
public void setFormat(int format) throws CDIException {
int fmt = Format.toMIFormat(format);
MISession mi = ((Session) (getTarget().getSession())).getMISession();
CommandFactory factory = mi.getCommandFactory();
MIVarSetFormat var = factory.createMIVarSetFormat(miVar.getVarName(), fmt);
try {
mi.postCommand(var);
MIInfo info = var.getMIInfo();
if (info == null) {
throw new CDIException("No answer");
}
} catch (MIException e) {
throw new MI2CDIException(e);
}
}
/**
* @see org.eclipse.cdt.debug.core.cdi.model.ICDIVariable#equals()
*/
public boolean equals(ICDIVariable var) {
if (var instanceof Variable) {
Variable variable = (Variable) var;
return miVar.getVarName().equals(variable.getMIVar().getVarName());
}
return super.equals(var);
}
}