| /******************************************************************************* |
| * Copyright (c) 2007, 2016 Wind River Systems and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Wind River Systems - initial API and implementation |
| * Patrick Chuong (Texas Instruments) - Bug 315443 |
| *******************************************************************************/ |
| package org.eclipse.cdt.dsf.debug.internal.ui.disassembly.model; |
| |
| import static org.eclipse.cdt.debug.internal.ui.disassembly.dsf.DisassemblyUtils.DEBUG; |
| |
| import java.io.File; |
| import java.math.BigInteger; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.StringJoiner; |
| |
| import org.eclipse.cdt.debug.internal.ui.disassembly.dsf.AddressRangePosition; |
| import org.eclipse.cdt.debug.internal.ui.disassembly.dsf.DisassemblyPosition; |
| import org.eclipse.cdt.debug.internal.ui.disassembly.dsf.ErrorPosition; |
| import org.eclipse.cdt.debug.internal.ui.disassembly.dsf.IDisassemblyDocument; |
| import org.eclipse.cdt.debug.internal.ui.disassembly.dsf.LabelPosition; |
| import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.SourcePosition; |
| import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.text.REDDocument; |
| import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.text.REDTextStore; |
| import org.eclipse.core.resources.IStorage; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.debug.core.sourcelookup.containers.LocalFileStorage; |
| import org.eclipse.jface.text.BadLocationException; |
| import org.eclipse.jface.text.BadPositionCategoryException; |
| import org.eclipse.jface.text.DefaultLineTracker; |
| import org.eclipse.jface.text.DocumentRewriteSession; |
| import org.eclipse.jface.text.DocumentRewriteSessionType; |
| import org.eclipse.jface.text.IDocument; |
| import org.eclipse.jface.text.IRegion; |
| import org.eclipse.jface.text.Position; |
| import org.eclipse.swt.widgets.Display; |
| |
| /** |
| * DisassemblyDocument |
| */ |
| public class DisassemblyDocument extends REDDocument implements IDisassemblyDocument { |
| public final static String CATEGORY_MODEL = "category_model"; //$NON-NLS-1$ |
| public final static String CATEGORY_DISASSEMBLY = "category_disassembly"; //$NON-NLS-1$ |
| public final static String CATEGORY_SOURCE = "category_source"; //$NON-NLS-1$ |
| public final static String CATEGORY_LABELS = "category_labels"; //$NON-NLS-1$ |
| |
| /** |
| * For ease of troubleshooting, don't add or remove from this list directly. |
| * Use the add/remove methods. Note that we're not the only ones that |
| * manipulate the list. This list should be accessed only from the GUI thread |
| */ |
| private final List<AddressRangePosition> fInvalidAddressRanges = new ArrayList<>(); |
| |
| /** |
| * For ease of troubleshooting, don't add or remove from this list directly. |
| * Use the add/remove methods. Note that we're not the only ones that |
| * manipulate the list. This list should be accessed only from the GUI thread |
| */ |
| private final List<SourcePosition> fInvalidSource = new ArrayList<>(); |
| |
| private final Map<IStorage, SourceFileInfo> fFileInfoMap = new HashMap<>(); |
| |
| private int fMaxFunctionLength = 0; |
| /** Max opcode length is the maximum string length of the opcode strings */ |
| private int fMaxOpcodeLength = 0; |
| |
| private boolean fShowAddresses = false; |
| private int fRadix = 16; |
| private boolean fShowRadixPrefix = false; |
| private String fRadixPrefix; |
| private int fNumberOfDigits; |
| private boolean fShowFunctionOffset = false; |
| |
| private int fNumberOfInstructions; |
| private double fMeanSizeOfInstructions = 4; |
| |
| private long fErrorAlignment = 0x1L; |
| |
| public DisassemblyDocument() { |
| super(); |
| } |
| |
| /* |
| * @see org.eclipse.jface.text.AbstractDocument#completeInitialization() |
| */ |
| @Override |
| protected void completeInitialization() { |
| super.completeInitialization(); |
| addPositionCategory(CATEGORY_MODEL); |
| addPositionCategory(CATEGORY_DISASSEMBLY); |
| addPositionCategory(CATEGORY_SOURCE); |
| addPositionCategory(CATEGORY_LABELS); |
| setRadix(16); |
| setShowRadixPrefix(false); |
| fNumberOfInstructions = 0; |
| fMeanSizeOfInstructions = 4; |
| fMaxFunctionLength = 0; |
| } |
| |
| /** |
| * Cleanup. |
| */ |
| @Override |
| public void dispose() { |
| assert isGuiThread(); |
| |
| super.dispose(); |
| |
| // cleanup source info |
| for (Iterator<SourceFileInfo> iter = fFileInfoMap.values().iterator(); iter.hasNext();) { |
| SourceFileInfo fi = iter.next(); |
| fi.dispose(); |
| } |
| fFileInfoMap.clear(); |
| fInvalidAddressRanges.clear(); |
| fInvalidSource.clear(); |
| } |
| |
| /** |
| * Clears all content and state. |
| */ |
| public void clear() { |
| dispose(); |
| setTextStore(new REDTextStore()); |
| setLineTracker(new DefaultLineTracker()); |
| completeInitialization(); |
| } |
| |
| public AddressRangePosition[] getInvalidAddressRanges() { |
| assert isGuiThread(); |
| return fInvalidAddressRanges.toArray(new AddressRangePosition[fInvalidAddressRanges.size()]); |
| } |
| |
| public void setMaxFunctionLength(int functionLength) { |
| fMaxFunctionLength = functionLength; |
| } |
| |
| public int getMaxFunctionLength() { |
| return fMaxFunctionLength; |
| } |
| |
| public void setMaxOpcodeLength(int opcodeLength) { |
| fMaxOpcodeLength = opcodeLength; |
| } |
| |
| public int getMaxOpcodeLength() { |
| return fMaxOpcodeLength; |
| } |
| |
| public int getAddressLength() { |
| return fNumberOfDigits + 2; |
| } |
| |
| public int getMeanSizeOfInstructions() { |
| return (int) (fMeanSizeOfInstructions + .9); |
| } |
| |
| public Iterator<Position> getModelPositionIterator(BigInteger address) { |
| try { |
| return getPositionIterator(CATEGORY_MODEL, address); |
| } catch (BadPositionCategoryException e) { |
| // cannot happen |
| } |
| return null; |
| } |
| |
| public Iterator<Position> getPositionIterator(String category, int offset) throws BadPositionCategoryException { |
| List<Position> positions = getDocumentManagedPositions().get(category); |
| if (positions == null) { |
| throw new BadPositionCategoryException(); |
| } |
| int idx = computeIndexInPositionList(positions, offset, true); |
| return positions.listIterator(idx); |
| } |
| |
| public Iterator<Position> getPositionIterator(String category, BigInteger address) |
| throws BadPositionCategoryException { |
| List<Position> positions = getDocumentManagedPositions().get(category); |
| if (positions == null) { |
| throw new BadPositionCategoryException(); |
| } |
| int idx = computeIndexInPositionListFirst(positions, address); |
| return positions.listIterator(idx); |
| } |
| |
| public int computeIndexInCategory(String category, BigInteger address) throws BadPositionCategoryException { |
| List<Position> c = getDocumentManagedPositions().get(category); |
| if (c == null) { |
| throw new BadPositionCategoryException(); |
| } |
| return computeIndexInPositionListFirst(c, address); |
| } |
| |
| /** |
| * Computes the index in the list of positions at which a position with the |
| * given address would be inserted. The position is supposed to become the |
| * first in this list of all positions with the same offset. |
| * |
| * @param positions the list in which the index is computed |
| * @param address the address for which the index is computed |
| * @return the computed index |
| * |
| */ |
| protected int computeIndexInPositionListFirst(List<Position> positions, BigInteger address) { |
| int size = positions.size(); |
| if (size == 0) { |
| return 0; |
| } |
| int low = 0; |
| int high = size; |
| int mid = 0; |
| while (low < high) { |
| mid = (low + high) >>> 1; |
| AddressRangePosition range = (AddressRangePosition) positions.get(mid); |
| int compareSign = address.compareTo(range.fAddressOffset); |
| if (compareSign < 0) { |
| high = mid; |
| } else if (compareSign == 0) { |
| break; |
| } else if (address.compareTo(range.fAddressOffset.add(range.fAddressLength)) >= 0) { |
| low = mid + 1; |
| } else { |
| break; |
| } |
| } |
| |
| int idx = mid; |
| AddressRangePosition p = (AddressRangePosition) positions.get(idx); |
| if (address.compareTo(p.fAddressOffset) == 0) { |
| do { |
| --idx; |
| if (idx < 0) { |
| break; |
| } |
| p = (AddressRangePosition) positions.get(idx); |
| } while (address.compareTo(p.fAddressOffset) == 0); |
| ++idx; |
| } else if (address.compareTo(p.fAddressOffset.add(p.fAddressLength)) >= 0) { |
| ++idx; |
| } |
| return idx; |
| } |
| |
| /** |
| * Computes the index in the list of positions at which a position with the |
| * given address would be inserted. The position is supposed to become the |
| * last but one in this list of all positions with the same address. |
| * |
| * @param positions the list in which the index is computed |
| * @param address the address for which the index is computed |
| * @return the computed index |
| * |
| */ |
| protected int computeIndexInPositionListLast(List<Position> positions, BigInteger address) { |
| int size = positions.size(); |
| if (size == 0) { |
| return 0; |
| } |
| int low = 0; |
| int high = size; |
| int mid = 0; |
| while (low < high) { |
| mid = (low + high) >>> 1; |
| AddressRangePosition range = (AddressRangePosition) positions.get(mid); |
| if (address.compareTo(range.fAddressOffset) < 0) { |
| high = mid; |
| } else if (address.compareTo(range.fAddressOffset) == 0) { |
| break; |
| } else if (address.compareTo(range.fAddressOffset.add(range.fAddressLength)) >= 0) { |
| low = mid + 1; |
| } else { |
| break; |
| } |
| } |
| |
| int idx = mid; |
| AddressRangePosition p = (AddressRangePosition) positions.get(idx); |
| if (address.compareTo(p.fAddressOffset) > 0) { |
| ++idx; |
| } else if (address.compareTo(p.fAddressOffset) == 0 && p.fAddressLength.compareTo(BigInteger.ZERO) == 0) { |
| do { |
| ++idx; |
| if (idx == size) { |
| break; |
| } |
| p = (AddressRangePosition) positions.get(idx); |
| } while (address.compareTo(p.fAddressOffset) == 0 && p.fAddressLength.compareTo(BigInteger.ZERO) == 0); |
| // --idx; |
| } |
| return idx; |
| } |
| |
| /** |
| * Computes the index in the list of positions at which a position with the |
| * given offset would be inserted. The position is supposed to become the |
| * last in this list of all positions with the same offset. |
| * |
| * @param positions the list in which the index is computed |
| * @param offset the offset for which the index is computed |
| * @return the computed index |
| * |
| * @see IDocument#computeIndexInCategory(String, int) |
| * @deprecated Use {@link #computeIndexInPositionListLast(List, BigInteger)} |
| * as it is for managing lists of AddressRangePositions |
| */ |
| @Deprecated |
| protected int computeIndexInPositionListLast(List<Position> positions, int offset) { |
| if (positions.size() == 0) |
| return 0; |
| |
| int low = 0; |
| int high = positions.size() - 1; |
| int mid = 0; |
| Position p = null; |
| |
| while (low < high) { |
| mid = (low + high) >>> 1; |
| |
| p = positions.get(mid); |
| if (offset < p.getOffset()) { |
| if (low == mid) { |
| high = low; |
| } else { |
| high = mid - 1; |
| } |
| } else if (offset > p.getOffset()) { |
| if (high == mid) { |
| low = high; |
| } else { |
| low = mid + 1; |
| } |
| } else if (offset == p.getOffset()) { |
| low = high = mid; |
| } |
| } |
| |
| int pos = low; |
| p = positions.get(pos); |
| while (offset >= p.getOffset()) { |
| // entry will become the last of all entries with the same offset |
| ++pos; |
| if (pos == positions.size()) { |
| break; |
| } |
| p = positions.get(pos); |
| } |
| |
| assert 0 <= pos && pos <= positions.size(); |
| return pos; |
| } |
| |
| /** |
| * Returns the position for the supplied category and index. |
| * |
| * @param category |
| * @param index |
| * @return a Position matching the category and index, or <code>null</code>. |
| */ |
| public Position getPositionOfIndex(String category, int index) throws BadPositionCategoryException { |
| if (index >= 0) { |
| List<Position> positions = getDocumentManagedPositions().get(category); |
| if (positions == null) { |
| throw new BadPositionCategoryException(); |
| } |
| if (index < positions.size()) { |
| return positions.get(index); |
| } |
| } |
| return null; |
| } |
| |
| public AddressRangePosition getPositionOfAddress(BigInteger address) { |
| AddressRangePosition pos = getPositionOfAddress(CATEGORY_DISASSEMBLY, address); |
| return pos; |
| } |
| |
| public AddressRangePosition getPositionOfAddress(String category, BigInteger address) { |
| List<Position> positions = getDocumentManagedPositions().get(category); |
| if (positions == null) { |
| return null; |
| } |
| int index = computeIndexInPositionListFirst(positions, address); |
| if (index < positions.size()) { |
| AddressRangePosition p = (AddressRangePosition) positions.get(index); |
| if (address.compareTo(p.fAddressOffset) == 0 || p.containsAddress(address)) { |
| return p; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * @param category |
| * @param range |
| * @return |
| */ |
| public AddressRangePosition getPositionInAddressRange(String category, AddressRangePosition range) { |
| List<Position> positions = getDocumentManagedPositions().get(category); |
| if (positions == null) { |
| return null; |
| } |
| BigInteger endAddress = range.fAddressOffset.add(range.fAddressLength); |
| int index = computeIndexInPositionListFirst(positions, range.fAddressOffset); |
| if (index < positions.size()) { |
| do { |
| AddressRangePosition p = (AddressRangePosition) positions.get(index); |
| if (p.fAddressOffset.compareTo(endAddress) >= 0) { |
| --index; |
| } else { |
| return p; |
| } |
| } while (index >= 0); |
| } |
| return null; |
| } |
| |
| /** |
| * Compute the address of the given document line number. |
| * |
| * @param line |
| * @return the address of the given document line number, -1 if no valid |
| * address can be computed |
| */ |
| @Override |
| public BigInteger getAddressOfLine(int line) { |
| try { |
| int offset = getLineOffset(line); |
| return getAddressOfOffset(offset); |
| } catch (BadLocationException e) { |
| // intentionally ignored |
| } |
| return BigInteger.valueOf(-1); |
| } |
| |
| /** |
| * Compute the address off the given document offset. |
| * |
| * @param offset |
| * @return the address of the given document offset, -1 if no valid address |
| * can be computed |
| */ |
| public BigInteger getAddressOfOffset(int offset) { |
| AddressRangePosition pos; |
| try { |
| pos = getModelPosition(offset); |
| } catch (BadLocationException e) { |
| internalError(e); |
| return BigInteger.valueOf(-1); |
| } |
| if (pos == null) { |
| return BigInteger.valueOf(-1); |
| } |
| return pos.fAddressOffset; |
| } |
| |
| /** |
| * @param offset |
| * @return |
| */ |
| public AddressRangePosition getDisassemblyPosition(int offset) throws BadLocationException { |
| Position p = null; |
| try { |
| p = getPosition(CATEGORY_DISASSEMBLY, offset, false); |
| } catch (BadPositionCategoryException e) { |
| // cannot happen |
| } |
| return (AddressRangePosition) p; |
| } |
| |
| /** |
| * @param address |
| * @return |
| */ |
| @Override |
| public AddressRangePosition getDisassemblyPosition(BigInteger address) { |
| return getPositionOfAddress(CATEGORY_DISASSEMBLY, address); |
| } |
| |
| /** |
| * @param offset |
| * @return |
| * @throws BadLocationException |
| */ |
| public AddressRangePosition getModelPosition(int offset) throws BadLocationException { |
| Position p = null; |
| try { |
| p = getPosition(CATEGORY_MODEL, offset, false); |
| } catch (BadPositionCategoryException e) { |
| // cannot happen |
| } |
| return (AddressRangePosition) p; |
| } |
| |
| /** |
| * @param offset |
| * @return |
| * @throws BadLocationException |
| */ |
| public SourcePosition getSourcePosition(int offset) throws BadLocationException { |
| Position p = null; |
| try { |
| p = getPosition(CATEGORY_SOURCE, offset, true); |
| } catch (BadPositionCategoryException e) { |
| // cannot happen |
| } |
| return (SourcePosition) p; |
| } |
| |
| /** |
| * @param address |
| * @return |
| */ |
| public SourcePosition getSourcePosition(BigInteger address) { |
| return (SourcePosition) getPositionOfAddress(CATEGORY_SOURCE, address); |
| } |
| |
| /** |
| * @param address |
| * @return |
| */ |
| public LabelPosition getLabelPosition(BigInteger address) { |
| return (LabelPosition) getPositionOfAddress(CATEGORY_LABELS, address); |
| } |
| |
| /** |
| * @param range |
| * @return |
| */ |
| public SourcePosition getSourcePositionInAddressRange(AddressRangePosition range) { |
| return (SourcePosition) getPositionInAddressRange(CATEGORY_SOURCE, range); |
| } |
| |
| /** |
| * Compute document position of the given source line. |
| * |
| * @param file the file as an <code>IStorage</code> |
| * @param lineNumber the 0-based line number |
| * @return the document position or <code>null</code> |
| */ |
| public Position getSourcePosition(IStorage file, int lineNumber) { |
| SourceFileInfo info = getSourceInfo(file); |
| return getSourcePosition(info, lineNumber); |
| } |
| |
| /** |
| * Compute document position of the given source line. |
| * |
| * @param fileName the file name, may be a raw debugger path or the path to an external file |
| * @param lineNumber the 0-based line number |
| * @return the document position or <code>null</code> |
| */ |
| public Position getSourcePosition(String fileName, int lineNumber) { |
| SourceFileInfo info = getSourceInfo(fileName); |
| if (info == null) { |
| info = getSourceInfo(new LocalFileStorage(new File(fileName))); |
| } |
| return getSourcePosition(info, lineNumber); |
| } |
| |
| /** |
| * Compute document position of the given source line. |
| * |
| * @param info |
| * @param lineNumber the 0-based line number |
| * @return the document position or <code>null</code> |
| */ |
| public Position getSourcePosition(SourceFileInfo info, int lineNumber) { |
| if (info == null || info.fSource == null) { |
| return null; |
| } |
| try { |
| SourcePosition srcPos = null; |
| IRegion stmtLineRegion = info.fSource.getLineInformation(lineNumber); |
| final int lineOffset = stmtLineRegion.getOffset(); |
| final int lineLength = stmtLineRegion.getLength() + 1; |
| BigInteger stmtAddress = info.fLine2Addr[lineNumber]; |
| if (stmtAddress != null && stmtAddress.compareTo(BigInteger.ZERO) > 0) { |
| srcPos = getSourcePosition(stmtAddress); |
| } |
| if (srcPos == null) { |
| for (Iterator<Position> iterator = getPositionIterator(CATEGORY_SOURCE, 0); iterator.hasNext();) { |
| SourcePosition pos = (SourcePosition) iterator.next(); |
| if (pos.fFileInfo == info && pos.fValid && lineNumber >= pos.fLine) { |
| int baseOffset = info.fSource.getLineOffset(pos.fLine); |
| if (lineOffset + lineLength - baseOffset <= pos.length) { |
| srcPos = pos; |
| break; |
| } |
| } |
| } |
| if (srcPos == null) { |
| return null; |
| } |
| } else if (!srcPos.fValid) { |
| return null; |
| } |
| assert lineNumber >= srcPos.fLine; |
| int baseOffset = info.fSource.getLineOffset(srcPos.fLine); |
| int offset = srcPos.offset + lineOffset - baseOffset; |
| if (offset >= srcPos.offset && offset < srcPos.offset + srcPos.length) { |
| return new Position(offset, lineLength); |
| } |
| } catch (BadLocationException exc) { |
| internalError(exc); |
| } catch (BadPositionCategoryException exc) { |
| internalError(exc); |
| } |
| return null; |
| } |
| |
| /** |
| * @param category |
| * @param offset |
| * @return |
| * @throws BadPositionCategoryException |
| * @throws BadLocationException |
| */ |
| public Position getPosition(String category, int offset, boolean allowZeroLength) |
| throws BadLocationException, BadPositionCategoryException { |
| List<Position> list = getDocumentManagedPositions().get(category); |
| int idx; |
| idx = computeIndexInPositionList(list, offset, true); |
| if (idx > 0) { |
| --idx; |
| } |
| while (idx < list.size()) { |
| Position pos = list.get(idx); |
| if (pos.offset > offset) { |
| break; |
| } |
| if (pos.includes(offset)) { |
| return pos; |
| } |
| if (allowZeroLength && pos.offset == offset) { |
| return pos; |
| } |
| ++idx; |
| } |
| return null; |
| } |
| |
| /** |
| * @param pos |
| */ |
| public void addModelPosition(AddressRangePosition pos) { |
| try { |
| addPositionLast(CATEGORY_MODEL, pos); |
| } catch (BadPositionCategoryException e) { |
| // cannot happen |
| } |
| } |
| |
| /** |
| * @param pos |
| */ |
| public void addModelPositionFirst(AddressRangePosition pos) { |
| List<Position> list = getDocumentManagedPositions().get(CATEGORY_MODEL); |
| int idx; |
| idx = computeIndexInPositionListFirst(list, pos.fAddressOffset.add(pos.fAddressLength)); |
| if (idx < list.size()) { |
| AddressRangePosition nextPos = (AddressRangePosition) list.get(idx); |
| assert nextPos.fAddressOffset.compareTo(pos.fAddressOffset.add(pos.fAddressLength)) == 0; |
| } |
| list.add(idx, pos); |
| } |
| |
| /** |
| * @param pos |
| * @throws BadLocationException |
| */ |
| public void addDisassemblyPosition(AddressRangePosition pos) throws BadLocationException { |
| try { |
| addPositionLast(CATEGORY_DISASSEMBLY, pos); |
| } catch (BadPositionCategoryException e) { |
| // cannot happen |
| } |
| if (pos instanceof DisassemblyPosition) { |
| DisassemblyPosition disassPos = (DisassemblyPosition) pos; |
| int functionLength = disassPos.fFunction.length; |
| if (functionLength > fMaxFunctionLength) { |
| fMaxFunctionLength = functionLength; |
| } |
| if (disassPos.fRawOpcode != null) { |
| int opcodeLength = disassPos.fRawOpcode.length(); |
| if (opcodeLength > fMaxOpcodeLength) { |
| fMaxOpcodeLength = opcodeLength; |
| } |
| } |
| if (fNumberOfInstructions < 100 && fMeanSizeOfInstructions < 16.0) { |
| fMeanSizeOfInstructions = (fMeanSizeOfInstructions * fNumberOfInstructions |
| + pos.fAddressLength.floatValue()) / (++fNumberOfInstructions); |
| } |
| } |
| } |
| |
| /** |
| * @param pos |
| * @throws BadPositionCategoryException |
| */ |
| public void addPositionLast(String category, AddressRangePosition pos) throws BadPositionCategoryException { |
| List<Position> list = getDocumentManagedPositions().get(category); |
| if (list == null) { |
| throw new BadPositionCategoryException(); |
| } |
| if (DEBUG) |
| System.out.println("Adding position to category <" + category + "> : " + pos); //$NON-NLS-1$ //$NON-NLS-2$ |
| list.add(computeIndexInPositionListLast(list, pos.fAddressOffset), pos); |
| } |
| |
| /** |
| * @param pos |
| * @throws BadLocationException |
| */ |
| public void addLabelPosition(AddressRangePosition pos) throws BadLocationException { |
| try { |
| addPositionLast(CATEGORY_LABELS, pos); |
| } catch (BadPositionCategoryException e) { |
| // cannot happen |
| } |
| } |
| |
| /** |
| * @param pos |
| */ |
| public void addSourcePosition(AddressRangePosition pos) throws BadLocationException { |
| try { |
| addPositionLast(CATEGORY_SOURCE, pos); |
| } catch (BadPositionCategoryException e) { |
| // cannot happen |
| } |
| } |
| |
| /** |
| * @param pos |
| */ |
| public void removeDisassemblyPosition(AddressRangePosition pos) { |
| try { |
| removePosition(CATEGORY_DISASSEMBLY, pos); |
| } catch (BadPositionCategoryException e) { |
| // cannot happen |
| } |
| } |
| |
| /** |
| * @param pos |
| */ |
| public void removeSourcePosition(AddressRangePosition pos) { |
| try { |
| removePosition(CATEGORY_SOURCE, pos); |
| } catch (BadPositionCategoryException e) { |
| // cannot happen |
| } |
| } |
| |
| /** |
| * @param pos |
| */ |
| public void removeModelPosition(AddressRangePosition pos) { |
| try { |
| removePosition(getCategory(pos), pos); |
| } catch (BadPositionCategoryException e) { |
| // cannot happen |
| } |
| } |
| |
| /** |
| * @param pos |
| * @return |
| */ |
| private static String getCategory(AddressRangePosition pos) { |
| if (pos instanceof LabelPosition) { |
| return CATEGORY_LABELS; |
| } else if (pos instanceof SourcePosition) { |
| return CATEGORY_SOURCE; |
| } |
| return CATEGORY_DISASSEMBLY; |
| } |
| |
| /* |
| * @see org.eclipse.jface.text.IDocument#removePosition(java.lang.String, |
| * org.eclipse.jface.text.Position) |
| */ |
| @Override |
| public void removePosition(String category, Position position) throws BadPositionCategoryException { |
| super.removePosition(category, position); |
| |
| if (DEBUG && isOneOfOurs(category)) |
| System.out.println("Removing position from category(" + category + ") :" + position); //$NON-NLS-1$ //$NON-NLS-2$ |
| |
| if (!category.equals(CATEGORY_MODEL) && position instanceof AddressRangePosition) { |
| super.removePosition(CATEGORY_MODEL, position); |
| } |
| } |
| |
| public void removePositions(String category, List<AddressRangePosition> toRemove) { |
| if (toRemove.isEmpty()) { |
| return; |
| } |
| |
| if (DEBUG && isOneOfOurs(category)) { |
| System.out.println("Removing positions from category(" + category + ')'); //$NON-NLS-1$ |
| int i = 0; |
| for (AddressRangePosition pos : toRemove) { |
| System.out.println("[" + i++ + "] " + pos); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| } |
| |
| List<Position> positions = getDocumentManagedPositions().get(category); |
| if (positions != null) { |
| positions.removeAll(toRemove); |
| } |
| if (!category.equals(CATEGORY_MODEL)) { |
| positions = getDocumentManagedPositions().get(CATEGORY_MODEL); |
| if (positions != null) { |
| positions.removeAll(toRemove); |
| } |
| } |
| } |
| |
| /** |
| * @deprecated Use {@link #addPositionLast(String, AddressRangePosition)} |
| * instead as DissemblyDocument's lists are AddressRangePositions |
| */ |
| @Deprecated |
| public void addPositionLast(String category, Position position) |
| throws BadLocationException, BadPositionCategoryException { |
| |
| if ((0 > position.offset) || (0 > position.length) || (position.offset + position.length > getLength())) |
| throw new BadLocationException(); |
| |
| if (category == null) |
| throw new BadPositionCategoryException(); |
| |
| List<Position> list = getDocumentManagedPositions().get(category); |
| if (list == null) |
| throw new BadPositionCategoryException(); |
| |
| list.add(computeIndexInPositionListLast(list, position.offset), position); |
| } |
| |
| public void checkConsistency() { |
| AddressRangePosition last = null; |
| try { |
| for (Iterator<Position> it = getPositionIterator(CATEGORY_MODEL, 0); it.hasNext();) { |
| AddressRangePosition pos = (AddressRangePosition) it.next(); |
| if (last != null) { |
| assert last.fAddressOffset.compareTo(pos.fAddressOffset) <= 0; |
| assert last.fAddressOffset.add(last.fAddressLength).compareTo(pos.fAddressOffset) == 0; |
| assert last.offset <= pos.offset; |
| assert last.offset + last.length == pos.offset; |
| } |
| last = pos; |
| } |
| } catch (BadPositionCategoryException e) { |
| assert false; |
| } |
| } |
| |
| /** |
| * @param insertPos |
| * @param replaceLength |
| * @param text |
| * @throws BadLocationException |
| */ |
| public void replace(AddressRangePosition insertPos, int replaceLength, String text) throws BadLocationException { |
| int delta = (text != null ? text.length() : 0) - replaceLength; |
| if (delta != 0) { |
| BigInteger address = insertPos.fAddressOffset; |
| Iterator<Position> it = getModelPositionIterator(address); |
| while (it.hasNext()) { |
| AddressRangePosition pos = (AddressRangePosition) it.next(); |
| assert pos.fAddressOffset.compareTo(address) >= 0; |
| if (pos.fAddressOffset.compareTo(address) > 0) { |
| break; |
| } |
| if (pos.offset > insertPos.offset) { |
| break; |
| } |
| if (pos == insertPos) { |
| break; |
| } |
| } |
| while (it.hasNext()) { |
| AddressRangePosition pos = (AddressRangePosition) it.next(); |
| pos.offset += delta; |
| } |
| } |
| |
| if (DEBUG) { |
| String escapedText = null; |
| if (text != null) { |
| escapedText = text.replace(new StringBuilder("\n"), new StringBuilder("\\n")); //$NON-NLS-1$ //$NON-NLS-2$ |
| escapedText = escapedText.replace(new StringBuilder("\r"), new StringBuilder("\\r")); //$NON-NLS-1$ //$NON-NLS-2$ |
| escapedText = escapedText.replace(new StringBuilder("\t"), new StringBuilder("\\t")); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| System.out.println("Calling AbstractDocument.replace(" + insertPos.offset + ',' + replaceLength + ",\"" //$NON-NLS-1$//$NON-NLS-2$ |
| + escapedText + "\")"); //$NON-NLS-1$ |
| } |
| super.replace(insertPos.offset, replaceLength, text); |
| } |
| |
| /** |
| * @param pos |
| * @param insertPos |
| * @param line |
| * @throws BadPositionCategoryException |
| * @throws BadLocationException |
| */ |
| public AddressRangePosition insertAddressRange(AddressRangePosition pos, AddressRangePosition insertPos, |
| String line, boolean addToModel) throws BadLocationException { |
| assert isGuiThread(); |
| final BigInteger address = insertPos.fAddressOffset; |
| BigInteger length = insertPos.fAddressLength; |
| if (pos == null) { |
| pos = getPositionOfAddress(address); |
| } |
| assert !pos.isDeleted && !pos.fValid |
| && (length.compareTo(BigInteger.ZERO) == 0 || pos.containsAddress(address)); |
| int insertOffset; |
| int replaceLength = 0; |
| if (length.compareTo(BigInteger.ONE) > 0 |
| && !pos.containsAddress(address.add(length.subtract(BigInteger.ONE)))) { |
| // merge with successor positions |
| Iterator<Position> it = getModelPositionIterator(pos.fAddressOffset.add(pos.fAddressLength)); |
| assert it.hasNext(); |
| do { |
| AddressRangePosition overlap = (AddressRangePosition) it.next(); |
| BigInteger posEndAddress = pos.fAddressOffset.add(pos.fAddressLength); |
| assert pos.offset <= overlap.offset && overlap.fAddressOffset.compareTo(posEndAddress) == 0; |
| if (overlap instanceof LabelPosition || overlap instanceof SourcePosition) { |
| // don't override label or source positions, instead fix |
| // length of disassembly line to insert |
| length = insertPos.fAddressLength = posEndAddress.subtract(address.max(pos.fAddressOffset)); |
| break; |
| } |
| pos.fAddressLength = pos.fAddressLength.add(overlap.fAddressLength); |
| replaceLength = overlap.offset + overlap.length - pos.offset - pos.length; |
| it.remove(); |
| removeModelPosition(overlap); |
| if (!overlap.fValid) { |
| removeInvalidAddressRange(overlap); |
| } |
| } while (!pos.containsAddress(address.add(length.subtract(BigInteger.ONE)))); |
| } |
| BigInteger newEndAddress = pos.fAddressOffset.add(pos.fAddressLength); |
| BigInteger newStartAddress = address.add(length); |
| assert newEndAddress.compareTo(newStartAddress) >= 0; |
| if (address.compareTo(pos.fAddressOffset) == 0) { |
| // insert at start of range |
| insertOffset = pos.offset; |
| if (replaceLength == 0 && newEndAddress.compareTo(newStartAddress) > 0) { |
| // optimization: shrink position in place |
| pos.fAddressOffset = newStartAddress; |
| pos.fAddressLength = pos.fAddressLength.subtract(length); |
| // don't insert new pos |
| newEndAddress = newStartAddress; |
| } else { |
| replaceLength += pos.length; |
| removeInvalidAddressRange(pos); |
| removeDisassemblyPosition(pos); |
| pos = null; |
| } |
| } else { |
| // insert in mid/end of range |
| insertOffset = pos.offset + pos.length; |
| pos.fAddressLength = address.subtract(pos.fAddressOffset); |
| assert pos.fAddressLength.compareTo(BigInteger.ZERO) > 0; |
| pos = null; |
| } |
| if (newEndAddress.compareTo(newStartAddress) > 0) { |
| pos = insertInvalidAddressRange(insertOffset + replaceLength, 0, newStartAddress, newEndAddress); |
| } |
| assert pos == null |
| || pos.fAddressLength.compareTo(BigInteger.ZERO) > 0 && pos.containsAddress(address.add(length)); |
| assert insertOffset + replaceLength <= getLength(); |
| |
| insertPos.offset = insertOffset; |
| if (addToModel) { |
| addModelPosition(insertPos); |
| } |
| replace(insertPos, replaceLength, line); |
| if (DEBUG) |
| checkConsistency(); |
| return pos; |
| } |
| |
| @Override |
| public AddressRangePosition insertDisassemblyLine(AddressRangePosition pos, BigInteger address, int length, |
| String functionOffset, String instruction, String file, int lineNr) throws BadLocationException { |
| return insertDisassemblyLine(pos, address, length, functionOffset, (String) null, instruction, file, lineNr); |
| } |
| |
| @Override |
| public AddressRangePosition insertDisassemblyLine(AddressRangePosition pos, BigInteger address, int length, |
| String functionOffset, Byte[] opcode, String instruction, String file, int lineNr) |
| throws BadLocationException { |
| |
| String opcodeString = "??"; //$NON-NLS-1$ |
| if (opcode != null && opcode.length > 0) { |
| StringJoiner opcodeStringJoiner = new StringJoiner(" "); //$NON-NLS-1$ |
| for (int i = 0; i < opcode.length; i++) { |
| opcodeStringJoiner.add(String.format("%02x", //$NON-NLS-1$ |
| opcode[i].intValue() & 0xff)); |
| } |
| opcodeString = opcodeStringJoiner.toString(); |
| } |
| return insertDisassemblyLine(pos, address, length, functionOffset, opcodeString, instruction, file, lineNr); |
| } |
| |
| @Override |
| public AddressRangePosition insertDisassemblyLine(AddressRangePosition pos, BigInteger address, int length, |
| String functionOffset, String rawOpcode, String instruction, String file, int lineNr) |
| throws BadLocationException { |
| assert isGuiThread(); |
| String disassLine = null; |
| if (instruction == null || instruction.length() == 0) { |
| disassLine = ""; //$NON-NLS-1$ |
| } else { |
| disassLine = buildDisassemblyLine(address, functionOffset, instruction); |
| } |
| AddressRangePosition disassPos; |
| if (lineNr < 0) { |
| disassPos = new DisassemblyPosition(0, disassLine.length(), address, BigInteger.valueOf(length), |
| functionOffset, rawOpcode); |
| } else { |
| disassPos = new DisassemblyWithSourcePosition(0, disassLine.length(), address, BigInteger.valueOf(length), |
| functionOffset, rawOpcode, file, lineNr); |
| } |
| pos = insertAddressRange(pos, disassPos, disassLine, true); |
| addDisassemblyPosition(disassPos); |
| return pos; |
| |
| } |
| |
| /** |
| * @param address |
| * @param functionOffset |
| * @param instruction |
| */ |
| private String buildDisassemblyLine(BigInteger address, String functionOffset, String instruction) { |
| StringBuilder buf = new StringBuilder(40); |
| if (fShowAddresses) { |
| if (fRadixPrefix != null) { |
| buf.append(fRadixPrefix); |
| } |
| String str = address.toString(fRadix); |
| for (int i = str.length(); i < fNumberOfDigits; ++i) |
| buf.append('0'); |
| buf.append(str); |
| buf.append(':'); |
| buf.append(' '); |
| } |
| if (fShowFunctionOffset && functionOffset != null && !functionOffset.isEmpty()) { |
| buf.append(functionOffset); |
| int tab = 16; |
| if (functionOffset.length() >= 16) { |
| tab = (functionOffset.length() + 8) & ~7; |
| } |
| int diff = tab - functionOffset.length(); |
| while (diff-- > 0) { |
| buf.append(' '); |
| } |
| } else if (!fShowAddresses) { |
| buf.append(' '); |
| buf.append(' '); |
| } |
| int n = instruction.length(); |
| int prefixLen = buf.length(); |
| for (int j = 0; j < n; j++) { |
| char ch = instruction.charAt(j); |
| if (ch == '\t') { |
| int tab = (buf.length() - prefixLen + 8) & ~0x7; |
| do |
| buf.append(' '); |
| while (buf.length() - prefixLen < tab); |
| } else { |
| buf.append(ch); |
| } |
| } |
| buf.append('\n'); |
| return buf.toString(); |
| } |
| |
| public void setRadix(int radix) { |
| fRadix = radix; |
| fNumberOfDigits = (int) (Math.log(1L << 32) / Math.log(radix) + 0.9); |
| setShowRadixPrefix(fShowRadixPrefix); |
| } |
| |
| public void setShowRadixPrefix(boolean showRadixPrefix) { |
| fShowRadixPrefix = showRadixPrefix; |
| if (!fShowRadixPrefix) { |
| fRadixPrefix = null; |
| } else if (fRadix == 16) { |
| fRadixPrefix = "0x"; //$NON-NLS-1$ |
| } else if (fRadix == 8) { |
| fRadixPrefix = "0"; //$NON-NLS-1$ |
| } else { |
| fRadixPrefix = null; |
| } |
| } |
| |
| public AddressRangePosition insertErrorLine(AddressRangePosition pos, BigInteger address, BigInteger length, |
| String line) throws BadLocationException { |
| assert isGuiThread(); |
| int hashCode = line.hashCode(); |
| final long alignment = fErrorAlignment; |
| if (alignment > 1 && !(pos instanceof ErrorPosition)) { |
| AddressRangePosition before = getPositionOfAddress(address.subtract(BigInteger.ONE)); |
| if (before instanceof ErrorPosition && before.hashCode() == hashCode |
| && before.offset + before.length == pos.offset) { |
| assert before.fAddressOffset.add(before.fAddressLength).compareTo(address) == 0; |
| assert pos.fAddressOffset.compareTo(address) == 0; |
| // merge with previous error position |
| BigInteger pageOffset = before.fAddressOffset.and(BigInteger.valueOf(~(alignment - 1))); |
| BigInteger mergeLen = pageOffset.add(BigInteger.valueOf(alignment)) |
| .subtract((before.fAddressOffset.add(before.fAddressLength))).min(length); |
| if (mergeLen.compareTo(BigInteger.ZERO) > 0) { |
| pos.fAddressLength = pos.fAddressLength.subtract(mergeLen); |
| if (pos.fAddressLength.compareTo(BigInteger.ZERO) == 0) { |
| replace(pos, pos.length, null); |
| removeModelPosition(pos); |
| removeInvalidAddressRange(pos); |
| pos = null; |
| } else { |
| pos.fAddressOffset = pos.fAddressOffset.add(mergeLen); |
| } |
| before.fAddressLength = before.fAddressLength.add(mergeLen); |
| address = address.add(mergeLen); |
| length = length.subtract(mergeLen); |
| if (DEBUG) |
| checkConsistency(); |
| if (length.compareTo(BigInteger.ZERO) == 0) { |
| return pos; |
| } |
| } |
| } |
| AddressRangePosition after = getPositionOfAddress(address.add(length)); |
| if (after instanceof ErrorPosition && after.hashCode() == hashCode && pos != null |
| && pos.offset + pos.length == after.offset) { |
| assert after.fAddressOffset == address.add(length); |
| assert pos.fAddressOffset.add(pos.fAddressLength).compareTo(after.fAddressOffset) == 0; |
| // merge with next error position |
| BigInteger pageOffset = after.fAddressOffset.add(BigInteger.valueOf(~(alignment - 1))); |
| BigInteger mergeLen = after.fAddressOffset.subtract(pageOffset).min(length); |
| if (mergeLen.compareTo(BigInteger.ZERO) > 0) { |
| after.fAddressOffset = after.fAddressOffset.subtract(mergeLen); |
| after.fAddressLength = after.fAddressLength.add(mergeLen); |
| pos.fAddressLength = pos.fAddressLength.subtract(mergeLen); |
| if (pos.fAddressLength.compareTo(BigInteger.ZERO) == 0) { |
| replace(pos, pos.length, null); |
| removeModelPosition(pos); |
| removeInvalidAddressRange(pos); |
| pos = null; |
| } |
| if (DEBUG) |
| checkConsistency(); |
| length = length.subtract(mergeLen); |
| if (length.compareTo(BigInteger.ZERO) == 0) { |
| return pos; |
| } |
| } |
| } |
| } |
| BigInteger pageOffset = address.and(BigInteger.valueOf(~(alignment - 1))); |
| BigInteger posLen = pageOffset.add(BigInteger.valueOf(alignment)).subtract(address).min(length); |
| while (length.compareTo(BigInteger.ZERO) > 0) { |
| AddressRangePosition errorPos = new ErrorPosition(0, 0, address, posLen, hashCode); |
| String errorLine = buildDisassemblyLine(address, null, line); |
| errorPos.length = errorLine.length(); |
| pos = insertAddressRange(pos, errorPos, errorLine, true); |
| addDisassemblyPosition(errorPos); |
| if (!errorPos.fValid) { |
| addInvalidAddressRange(errorPos); |
| } |
| length = length.subtract(posLen); |
| address = address.add(posLen); |
| posLen = BigInteger.valueOf(alignment).min(length); |
| } |
| return pos; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.cdt.debug.internal.ui.disassembly.dsf.IDisassemblyDocument#insertLabel(org.eclipse.cdt.debug.internal.ui.disassembly.dsf.AddressRangePosition, java.math.BigInteger, java.lang.String, boolean) |
| */ |
| @Override |
| public AddressRangePosition insertLabel(AddressRangePosition pos, BigInteger address, String label, |
| boolean showLabels) throws BadLocationException { |
| assert isGuiThread(); |
| String labelLine = showLabels ? label + ":\n" : ""; //$NON-NLS-1$ //$NON-NLS-2$ |
| LabelPosition labelPos = getLabelPosition(address); |
| if (labelPos != null) { |
| assert labelPos.fAddressOffset.compareTo(address) == 0; |
| if (labelPos.length != labelLine.length()) { |
| int oldLength = labelPos.length; |
| labelPos.length = labelLine.length(); |
| replace(labelPos, oldLength, labelLine); |
| } |
| return pos; |
| } |
| labelPos = new LabelPosition(0, labelLine.length(), address, label); |
| pos = insertAddressRange(pos, labelPos, labelLine, true); |
| addLabelPosition(labelPos); |
| return pos; |
| } |
| |
| /** |
| * @param pos |
| * @param address |
| * @param source |
| * @param line |
| * @param endOfSource |
| * @throws BadLocationException |
| * @throws BadPositionCategoryException |
| */ |
| public SourcePosition insertSource(SourcePosition pos, String source, int line, boolean endOfSource) { |
| // System.out.println("insertSource at "+getAddressText(pos.fAddressOffset)); |
| // System.out.println(source); |
| String sourceLines = source; |
| if (!source.isEmpty() && sourceLines.charAt(source.length() - 1) != '\n') { |
| sourceLines += "\n"; //$NON-NLS-1$ |
| } |
| try { |
| assert !pos.fValid; |
| int oldLength = pos.length; |
| pos.length = sourceLines.length(); |
| pos.fLine = line; |
| pos.fValid = true; |
| removeInvalidSourcePosition(pos); |
| replace(pos, oldLength, sourceLines); |
| if (!endOfSource) { |
| if (pos.length > 0) { |
| SourcePosition oldPos = getSourcePosition(pos.offset + pos.length); |
| if (oldPos == null || oldPos.fAddressOffset.compareTo(pos.fAddressOffset) != 0) { |
| pos = new SourcePosition(pos.offset + pos.length, 0, pos.fAddressOffset, pos.fFileInfo, line, |
| pos.fLast, false); |
| addSourcePosition(pos); |
| addModelPosition(pos); |
| addInvalidSourcePositions(pos); |
| } else { |
| //TLETODO need more checks for correct source pos |
| pos = oldPos; |
| } |
| } |
| } |
| } catch (BadLocationException e) { |
| internalError(e); |
| } |
| return pos; |
| } |
| |
| /** |
| * @param pos |
| * @param address |
| * @param fi |
| * @param firstLine |
| * @param lastLine |
| * @return |
| */ |
| public AddressRangePosition insertInvalidSource(AddressRangePosition pos, BigInteger address, SourceFileInfo fi, |
| int firstLine, int lastLine) { |
| assert isGuiThread(); |
| SourcePosition sourcePos = getSourcePosition(address); |
| if (sourcePos != null) { |
| return pos; |
| } |
| String sourceLine = ""; //$NON-NLS-1$ |
| sourcePos = new SourcePosition(0, sourceLine.length(), address, fi, firstLine, lastLine, false); |
| try { |
| pos = insertAddressRange(pos, sourcePos, sourceLine, true); |
| addSourcePosition(sourcePos); |
| assert !fInvalidSource.contains(sourcePos); |
| addInvalidSourcePositions(sourcePos); |
| } catch (BadLocationException e) { |
| internalError(e); |
| } |
| return pos; |
| } |
| |
| /** |
| * @param offset |
| * @param replaceLength |
| * @param startAddress |
| * @param endAddress |
| * @return |
| */ |
| public AddressRangePosition insertInvalidAddressRange(int offset, int replaceLength, BigInteger startAddress, |
| BigInteger endAddress) { |
| assert isGuiThread(); |
| String periods = "...\n"; //$NON-NLS-1$ |
| AddressRangePosition newPos = new AddressRangePosition(offset, periods.length(), startAddress, |
| endAddress.subtract(startAddress), false); |
| try { |
| addModelPositionFirst(newPos); |
| replace(newPos, replaceLength, periods); |
| addDisassemblyPosition(newPos); |
| addInvalidAddressRange(newPos); |
| } catch (BadLocationException e) { |
| internalError(e); |
| } |
| return newPos; |
| } |
| |
| public void invalidateAddressRange(BigInteger startAddress, BigInteger endAddress, boolean collapse) { |
| deleteDisassemblyRange(startAddress, endAddress, true, collapse); |
| } |
| |
| public void deleteDisassemblyRange(BigInteger startAddress, BigInteger endAddress, boolean invalidate, |
| boolean collapse) { |
| assert isGuiThread(); |
| DocumentRewriteSession session = startRewriteSession(DocumentRewriteSessionType.STRICTLY_SEQUENTIAL); |
| try { |
| String replacement = invalidate ? "...\n" : null; //$NON-NLS-1$ |
| int replaceLen = replacement != null ? replacement.length() : 0; |
| AddressRangePosition lastPos = null; |
| ArrayList<AddressRangePosition> toRemove = new ArrayList<>(); |
| Iterator<Position> it = getModelPositionIterator(startAddress); |
| while (it.hasNext()) { |
| AddressRangePosition pos = (AddressRangePosition) it.next(); |
| BigInteger posEndAddress = pos.fAddressOffset.add(pos.fAddressLength); |
| if (pos instanceof LabelPosition) { |
| if (!invalidate && pos.length > 0 && posEndAddress.compareTo(endAddress) > 0) { |
| try { |
| int oldLength = pos.length; |
| pos.length = 0; |
| replace(pos, oldLength, null); |
| } catch (BadLocationException e) { |
| internalError(e); |
| } |
| } |
| pos = null; |
| } else if (pos instanceof SourcePosition) { |
| pos = null; |
| } else if (pos instanceof ErrorPosition) { |
| pos = null; |
| } else if (pos instanceof DisassemblyPosition) { |
| // optimization: join adjacent positions |
| if (collapse && lastPos != null && (invalidate || lastPos.fValid == pos.fValid) |
| && lastPos.offset + lastPos.length == pos.offset) { |
| assert lastPos.fAddressOffset.add(lastPos.fAddressLength).compareTo(pos.fAddressOffset) == 0; |
| lastPos.length += pos.length; |
| lastPos.fAddressLength = lastPos.fAddressLength.add(pos.fAddressLength); |
| toRemove.add(pos); |
| if (!pos.fValid) { |
| removeInvalidAddressRange(pos); |
| } |
| pos = null; |
| if (posEndAddress.compareTo(endAddress) < 0) { |
| continue; |
| } |
| } |
| } |
| if (lastPos != null) { |
| try { |
| if (lastPos.length > 0 || replaceLen > 0) { |
| int oldLength = lastPos.length; |
| lastPos.length = replaceLen; |
| replace(lastPos, oldLength, replacement); |
| } |
| } catch (BadLocationException e) { |
| internalError(e); |
| } |
| } |
| if (pos == null && posEndAddress.compareTo(endAddress) >= 0) { |
| break; |
| } |
| lastPos = null; |
| if (pos != null) { |
| if (pos.fValid && invalidate) { |
| pos.fValid = false; |
| addInvalidAddressRange(pos); |
| } |
| lastPos = pos; |
| } |
| } |
| removePositions(CATEGORY_DISASSEMBLY, toRemove); |
| } finally { |
| stopRewriteSession(session); |
| } |
| if (DEBUG) |
| checkConsistency(); |
| } |
| |
| public void invalidateSource() { |
| assert isGuiThread(); |
| Iterator<Position> it; |
| try { |
| it = getPositionIterator(CATEGORY_SOURCE, 0); |
| } catch (BadPositionCategoryException e) { |
| internalError(e); |
| return; |
| } |
| while (it.hasNext()) { |
| SourcePosition srcPos = (SourcePosition) it.next(); |
| if (srcPos != null && srcPos.fValid) { |
| srcPos.fValid = false; |
| assert !fInvalidSource.contains(srcPos); |
| addInvalidSourcePositions(srcPos); |
| } |
| } |
| } |
| |
| public SourcePosition[] getInvalidSourcePositions() { |
| assert isGuiThread(); |
| return fInvalidSource.toArray(new SourcePosition[fInvalidSource.size()]); |
| } |
| |
| public boolean addInvalidSourcePositions(SourcePosition srcPos) { |
| assert isGuiThread(); |
| if (DEBUG) |
| System.out.println("Adding invalid source position to list: " + srcPos); //$NON-NLS-1$ |
| return fInvalidSource.add(srcPos); |
| } |
| |
| public boolean removeInvalidSourcePosition(SourcePosition srcPos) { |
| assert isGuiThread(); |
| if (DEBUG) |
| System.out.println("Removing invalid source position from list: " + srcPos); //$NON-NLS-1$ |
| return fInvalidSource.remove(srcPos); |
| } |
| |
| public boolean hasInvalidSourcePositions() { |
| assert isGuiThread(); |
| return !fInvalidSource.isEmpty(); |
| } |
| |
| public void invalidateDisassemblyWithSource(boolean removeDisassembly) { |
| for (Iterator<SourceFileInfo> it = fFileInfoMap.values().iterator(); it.hasNext();) { |
| SourceFileInfo info = it.next(); |
| if (info.fLine2Addr != null) { |
| deleteDisassemblyRange(info.fStartAddress, info.fEndAddress.add(BigInteger.ONE), !removeDisassembly, |
| !removeDisassembly); |
| } |
| } |
| } |
| |
| /** |
| * @param start |
| * @param end |
| * @throws BadLocationException |
| */ |
| public void deleteLineRange(int start, int end) throws BadLocationException { |
| assert isGuiThread(); |
| if (start >= end) { |
| return; |
| } |
| int startOffset = getLineOffset(start); |
| int endOffset = getLineOffset(end); |
| int replaceLength = 0; |
| AddressRangePosition startPos = getDisassemblyPosition(startOffset); |
| if (startPos == null) { |
| return; |
| } |
| startOffset = startPos.offset; |
| AddressRangePosition endPos = getDisassemblyPosition(endOffset); |
| if (endPos == null) { |
| return; |
| } |
| BigInteger startAddress = BigInteger.ZERO; |
| BigInteger addressLength = BigInteger.ZERO; |
| ArrayList<AddressRangePosition> toRemove = new ArrayList<>(); |
| try { |
| Iterator<Position> it = getPositionIterator(DisassemblyDocument.CATEGORY_MODEL, startAddress); |
| while (it.hasNext()) { |
| AddressRangePosition p = (AddressRangePosition) it.next(); |
| addressLength = addressLength.add(p.fAddressLength); |
| replaceLength += p.length; |
| toRemove.add(p); |
| if (!p.fValid) { |
| if (p instanceof SourcePosition) { |
| removeInvalidSourcePosition((SourcePosition) p); |
| } else { |
| removeInvalidAddressRange(p); |
| } |
| } |
| if (addressLength.compareTo(BigInteger.ZERO) > 0 |
| && p.fAddressOffset.compareTo(endPos.fAddressOffset) >= 0) { |
| break; |
| } |
| } |
| } catch (BadPositionCategoryException e) { |
| // cannot happen |
| } |
| for (Iterator<AddressRangePosition> iter = toRemove.iterator(); iter.hasNext();) { |
| AddressRangePosition pos = iter.next(); |
| removeModelPosition(pos); |
| } |
| if (addressLength.compareTo(BigInteger.ZERO) > 0) { |
| insertInvalidAddressRange(startOffset, replaceLength, startAddress, startAddress.add(addressLength)); |
| } |
| } |
| |
| public SourceFileInfo getSourceInfo(BigInteger address) { |
| AddressRangePosition pos = getDisassemblyPosition(address); |
| if (pos instanceof DisassemblyPosition) { |
| DisassemblyPosition disassPos = (DisassemblyPosition) pos; |
| return getSourceInfo(disassPos.getFile()); |
| } |
| return null; |
| } |
| |
| public SourceFileInfo getSourceInfo(String file) { |
| if (fFileInfoMap == null || file == null) { |
| return null; |
| } |
| for (Iterator<SourceFileInfo> iter = fFileInfoMap.values().iterator(); iter.hasNext();) { |
| SourceFileInfo info = iter.next(); |
| if (file.equals(info.fFileKey)) { |
| return info; |
| } |
| } |
| return getSourceInfo(new Path(file)); |
| } |
| |
| public SourceFileInfo getSourceInfo(IPath file) { |
| if (fFileInfoMap == null || file == null) { |
| return null; |
| } |
| for (Iterator<SourceFileInfo> iter = fFileInfoMap.values().iterator(); iter.hasNext();) { |
| SourceFileInfo info = iter.next(); |
| if (file.equals(new Path(info.fFileKey))) { |
| return info; |
| } |
| } |
| return null; |
| } |
| |
| public SourceFileInfo getSourceInfo(IStorage sourceElement) { |
| if (fFileInfoMap == null) { |
| return null; |
| } |
| SourceFileInfo fi = fFileInfoMap.get(sourceElement); |
| return fi; |
| } |
| |
| public SourceFileInfo createSourceInfo(String fileKey, IStorage sourceElement, Runnable done) { |
| SourceFileInfo fi = new SourceFileInfo(fileKey, sourceElement); |
| assert fFileInfoMap != null; |
| if (fFileInfoMap != null) { |
| fFileInfoMap.put(sourceElement, fi); |
| new SourceReadingJob(fi, done); |
| } |
| return fi; |
| } |
| |
| private void internalError(Throwable e) { |
| if (DEBUG) { |
| System.err.println("Disassembly: Internal error"); //$NON-NLS-1$ |
| e.printStackTrace(); |
| } |
| } |
| |
| @Override |
| public void addInvalidAddressRange(AddressRangePosition pos) { |
| assert isGuiThread(); |
| if (DEBUG) |
| System.out.println("Adding to invalid range list: " + pos); //$NON-NLS-1$ |
| fInvalidAddressRanges.add(pos); |
| } |
| |
| public void removeInvalidAddressRanges(Collection<AddressRangePosition> positions) { |
| assert isGuiThread(); |
| if (DEBUG) { |
| for (AddressRangePosition pos : positions) |
| System.out.println("Removing from invalid range list: " + pos); //$NON-NLS-1$ |
| } |
| fInvalidAddressRanges.removeAll(positions); |
| } |
| |
| public void removeInvalidAddressRange(AddressRangePosition pos) { |
| assert isGuiThread(); |
| if (DEBUG) |
| System.out.println("Removing from invalid range list: " + pos); //$NON-NLS-1$ |
| fInvalidAddressRanges.remove(pos); |
| } |
| |
| private static boolean isGuiThread() { |
| return Display.getCurrent() != null; |
| } |
| |
| private static boolean isOneOfOurs(String category) { |
| return category.equals(CATEGORY_MODEL) || category.equals(CATEGORY_DISASSEMBLY) |
| || category.equals(CATEGORY_LABELS) || category.equals(CATEGORY_SOURCE); |
| } |
| } |