/******************************************************************************* * Copyright (c) 2010, 2011 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.tm.internal.tcf.cdt.ui.disassembly; import static org.eclipse.cdt.debug.internal.ui.disassembly.dsf.DisassemblyUtils.DEBUG; import java.math.BigInteger; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import org.eclipse.cdt.debug.internal.ui.disassembly.dsf.AbstractDisassemblyBackend; import org.eclipse.cdt.debug.internal.ui.disassembly.dsf.AddressRangePosition; import org.eclipse.cdt.debug.internal.ui.disassembly.dsf.DisassemblyUtils; import org.eclipse.cdt.debug.internal.ui.disassembly.dsf.ErrorPosition; import org.eclipse.cdt.debug.internal.ui.disassembly.dsf.IDisassemblyPartCallback; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchesListener; import org.eclipse.jface.dialogs.ErrorDialog; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocumentExtension4; import org.eclipse.jface.text.Position; import org.eclipse.tm.internal.tcf.cdt.ui.Activator; import org.eclipse.tm.internal.tcf.debug.launch.TCFSourceLookupDirector; import org.eclipse.tm.internal.tcf.debug.model.TCFContextState; import org.eclipse.tm.internal.tcf.debug.model.TCFSourceRef; import org.eclipse.tm.internal.tcf.debug.ui.model.TCFChildrenStackTrace; import org.eclipse.tm.internal.tcf.debug.ui.model.TCFModel; import org.eclipse.tm.internal.tcf.debug.ui.model.TCFNode; import org.eclipse.tm.internal.tcf.debug.ui.model.TCFNodeExecContext; import org.eclipse.tm.internal.tcf.debug.ui.model.TCFNodeStackFrame; import org.eclipse.tm.tcf.protocol.IChannel; import org.eclipse.tm.tcf.protocol.IChannel.IChannelListener; import org.eclipse.tm.tcf.protocol.IToken; import org.eclipse.tm.tcf.protocol.JSON; import org.eclipse.tm.tcf.protocol.Protocol; import org.eclipse.tm.tcf.services.IDisassembly; import org.eclipse.tm.tcf.services.IDisassembly.DoneDisassemble; import org.eclipse.tm.tcf.services.IDisassembly.IDisassemblyLine; import org.eclipse.tm.tcf.services.IExpressions; import org.eclipse.tm.tcf.services.IExpressions.DoneCreate; import org.eclipse.tm.tcf.services.IExpressions.DoneDispose; import org.eclipse.tm.tcf.services.IExpressions.DoneEvaluate; import org.eclipse.tm.tcf.services.IExpressions.Expression; import org.eclipse.tm.tcf.services.IExpressions.Value; import org.eclipse.tm.tcf.services.ILineNumbers; import org.eclipse.tm.tcf.services.ILineNumbers.CodeArea; import org.eclipse.tm.tcf.services.ILineNumbers.DoneMapToSource; import org.eclipse.tm.tcf.services.IMemory; import org.eclipse.tm.tcf.services.IRunControl; import org.eclipse.tm.tcf.services.IRunControl.RunControlContext; import org.eclipse.tm.tcf.services.IRunControl.RunControlListener; import org.eclipse.tm.tcf.services.ISymbols; import org.eclipse.tm.tcf.util.TCFDataCache; import org.eclipse.tm.tcf.util.TCFTask; import org.eclipse.ui.PlatformUI; @SuppressWarnings("restriction") public class TCFDisassemblyBackend extends AbstractDisassemblyBackend { private static class AddressRange { BigInteger start; BigInteger end; } private static class FunctionOffset { static final FunctionOffset NONE = new FunctionOffset(null, null); String name; BigInteger offset; FunctionOffset(String name, BigInteger offset) { this.name = name; this.offset = offset; } @Override public String toString() { if (name == null || name.length() == 0) { return ""; } if (isZeroOffset()) { return name; } return name + '+' + offset.toString(); } boolean isZeroOffset() { return offset == null || offset.compareTo(BigInteger.ZERO) == 0; } } private class TCFLaunchListener implements ILaunchesListener { public void launchesRemoved(ILaunch[] launches) { } public void launchesAdded(ILaunch[] launches) { } public void launchesChanged(ILaunch[] launches) { if(fExecContext == null) { return; } for (ILaunch launch : launches) { if (launch == fExecContext.getModel().getLaunch()) { if (launch.isTerminated()) { handleSessionEnded(); } break; } } } } private class TCFChannelListener implements IChannelListener { public void onChannelOpened() { } public void onChannelClosed(Throwable error) { handleSessionEnded(); } public void congestionLevel(int level) { } } private class TCFRunControlListener implements RunControlListener { public void contextAdded(RunControlContext[] contexts) { } public void contextChanged(RunControlContext[] contexts) { } public void contextRemoved(String[] context_ids) { String id = fExecContext.getID(); for (String contextId : context_ids) { if (id.equals(contextId)) { fCallback.handleTargetEnded(); return; } } } public void contextSuspended(String context, String pc, String reason, Map<String, Object> params) { if (fExecContext.getID().equals(context)) { handleContextSuspended(pc != null ? new BigInteger(pc) : null); } } public void contextResumed(String context) { if (fExecContext.getID().equals(context)) { fCallback.handleTargetResumed(); } } public void containerSuspended(String context, String pc, String reason, Map<String, Object> params, String[] suspended_ids) { String id = fExecContext.getID(); if (id.equals(context)) { handleContextSuspended(pc != null ? new BigInteger(pc) : null); return; } for (String contextId : suspended_ids) { if (id.equals(contextId)) { handleContextSuspended(null); return; } } } public void containerResumed(String[] context_ids) { String id = fExecContext.getID(); for (String contextId : context_ids) { if (id.equals(contextId)) { fCallback.handleTargetResumed(); return; } } } public void contextException(String context, String msg) { } } private IDisassemblyPartCallback fCallback; private volatile TCFNodeExecContext fExecContext; private volatile TCFNodeStackFrame fActiveFrame; private volatile BigInteger fSuspendAddress; private volatile int fSuspendCount; private final IRunControl.RunControlListener fRunControlListener = new TCFRunControlListener(); private final IChannelListener fChannelListener = new TCFChannelListener(); private final ILaunchesListener fLaunchesListener = new TCFLaunchListener(); @Override public void init(IDisassemblyPartCallback callback) { fCallback = callback; } public boolean supportsDebugContext(IAdaptable context) { return (context instanceof TCFNodeExecContext || context instanceof TCFNodeStackFrame) && hasDisassemblyService((TCFNode) context); } private boolean hasDisassemblyService(final TCFNode context) { Boolean hasService = new TCFTask<Boolean>() { public void run() { IDisassembly disass = null; IChannel channel = context.getChannel(); if (channel != null && channel.getState() != IChannel.STATE_CLOSED) { disass = channel.getRemoteService(IDisassembly.class); } done(disass != null); } }.getE(); return hasService != null && hasService.booleanValue(); } public boolean hasDebugContext() { return fExecContext != null; } public SetDebugContextResult setDebugContext(IAdaptable context) { TCFNodeExecContext newContext = null; TCFNodeStackFrame frame = null; SetDebugContextResult result = new SetDebugContextResult(); if (context instanceof TCFNodeExecContext) { newContext = (TCFNodeExecContext) context; final TCFNodeExecContext _execContext = newContext; frame = new TCFTask<TCFNodeStackFrame>(_execContext.getChannel()) { public void run() { TCFChildrenStackTrace stack = _execContext.getStackTrace(); if (!stack.validate(this)) { return; } done(stack.getTopFrame()); } }.getE(); if (frame == null) { newContext = null; } } else if (context instanceof TCFNodeStackFrame) { final TCFNodeStackFrame _frame = frame = (TCFNodeStackFrame) context; newContext = new TCFTask<TCFNodeExecContext>(_frame.getChannel()) { public void run() { TCFNode parent = _frame.getParent(); if (parent instanceof TCFNodeExecContext) { done((TCFNodeExecContext) parent); } else { done(null); } } }.getE(); } TCFNodeExecContext oldContext = fExecContext; if (oldContext == null || newContext == null || oldContext.compareTo(newContext) != 0) { result.contextChanged = true; fSuspendCount++; if (oldContext != null) { removeListeners(oldContext); } } fExecContext = newContext; if (newContext != null && result.contextChanged) { addListeners(newContext); } fActiveFrame = frame; result.sessionId = newContext != null ? newContext.getID() : null; if (!result.contextChanged && fActiveFrame != null) { fCallback.asyncExec(new Runnable() { public void run() { fCallback.gotoFrameIfActive(getFrameLevel()); } }); } return result; } private void addListeners(final TCFNodeExecContext context) { assert context != null; Protocol.invokeAndWait(new Runnable() { public void run() { IChannel channel = context.getChannel(); IRunControl rctl = channel.getRemoteService(IRunControl.class); if (rctl != null) { rctl.addListener(fRunControlListener); } channel.addChannelListener(fChannelListener); } }); DebugPlugin.getDefault().getLaunchManager().addLaunchListener(fLaunchesListener ); } private void removeListeners(final TCFNodeExecContext context) { assert context != null; DebugPlugin.getDefault().getLaunchManager().removeLaunchListener(fLaunchesListener); Protocol.invokeAndWait(new Runnable() { public void run() { IChannel channel = context.getChannel(); IRunControl rctl = channel.getRemoteService(IRunControl.class); if (rctl != null) { rctl.removeListener(fRunControlListener); } channel.removeChannelListener(fChannelListener); } }); } private void handleContextSuspended(BigInteger pc) { ++fSuspendCount; fSuspendAddress = pc; fCallback.handleTargetSuspended(); } private void handleSessionEnded() { clearDebugContext(); fCallback.handleTargetEnded(); } public void clearDebugContext() { if (fExecContext != null) { removeListeners(fExecContext); } fExecContext = null; fActiveFrame = null; } public void retrieveFrameAddress(final int targetFrame) { final TCFNodeExecContext execContext = fExecContext; if (execContext == null) { fCallback.setUpdatePending(false); return; } BigInteger address; if (targetFrame == 0 && fSuspendAddress != null) { // shortcut for goto frame on suspend address = fSuspendAddress; fSuspendAddress = null; } else { final int suspendCount = fSuspendCount; final TCFChildrenStackTrace stack = execContext.getStackTrace(); address = new TCFTask<BigInteger>(execContext.getChannel()) { public void run() { if (suspendCount != fSuspendCount || execContext != fExecContext) { done(null); return; } if (!stack.validate(this)) { return; } TCFNodeStackFrame frame = null; if (targetFrame == 0) { frame = stack.getTopFrame(); } else { Map<String,TCFNode> frameData = stack.getData(); for (TCFNode node : frameData.values()) { if (node instanceof TCFNodeStackFrame) { TCFNodeStackFrame cand = (TCFNodeStackFrame) node; if (cand.getFrameNo() == targetFrame) { frame = cand; break; } } } } if (frame != null) { TCFDataCache<BigInteger> addressCache = frame.getAddress(); if (!addressCache.validate(this)) { return; } done(addressCache.getData()); return; } done(null); } }.getE(); } if (execContext == fExecContext) { fCallback.setUpdatePending(false); if (address == null) address = BigInteger.valueOf(-2); if (targetFrame == 0) { fCallback.updatePC(address); } else { fCallback.gotoFrame(targetFrame, address); } } } public int getFrameLevel() { if (fActiveFrame == null) { return -1; } Integer level = new TCFTask<Integer>() { public void run() { done(fActiveFrame != null ? fActiveFrame.getFrameNo() : -1); } }.getE(); return level != null ? level.intValue() : -1; } public boolean isSuspended() { if (fExecContext == null) { return false; } Boolean suspended = new TCFTask<Boolean>(fExecContext.getChannel()) { public void run() { if (fExecContext == null) { done(null); return; } TCFDataCache<TCFContextState> stateCache = fExecContext.getState(); if (!stateCache.validate(this)) { return; } TCFContextState state = stateCache.getData(); if (state != null) { done(state.is_suspended); return; } done(null); } }.getE(); return suspended != null ? suspended.booleanValue() : false; } public boolean hasFrameContext() { return fActiveFrame != null; } public String getFrameFile() { final TCFNodeStackFrame frame = fActiveFrame; if (frame == null) { return null; } String file = new TCFTask<String>(frame.getChannel()) { public void run() { if (frame != fActiveFrame) { done(null); return; } TCFDataCache<TCFSourceRef> sourceRefCache = frame.getLineInfo(); if (!sourceRefCache.validate(this)) { return; } TCFSourceRef sourceRef = sourceRefCache.getData(); String file = sourceRef.area.file; if (file != null) { IPath filePath = new Path(file); if (!filePath.isAbsolute()) { String dir = sourceRef.area.directory; if (dir != null) { filePath = new Path(dir).append(filePath); } } done(filePath.toString()); } done(null); } }.getE(); return file; } public int getFrameLine() { final TCFNodeStackFrame frame = fActiveFrame; if (frame == null) { return -1; } Integer line = new TCFTask<Integer>(frame.getChannel()) { public void run() { if (frame != fActiveFrame) { done(null); return; } TCFDataCache<TCFSourceRef> sourceRefCache = frame.getLineInfo(); if (!sourceRefCache.validate(this)) { return; } TCFSourceRef sourceRef = sourceRefCache.getData(); done(sourceRef.area.start_line); } }.getE(); return line != null ? line.intValue() : -1; } public void retrieveDisassembly(final BigInteger startAddress, BigInteger endAddress, String file, int lineNumber, int lines, final boolean mixed, final boolean showSymbols, boolean showDisassembly, final int linesHint) { final TCFNodeExecContext execContext = fExecContext; if (execContext == null || execContext.isDisposed()) { fCallback.setUpdatePending(false); return; } final int suspendCount = fSuspendCount; final long modCount = getModCount(); Protocol.invokeLater(new Runnable() { public void run() { if (execContext != fExecContext) { return; } if (suspendCount != fSuspendCount) { fCallback.setUpdatePending(false); return; } final IChannel channel = execContext.getChannel(); IDisassembly disass = channel.getRemoteService(IDisassembly.class); if (disass == null) { fCallback.setUpdatePending(false); return; } TCFDataCache<TCFNodeExecContext> mem_node_cache = execContext.getModel().searchMemoryContext(execContext); if (!mem_node_cache.validate(this)) return; TCFNodeExecContext memContext = mem_node_cache.getData(); if (memContext == null) { fCallback.setUpdatePending(false); return; } TCFDataCache<IMemory.MemoryContext> cache = memContext.getMemoryContext(); if (!cache.validate(this)) return; final IMemory.MemoryContext mem = cache.getData(); if (mem == null) { fCallback.setUpdatePending(false); return; } final String contextId = mem.getID(); Map<String, Object> params = new HashMap<String, Object>(); disass.disassemble(contextId, startAddress, linesHint*4, params, new DoneDisassemble() { public void doneDisassemble(IToken token, final Throwable error, final IDisassemblyLine[] disassembly) { if (execContext != fExecContext) { return; } if (error != null) { fCallback.asyncExec(new Runnable() { public void run() { if (execContext != fExecContext) { return; } if (modCount == getModCount()) { fCallback.insertError(startAddress, TCFModel.getErrorMessage(error, false)); fCallback.setUpdatePending(false); int addr_bits = mem.getAddressSize() * 8; if (fCallback.getAddressSize() < addr_bits) fCallback.addressSizeChanged(addr_bits); } } }); return; } doneGetDisassembly(disassembly); } private void doneGetDisassembly(final IDisassemblyLine[] disassembly) { if (!showSymbols) { doneGetSymbols(disassembly, null); return; } final ISymbols symbols = channel.getRemoteService(ISymbols.class); if (symbols == null) { doneGetSymbols(disassembly, null); return; } final ArrayList<ISymbols.Symbol> symbolList = new ArrayList<ISymbols.Symbol>(); final int[] idx = { 0 }; IDisassemblyLine line = disassembly[idx[0]]; Number address = line.getAddress(); symbols.findByAddr(contextId, address, new ISymbols.DoneFind() { ISymbols.DoneFind doneFind = this; public void doneFind(IToken token, Exception error, String symbol_id) { if (error == null && symbol_id != null) { symbols.getContext(symbol_id, new ISymbols.DoneGetContext() { public void doneGetContext(IToken token, Exception error, ISymbols.Symbol context) { BigInteger nextAddress = null; if (error == null && context != null) { if (context.getTypeClass().equals(ISymbols.TypeClass.function)) { symbolList.add(context); nextAddress = JSON.toBigInteger(context.getAddress()).add(BigInteger.valueOf(context.getSize())); } } findNextSymbol(nextAddress); } }); return; } findNextSymbol(null); } private void findNextSymbol(BigInteger nextAddress) { while (++idx[0] < disassembly.length) { BigInteger instrAddress = JSON.toBigInteger(disassembly[idx[0]].getAddress()); if (nextAddress == null) { nextAddress = instrAddress; } else if (instrAddress.compareTo(nextAddress) < 0) { continue; } symbols.findByAddr(contextId, instrAddress, doneFind); return; } ISymbols.Symbol[] functionSymbols = symbolList.toArray(new ISymbols.Symbol[symbolList.size()]); doneGetSymbols(disassembly, functionSymbols); } }); } private void doneGetSymbols(final IDisassemblyLine[] disassembly, final ISymbols.Symbol[] symbols) { ILineNumbers lineNumbers = null; if (mixed) { lineNumbers = channel.getRemoteService(ILineNumbers.class); } if (lineNumbers == null) { doneGetLineNumbers(disassembly, symbols, null); } else { AddressRange range = getAddressRange(disassembly); lineNumbers.mapToSource(contextId, range.start, range.end, new DoneMapToSource() { public void doneMapToSource(IToken token, Exception error, final CodeArea[] areas) { if (error != null) { Activator.log(error); doneGetLineNumbers(disassembly, symbols, null); } else { doneGetLineNumbers(disassembly, symbols, areas); } } }); } } private void doneGetLineNumbers( final IDisassemblyLine[] disassembly, final ISymbols.Symbol[] symbols, final CodeArea[] areas) { fCallback.asyncExec(new Runnable() { public void run() { insertDisassembly(modCount, startAddress, disassembly, symbols, areas); int addr_bits = mem.getAddressSize() * 8; if (fCallback.getAddressSize() < addr_bits) fCallback.addressSizeChanged(addr_bits); } }); } private AddressRange getAddressRange(IDisassemblyLine[] lines) { AddressRange range = new AddressRange(); range.start = JSON.toBigInteger(lines[0].getAddress()); IDisassemblyLine lastLine = lines[lines.length-1]; range.end = JSON.toBigInteger(lastLine.getAddress()).add(BigInteger.valueOf(lastLine.getSize())); return range; } }); } }); } private long getModCount() { return ((IDocumentExtension4) fCallback.getDocument()).getModificationStamp(); } protected final void insertDisassembly(long modCount, BigInteger startAddress, IDisassemblyLine[] instructions, ISymbols.Symbol[] symbols, CodeArea[] codeAreas) { if (!fCallback.hasViewer() || fExecContext == null) { return; } if (modCount != getModCount()) { return; } if (DEBUG) System.out.println("insertDisassembly "+ DisassemblyUtils.getAddressText(startAddress)); //$NON-NLS-1$ boolean updatePending = fCallback.getUpdatePending(); assert updatePending; if (!updatePending) { // safe-guard in case something weird is going on return; } boolean insertedAnyAddress = false; try { fCallback.lockScroller(); AddressRangePosition p= null; for (IDisassemblyLine instruction : instructions) { BigInteger address = JSON.toBigInteger(instruction.getAddress()); if (startAddress == null) { startAddress = address; fCallback.setGotoAddressPending(address); } if (p == null || !p.containsAddress(address)) { p = fCallback.getPositionOfAddress(address); } if (p instanceof ErrorPosition && p.fValid) { p.fValid = false; fCallback.getDocument().addInvalidAddressRange(p); } else if (p == null /* || address.compareTo(endAddress) > 0 */) { if (DEBUG) System.out.println("Excess disassembly lines at " + DisassemblyUtils.getAddressText(address)); //$NON-NLS-1$ return; } else if (p.fValid) { if (DEBUG) System.out.println("Excess disassembly lines at " + DisassemblyUtils.getAddressText(address)); //$NON-NLS-1$ // if (!p.fAddressOffset.equals(address)) { // // override probably unaligned disassembly // p.fValid = false; // fCallback.getDocument().addInvalidAddressRange(p); // } else { continue; // } } // insert source String sourceFile = null; int firstLine = -1; int lastLine = -1; CodeArea area = findCodeArea(address, codeAreas); if (area != null) { if (area.file != null) { IPath filePath = new Path(area.file); if (!filePath.isAbsolute() && area.directory != null) { filePath = new Path(area.directory).append(filePath); } sourceFile = filePath.toString(); firstLine = area.start_line - 1; lastLine = area.end_line - 2; } } if (sourceFile != null && firstLine >= 0) { try { p = fCallback.insertSource(p, address, sourceFile, firstLine, lastLine); } catch (NoSuchMethodError nsme) { // use fallback p = fCallback.insertSource(p, address, sourceFile, firstLine); } } // insert symbol label FunctionOffset functionOffset = getFunctionOffset(address, symbols); if (functionOffset.name != null && functionOffset.isZeroOffset()) { p = fCallback.getDocument().insertLabel(p, address, functionOffset.name, true); } // insert instruction int instrLength= instruction.getSize(); Map<String, Object>[] instrAttrs = instruction.getInstruction(); String instr = formatInstruction(instrAttrs); p = fCallback.getDocument().insertDisassemblyLine(p, address, instrLength, functionOffset.toString(), instr, sourceFile, firstLine); if (p == null) { break; } insertedAnyAddress = true; } } catch (BadLocationException e) { // should not happen DisassemblyUtils.internalError(e); } finally { fCallback.setUpdatePending(false); if (insertedAnyAddress) { fCallback.updateInvalidSource(); fCallback.unlockScroller(); fCallback.doPending(); fCallback.updateVisibleArea(); } else { fCallback.unlockScroller(); } } } private FunctionOffset getFunctionOffset(BigInteger address, ISymbols.Symbol[] symbols) { if (symbols != null) { for (ISymbols.Symbol symbol : symbols) { BigInteger symbolAddress = JSON.toBigInteger(symbol.getAddress()); BigInteger offset = address.subtract(symbolAddress); switch (offset.compareTo(BigInteger.ZERO)) { case 0: return new FunctionOffset(symbol.getName(), BigInteger.ZERO); case 1: if (offset.compareTo(BigInteger.valueOf(symbol.getSize())) < 0) { return new FunctionOffset(symbol.getName(), offset); } break; default: break; } } } return FunctionOffset.NONE; } private CodeArea findCodeArea(BigInteger address, CodeArea[] codeAreas) { if (codeAreas != null) { for (CodeArea codeArea : codeAreas) { if (address.equals(JSON.toBigInteger(codeArea.start_address))) { return codeArea; } } } return null; } /** * Format an instruction. * * @param instrAttrs * @return string representation */ private String formatInstruction(Map<String, Object>[] instrAttrs) { StringBuilder buf = new StringBuilder(20); for (Map<String, Object> attrs : instrAttrs) { Object type = attrs.get(IDisassembly.FIELD_TYPE); if (IDisassembly.FTYPE_STRING.equals(type) || IDisassembly.FTYPE_Register.equals(type)) { Object text = attrs.get(IDisassembly.FIELD_TEXT); buf.append(text); } else { Object value = attrs.get(IDisassembly.FIELD_VALUE); BigInteger bigValue = new BigInteger(value.toString()); // TODO number format buf.append("0x").append(bigValue.toString(16)).append(' '); } } return buf.toString(); } public void gotoSymbol(final String symbol) { final TCFNodeStackFrame activeFrame = fActiveFrame; if (activeFrame == null) { return; } Protocol.invokeLater(new Runnable() { public void run() { if (activeFrame != fActiveFrame) { return; } IChannel channel = activeFrame.getChannel(); final IExpressions exprSvc = channel.getRemoteService(IExpressions.class); if (exprSvc != null) { TCFNode evalContext = activeFrame.isEmulated() ? activeFrame.getParent() : activeFrame; exprSvc.create(evalContext.getID(), null, symbol, new DoneCreate() { public void doneCreate(IToken token, Exception error, final Expression context) { if (error == null) { exprSvc.evaluate(context.getID(), new DoneEvaluate() { public void doneEvaluate(IToken token, Exception error, Value value) { if (error == null) { final BigInteger address = toBigInteger(value.getValue(), value.isBigEndian(), false); fCallback.asyncExec(new Runnable() { public void run() { fCallback.gotoAddress(address); } }); } else { handleError(error); } exprSvc.dispose(context.getID(), new DoneDispose() { public void doneDispose(IToken token, Exception error) { // no-op } }); } }); } else { handleError(error); } } }); } } protected void handleError(final Exception error) { fCallback.asyncExec(new Runnable() { public void run() { Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, error.getLocalizedMessage(), error); ErrorDialog.openError(fCallback.getSite().getShell(), "Error", null, status); //$NON-NLS-1$ } }); } }); } public void retrieveDisassembly(String file, int lines, BigInteger endAddress, boolean mixed, boolean showSymbols, boolean showDisassembly) { // TODO disassembly for source file fCallback.setUpdatePending(false); } public String evaluateExpression(final String expression) { final TCFNodeStackFrame activeFrame = fActiveFrame; if (activeFrame == null) { return null; } String value = new TCFTask<String>(activeFrame.getChannel()) { public void run() { if (activeFrame != fActiveFrame) { done(null); return; } IChannel channel = activeFrame.getChannel(); final IExpressions exprSvc = channel.getRemoteService(IExpressions.class); if (exprSvc != null) { TCFNode evalContext = activeFrame.isEmulated() ? activeFrame.getParent() : activeFrame; exprSvc.create(evalContext.getID(), null, expression, new DoneCreate() { public void doneCreate(IToken token, Exception error, final Expression context) { if (error == null) { exprSvc.evaluate(context.getID(), new DoneEvaluate() { public void doneEvaluate(IToken token, Exception error, Value value) { if (error == null) { final BigInteger address = toBigInteger(value.getValue(), value.isBigEndian(), false); done("0x" + address.toString(16)); } else { done(null); } exprSvc.dispose(context.getID(), new DoneDispose() { public void doneDispose(IToken token, Exception error) { // no-op } }); } }); } else { done(null); } } }); } else { done(null); } } }.getE(); return value; } public void dispose() { } public Object insertSource(Position pos, BigInteger address, String file, int lineNumber) { TCFNodeExecContext execContext = fExecContext; if (execContext == null) return null; return TCFSourceLookupDirector.lookup(execContext.getModel().getLaunch().getSourceLocator(), file); } private static BigInteger toBigInteger(byte[] data, boolean big_endian, boolean sign_extension) { byte[] temp = null; if (sign_extension) { temp = new byte[data.length]; } else { temp = new byte[data.length + 1]; temp[0] = 0; // Extra byte to avoid sign extension by BigInteger } if (big_endian) { System.arraycopy(data, 0, temp, sign_extension ? 0 : 1, data.length); } else { for (int i = 0; i < data.length; i++) { temp[temp.length - i - 1] = data[i]; } } return new BigInteger(temp); } /* * @see org.eclipse.cdt.debug.internal.ui.disassembly.dsf.AbstractDisassemblyBackend#evaluateAddressExpression(java.lang.String, boolean) */ @Override public BigInteger evaluateAddressExpression(String expression, boolean suppressError) { String value = evaluateExpression(expression); if (value != null) { try { return DisassemblyUtils.decodeAddress(value); } catch (NumberFormatException e) { if (!suppressError) { MessageDialog.openError(PlatformUI.getWorkbench().getDisplay().getActiveShell(), "Error", "Expression does not evaluate to an address"); } } } return null; } }