diff options
Diffstat (limited to 'plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/MemoryProxy.java')
-rw-r--r-- | plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/MemoryProxy.java | 366 |
1 files changed, 366 insertions, 0 deletions
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/MemoryProxy.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/MemoryProxy.java new file mode 100644 index 000000000..19b3e1aa4 --- /dev/null +++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/MemoryProxy.java @@ -0,0 +1,366 @@ +/******************************************************************************* + * Copyright (c) 2007 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 com.windriver.tcf.api.internal.services.remote; + +import java.io.IOException; +import java.math.BigInteger; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import com.windriver.tcf.api.core.Base64; +import com.windriver.tcf.api.core.Command; +import com.windriver.tcf.api.internal.core.ReadOnlyMap; +import com.windriver.tcf.api.protocol.IChannel; +import com.windriver.tcf.api.protocol.IToken; +import com.windriver.tcf.api.protocol.JSON; +import com.windriver.tcf.api.services.IMemory; + +public class MemoryProxy implements IMemory { + + private final IChannel channel; + private final Map<MemoryListener,IChannel.IEventListener> listeners = + new HashMap<MemoryListener,IChannel.IEventListener>(); + + private static class Range implements Comparable<Range> { + int offs; + int size; + int stat; + String msg; + + public int compareTo(Range o) { + if (offs < o.offs) return -1; + if (offs > o.offs) return +1; + return 0; + } + } + + private class MemoryErrorReport extends MemoryError implements ErrorOffset { + + private static final long serialVersionUID = 796525409870265390L; + private final Range[] ranges; + + @SuppressWarnings("unchecked") + MemoryErrorReport(String msg, Number addr, Object ranges) { + super(msg); + Collection<Map<String,Object>> c = (Collection<Map<String,Object>>)ranges; + this.ranges = new Range[c.size()]; + int n = 0; + BigInteger addr_bi = addr instanceof BigInteger ? + (BigInteger)addr : new BigInteger(addr.toString()); + for (Map<String,Object> m : c) { + Range r = new Range(); + Number x = (Number)m.get("addr"); + BigInteger y = x instanceof BigInteger ? + (BigInteger)x : new BigInteger(x.toString()); + r.offs = addr_bi.subtract(y).intValue(); + r.size = ((Number)m.get("size")).intValue(); + r.stat = ((Number)m.get("stat")).intValue(); + r.msg = Command.toErrorString(m.get("msg")); + assert r.offs >= 0; + assert r.size >= 0; + this.ranges[n++] = r; + } + Arrays.sort(this.ranges); + } + + public String getMessage(int offset) { + int l = 0; + int h = ranges.length - 1; + while (l <= h) { + int n = (l + h) / 2; + Range r = ranges[n]; + if (r.offs > offset) { + h = n - 1; + } + else if (offset >= r.offs + r.size) { + l = n + 1; + } + else { + return r.msg; + } + } + return null; + } + + public int getStatus(int offset) { + int l = 0; + int h = ranges.length - 1; + while (l <= h) { + int n = (l + h) / 2; + Range r = ranges[n]; + if (r.offs > offset) { + h = n - 1; + } + else if (offset >= r.offs + r.size) { + l = n + 1; + } + else { + return r.stat; + } + } + return BYTE_UNKNOWN; + } + } + + private class MemContext implements MemoryContext { + + private final Map<String,Object> props; + + MemContext(Map<String,Object> props) { + assert props instanceof ReadOnlyMap; + this.props = props; + } + + public String getID() { + return (String)props.get(PROP_ID); + } + + public String getParentID() { + String s = (String)props.get(PROP_PARENT_ID); + if (s == null) return ""; + return s; + } + + public int getAddressSize() { + Number n = (Number)props.get(PROP_ADDRESS_SIZE); + if (n == null) return 0; + return n.intValue(); + } + + public int getProcessID() { + Number n = (Number)props.get(PROP_PROCESS_ID); + if (n == null) return 0; + return n.intValue(); + } + + public boolean isBigEndian() { + Boolean n = (Boolean)props.get(PROP_BIG_ENDIAN); + if (n == null) return false; + return n.booleanValue(); + } + + public Map<String, Object> getProperties() { + return props; + } + + public IToken fill(final Number addr, int word_size, + byte[] value, int size, int mode, final DoneMemory done) { + return new MemoryCommand("fill", new Object[] { + getID(), addr, word_size, size, mode, value + } ) { + public void done(Exception error, Object[] args) { + MemoryError e = null; + if (error != null) { + e = new MemoryError(error.getMessage()); + } + else { + assert args.length == 3; + e = toMemoryError(addr, args[0], args[1], args[2]); + } + done.doneMemory(token, e); + } + }.token; + } + + public IToken get(final Number addr, int word_size, + final byte[] buf, final int offs, final int size, + int mode, final DoneMemory done) { + return new MemoryCommand("get", new Object[] { + getID(), addr, word_size, size, mode + } ) { + public void done(Exception error, Object[] args) { + MemoryError e = null; + if (error != null) { + e = new MemoryError(error.getMessage()); + } + else { + assert args.length == 4; + String str = (String)args[0]; + if (str != null) Base64.toByteArray(buf, offs, size, str.toCharArray()); + e = toMemoryError(addr, args[1], args[2], args[3]); + } + done.doneMemory(token, e); + } + }.token; + } + + public IToken set(final Number addr, int word_size, + byte[] buf, int offs, int size, int mode, final DoneMemory done) { + return new MemoryCommand("set", new Object[] { + getID(), addr, word_size, size, mode, Base64.toBase64(buf, offs, size) + } ) { + public void done(Exception error, Object[] args) { + MemoryError e = null; + if (error != null) { + e = new MemoryError(error.getMessage()); + } + else { + assert args.length == 3; + e = toMemoryError(addr, args[0], args[1], args[2]); + } + done.doneMemory(token, e); + } + }.token; + } + + public String toString() { + return "[Memory Context " + props.toString() + "]"; + } + } + + public MemoryProxy(IChannel channel) { + this.channel = channel; + } + + public void addListener(final MemoryListener listener) { + IChannel.IEventListener l = new IChannel.IEventListener() { + + public void event(String name, byte[] data) { + try { + Object[] args = JSON.parseSequence(data); + if (name.equals("contextAdded")) { + assert args.length == 1; + listener.contextAdded(toContextArray(args[0])); + } + else if (name.equals("contextChanged")) { + assert args.length == 1; + listener.contextChanged(toContextArray(args[0])); + } + else if (name.equals("contextRemoved")) { + assert args.length == 1; + listener.contextRemoved(toStringArray(args[0])); + } + else if (name.equals("memoryChanged")) { + assert args.length == 2; + listener.memoryChanged((String)args[0], + toAddrArray(args[1]), toSizeArray(args[1])); + } + else { + throw new IOException("Memory service: unknown event: " + name); + } + } + catch (Throwable x) { + channel.terminate(x); + } + } + }; + channel.addEventListener(this, l); + listeners.put(listener, l); + } + + public void removeListener(MemoryListener listener) { + IChannel.IEventListener l = listeners.remove(listener); + if (l != null) channel.removeEventListener(this, l); + } + + public IToken getContext(String context_id, final DoneGetContext done) { + return new Command(channel, this, "getContext", new Object[]{ context_id }) { + @SuppressWarnings("unchecked") + @Override + public void done(Exception error, Object[] args) { + MemContext ctx = null; + if (error == null) { + assert args.length == 3; + error = toError(args[0], args[1]); + if (args[2] != null) { + ctx = new MemContext((Map<String,Object>)args[2]); + } + } + done.doneGetContext(token, error, ctx); + } + }.token; + } + + public IToken getChildren(String parent_context_id, final DoneGetChildren done) { + return new Command(channel, this, "getChildren", new Object[]{ parent_context_id }) { + @Override + public void done(Exception error, Object[] args) { + String[] arr = null; + if (error == null) { + assert args.length == 3; + error = toError(args[0], args[1]); + arr = toStringArray(args[2]); + } + done.doneGetChildren(token, error, arr); + } + }.token; + } + + public String getName() { + return NAME; + } + + private abstract class MemoryCommand extends Command { + + MemoryCommand(String cmd, Object[] args) { + super(channel, MemoryProxy.this, cmd, args); + } + + MemoryError toMemoryError(Number addr, Object code, Object data, Object ranges) { + int error_code = ((Number)code).intValue(); + if (error_code == 0) return null; + String cmd = getCommandString(); + if (cmd.length() > 72) cmd = cmd.substring(0, 72) + "..."; + return new MemoryErrorReport( + "TCF command exception:" + + "\nCommand: " + cmd + + "\nException: " + toErrorString(data) + + "\nError code: " + code, addr, ranges); + } + } + + @SuppressWarnings("unchecked") + private MemoryContext[] toContextArray(Object o) { + Collection<Map<String,Object>> c = (Collection<Map<String,Object>>)o; + if (c == null) return new MemoryContext[0]; + int n = 0; + MemoryContext[] ctx = new MemoryContext[c.size()]; + for (Iterator<Map<String,Object>> i = c.iterator(); i.hasNext();) { + ctx[n++] = new MemContext(i.next()); + } + return ctx; + } + + @SuppressWarnings("unchecked") + private long[] toSizeArray(Object o) { + Collection<Map<String,Object>> c = (Collection<Map<String,Object>>)o; + if (c == null) return null; + long[] a = new long[c.size()]; + int n = 0; + for (Map<String,Object> m : c) { + Number sz = (Number)m.get("size"); + a[n++] = sz == null ? 0 : sz.longValue(); + } + return a; + } + + @SuppressWarnings("unchecked") + private Number[] toAddrArray(Object o) { + Collection<Map<String,Object>> c = (Collection<Map<String,Object>>)o; + if (c == null) return null; + Number[] a = new Number[c.size()]; + int n = 0; + for (Map<String,Object> m : c) { + a[n++] = (Number)m.get("addr"); + } + return a; + } + + @SuppressWarnings("unchecked") + private String[] toStringArray(Object o) { + Collection<String> c = (Collection<String>)o; + if (c == null) return new String[0]; + return (String[])c.toArray(new String[c.size()]); + } +} |