From 43bd0e13f016c93594cfaa025cadf6e7861b97dd Mon Sep 17 00:00:00 2001 From: eutarass Date: Mon, 26 Sep 2011 16:57:02 +0000 Subject: TCF Debugger: lost revisions (2094..) re-applied to TCFDisassemblyBackend.java --- .../cdt/ui/disassembly/TCFDisassemblyBackend.java | 1984 ++++++++++---------- 1 file changed, 985 insertions(+), 999 deletions(-) (limited to 'plugins') diff --git a/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/disassembly/TCFDisassemblyBackend.java b/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/disassembly/TCFDisassemblyBackend.java index 596bfc3e9..efcc2812c 100644 --- a/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/disassembly/TCFDisassemblyBackend.java +++ b/plugins/org.eclipse.tm.tcf.cdt.ui/src/org/eclipse/tm/internal/tcf/cdt/ui/disassembly/TCFDisassemblyBackend.java @@ -1,999 +1,985 @@ -/******************************************************************************* - * 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.debug.core.model.ISourceLocator; -import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector; -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.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.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 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 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() { - 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(_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(_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(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 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 addressCache = frame.getAddress(); - if (!addressCache.validate(this)) { - return; - } - done(addressCache.getData()); - return; - } - done(null); - } - }.getE(); - } - - if (execContext == fExecContext) { - fCallback.setUpdatePending(false); - if (address != null) { - if (targetFrame == 0) { - fCallback.updatePC(address); - } else { - fCallback.gotoFrame(targetFrame, address); - } - } - } - } - - public int getFrameLevel() { - if (fActiveFrame == null) { - return -1; - } - Integer level = new TCFTask() { - 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(fExecContext.getChannel()) { - public void run() { - if (fExecContext == null) { - done(null); - return; - } - TCFDataCache 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(frame.getChannel()) { - public void run() { - if (frame != fActiveFrame) { - done(null); - return; - } - TCFDataCache 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(frame.getChannel()) { - public void run() { - if (frame != fActiveFrame) { - done(null); - return; - } - TCFDataCache 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 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 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 params = new HashMap(); - 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); - } - } - }); - 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 symbolList = new ArrayList(); - 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 = 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 = 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); - } - }); - } - - private AddressRange getAddressRange(IDisassemblyLine[] lines) { - AddressRange range = new AddressRange(); - range.start = toBigInteger(lines[0].getAddress()); - IDisassemblyLine lastLine = lines[lines.length-1]; - range.end = 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; - if (instruction.getAddress() instanceof BigInteger) { - address = (BigInteger) instruction.getAddress(); - } else { - address = BigInteger.valueOf(instruction.getAddress().longValue()); - } - 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[] 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(); - } - } - return; - } - - private FunctionOffset getFunctionOffset(BigInteger address, ISymbols.Symbol[] symbols) { - if (symbols != null) { - for (ISymbols.Symbol symbol : symbols) { - BigInteger symbolAddress = 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(toBigInteger(codeArea.start_address))) { - return codeArea; - } - } - } - return null; - } - - /** - * Format an instruction. - * - * @param instrAttrs - * @return string representation - */ - private String formatInstruction(Map[] instrAttrs) { - StringBuilder buf = new StringBuilder(20); - for (Map 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(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) { - ISourceLocator locator = fExecContext.getModel().getLaunch().getSourceLocator(); - if (locator instanceof ISourceLookupDirector) { - return ((ISourceLookupDirector)locator).getSourceElement(file); - } - } - return null; - } - - 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); - } - - private static BigInteger toBigInteger(Number address) { - if (address instanceof BigInteger) { - return (BigInteger) address; - } - return new BigInteger(address.toString()); - } - - /* - * @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; - } - -} +/******************************************************************************* + * 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 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 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() { + 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(_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(_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(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 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 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() { + 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(fExecContext.getChannel()) { + public void run() { + if (fExecContext == null) { + done(null); + return; + } + TCFDataCache 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(frame.getChannel()) { + public void run() { + if (frame != fActiveFrame) { + done(null); + return; + } + TCFDataCache 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(frame.getChannel()) { + public void run() { + if (frame != fActiveFrame) { + done(null); + return; + } + TCFDataCache 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 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 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 params = new HashMap(); + 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 symbolList = new ArrayList(); + 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[] 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[] instrAttrs) { + StringBuilder buf = new StringBuilder(20); + for (Map 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(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; + } + +} -- cgit v1.2.3