blob: 73941ef1d980c59a47d2aa0873b1dad0bda63529 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2014 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.tcf.internal.debug.ui.model;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementEditor;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.tcf.debug.ui.ITCFRegister;
import org.eclipse.tcf.internal.debug.model.TCFContextState;
import org.eclipse.tcf.internal.debug.ui.ColorCache;
import org.eclipse.tcf.internal.debug.ui.ImageCache;
import org.eclipse.tcf.protocol.IToken;
import org.eclipse.tcf.protocol.JSON;
import org.eclipse.tcf.services.IRegisters;
import org.eclipse.tcf.services.IRunControl;
import org.eclipse.tcf.util.TCFDataCache;
import org.eclipse.tcf.util.TCFTask;
public class TCFNodeRegister extends TCFNode implements IElementEditor, IWatchInExpressions, IDetailsProvider, ITCFRegister {
public static final String PROPERTY_REG_REPRESENTATION = "PROPERTY_REGISTER_REPRESENTATION";
private final TCFChildrenRegisters children;
private final TCFData<IRegisters.RegistersContext> context;
private final TCFData<String> expression_text;
private final TCFData<byte[]> value;
private final boolean is_stack_frame_register;
private byte[] prev_value;
private byte[] next_value;
private int index;
TCFNodeRegister(final TCFNode parent, final String id) {
super(parent, id);
if (parent instanceof TCFNodeStackFrame) is_stack_frame_register = true;
else if (parent instanceof TCFNodeRegister) is_stack_frame_register = ((TCFNodeRegister)parent).is_stack_frame_register;
else is_stack_frame_register = false;
children = new TCFChildrenRegisters(this);
context = new TCFData<IRegisters.RegistersContext>(channel) {
@Override
protected boolean startDataRetrieval() {
IRegisters regs = launch.getService(IRegisters.class);
command = regs.getContext(id, new IRegisters.DoneGetContext() {
public void doneGetContext(IToken token, Exception error, IRegisters.RegistersContext context) {
if (context != null) model.getContextMap().put(id, context);
set(token, error, context);
}
});
return false;
}
};
expression_text = new TCFData<String>(channel) {
@Override
protected boolean startDataRetrieval() {
Throwable err = null;
TCFNodeRegister n = TCFNodeRegister.this;
ArrayList<String> names = new ArrayList<String>();
for (;;) {
if (!n.context.validate(this)) return false;
IRegisters.RegistersContext ctx = n.context.getData();
if (ctx == null) {
err = n.context.getError();
break;
}
String s = ctx.getName();
if (s == null) break;
names.add(s);
if (!(n.parent instanceof TCFNodeRegister)) break;
n = (TCFNodeRegister)n.parent;
}
if (names.size() == 0 || err != null) {
set(null, err, null);
}
else {
StringBuffer bf = new StringBuffer();
boolean first = true;
int m = names.size();
while (m > 0) {
String s = names.get(--m);
boolean need_quotes = false;
int l = s.length();
for (int i = 0; i < l; i++) {
char ch = s.charAt(i);
if (ch >= 'A' && ch <= 'Z') continue;
if (ch >= 'a' && ch <= 'z') continue;
if (i > 0) {
if (ch >= '0' && ch <= '9') continue;
if (ch == '_') continue;
}
need_quotes = true;
break;
}
if (!first) bf.append('.');
if (need_quotes) bf.append("$\"");
if (first) bf.append('$');
bf.append(s);
if (need_quotes) bf.append('"');
first = false;
}
set(null, null, bf.toString());
}
return true;
}
};
value = new TCFData<byte[]>(channel) {
@Override
protected boolean startDataRetrieval() {
Boolean b = usePrevValue(this);
if (b == null) return false;
if (b) {
set(null, null, prev_value);
return true;
}
if (!context.validate(this)) return false;
IRegisters.RegistersContext ctx = context.getData();
int[] bits = ctx.getBitNumbers();
if (bits != null) {
// handle bit fields
TCFNodeRegister p = (TCFNodeRegister)parent;
if (!p.value.validate(this)) return false;
byte[] parent_value = p.value.getData();
byte[] bitfield_value = new byte[(bits.length + 7) / 8];
if (parent_value != null) {
for (int pos = 0; pos < bits.length; pos++) {
int bit = bits[pos];
if (bit / 8 >= parent_value.length) continue;
if ((parent_value[bit / 8] & (1 << (bit % 8))) == 0) continue;
bitfield_value[pos / 8] |= 1 << (pos % 8);
}
}
set(null, p.value.getError(), bitfield_value);
return true;
}
else {
if (ctx == null || ctx.getSize() <= 0) {
set(null, null, null);
return true;
}
final TCFDataCache<?> cache = this;
command = ctx.get(new IRegisters.DoneGet() {
public void doneGet(IToken token, Exception error, byte[] value) {
if (command != token) return;
command = null;
if (error != null) {
Boolean b = usePrevValue(cache);
if (b == null) return;
if (b) {
set(null, null, prev_value);
return;
}
}
set(null, error, value);
}
});
}
return false;
}
};
}
public TCFDataCache<IRegisters.RegistersContext> getContext() {
return context;
}
public TCFDataCache<byte[]> getValue() {
return value;
}
public TCFChildren getChildren() {
return children;
}
public TCFDataCache<String> getExpressionText() {
return expression_text;
}
void setIndex(int index) {
this.index = index;
}
private Boolean usePrevValue(Runnable done) {
// Check if view should show old value.
// Old value is shown if context is running or
// stack trace does not contain expression parent frame.
// Return null if waiting for cache update.
if (prev_value == null) return false;
TCFNode p = parent;
while (p instanceof TCFNodeRegister) p = p.parent;
if (p instanceof TCFNodeStackFrame) {
TCFNodeExecContext exe = (TCFNodeExecContext)p.parent;
TCFDataCache<TCFContextState> state_cache = exe.getState();
if (!state_cache.validate(done)) return null;
TCFContextState state = state_cache.getData();
if (state == null || !state.is_suspended) return true;
TCFChildrenStackTrace stack_trace_cache = exe.getStackTrace();
if (!stack_trace_cache.validate(done)) return null;
if (stack_trace_cache.getData().get(p.id) == null) return true;
}
else if (p instanceof TCFNodeExecContext) {
TCFNodeExecContext exe = (TCFNodeExecContext)p;
TCFDataCache<IRunControl.RunControlContext> ctx_cache = exe.getRunContext();
if (!ctx_cache.validate(done)) return null;
IRunControl.RunControlContext ctx_data = ctx_cache.getData();
if (ctx_data != null && ctx_data.hasState()) {
TCFDataCache<TCFContextState> state_cache = exe.getState();
if (!state_cache.validate(done)) return null;
TCFContextState state_data = state_cache.getData();
if (state_data == null || !state_data.is_suspended) return true;
}
}
return false;
}
public boolean getDetailText(StyledStringBuffer bf, Runnable done) {
if (!context.validate(done)) return false;
if (!value.validate(done)) return false;
if (context.getError() != null) {
bf.append(context.getError(), ColorCache.rgb_error);
return true;
}
IRegisters.RegistersContext ctx = context.getData();
if (ctx != null) {
if (ctx.getDescription() != null) {
bf.append(ctx.getDescription());
bf.append('\n');
}
}
if (value.getError() != null) {
bf.append(value.getError(), ColorCache.rgb_error);
}
else {
byte[] v = value.getData();
if (v != null) {
bf.append("Hex: ", SWT.BOLD);
bf.append(toNumberString(16), StyledStringBuffer.MONOSPACED);
bf.append(", ");
bf.append("Dec: ", SWT.BOLD);
bf.append(toNumberString(10), StyledStringBuffer.MONOSPACED);
bf.append(", ");
bf.append("Oct: ", SWT.BOLD);
bf.append(toNumberString(8), StyledStringBuffer.MONOSPACED);
if ("PC".equals(ctx.getRole())) {
TCFNode p = parent;
while (p != null) {
if (p instanceof TCFNodeExecContext) {
TCFNodeExecContext exe = (TCFNodeExecContext)p;
BigInteger addr = TCFNumberFormat.toBigInteger(v, 0, v.length, ctx.isBigEndian(), false);
if (!exe.appendPointedObject(bf, addr, done)) return false;
break;
}
p = p.parent;
}
}
bf.append('\n');
bf.append("Bin: ", SWT.BOLD);
bf.append(toNumberString(2), StyledStringBuffer.MONOSPACED);
bf.append('\n');
}
}
if (ctx != null) {
int l = bf.length();
int[] bits = ctx.getBitNumbers();
BigInteger addr = JSON.toBigInteger(ctx.getMemoryAddress());
if (bits != null && addr == null && parent instanceof TCFNodeRegister) {
if (!((TCFNodeRegister)parent).context.validate(done)) return false;
IRegisters.RegistersContext parent_ctx = ((TCFNodeRegister)parent).context.getData();
if (parent_ctx != null) addr = JSON.toBigInteger(parent_ctx.getMemoryAddress());
}
if (addr != null) {
bf.append("Address: ", SWT.BOLD);
bf.append("0x", StyledStringBuffer.MONOSPACED);
bf.append(addr.toString(16), StyledStringBuffer.MONOSPACED);
}
if (bits != null) {
if (bits.length > 0) {
if (l < bf.length()) bf.append(", ");
bf.append("Bits: ", SWT.BOLD);
bf.append("[");
for (int i = bits.length; i > 0; i--) {
if (i != bits.length) bf.append(",");
bf.append(bits[i - 1]);
}
bf.append("]");
}
}
else {
BigInteger size = JSON.toBigInteger(ctx.getSize());
if (size != null && size.compareTo(BigInteger.ZERO) > 0) {
if (l < bf.length()) bf.append(", ");
bf.append("Size: ", SWT.BOLD);
bf.append(size.toString(10), StyledStringBuffer.MONOSPACED);
bf.append(size.compareTo(BigInteger.ONE) == 0 ? " byte" : " bytes");
}
}
if (ctx.isReadable()) {
if (l < bf.length()) bf.append(", ");
bf.append("readable");
}
if (ctx.isReadOnce()) {
if (l < bf.length()) bf.append(", ");
bf.append("read once");
}
if (ctx.isWriteable()) {
if (l < bf.length()) bf.append(", ");
bf.append("writable");
}
if (ctx.isWriteOnce()) {
if (l < bf.length()) bf.append(", ");
bf.append("write once");
}
if (ctx.hasSideEffects()) {
if (l < bf.length()) bf.append(", ");
bf.append("side effects");
}
if (l < bf.length()) bf.append('\n');
}
return true;
}
@SuppressWarnings("unchecked")
private boolean getChildren(IPresentationContext ctx, List<TCFNode> list, Runnable done) {
AtomicBoolean b = new AtomicBoolean();
if (!isRepresentationGroup(b, done)) return false;
boolean rep_group = b.get();
String rep_id = null;
if (rep_group) {
Map<String,String> map = (Map<String,String>)ctx.getProperty(
TCFNodeRegister.PROPERTY_REG_REPRESENTATION);
if (map != null) rep_id = map.get(id);
}
for (TCFNode child : children.toArray()) {
if (!rep_group || child.id.equals(rep_id)) list.add(child);
}
return true;
}
@Override
protected boolean getData(IHasChildrenUpdate result, Runnable done) {
List<TCFNode> list = new ArrayList<TCFNode>();
if (!getChildren(result.getPresentationContext(), list, done)) return false;
result.setHasChilren(list.size() > 0);
return true;
}
@Override
protected boolean getData(IChildrenCountUpdate result, Runnable done) {
List<TCFNode> list = new ArrayList<TCFNode>();
if (!getChildren(result.getPresentationContext(), list, done)) return false;
result.setChildCount(list.size());
return true;
}
@Override
protected boolean getData(IChildrenUpdate result, Runnable done) {
List<TCFNode> list = new ArrayList<TCFNode>();
if (!getChildren(result.getPresentationContext(), list, done)) return false;
int r_offset = result.getOffset();
int r_length = result.getLength();
for (int n = r_offset; n < r_offset + r_length && n < list.size(); n++) {
result.setChild(list.get(n), n);
}
return true;
}
@Override
protected boolean getData(ILabelUpdate result, Runnable done) {
TCFDataCache<?> pending = null;
if (!context.validate()) pending = context;
if (!value.validate()) pending = value;
if (pending != null) {
pending.wait(done);
return false;
}
String[] cols = result.getColumnIds();
if (cols == null) {
setLabel(result, -1, 16);
}
else {
IRegisters.RegistersContext ctx = context.getData();
for (int i = 0; i < cols.length; i++) {
String c = cols[i];
if (ctx == null) {
result.setForeground(ColorCache.rgb_error, i);
result.setLabel("N/A", i);
}
else if (c.equals(TCFColumnPresentationRegister.COL_NAME)) {
result.setLabel(ctx.getName(), i);
}
else if (c.equals(TCFColumnPresentationRegister.COL_HEX_VALUE)) {
setLabel(result, i, 16);
}
else if (c.equals(TCFColumnPresentationRegister.COL_DEC_VALUE)) {
setLabel(result, i, 10);
}
else if (c.equals(TCFColumnPresentationRegister.COL_DESCRIPTION)) {
result.setLabel(ctx.getDescription(), i);
}
else if (c.equals(TCFColumnPresentationRegister.COL_READBLE)) {
result.setLabel(bool(ctx.isReadable()), i);
}
else if (c.equals(TCFColumnPresentationRegister.COL_READ_ONCE)) {
result.setLabel(bool(ctx.isReadOnce()), i);
}
else if (c.equals(TCFColumnPresentationRegister.COL_WRITEABLE)) {
result.setLabel(bool(ctx.isWriteable()), i);
}
else if (c.equals(TCFColumnPresentationRegister.COL_WRITE_ONCE)) {
result.setLabel(bool(ctx.isWriteOnce()), i);
}
else if (c.equals(TCFColumnPresentationRegister.COL_SIDE_EFFECTS)) {
result.setLabel(bool(ctx.hasSideEffects()), i);
}
else if (c.equals(TCFColumnPresentationRegister.COL_VOLATILE)) {
result.setLabel(bool(ctx.isVolatile()), i);
}
else if (c.equals(TCFColumnPresentationRegister.COL_FLOAT)) {
result.setLabel(bool(ctx.isFloat()), i);
}
else if (c.equals(TCFColumnPresentationRegister.COL_MNEMONIC)) {
result.setLabel(getMnemonic(ctx), i);
}
}
}
next_value = value.getData();
if (prev_value != null && next_value != null) {
boolean changed = false;
if (prev_value.length != next_value.length) {
changed = true;
}
else {
for (int i = 0; i < prev_value.length; i++) {
if (prev_value[i] != next_value[i]) changed = true;
}
}
if (changed) {
if (cols != null) {
for (int i = 1; i < cols.length; i++) {
result.setBackground(ColorCache.rgb_highlight, i);
}
}
else {
result.setForeground(ColorCache.rgb_no_columns_color_change, 0);
}
}
}
result.setImageDescriptor(ImageCache.getImageDescriptor(ImageCache.IMG_REGISTER), 0);
return true;
}
private void setLabel(ILabelUpdate result, int col, int radix) {
String name = null;
IRegisters.RegistersContext ctx = context.getData();
if (ctx != null) name = ctx.getName();
Throwable error = context.getError();
if (error == null) error = value.getError();
byte[] data = value.getData();
if (error != null && col >= 0) {
result.setForeground(ColorCache.rgb_error, col);
result.setLabel("N/A", col);
}
else if (data != null && error == null) {
String s = toNumberString(radix);
if (col >= 0) {
result.setLabel(s, col);
}
else if (name != null) {
result.setLabel(name + " = " + s, 0);
}
}
else if (col < 0 && name != null) {
result.setLabel(name, 0);
}
}
@Override
protected void getFontData(ILabelUpdate update, String view_id) {
FontData fn = TCFModelFonts.getNormalFontData(view_id);
String[] cols = update.getColumnIds();
if (cols == null || cols.length == 0) {
update.setFontData(fn, 0);
}
else {
String[] ids = update.getColumnIds();
for (int i = 0; i < cols.length; i++) {
if (TCFColumnPresentationRegister.COL_HEX_VALUE.equals(ids[i]) ||
TCFColumnPresentationExpression.COL_DEC_VALUE.equals(ids[i])) {
update.setFontData(TCFModelFonts.getMonospacedFontData(view_id), i);
}
else {
update.setFontData(fn, i);
}
}
}
}
private String toNumberString(int radix) {
IRegisters.RegistersContext ctx = context.getData();
byte[] data = value.getData();
int[] bits = ctx.getBitNumbers();
if (ctx == null || data == null) return "N/A";
if (radix == 2) {
StringBuffer bf = new StringBuffer();
int i = data.length * 8;
if (bits != null) i = bits.length;
while (i > 0) {
if (i % 4 == 0 && bf.length() > 0) bf.append(',');
i--;
int j = i / 8;
if (ctx.isBigEndian()) j = data.length - j - 1;
if ((data[j] & (1 << (i % 8))) != 0) {
bf.append('1');
}
else {
bf.append('0');
}
}
return bf.toString();
}
if (radix == 10 && ctx.isFloat()) {
String s = TCFNumberFormat.toFPString(data, 0, data.length, ctx.isBigEndian());
if (s != null) return s;
}
BigInteger b = TCFNumberFormat.toBigInteger(data, ctx.isBigEndian(), false);
String s = b.toString(radix);
switch (radix) {
case 8:
if (!s.startsWith("0")) s = "0" + s;
break;
case 16:
if (s.length() < (bits == null ? data.length * 2 : (bits.length + 3) / 4)) {
StringBuffer bf = new StringBuffer();
while (bf.length() + s.length() < data.length * 2) bf.append('0');
bf.append(s);
s = bf.toString();
}
break;
}
return s;
}
private String bool(boolean b) {
return b ? "yes" : "no";
}
private String getMnemonic(IRegisters.RegistersContext ctx) {
if (value.getData() != null) {
IRegisters.NamedValue[] arr = ctx.getNamedValues();
if (arr != null) {
for (IRegisters.NamedValue n : arr) {
if (Arrays.equals(n.getValue(), value.getData())) return n.getName();
}
}
}
return "";
}
private void postStateChangedDelta() {
for (TCFModelProxy p : model.getModelProxies()) {
if (!IDebugUIConstants.ID_REGISTER_VIEW.equals(p.getPresentationContext().getId())) continue;
p.addDelta(this, IModelDelta.STATE);
}
}
void onValueChanged() {
prev_value = next_value;
value.reset();
TCFNode n = parent;
while (n != null) {
if (n instanceof TCFNodeExecContext) {
((TCFNodeExecContext)n).onRegisterValueChanged();
break;
}
else if (n instanceof TCFNodeRegister) {
TCFNodeRegister r = (TCFNodeRegister)n;
if (r.value.isValid() && r.value.getData() != null) {
r.value.reset();
r.postStateChangedDelta();
}
}
n = n.parent;
}
children.onParentValueChanged();
postStateChangedDelta();
}
void onParentValueChanged() {
value.reset();
children.onParentValueChanged();
postStateChangedDelta();
}
void onSuspended(boolean func_call) {
if (!func_call) {
prev_value = next_value;
value.reset();
// Unlike thread registers, stack frame register list must be retrieved on every suspend
if (is_stack_frame_register) children.reset();
// No need to post delta: parent posted CONTENT
}
else if (value.isValid() && value.getError() != null) {
value.reset();
}
children.onSuspended(func_call);
}
void onRegistersChanged() {
children.onRegistersChanged();
expression_text.reset();
context.reset();
value.reset();
// No need to post delta: parent posted CONTENT
}
public CellEditor getCellEditor(IPresentationContext context, String column_id, Object element, Composite parent) {
assert element == this;
if (TCFColumnPresentationRegister.COL_HEX_VALUE.equals(column_id)) {
return new TextCellEditor(parent);
}
if (TCFColumnPresentationRegister.COL_DEC_VALUE.equals(column_id)) {
return new TextCellEditor(parent);
}
return null;
}
private static final ICellModifier cell_modifier = new ICellModifier() {
private Object original_value;
public boolean canModify(Object element, final String property) {
final TCFNodeRegister node = (TCFNodeRegister)element;
try {
return new TCFTask<Boolean>() {
public void run() {
if (!node.context.validate(this)) return;
IRegisters.RegistersContext ctx = node.context.getData();
if (ctx != null && ctx.isWriteable()) {
if (!ctx.isReadable()) {
done(Boolean.TRUE);
return;
}
if (!node.value.validate(this)) return;
if (node.value.getError() == null) {
if (TCFColumnPresentationRegister.COL_HEX_VALUE.equals(property)) {
done(TCFNumberFormat.isValidHexNumber(node.toNumberString(16)) == null);
return;
}
if (TCFColumnPresentationRegister.COL_DEC_VALUE.equals(property)) {
done(TCFNumberFormat.isValidDecNumber(true, node.toNumberString(10)) == null);
return;
}
}
}
done(Boolean.FALSE);
}
}.get(1, TimeUnit.SECONDS);
}
catch (Exception e) {
return false;
}
}
public Object getValue(Object element, final String property) {
original_value = null;
final TCFNodeRegister node = (TCFNodeRegister)element;
try {
return original_value = new TCFTask<String>() {
public void run() {
if (!node.context.validate(this)) return;
IRegisters.RegistersContext ctx = node.context.getData();
if (!ctx.isReadable()) {
done("0");
return;
}
if (!node.value.validate(this)) return;
if (node.value.getError() == null) {
if (TCFColumnPresentationRegister.COL_HEX_VALUE.equals(property)) {
done(node.toNumberString(16));
return;
}
if (TCFColumnPresentationRegister.COL_DEC_VALUE.equals(property)) {
done(node.toNumberString(10));
return;
}
}
done(null);
}
}.get(1, TimeUnit.SECONDS);
}
catch (Exception e) {
return null;
}
}
public void modify(Object element, final String property, final Object value) {
if (value == null) return;
if (original_value != null && original_value.equals(value)) return;
final TCFNodeRegister node = (TCFNodeRegister)element;
try {
new TCFTask<Boolean>() {
public void run() {
try {
if (!node.context.validate(this)) return;
IRegisters.RegistersContext ctx = node.context.getData();
if (ctx != null && ctx.isWriteable()) {
byte[] bf = null;
boolean is_float = ctx.isFloat();
int size = ctx.getSize();
boolean big_endian = ctx.isBigEndian();
String input = (String)value;
String error = null;
int[] bits = ctx.getBitNumbers();
if (bits != null) size = (bits.length + 7) / 8;
if (TCFColumnPresentationRegister.COL_HEX_VALUE.equals(property)) {
if (input.startsWith("0x")) input = input.substring(2);
error = TCFNumberFormat.isValidHexNumber(input);
if (error == null) bf = TCFNumberFormat.toByteArray(input, 16, false, size, false, big_endian);
}
else if (TCFColumnPresentationRegister.COL_DEC_VALUE.equals(property)) {
error = TCFNumberFormat.isValidDecNumber(is_float, input);
if (error == null) bf = TCFNumberFormat.toByteArray(input, 10, is_float, size, is_float, big_endian);
}
if (error != null) throw new Exception("Invalid value: " + value, new Exception(error));
if (bf != null) {
// handle bit fields
if (bits != null) {
TCFNodeRegister p = (TCFNodeRegister)node.parent;
if (!p.value.validate(this)) return;
byte[] parent_value = p.value.getData();
if (!p.context.validate(this)) return;
IRegisters.RegistersContext parent_context = p.context.getData();
if (parent_context != null && parent_value != null) {
byte[] new_value = new byte[parent_value.length];
System.arraycopy(parent_value, 0, new_value, 0, parent_value.length);
for (int pos = 0; pos < bits.length; pos++) {
int bit = bits[pos];
if (bit / 8 >= new_value.length) continue;
if ((bf[pos / 8] & (1 << (pos % 8))) == 0) {
new_value[bit / 8] &= ~(1 << (bit % 8));
}
else {
new_value[bit / 8] |= 1 << (bit % 8);
}
}
parent_context.set(new_value, new IRegisters.DoneSet() {
public void doneSet(IToken token, Exception error) {
TCFNodeRegister p = (TCFNodeRegister)node.parent;
if (error != null) {
p.model.showMessageBox("Cannot modify register value", error);
done(Boolean.FALSE);
}
else {
p.value.reset();
p.postStateChangedDelta();
done(Boolean.TRUE);
}
}
});
return;
}
}
else {
ctx.set(bf, new IRegisters.DoneSet() {
public void doneSet(IToken token, Exception error) {
if (error != null) {
node.model.showMessageBox("Cannot modify register value", error);
done(Boolean.FALSE);
}
else {
node.value.reset();
node.postStateChangedDelta();
done(Boolean.TRUE);
}
}
});
return;
}
}
}
done(Boolean.FALSE);
}
catch (Throwable x) {
node.model.showMessageBox("Cannot modify register value", x);
done(Boolean.FALSE);
}
}
}.get(10, TimeUnit.SECONDS);
}
catch (TimeoutException e) {
node.model.showMessageBox("Timeout modifying register value", new Exception("No response for 10 seconds."));
}
catch (Exception e) {
node.model.showMessageBox("Error modifying register value", e);
}
}
};
public ICellModifier getCellModifier(IPresentationContext context, Object element) {
assert element == this;
return cell_modifier;
}
@Override
public int compareTo(TCFNode n) {
if (n instanceof TCFNodeRegister) {
TCFNodeRegister r = (TCFNodeRegister)n;
if (index < r.index) return -1;
if (index > r.index) return +1;
}
return id.compareTo(n.id);
}
/**
* Check if this register has multiple representations.
*/
public boolean isRepresentationGroup(AtomicBoolean res, Runnable done) {
res.set(false);
HashSet<Integer> offsets = new HashSet<Integer>();
if (!context.validate(done)) return false;
if (!children.validate(done)) return false;
IRegisters.RegistersContext reg_ctx = context.getData();
if (reg_ctx == null) return true;
if (reg_ctx.getSize() == 0) return true;
for (TCFNode child_node : children.toArray()) {
TCFNodeRegister child_reg = (TCFNodeRegister)child_node;
if (!child_reg.context.validate(done)) return false;
IRegisters.RegistersContext ctx = child_reg.context.getData();
if (ctx == null) continue;
int offs = ctx.getOffset();
if (offs >= 0) {
if (!offsets.add(Integer.valueOf(offs))) {
res.set(true);
return true;
}
continue;
}
// TODO: checking grand children should not be needed
if (!child_reg.children.validate(done)) return false;
for (TCFNode grand_child_node : child_reg.children.toArray()) {
TCFNodeRegister grand_child_reg = (TCFNodeRegister)grand_child_node;
if (!grand_child_reg.context.validate(done)) return false;
ctx = grand_child_reg.context.getData();
if (ctx == null) continue;
offs = ctx.getOffset();
if (offs >= 0) {
if (!offsets.add(Integer.valueOf(offs))) {
res.set(true);
return true;
}
}
}
}
return true;
}
}