Test fix; update Code Browser to have both setView() and updateView()

This commit is contained in:
dragonmacher 2025-04-30 11:05:11 -04:00
parent 15203337f5
commit dd15eca6b5
10 changed files with 297 additions and 61 deletions

View file

@ -15,7 +15,7 @@
*/
package ghidra.app.plugin.core.debug.gui.listing;
import static ghidra.app.plugin.core.debug.gui.DebuggerResources.GROUP_TRANSIENT_VIEWS;
import static ghidra.app.plugin.core.debug.gui.DebuggerResources.*;
import java.util.List;
import java.util.function.Consumer;
@ -81,7 +81,8 @@ import ghidra.trace.model.program.TraceProgramView;
},
servicesProvided = {
DebuggerListingService.class,
})
}
)
public class DebuggerListingPlugin extends AbstractCodeBrowserPlugin<DebuggerListingProvider>
implements DebuggerListingService {
private static final String KEY_CONNECTED_PROVIDER = "connectedProvider";
@ -180,13 +181,13 @@ public class DebuggerListingPlugin extends AbstractCodeBrowserPlugin<DebuggerLis
}
@Override
protected void viewChanged(AddressSetView addrSet) {
protected void setView(AddressSetView addrSet) {
TraceProgramView view = current.getView();
if (view == null) {
super.viewChanged(new AddressSet());
super.setView(new AddressSet());
}
else {
super.viewChanged(view.getMemory());
super.setView(view.getMemory());
}
}

View file

@ -80,7 +80,7 @@ public abstract class AbstractCodeBrowserPlugin<P extends CodeViewerProvider> ex
protected FormatManager formatMgr;
protected ViewManagerService viewManager;
private MarkerService markerService;
protected AddressSetView currentView;
protected AddressSetView currentView = ImmutableAddressSet.EMPTY_SET;
protected Program currentProgram;
private boolean selectionChanging;
private MarkerSet currentSelectionMarkers;
@ -118,20 +118,26 @@ public abstract class AbstractCodeBrowserPlugin<P extends CodeViewerProvider> ex
protected abstract P createProvider(FormatManager formatManager, boolean isConnected);
protected void viewChanged(AddressSetView addrSet) {
ProgramLocation currLoc = getCurrentLocation();
currentView = addrSet;
if (addrSet != null && !addrSet.isEmpty()) {
connectedProvider.setView(addrSet);
if (currLoc != null && addrSet.contains(currLoc.getAddress())) {
goTo(currLoc, true);
}
}
else {
connectedProvider.setView(new AddressSet());
}
updateBackgroundColorModel();
protected void setView(AddressSetView newView) {
if (currentView.hasSameAddresses(newView)) {
return;
}
ProgramLocation location = getCurrentLocation();
currentView = ImmutableAddressSet.asImmutable(newView);
connectedProvider.setView(currentView);
if (location != null && currentView.contains(location.getAddress())) {
goTo(location, true);
}
viewUpdated();
}
private void viewUpdated() {
updateBackgroundColorModel();
setHighlight(connectedProvider.getHighlight());
setSelection(connectedProvider.getSelection());
}
@ -168,7 +174,7 @@ public abstract class AbstractCodeBrowserPlugin<P extends CodeViewerProvider> ex
listingPanel.setBackgroundColorModel(null);
}
// TODO: update all providers, not just the connected provider
// Note: this should update all providers, not just the connected provider
}
@Override
@ -220,14 +226,14 @@ public abstract class AbstractCodeBrowserPlugin<P extends CodeViewerProvider> ex
public void serviceAdded(Class<?> interfaceClass, Object service) {
if (interfaceClass == ViewManagerService.class && viewManager == null) {
viewManager = (ViewManagerService) service;
viewChanged(viewManager.getCurrentView());
setView(viewManager.getCurrentView());
}
if (interfaceClass == MarkerService.class && markerService == null) {
markerService = tool.getService(MarkerService.class);
markerService.addChangeListener(markerChangeListener);
updateBackgroundColorModel();
if (viewManager != null) {
viewChanged(viewManager.getCurrentView());
viewUpdated();
}
}
if (interfaceClass == ListingHoverService.class) {
@ -247,7 +253,7 @@ public abstract class AbstractCodeBrowserPlugin<P extends CodeViewerProvider> ex
public void serviceRemoved(Class<?> interfaceClass, Object service) {
if ((service == viewManager) && (currentProgram != null)) {
viewManager = null;
viewChanged(currentProgram.getMemory());
setView(currentProgram.getMemory());
}
if (service == markerService) {
markerService.removeChangeListener(markerChangeListener);
@ -338,7 +344,7 @@ public abstract class AbstractCodeBrowserPlugin<P extends CodeViewerProvider> ex
@Override
public void setListingPanel(ListingPanel lp) {
connectedProvider.setOtherPanel(lp);
viewChanged(currentView);
viewUpdated();
}
@Override
@ -363,7 +369,7 @@ public abstract class AbstractCodeBrowserPlugin<P extends CodeViewerProvider> ex
}
if (connectedProvider.getOtherPanel() == lp) {
connectedProvider.clearPanel();
viewChanged(currentView);
viewUpdated();
}
}
@ -857,11 +863,11 @@ public abstract class AbstractCodeBrowserPlugin<P extends CodeViewerProvider> ex
connectedProvider.updateTitle();
}
if (viewManager != null) {
return;
}
if (ev.contains(DomainObjectEvent.RESTORED)) {
viewChanged(currentProgram.getMemory());
if (viewManager == null) {
setView(currentProgram.getMemory());
viewUpdated();
}
}
}

View file

@ -113,9 +113,6 @@ public class CodeBrowserPlugin extends AbstractCodeBrowserPlugin<CodeViewerProvi
}
}
/**
* Interface method called to process a plugin event.
*/
@Override
public void processEvent(PluginEvent event) {
if (event instanceof ProgramClosedPluginEvent) {
@ -150,7 +147,8 @@ public class CodeBrowserPlugin extends AbstractCodeBrowserPlugin<CodeViewerProvi
ProgramLocation location = evt.getLocation();
if (!connectedProvider.setLocation(location)) {
if (viewManager != null) {
connectedProvider.setView(viewManager.addToView(location));
AddressSetView updatedView = viewManager.addToView(location);
setView(updatedView);
ListingPanel lp = connectedProvider.getListingPanel();
lp.goTo(location, true);
}
@ -168,7 +166,7 @@ public class CodeBrowserPlugin extends AbstractCodeBrowserPlugin<CodeViewerProvi
}
else if (event instanceof ViewChangedPluginEvent) {
AddressSet view = ((ViewChangedPluginEvent) event).getView();
viewChanged(view);
setView(view);
}
}
@ -203,7 +201,7 @@ public class CodeBrowserPlugin extends AbstractCodeBrowserPlugin<CodeViewerProvi
ProgramSelection highlight = (ProgramSelection) state[2];
ProgramSelection selection = (ProgramSelection) state[3];
viewChanged((AddressSetView) state[4]);
setView((AddressSetView) state[4]);
if (location != null) {
connectedProvider.setLocation(location);

View file

@ -60,6 +60,7 @@ import ghidra.framework.plugintool.NavigatableComponentProviderAdapter;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.Memory;
import ghidra.program.util.*;
import ghidra.util.HelpLocation;
import ghidra.util.Swing;
@ -958,25 +959,26 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
return fieldNavigator;
}
public void setView(AddressSetView view) {
void setView(AddressSetView view) {
// If we are using a MultiListingLayoutModel then adjust the view address set.
AddressSetView adjustedView = view;
if (multiModel != null) {
if ((program != null) && view.contains(new AddressSet(program.getMemory()))) {
Program otherProgram = otherPanel.getProgram();
Program otherProgram = otherPanel.getProgram();
Memory memory = program.getMemory();
if (view.contains(memory)) {
adjustedView = ProgramMemoryComparator.getCombinedAddresses(program, otherProgram);
}
multiModel.setAddressSet(adjustedView);
// convert the view addresses to ones compatible with the otherPanel's model
AddressSet diffAddrs = DiffUtility.getCompatibleAddressSet(adjustedView, otherProgram);
otherPanel.setView(diffAddrs);
}
listingPanel.setView(adjustedView);
if (otherPanel != null) {
// Convert the view addresses to ones compatible with the otherPanel's model.
AddressSet compatibleAddressSet =
DiffUtility.getCompatibleAddressSet(adjustedView, otherPanel.getProgram());
otherPanel.setView(compatibleAddressSet);
}
}
@Override

View file

@ -330,9 +330,7 @@ public class ListingModelAdapter implements LayoutModel, ListingModelListener {
}
public ProgramSelection getAllProgramSelection() {
Program program = model.getProgram();
AddressFactory factory = program == null ? null : program.getAddressFactory();
return new ProgramSelection(factory, model.getAddressSet());
return new ProgramSelection(model.getAddressSet());
}
// This method works for structures inside unions, but doesn't handle data
@ -346,7 +344,7 @@ public class ListingModelAdapter implements LayoutModel, ListingModelListener {
}
}
addrSet = model.adjustAddressSetToCodeUnitBoundaries(addrSet);
return new ProgramSelection(null, addrSet);
return new ProgramSelection(addrSet);
}
// this methods does NOT work for structures inside of unions, but handles structures
@ -519,9 +517,14 @@ public class ListingModelAdapter implements LayoutModel, ListingModelListener {
* associated with this model.
*/
public void setAddressSet(AddressSetView view) {
view = ImmutableAddressSet.asImmutable(view);
addressToIndexMap = new AddressIndexMap(view);
removeUnviewableAddressRanges();
modelSizeChanged();
}
public void viewUpdated() {
removeUnviewableAddressRanges();
modelSizeChanged();
}
}

View file

@ -20,7 +20,6 @@ import java.awt.event.*;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import javax.swing.*;
import javax.swing.event.ChangeListener;
@ -875,9 +874,11 @@ public class ListingPanel extends JPanel implements FieldMouseListener, FieldLoc
*/
public void setView(AddressSetView view) {
view = ImmutableAddressSet.asImmutable(view);
AddressIndexMap currentMap = layoutModel.getAddressIndexMap();
AddressSetView originalView = currentMap.getOriginalAddressSet();
if (Objects.equals(originalView, view)) {
if (view.hasSameAddresses(originalView)) {
return;
}

View file

@ -370,7 +370,7 @@ public class MultiListingLayoutModel implements ListingModelListener, FormatMode
* primary program and listingModel
*/
public void setAddressSet(AddressSetView view) {
primaryAddrSet = view;
primaryAddrSet = ImmutableAddressSet.asImmutable(view);
modelSizeChanged();
}
}

View file

@ -44,7 +44,8 @@ import ghidra.app.util.viewer.listingpanel.ListingPanel;
import ghidra.framework.options.Options;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.model.address.*;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSet;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.RefType;
@ -56,7 +57,6 @@ public class CodeBrowserScreenMovementTest extends AbstractProgramBasedTest {
private static final String NESTED_STRUCT_ADDR = "0x1007000";
private AddressFactory addrFactory;
private FieldPanel fp;
@Before
@ -629,7 +629,7 @@ public class CodeBrowserScreenMovementTest extends AbstractProgramBasedTest {
// now make a real program selection and verify the text selection goes away
ProgramSelection programSelection =
new ProgramSelection(addrFactory, addr("0x1003600"), addr("0x10036f0"));
new ProgramSelection(addr("0x1003600"), addr("0x10036f0"));
tool.firePluginEvent(
new ProgramSelectionPluginEvent(testName.getMethodName(), programSelection, program));
@ -705,8 +705,7 @@ public class CodeBrowserScreenMovementTest extends AbstractProgramBasedTest {
}
private void setView(final AddressSet addrSet) {
runSwing(() -> codeBrowser.viewChanged(addrSet), true);
runSwing(() -> codeBrowser.setView(addrSet), true);
}
private void adjustFieldPanelSize(int numRows) {

View file

@ -664,7 +664,7 @@ public class CodeBrowserTest extends AbstractGhidraHeadedIntegrationTest {
}
private void setView(AddressSet addrSet) {
runSwing(() -> cb.viewChanged(addrSet), true);
runSwing(() -> cb.setView(addrSet), true);
}
private void setSelection(final AddressSet addrSet) {

View file

@ -0,0 +1,226 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.model.address;
import java.util.Iterator;
/**
* Immutable implementation of the {@link AddressSetView} interface;
*/
public class ImmutableAddressSet implements AddressSetView {
public static final ImmutableAddressSet EMPTY_SET = new ImmutableAddressSet(new AddressSet());
public static ImmutableAddressSet asImmutable(AddressSetView view) {
if (view == null) {
return EMPTY_SET;
}
if (view instanceof ImmutableAddressSet ias) {
return ias;
}
return new ImmutableAddressSet(view);
}
private AddressSet set;
public ImmutableAddressSet(AddressSetView addresses) {
set = new AddressSet(addresses);
}
@Override
public boolean contains(Address addr) {
return set.contains(addr);
}
@Override
public boolean contains(Address start, Address end) {
return set.contains(start, end);
}
@Override
public boolean contains(AddressSetView rangeSet) {
return set.contains(rangeSet);
}
@Override
public boolean isEmpty() {
return set.isEmpty();
}
@Override
public Address getMinAddress() {
return set.getMinAddress();
}
@Override
public Address getMaxAddress() {
return set.getMaxAddress();
}
@Override
public int getNumAddressRanges() {
return set.getNumAddressRanges();
}
@Override
public AddressRangeIterator getAddressRanges() {
return set.getAddressRanges();
}
@Override
public AddressRangeIterator getAddressRanges(boolean forward) {
return set.getAddressRanges(forward);
}
@Override
public AddressRangeIterator getAddressRanges(Address start, boolean forward) {
return set.getAddressRanges(start, forward);
}
@Override
public Iterator<AddressRange> iterator() {
return set.iterator();
}
@Override
public Iterator<AddressRange> iterator(boolean forward) {
return set.iterator(forward);
}
@Override
public Iterator<AddressRange> iterator(Address start, boolean forward) {
return set.iterator(start, forward);
}
@Override
public long getNumAddresses() {
return set.getNumAddresses();
}
@Override
public AddressIterator getAddresses(boolean forward) {
return set.getAddresses(forward);
}
@Override
public AddressIterator getAddresses(Address start, boolean forward) {
return set.getAddresses(start, forward);
}
@Override
public boolean intersects(AddressSetView addrSet) {
return set.intersects(addrSet);
}
@Override
public boolean intersects(Address start, Address end) {
return set.intersects(start, end);
}
@Override
public AddressSet intersect(AddressSetView view) {
return set.intersect(view);
}
@Override
public AddressSet intersectRange(Address start, Address end) {
return set.intersectRange(start, end);
}
@Override
public AddressSet union(AddressSetView addrSet) {
return set.union(addrSet);
}
@Override
public AddressSet subtract(AddressSetView addrSet) {
return set.subtract(addrSet);
}
@Override
public AddressSet xor(AddressSetView addrSet) {
return set.xor(addrSet);
}
@Override
public boolean hasSameAddresses(AddressSetView view) {
return set.hasSameAddresses(view);
}
@Override
public AddressRange getFirstRange() {
return set.getFirstRange();
}
@Override
public AddressRange getLastRange() {
return set.getLastRange();
}
@Override
public AddressRange getRangeContaining(Address address) {
return set.getRangeContaining(address);
}
@Override
public Address findFirstAddressInCommon(AddressSetView addresses) {
return set.findFirstAddressInCommon(addresses);
}
@Override
public final boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (obj == this) {
return true;
}
if (!(obj instanceof ImmutableAddressSet)) {
return false;
}
ImmutableAddressSet otherSet = (ImmutableAddressSet) obj;
if (this.getNumAddresses() != otherSet.getNumAddresses()) {
return false;
}
// if don't have same number of ranges, not equal
if (this.getNumAddressRanges() != otherSet.getNumAddressRanges()) {
return false;
}
AddressRangeIterator otherRanges = otherSet.getAddressRanges();
AddressRangeIterator myRanges = getAddressRanges();
while (myRanges.hasNext()) {
AddressRange myRange = myRanges.next();
AddressRange otherRange = otherRanges.next();
if (!myRange.equals(otherRange)) {
return false;
}
}
return true;
}
@Override
public int hashCode() {
if (isEmpty()) {
return 0;
}
return getMinAddress().hashCode() + getMaxAddress().hashCode();
}
}