From f2ff4a73e03b55ee69b3851184e77702b3c7e890 Mon Sep 17 00:00:00 2001 From: Randy Rohrbach Date: Fri, 30 Jul 2010 21:40:46 +0000 Subject: [PATCH] Bug 315020 - The Memory Browser Find/Replace logic prefetchs data outside the specified memory range. Bug 321407 - "Case Insensitive" option is supposed to be disabled while the searching format is Hex/decimal/octal/binary. Bug 321408 - Setting "Direction-->Backward" of "Find/Replace Memory" dialog can not find memory address one by one in Memory view. --- .../ui/memory/search/FindReplaceDialog.java | 256 +++++++++++++++--- .../search/MemorySearchResultsPage.java | 143 +++------- 2 files changed, 266 insertions(+), 133 deletions(-) diff --git a/memory/org.eclipse.cdt.debug.ui.memory.search/src/org/eclipse/cdt/debug/ui/memory/search/FindReplaceDialog.java b/memory/org.eclipse.cdt.debug.ui.memory.search/src/org/eclipse/cdt/debug/ui/memory/search/FindReplaceDialog.java index 845ae9eed61..b44a93ff497 100644 --- a/memory/org.eclipse.cdt.debug.ui.memory.search/src/org/eclipse/cdt/debug/ui/memory/search/FindReplaceDialog.java +++ b/memory/org.eclipse.cdt.debug.ui.memory.search/src/org/eclipse/cdt/debug/ui/memory/search/FindReplaceDialog.java @@ -63,7 +63,7 @@ public class FindReplaceDialog extends SelectionDialog private IMemoryBlockExtension fMemoryBlock; - final static int preFetchSize = 10 * 1024; + final static int preFetchSize = 20 * 1024; private Text fFindText; private Text fReplaceText; @@ -98,7 +98,8 @@ public class FindReplaceDialog extends SelectionDialog protected final static String SEARCH_REPLACE = "SEARCH_REPLACE"; //$NON-NLS-1$ protected final static String SEARCH_START = "SEARCH_START"; //$NON-NLS-1$ protected final static String SEARCH_END = "SEARCH_END"; //$NON-NLS-1$ - protected final static String SEARCH_LAST_FOUND = "SEARCH_LAST_FOUND"; //$NON-NLS-1$ + protected final static String SEARCH_LAST_START = "SEARCH_LAST_START"; //$NON-NLS-1$ + protected final static String SEARCH_LAST_END = "SEARCH_LAST_END"; //$NON-NLS-1$ protected final static String SEARCH_FORMAT = "SEARCH_FORMAT"; //$NON-NLS-1$ protected final static String SEARCH_FORMAT_ASCII = "SEARCH_FORMAT_ASCII"; //$NON-NLS-1$ protected final static String SEARCH_FORMAT_HEX = "SEARCH_FORMAT_HEX"; //$NON-NLS-1$ @@ -705,6 +706,7 @@ public class FindReplaceDialog extends SelectionDialog fCaseInSensitiveCheckbox = new Button(optionsGroup, SWT.CHECK); fCaseInSensitiveCheckbox.setText(Messages.getString("FindReplaceDialog.ButtonCaseInsensitive")); //$NON-NLS-1$ + fCaseInSensitiveCheckbox.setEnabled(format.equals(SEARCH_FORMAT_ASCII)); fFormatAsciiButton.addSelectionListener(new SelectionListener() { @@ -802,26 +804,212 @@ public class FindReplaceDialog extends SelectionDialog MemoryByte memoryCacheData[] = new MemoryByte[0]; } - MemoryByte[] getBytesFromAddress(final BigInteger address, final int length, FindReplaceMemoryCache cache) - throws DebugException + /** + * Function : getSearchableBytes + * + * This function returns to the user an array of memory + * @param start Address ( inclusive ) of the beginning byte of the memory region to be searched + * @param end Address ( inclusive ) of the ending + * @param forwardSearch direction of the search ( true == searching forward , false = searching backwards + * @param address Address ( inclusive ) of the byte set being requested/returned + * @param length Number of bytes of data to be returned + * @param cache Cached memory byte data ( this routine fetches additional bytes of memory to try and reduce interaction with the debug engine ) + * @return MemoryByte[] array which contains the requested bytes + * @throws DebugException + */ + private MemoryByte[] getSearchableBytes(BigInteger start, BigInteger end, boolean forwardSearch, BigInteger address, int length, FindReplaceMemoryCache cache) throws DebugException { - if(! (address.compareTo(cache.memoryCacheStartAddress) >= 0 - && address.add(BigInteger.valueOf(length)).compareTo(cache.memoryCacheStartAddress - .add(BigInteger.valueOf(cache.memoryCacheData.length))) < 0)) + BigInteger endCacheAddress = cache.memoryCacheStartAddress.add(BigInteger.valueOf(cache.memoryCacheData.length)); + + /* + * Determine if the requested data is already within the cache. + */ + + if( ! ( ( address.compareTo(cache.memoryCacheStartAddress) >= 0 ) && + ( address.add(BigInteger.valueOf(length)).compareTo(endCacheAddress) < 0 ) ) ) { - BigInteger fetchAddress = address.subtract(BigInteger.valueOf(preFetchSize)); - if(fetchAddress.compareTo(BigInteger.ZERO) < 0) // TODO replace ZERO with address space start - fetchAddress = BigInteger.ZERO; - - MemoryByte bytes[] = fMemoryBlock.getBytesFromAddress(fetchAddress, preFetchSize * 2); - + BigInteger prefetchSize = BigInteger.valueOf(preFetchSize); + BigInteger len = BigInteger.valueOf(length); + BigInteger fetchAddress = address; + BigInteger fetchSize; + + /* + * Determine which way we are searching. Whichever way we are searching we need to make sure + * we capture the minimum requested amount of data in the forward direction. + */ + + if ( forwardSearch ) { + /* + * Legend : "#" == minimum requested data , "*" == additional data we want to prefetch/cache + * + * This is the best case where everything cleanly fits within the starting/ending ranges + * to be searched. What we cannot do is to fetch data outside of these ranges. The user + * has specified them, if they are in error that is OK, but we must respect the boundaries + * they specified. + * + * +-- address + * | + * +--length--+--prefetch--+------------------------------------+ + * |##########|************| | + * |##########|************| | + * |##########|************| | + * +----------+------------+------------------------------------+ + * | | + * +-- start end --+ + * + * This is the worst case scenario. We cannot even get the requested minimum ( no matter + * the desired prefetch ) before we run out of the specified range. + * + * +-- address + * | + * +----------------------------------------------------+--length--+--prefetch--+ + * | |##########|************| + * | |##########|************| + * | |##########|************| + * +----------------------------------------------------+-------+--+------------+ + * | | + * +-- start end --+ + * + * See if the desired size ( minimum length + desired prefetch ) fits in to the current range. + * If so there is nothing to adjust. + */ + + if ( prefetchSize.compareTo(len) >= 0 ) { + fetchSize = prefetchSize; + } + else { + fetchSize = len; + } + + if ( address.add( fetchSize ).compareTo(end) > 0 ) { + /* + * It does not all fit. Get as much as we can ( end - current ) + 1. + */ + fetchSize = end.subtract(address).add(BigInteger.ONE); + + /* + * If the amount of data we can get does not even meet the minimum request. In this case + * we have to readjust how much we copy to match what we can actually read. If we do not + * do this then we will run past the actual data fetched and generate an exception. + */ + if ( fetchSize.compareTo(len) < 0 ) { + length = fetchSize.intValue(); + } + } + + /* + * The fetch address just starts at the current requested location since we are searching in + * the forward direction and thus prefetching in the forward direction. + */ + fetchAddress = address; + } + else { + + /* + * Legend : "#" == minimum requested data , "*" == additional data we want to prefetch/cache + * + * This is the best case where everything cleanly fits within the starting/ending ranges + * to be searched. What we cannot do is to fetch data outside of these ranges. The user + * has specified them, if they are in error that is OK, but we must respect the boundaries + * they specified. + * + * +-- address + * | + * +--prefetch--+--length--+------------------------------------+ + * |************|##########| | + * |************|##########| | + * |************|##########| | + * +------------+----------+------------------------------------+ + * | | + * +-- start end --+ + * + * This is the second worst case scenario. We cannot even get the requested minimum ( no matter + * the desired prefetch ) before we run out of the specified range. + * + * +-- address + * | + * +--------------------------------------------+--prefetch--+--length--+ + * | |************|##########| + * | |************|##########| + * | |************|##########| + * +--------------------------------------------+------------+--+-------+ + * | | + * +-- start end --+ + * + * This is the worst case scenario. The minimum length moves us off the end of the high range + * end and the prefetch before this minimum data request ( remember we are fetching backwards + * since we are searching backwards ) runs us off the start of the data. + * + * +-- address + * | + * +---+-----------------------------------------------prefetch--+--length--+ + * |*************************************************************|##########| + * |*************************************************************|##########| + * |*************************************************************|##########| + * +---+---------------------------------------------------------+--+-------+ + * | | + * +-- start end --+ + * + * See if the desired size ( minimum length + desired prefetch ) fits in to the current range. + * Without running off the end. + */ + if ( address.add(len).compareTo(end) > 0 ) { + /* + * We need to reduce the amount we can ask for to whats left. Also make sure to reduce the + * amount to copy, otherwise we will overrun the buffer and generate an exception. + */ + len = end.subtract(address).add(BigInteger.ONE); + length = len.intValue(); + } + + /* + * Now determine if the prefetch is going to run backwards past the "start" of where we are allowed + * to access the memory. We will normalize the prefetch size so it takes in to account the amount of + * data being gathered as part of the length requested portion. This should insure that in the end + * we will request the prefetch amount of data unless there is not enough to service this request. + */ + if ( len.compareTo(prefetchSize) > 0 ) { + prefetchSize = BigInteger.ZERO; + } + else { + prefetchSize = prefetchSize.subtract(len); + } + + if ( address.subtract(prefetchSize).compareTo(start) < 0) { + /* + * Just get what we can from the beginning up to the current required address. + */ + prefetchSize = address.subtract(start); + fetchAddress = start; + } + else { + /* + * It fits so just start reading from the calculated position prior to the requested point. + */ + fetchAddress = address.subtract(prefetchSize); + } + + fetchSize = len.add(prefetchSize); + } + + /* + * OK, we have determined where to start reading the data and how much. Just get the data + * and store it in the cache. + */ + MemoryByte bytes[] = fMemoryBlock.getBytesFromAddress(fetchAddress, fetchSize.longValue()); + cache.memoryCacheStartAddress = fetchAddress; cache.memoryCacheData = bytes; } - + + /* + * Either it was already cached or just has been, either way we have the data so copy what we can + * back to the user buffer. + */ + MemoryByte bytes[] = new MemoryByte[length]; - System.arraycopy(cache.memoryCacheData, address.subtract(cache.memoryCacheStartAddress).intValue(), - bytes, 0, length); + System.arraycopy(cache.memoryCacheData, address.subtract(cache.memoryCacheStartAddress).intValue(), bytes, 0, length); + return bytes; } @@ -837,28 +1025,21 @@ public class FindReplaceDialog extends SelectionDialog { try { - BigInteger start = parseHexBigInteger(fProperties.getProperty(SEARCH_LAST_FOUND)); - BigInteger end = parseHexBigInteger(fProperties.getProperty(SEARCH_END)); + BigInteger start = parseHexBigInteger(fProperties.getProperty(SEARCH_LAST_START)); + BigInteger end = parseHexBigInteger(fProperties.getProperty(SEARCH_LAST_END)); boolean searchForward = Boolean.parseBoolean(fProperties.getProperty(SEARCH_FORMAT_FORWARD, Boolean.FALSE.toString())); boolean caseInSensitive = Boolean.parseBoolean(fProperties.getProperty(SEARCH_FORMAT_CASEINSENSTIVE, Boolean.FALSE.toString())); - if(searchForward) - start = start.add(BigInteger.ONE); - else - start = start.subtract(BigInteger.ONE); SearchPhrase phrase = null; String findText = fProperties.getProperty(SEARCH_FIND); if(fProperties.getProperty(SEARCH_FORMAT).equals(SEARCH_FORMAT_ASCII)) phrase = new AsciiSearchPhrase(findText, caseInSensitive); else if(fProperties.getProperty(SEARCH_FORMAT).equals(SEARCH_FORMAT_HEX)) - phrase = new BigIntegerSearchPhrase(new BigInteger(findText.toUpperCase().startsWith("0X") //$NON-NLS-1$ - ? findText.substring(2) : findText, 16), 16); + phrase = new BigIntegerSearchPhrase(new BigInteger(findText.toUpperCase().startsWith("0X") ? findText.substring(2) : findText, 16), 16); //$NON-NLS-1$ else if(fProperties.getProperty(SEARCH_FORMAT).equals(SEARCH_FORMAT_OCTAL)) - phrase = new BigIntegerSearchPhrase(new BigInteger(findText.startsWith("0") //$NON-NLS-1$ - ? findText.substring(1) : findText, 8), 8); + phrase = new BigIntegerSearchPhrase(new BigInteger(findText.startsWith("0") ? findText.substring(1) : findText, 8), 8); //$NON-NLS-1$ else if(fProperties.getProperty(SEARCH_FORMAT).equals(SEARCH_FORMAT_BINARY)) - phrase = new BigIntegerSearchPhrase(new BigInteger(findText.toUpperCase().startsWith("0B") //$NON-NLS-1$ - ? findText.substring(2) : findText, 2), 2); + phrase = new BigIntegerSearchPhrase(new BigInteger(findText.toUpperCase().startsWith("0B") ? findText.substring(2) : findText, 2), 2); //$NON-NLS-1$ else if(fProperties.getProperty(SEARCH_FORMAT).equals(SEARCH_FORMAT_DECIMAL)) phrase = new BigIntegerSearchPhrase(new BigInteger(findText, 10), 10); else if(fProperties.getProperty(SEARCH_FORMAT).equals(SEARCH_FORMAT_BYTESEQUENCE)) @@ -902,10 +1083,10 @@ public class FindReplaceDialog extends SelectionDialog throws OperationCanceledException { final BigInteger searchPhraseLength = BigInteger.valueOf(searchPhrase.getByteLength()); - BigInteger range = start.subtract(end); + BigInteger range = end.subtract(start).add(BigInteger.ONE); BigInteger currentPosition = searchForward ? start : end.subtract(searchPhraseLength); - if ( range.compareTo(searchPhraseLength) >= 0 ) { + if ( searchPhraseLength.compareTo(range) >= 0 ) { return Status.OK_STATUS; } @@ -933,7 +1114,7 @@ public class FindReplaceDialog extends SelectionDialog { try { - MemoryByte bytes[] = getBytesFromAddress(currentPosition, searchPhraseLength.intValue(), cache); + MemoryByte bytes[] = getSearchableBytes(start, end, searchForward, currentPosition, searchPhraseLength.intValue(), cache); matched = searchPhrase.isMatch(bytes); if(matched) { @@ -963,6 +1144,8 @@ public class FindReplaceDialog extends SelectionDialog if(matched && !all) { final BigInteger finalCurrentPosition = currentPosition; + final BigInteger finalStart = start ; + final BigInteger finalEnd = end; Display.getDefault().asyncExec(new Runnable(){ public void run() { @@ -995,7 +1178,16 @@ public class FindReplaceDialog extends SelectionDialog }); fProperties.setProperty(SEARCH_ENABLE_FIND_NEXT, Boolean.TRUE.toString()); - fProperties.setProperty(SEARCH_LAST_FOUND, "0x" + finalCurrentPosition.toString(16)); //$NON-NLS-1$ + if ( searchForward ) { + BigInteger newFinalStart = finalCurrentPosition.add(BigInteger.ONE); + fProperties.setProperty(SEARCH_LAST_START, "0x" + newFinalStart.toString(16)); //$NON-NLS-1$ + fProperties.setProperty(SEARCH_LAST_END, "0x" + finalEnd.toString(16)); //$NON-NLS-1$ + } + else { + BigInteger newFinalEnd = finalCurrentPosition.subtract(BigInteger.ONE); + fProperties.setProperty(SEARCH_LAST_START, "0x" + finalStart.toString(16)); //$NON-NLS-1$ + fProperties.setProperty(SEARCH_LAST_END, "0x" + newFinalEnd.toString(16)); //$NON-NLS-1$ + } if ( fFindAction != null ) { fFindAction.setEnabled(true); } diff --git a/memory/org.eclipse.cdt.debug.ui.memory.search/src/org/eclipse/cdt/debug/ui/memory/search/MemorySearchResultsPage.java b/memory/org.eclipse.cdt.debug.ui.memory.search/src/org/eclipse/cdt/debug/ui/memory/search/MemorySearchResultsPage.java index d1779ffd24c..06f001492a5 100644 --- a/memory/org.eclipse.cdt.debug.ui.memory.search/src/org/eclipse/cdt/debug/ui/memory/search/MemorySearchResultsPage.java +++ b/memory/org.eclipse.cdt.debug.ui.memory.search/src/org/eclipse/cdt/debug/ui/memory/search/MemorySearchResultsPage.java @@ -54,22 +54,11 @@ public class MemorySearchResultsPage extends Page implements ISearchResultPage, private ISearchResultViewPart fPart; - public void queryAdded(ISearchQuery query) { - - } - - public void queryFinished(ISearchQuery query) { - - } - - public void queryRemoved(ISearchQuery query) { - - } - - public void queryStarting(ISearchQuery query) { - - } - + public void queryAdded(ISearchQuery query) {} + public void queryFinished(ISearchQuery query) {} + public void queryRemoved(ISearchQuery query) {} + public void queryStarting(ISearchQuery query) {} + public String getID() { return MemorySearchPlugin.getUniqueIdentifier(); @@ -87,26 +76,14 @@ public class MemorySearchResultsPage extends Page implements ISearchResultPage, return fTreeViewer.getSelection(); } - public void restoreState(IMemento memento) { - - - } - - public void saveState(IMemento memento) { - - - } - - public void setID(String id) { - - - } + public void restoreState(IMemento memento) {} + public void saveState(IMemento memento) {} + public void setID(String id) {} public void setInput(ISearchResult search, Object uiState) { - if(search instanceof MemorySearchResult) + if(search instanceof MemorySearchResult) { ((MemorySearchResult) search).addListener(new ISearchResultListener() { - public void searchResultChanged(SearchResultEvent e) { Display.getDefault().asyncExec(new Runnable() { public void run() @@ -114,11 +91,9 @@ public class MemorySearchResultsPage extends Page implements ISearchResultPage, fTreeViewer.refresh(); } }); - } - }); - + } } public void setViewPart(ISearchResultViewPart part) { @@ -135,10 +110,7 @@ public class MemorySearchResultsPage extends Page implements ISearchResultPage, fTreeViewer.setContentProvider(new ITreeContentProvider() { - public void dispose() { - - - } + public void dispose() {} public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { @@ -166,7 +138,6 @@ public class MemorySearchResultsPage extends Page implements ISearchResultPage, return ((MemorySearchResult) fQuery.getSearchResult()).getMatches(); } } - }); fTreeViewer.setInput(new Object()); @@ -177,41 +148,38 @@ public class MemorySearchResultsPage extends Page implements ISearchResultPage, { IMemoryRenderingContainer containers[] = ((IMemorySearchQuery) fQuery).getMemoryView().getMemoryRenderingContainers(); MemoryMatch match = (MemoryMatch) ((StructuredSelection) event.getSelection()).getFirstElement(); - for(int i = 0; i < containers.length; i++) - { - IMemoryRendering rendering = containers[i].getActiveRendering(); - if(rendering instanceof IRepositionableMemoryRendering) + if ( match != null ) { + for(int i = 0; i < containers.length; i++) { - try { - ((IRepositionableMemoryRendering) rendering).goToAddress(match.getStartAddress()); - } catch (DebugException e) { - MemorySearchPlugin.logError(Messages.getString("MemorySearchResultsPage.RepositioningMemoryViewFailed"), e); //$NON-NLS-1$ + IMemoryRendering rendering = containers[i].getActiveRendering(); + if(rendering instanceof IRepositionableMemoryRendering) + { + try { + ((IRepositionableMemoryRendering) rendering).goToAddress(match.getStartAddress()); + } catch (DebugException e) { + MemorySearchPlugin.logError(Messages.getString("MemorySearchResultsPage.RepositioningMemoryViewFailed"), e); //$NON-NLS-1$ + } } - } - - if(rendering != null) - { - // Temporary, until platform accepts/adds new interface for setting the selection - try { - Method m = rendering.getClass().getMethod("setSelection", new Class[] { BigInteger.class, BigInteger.class } ); //$NON-NLS-1$ - if(m != null) - m.invoke(rendering, match.getStartAddress(), match.getEndAddress()); - } catch (Exception e) { - // do nothing + + if(rendering != null) + { + // Temporary, until platform accepts/adds new interface for setting the selection + try { + Method m = rendering.getClass().getMethod("setSelection", new Class[] { BigInteger.class, BigInteger.class } ); //$NON-NLS-1$ + if(m != null) + m.invoke(rendering, match.getStartAddress(), match.getEndAddress()); + } catch (Exception e) { + // do nothing + } } } } } } - }); + fTreeViewer.setLabelProvider(new ILabelProvider() { - public Image getImage(Object element) { - - return null; - } - public String getText(Object element) { if(element instanceof MemoryMatch) return "0x" + ((MemoryMatch) element).getStartAddress().toString(16); //$NON-NLS-1$ @@ -219,26 +187,11 @@ public class MemorySearchResultsPage extends Page implements ISearchResultPage, return element.toString(); } - public void addListener(ILabelProviderListener listener) { - - - } - - public void dispose() { - - - } - - public boolean isLabelProperty(Object element, String property) { - - return false; - } - - public void removeListener(ILabelProviderListener listener) { - - - } - + public Image getImage(Object element) { return null; } + public void addListener(ILabelProviderListener listener) {} + public void dispose() {} + public boolean isLabelProperty(Object element, String property) { return false; } + public void removeListener(ILabelProviderListener listener) {} }); fQueryListener = createQueryListener(); @@ -250,9 +203,7 @@ public class MemorySearchResultsPage extends Page implements ISearchResultPage, private IQueryListener createQueryListener() { return new IQueryListener() { - public void queryAdded(ISearchQuery query) { - // ignore - } + public void queryAdded(ISearchQuery query) {} public void queryRemoved(ISearchQuery query) { queryStarting(query); @@ -272,9 +223,7 @@ public class MemorySearchResultsPage extends Page implements ISearchResultPage, }); } - public void queryFinished(final ISearchQuery query) { - - } + public void queryFinished(final ISearchQuery query) {} }; } @@ -287,14 +236,6 @@ public class MemorySearchResultsPage extends Page implements ISearchResultPage, return fViewerContainer; } - public void setActionBars(IActionBars actionBars) { - - - } - - public void setFocus() { - - - } - + public void setActionBars(IActionBars actionBars) {} + public void setFocus() {} }