mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-09-28 17:11:11 -09:00
Merge remote-tracking branch
'origin/GP-5987_ghidragon_hiding_function_body_in_listing--SQUASHED' (Closes #4274)
This commit is contained in:
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -48,6 +48,15 @@ public class DBTraceProgramViewPropertyMapManager implements PropertyMapManager
|
||||
return map.getAddressSetView(Lifespan.at(program.snap));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
AddressSetView view = getAddressSetView();
|
||||
AddressRangeIterator addressRanges = view.getAddressRanges();
|
||||
for (AddressRange range : addressRanges) {
|
||||
removeRange(range.getMinAddress(), range.getMaxAddress());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean intersects(Address start, Address end) {
|
||||
return getAddressSetView().intersects(start, end);
|
||||
@@ -62,7 +71,7 @@ public class DBTraceProgramViewPropertyMapManager implements PropertyMapManager
|
||||
public boolean removeRange(Address start, Address end) {
|
||||
return map.clear(Lifespan.at(program.snap), new AddressRangeImpl(start, end));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean remove(Address addr) {
|
||||
return removeRange(addr, addr);
|
||||
|
||||
@@ -98,6 +98,7 @@ color.fg.listing.pcode.userop = color.palette.blue
|
||||
|
||||
color.fg.listing.stack.depth = color.palette.blue
|
||||
color.fg.listing.taint = color.fg
|
||||
color.fg.listing.collapsed = color.palette.gray
|
||||
|
||||
color.bg.listing.comparison.bytes = color.palette.lightgreen
|
||||
color.bg.listing.comparison.mnemonic = color.palette.lightgreen
|
||||
|
||||
@@ -654,27 +654,55 @@
|
||||
of where in the containing structure the popup menu was activated.</P>
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H2>Opening/Closing Functions</H2>
|
||||
<BLOCKQUOTE>
|
||||
<P>Functions can be open or closed in the listing display. When closed, all the instructions
|
||||
that make up that function are hidden from view in the listing display. Each consecutive
|
||||
range of instructions in a function are replaced with a "collapsed code" line to indicate
|
||||
that some code is hidden and which function the hidden code belongs to. On the function
|
||||
signature line, there is an open/close control (+/-) that can be used to open or close
|
||||
a function.</P>
|
||||
<P>The open/close state for functions is persisted across sessions. Also, navigating to
|
||||
an address in the body of a closed function will cause that function to be opened.</P>
|
||||
<H3>Actions for Opening/Closing a Function</H3>
|
||||
<BLOCKQUOTE>
|
||||
<P>In addition to the control widget in the display, there are also several actions
|
||||
that can be used to control the open/close state of a single function or all functions.
|
||||
</P>
|
||||
<UL>
|
||||
<LI><A name="Open_All_Functions"></A><B>Open All Functions</B> - This action will
|
||||
open all currently closed functions.</LI>
|
||||
<LI><A name="Close_All_Functions"></A><B>Close All Functions</B> - This action will
|
||||
close all currently open functions.</LI>
|
||||
<LI><A name="Toggle_Function"></A><B>Open/Close Functionn</B> - This action will
|
||||
open a closed function or close an open function.</LI>
|
||||
</UL>
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
<H2>Opening/Closing Function Variables Display</H2>
|
||||
<BLOCKQUOTE>
|
||||
The display of parameters and local variables for a function can be toggled on or off.
|
||||
Normally, these are displayed just below the function signature, but they can be turned off
|
||||
to conserve screen space. There is an open/close control (+/-)
|
||||
on the first parameter/variable line that can be used to toggle them on or off.</P>
|
||||
on the first parameter/variable line that can be used to toggle them on or off. Note that
|
||||
unlike the open/close state for functions, the open/close state for variables is not
|
||||
persistent across sessions for a program. The default state of whether or not to
|
||||
display variables is a tool state is persisted for the tool, not individual programs.</P>
|
||||
<H3>Actions for Opening/Closing Function Variables Display</H3>
|
||||
<BLOCKQUOTE>
|
||||
<P>In addition to the control widget in the display, there are also several actions that
|
||||
can be used to control the display of function variables.</P>
|
||||
<UL>
|
||||
<LI><A name="Show_All_Variables"></A><B>Show/Hide All Variables</B> - This toggle
|
||||
<LI><A name="Show_Variables"></A><B>Show/Hide Variables</B> - This action toggles
|
||||
the display of the variables section for a function. If they are showing, they will be
|
||||
hidden and if they hare hidden, they will be shown. The default keybinding is
|
||||
<CODE>Space</CODE> so if you are on a function or variable, pressing the space bar will
|
||||
toggle the display state.</LI>
|
||||
<LI><A name="Show_Variables_By_Default"></A><B>Show Variables By Default</B> - This toggle
|
||||
action can be used to globally control whether or not function variables are displayed.
|
||||
Individual functions can still be toggled on or off, but this sets the default for all
|
||||
functions.</LI>
|
||||
<LI><A name="Show_Variables"></A><B>Show/Hide Variables</B> - This action toggles
|
||||
the display of the variables. If they are showing, this will turn them off. And if they
|
||||
are not showing, this action will turn them on. The default keybinding is
|
||||
<CODE>Space</CODE> so if you are on a function or variable, pressing the space bar will
|
||||
toggle the display state.</LI>
|
||||
|
||||
</UL>
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
@@ -131,6 +131,7 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
|
||||
|
||||
private MultiListingLayoutModel multiModel;
|
||||
private ToggleDockingAction toggleVariablesAction;
|
||||
private ToggleDockingAction toggleFunctionsAction;
|
||||
|
||||
public CodeViewerProvider(CodeBrowserPluginInterface plugin, FormatManager formatMgr,
|
||||
boolean isConnected) {
|
||||
@@ -481,24 +482,49 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
|
||||
action = new GotoNextFunctionAction(tool, plugin.getName());
|
||||
tool.addAction(action);
|
||||
|
||||
new ActionBuilder("Open All Functions", plugin.getName())
|
||||
.popupMenuPath("Function", "Open All Functions")
|
||||
.popupMenuGroup("Visibility", "1")
|
||||
.helpLocation(new HelpLocation("CodeBrowserPlugin", "Open_All_Functions"))
|
||||
.withContext(ProgramLocationActionContext.class)
|
||||
.onAction(c -> showAllFunctions(true))
|
||||
.buildAndInstallLocal(this);
|
||||
new ActionBuilder("Close All Functions", plugin.getName())
|
||||
.popupMenuPath("Function", "Close All Functions")
|
||||
.popupMenuGroup("Visibility", "2")
|
||||
.helpLocation(new HelpLocation("CodeBrowserPlugin", "Close_All_Functions"))
|
||||
.withContext(ProgramLocationActionContext.class)
|
||||
.onAction(c -> showAllFunctions(false))
|
||||
.buildAndInstallLocal(this);
|
||||
new ActionBuilder("Toggle Open Function", plugin.getName())
|
||||
.popupMenuPath("Function", "Open/Close Function")
|
||||
.popupMenuGroup("Visibility", "3")
|
||||
.helpLocation(new HelpLocation("CodeBrowserPlugin", "Toggle_Function"))
|
||||
.keyBinding("SPACE")
|
||||
.withContext(ProgramLocationActionContext.class)
|
||||
.validWhen(this::isInCollapsableCodeArea)
|
||||
.enabledWhen(this::isInCollapsableCodeArea)
|
||||
.onAction(c -> toggleShowFunction(c))
|
||||
.buildAndInstallLocal(this);
|
||||
|
||||
toggleVariablesAction =
|
||||
new ToggleActionBuilder("Show All Function Variables", plugin.getName())
|
||||
.popupMenuPath("Function", "Show/Hide All Variables")
|
||||
.popupMenuGroup("Variables")
|
||||
new ToggleActionBuilder("Show Function Variables By Default", plugin.getName())
|
||||
.popupMenuPath("Function", "Show Variables By Default")
|
||||
.popupMenuGroup("Visibility", "5")
|
||||
.helpLocation(new HelpLocation("CodeBrowserPlugin", "Show_All_Variables"))
|
||||
.selected(true)
|
||||
.withContext(ProgramLocationActionContext.class)
|
||||
.onAction(c -> showVariablesForAllFunctions(toggleVariablesAction.isSelected()))
|
||||
.buildAndInstallLocal(this);
|
||||
|
||||
new ActionBuilder("Toggle Show Function Variables", plugin.getName())
|
||||
new ActionBuilder("Show/Hide Function Variables", plugin.getName())
|
||||
.popupMenuPath("Function", "Show/Hide Variables")
|
||||
.popupMenuGroup("Variables")
|
||||
.popupMenuGroup("Visibility", "4")
|
||||
.helpLocation(new HelpLocation("CodeBrowserPlugin", "Show_Variables"))
|
||||
.keyBinding("SPACE")
|
||||
.withContext(ProgramLocationActionContext.class)
|
||||
.validWhen(this::isInFunctionArea)
|
||||
.enabledWhen(this::isInFunctionArea)
|
||||
.validWhen(this::isInFunctionVariablesArea)
|
||||
.enabledWhen(this::isInFunctionVariablesArea)
|
||||
.onAction(c -> toggleShowVariables(c.getAddress()))
|
||||
.buildAndInstallLocal(this);
|
||||
|
||||
@@ -506,6 +532,45 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
|
||||
|
||||
}
|
||||
|
||||
private void showAllFunctions(boolean selected) {
|
||||
ListingModel model = listingPanel.getListingModel();
|
||||
model.setAllFunctionsOpen(selected);
|
||||
}
|
||||
|
||||
private void toggleShowFunction(ProgramLocationActionContext context) {
|
||||
Address cuAddress = context.getAddress();
|
||||
Function function = program.getListing().getFunctionContaining(cuAddress);
|
||||
if (function == null) {
|
||||
return;
|
||||
}
|
||||
ListingModel model = listingPanel.getListingModel();
|
||||
Address functionAddress = function.getEntryPoint();
|
||||
boolean open = model.isFunctionOpen(functionAddress);
|
||||
|
||||
model.setFunctionOpen(functionAddress, !open);
|
||||
if (context.getLocation() instanceof FunctionSignatureFieldLocation) {
|
||||
// no need to move cursor
|
||||
return;
|
||||
}
|
||||
if (!open) {
|
||||
setLocation(new ProgramLocation(program, cuAddress));
|
||||
}
|
||||
else {
|
||||
// We have to use the CollapsedCodeLocation in this case, any other goto to
|
||||
// an address that is collapse will open it up, which we don't want since
|
||||
// we just closed it. Also, we need to correct to the start of the range since
|
||||
// that is the address that will have the CollapsedField
|
||||
Address corrected = adjustToStartOfContainingRange(function, cuAddress);
|
||||
setLocation(new CollapsedCodeLocation(program, corrected));
|
||||
}
|
||||
}
|
||||
|
||||
private Address adjustToStartOfContainingRange(Function function, Address cuAddress) {
|
||||
AddressSetView body = function.getBody();
|
||||
AddressRange range = body.getRangeContaining(cuAddress);
|
||||
return range == null ? function.getEntryPoint() : range.getMinAddress();
|
||||
}
|
||||
|
||||
private void toggleShowVariables(Address address) {
|
||||
ListingModel model = listingPanel.getListingModel();
|
||||
boolean open = model.areFunctionVariablesOpen(address);
|
||||
@@ -518,12 +583,28 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
|
||||
model.setAllFunctionVariablesOpen(selected);
|
||||
}
|
||||
|
||||
private boolean isInFunctionArea(ProgramLocationActionContext context) {
|
||||
private boolean isInFunctionVariablesArea(ProgramLocationActionContext context) {
|
||||
ProgramLocation location = context.getLocation();
|
||||
return location instanceof FunctionLocation ||
|
||||
return location instanceof VariableLocation ||
|
||||
location instanceof VariablesOpenCloseLocation;
|
||||
}
|
||||
|
||||
private boolean isInCollapsableCodeArea(ProgramLocationActionContext context) {
|
||||
ProgramLocation location = context.getLocation();
|
||||
|
||||
// this allows the code collapse to be toggled on instructions in the body of a function,
|
||||
// but we have to exclude the variable locations so as to not interfere with the
|
||||
// open/close variables action which also is mapped to <SPACE>
|
||||
if (location instanceof CodeUnitLocation && !(location instanceof VariableLocation) &&
|
||||
!(location instanceof VariablesOpenCloseLocation)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return location instanceof FunctionSignatureFieldLocation ||
|
||||
location instanceof FunctionOpenCloseLocation ||
|
||||
location instanceof CollapsedCodeLocation;
|
||||
}
|
||||
|
||||
private void buildQuickTogleFieldActions() {
|
||||
List<String> quickToggleFieldNames = formatMgr.getQuickToggleFieldNames();
|
||||
int count = 0;
|
||||
|
||||
@@ -19,6 +19,7 @@ import java.awt.*;
|
||||
|
||||
import docking.widgets.fieldpanel.support.*;
|
||||
import generic.theme.GIcon;
|
||||
import generic.theme.Gui;
|
||||
import ghidra.app.util.viewer.proxy.EmptyProxy;
|
||||
import ghidra.app.util.viewer.proxy.ProxyObj;
|
||||
|
||||
@@ -26,6 +27,7 @@ import ghidra.app.util.viewer.proxy.ProxyObj;
|
||||
* FactoryField class for displaying the open/close field.
|
||||
*/
|
||||
public abstract class AbstractOpenCloseField implements ListingField {
|
||||
protected static final Font HIDDEN_FONT = Gui.getFont("font.listing.base.hidden.field");
|
||||
protected static final GIcon OPEN_ICON =
|
||||
new GIcon("icon.base.util.viewer.fieldfactory.openclose.open");
|
||||
protected static final GIcon CLOSED_ICON =
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
/* ###
|
||||
* 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.app.util.viewer.field;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import docking.widgets.fieldpanel.field.*;
|
||||
import docking.widgets.fieldpanel.support.FieldLocation;
|
||||
import ghidra.app.util.ListingHighlightProvider;
|
||||
import ghidra.app.util.viewer.format.FieldFormatModel;
|
||||
import ghidra.app.util.viewer.listingpanel.ListingModel;
|
||||
import ghidra.app.util.viewer.proxy.CodeUnitProxy;
|
||||
import ghidra.app.util.viewer.proxy.ProxyObj;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.framework.options.ToolOptions;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.util.CollapsedCodeLocation;
|
||||
import ghidra.program.util.ProgramLocation;
|
||||
|
||||
/**
|
||||
* Generates field to indicate collapsed function for areas of hidden code.
|
||||
*/
|
||||
public class CollapsedCodeFieldFactory extends FieldFactory {
|
||||
public static final String FIELD_NAME = "Collapsed Code";
|
||||
|
||||
public CollapsedCodeFieldFactory() {
|
||||
super(FIELD_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param model the model that the field belongs to.
|
||||
* @param hlProvider the HightLightStringProvider.
|
||||
* @param displayOptions the Options for display properties.
|
||||
* @param fieldOptions the Options for field specific properties.
|
||||
*/
|
||||
private CollapsedCodeFieldFactory(FieldFormatModel model, ListingHighlightProvider hlProvider,
|
||||
Options displayOptions, Options fieldOptions) {
|
||||
super(FIELD_NAME, model, hlProvider, displayOptions, fieldOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListingField getField(ProxyObj<?> proxy, int varWidth) {
|
||||
if (!enabled || !(proxy instanceof CodeUnitProxy cuProxy)) {
|
||||
return null;
|
||||
}
|
||||
CodeUnit cu = cuProxy.getObject();
|
||||
Address address = cu.getAddress();
|
||||
Function function = cu.getProgram().getListing().getFunctionContaining(address);
|
||||
if (function == null) {
|
||||
return null;
|
||||
}
|
||||
String text = "<Collapsed: " + function.getName() + "()>";
|
||||
AttributedString s = new AttributedString(text, ListingColors.COLLAPSED_CODE, getMetrics());
|
||||
FieldElement element = new TextFieldElement(s, 0, 0);
|
||||
return ListingTextField.createSingleLineTextField(this, cuProxy, element, startX + varWidth,
|
||||
width, hlProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProgramLocation getProgramLocation(int row, int col, ListingField bf) {
|
||||
Object obj = bf.getProxy().getObject();
|
||||
if (obj instanceof CodeUnit cu) {
|
||||
Address address = cu.getAddress();
|
||||
ListingModel layoutModel = bf.getProxy().getListingLayoutModel();
|
||||
Program program = layoutModel.getProgram();
|
||||
return new CollapsedCodeLocation(program, address);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldLocation getFieldLocation(ListingField bf, BigInteger index, int fieldNum,
|
||||
ProgramLocation programLoc) {
|
||||
if (programLoc instanceof CollapsedCodeLocation) {
|
||||
return new FieldLocation(index, fieldNum, 0, 0);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean acceptsType(int category, Class<?> proxyObjectClass) {
|
||||
// this factory only appears in the header DIVIDER tab (which is called "Address Break" in
|
||||
// the gui)
|
||||
return category == FieldFormatModel.DIVIDER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldFactory newInstance(FieldFormatModel formatModel, ListingHighlightProvider provider,
|
||||
ToolOptions displayOptions, ToolOptions fieldOptions) {
|
||||
return new CollapsedCodeFieldFactory(formatModel, provider, displayOptions, fieldOptions);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/* ###
|
||||
* 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.app.util.viewer.field;
|
||||
|
||||
import java.awt.event.MouseEvent;
|
||||
|
||||
import ghidra.app.nav.Navigatable;
|
||||
import ghidra.app.services.GoToService;
|
||||
import ghidra.framework.plugintool.ServiceProvider;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.util.*;
|
||||
|
||||
/**
|
||||
* A handler to process {@link CollapsedCodeLocation} mouse clicks.
|
||||
*/
|
||||
public class CollapsedCodeFieldMouseHandler implements FieldMouseHandlerExtension {
|
||||
|
||||
private final static Class<?>[] SUPPORTED_CLASSES = new Class[] {
|
||||
CollapsedCodeLocation.class };
|
||||
|
||||
@Override
|
||||
public boolean fieldElementClicked(Object clickedObject, Navigatable navigatable,
|
||||
ProgramLocation location, MouseEvent mouseEvent, ServiceProvider serviceProvider) {
|
||||
|
||||
if (mouseEvent.getClickCount() != 2 || mouseEvent.getButton() != MouseEvent.BUTTON1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GoToService goToService = serviceProvider.getService(GoToService.class);
|
||||
if (goToService == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Program program = location.getProgram();
|
||||
|
||||
if (location instanceof CollapsedCodeLocation loc) {
|
||||
Address address = loc.getAddress();
|
||||
Function function = program.getListing().getFunctionContaining(address);
|
||||
|
||||
if (function != null) {
|
||||
FunctionSignatureFieldLocation gotoLocation =
|
||||
new FunctionSignatureFieldLocation(program, function.getEntryPoint());
|
||||
goToService.goTo(navigatable, gotoLocation, program);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?>[] getSupportedProgramLocations() {
|
||||
return SUPPORTED_CLASSES;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/* ###
|
||||
* 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.app.util.viewer.field;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
|
||||
import docking.widgets.fieldpanel.internal.FieldBackgroundColorManager;
|
||||
import docking.widgets.fieldpanel.internal.PaintContext;
|
||||
import docking.widgets.fieldpanel.support.RowColLocation;
|
||||
import ghidra.app.util.viewer.proxy.FunctionProxy;
|
||||
import ghidra.app.util.viewer.proxy.ProxyObj;
|
||||
import ghidra.program.model.address.Address;
|
||||
|
||||
/**
|
||||
* Field class for displaying the open/close field widget for function variables.
|
||||
*/
|
||||
public class FunctionOpenCloseField extends AbstractOpenCloseField {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param factory the FieldFactory that created this field.
|
||||
* @param proxy the object associated with this field.
|
||||
* @param metrics the FontMetrics used to render this field.
|
||||
* @param x the starting x position of this field.
|
||||
* @param width the width of this field.
|
||||
*/
|
||||
public FunctionOpenCloseField(FieldFactory factory, ProxyObj<?> proxy,
|
||||
FontMetrics metrics, int x, int width) {
|
||||
super(factory, proxy, metrics, x, width);
|
||||
if (proxy instanceof FunctionProxy functionProxy) {
|
||||
Address functionAddress = functionProxy.getFunctionAddress();
|
||||
this.isOpen = proxy.getListingLayoutModel().isFunctionOpen(functionAddress);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return fieldWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint(JComponent c, Graphics g, PaintContext context,
|
||||
Rectangle clip, FieldBackgroundColorManager map, RowColLocation cursorLoc,
|
||||
int rowHeight) {
|
||||
|
||||
// center in the heightAbove area (negative, since 0 is the baseline of text, which is at
|
||||
// the bottom of the heightAbove)
|
||||
int toggleHandleStartY = -((heightAbove / 2) + (toggleHandleSize / 2));
|
||||
int toggleHandleStartX = startX;
|
||||
|
||||
// If we're in printing mode, trying to render these open/close images
|
||||
// causes the JVM to bomb. We'd like to eventually figure out why but in
|
||||
// the meantime we can safely comment this out and still generate an acceptable
|
||||
// image.
|
||||
if (!context.isPrinting()) {
|
||||
if (isOpen) {
|
||||
g.drawImage(OPEN_ICON.getImageIcon().getImage(), toggleHandleStartX,
|
||||
toggleHandleStartY, context.getBackground(), null);
|
||||
}
|
||||
else {
|
||||
g.drawImage(CLOSED_ICON.getImageIcon().getImage(), toggleHandleStartX,
|
||||
toggleHandleStartY, context.getBackground(), null);
|
||||
}
|
||||
}
|
||||
paintCursor(g, context.getCursorColor(), cursorLoc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the open state of this field.
|
||||
*/
|
||||
@Override
|
||||
public void toggleOpenCloseState() {
|
||||
if (proxy instanceof FunctionProxy functionProxy) {
|
||||
Address functionAddress = functionProxy.getFunctionAddress();
|
||||
proxy.getListingLayoutModel().setFunctionOpen(functionAddress, !isOpen);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/* ###
|
||||
* 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.app.util.viewer.field;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import docking.widgets.fieldpanel.support.FieldLocation;
|
||||
import ghidra.app.util.ListingHighlightProvider;
|
||||
import ghidra.app.util.viewer.format.FieldFormatModel;
|
||||
import ghidra.app.util.viewer.proxy.FunctionProxy;
|
||||
import ghidra.app.util.viewer.proxy.ProxyObj;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.framework.options.ToolOptions;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.util.FunctionOpenCloseLocation;
|
||||
import ghidra.program.util.ProgramLocation;
|
||||
|
||||
/**
|
||||
* Generates Open/Close Fields for variables under functions.
|
||||
*/
|
||||
public class FunctionOpenCloseFieldFactory extends FieldFactory {
|
||||
|
||||
public static final String FIELD_NAME = "+";
|
||||
|
||||
public FunctionOpenCloseFieldFactory() {
|
||||
super(FIELD_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param model the model that the field belongs to.
|
||||
* @param hlProvider the HightLightStringProvider.
|
||||
* @param displayOptions the Options for display properties.
|
||||
* @param fieldOptions the Options for field specific properties.
|
||||
*/
|
||||
private FunctionOpenCloseFieldFactory(FieldFormatModel model,
|
||||
ListingHighlightProvider hlProvider,
|
||||
Options displayOptions, Options fieldOptions) {
|
||||
super(FIELD_NAME, model, hlProvider, displayOptions, fieldOptions);
|
||||
servicesChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the FactoryField for the given object at index index.
|
||||
* @param varWidth the amount of variable width spacing for any fields
|
||||
* before this one.
|
||||
* @param proxy the object whose properties should be displayed.
|
||||
*/
|
||||
@Override
|
||||
public ListingField getField(ProxyObj<?> proxy, int varWidth) {
|
||||
if (!enabled) {
|
||||
return null;
|
||||
}
|
||||
if (proxy instanceof FunctionProxy) {
|
||||
return new FunctionOpenCloseField(this, proxy, getMetrics(), startX + varWidth, width);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProgramLocation getProgramLocation(int row, int col, ListingField bf) {
|
||||
ProxyObj<?> proxy = bf.getProxy();
|
||||
if (proxy instanceof FunctionProxy functionProxy) {
|
||||
Program program = functionProxy.getProgram();
|
||||
Address functionAddress = functionProxy.getFunctionAddress();
|
||||
return new FunctionOpenCloseLocation(program, functionAddress);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldLocation getFieldLocation(ListingField bf, BigInteger index, int fieldNum,
|
||||
ProgramLocation programLoc) {
|
||||
|
||||
if (!(programLoc instanceof FunctionOpenCloseLocation)) {
|
||||
return null;
|
||||
}
|
||||
return new FieldLocation(index, fieldNum, 0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean acceptsType(int category, Class<?> proxyObjectClass) {
|
||||
if (!Function.class.isAssignableFrom(proxyObjectClass)) {
|
||||
return false;
|
||||
}
|
||||
return (category == FieldFormatModel.FUNCTION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldFactory newInstance(FieldFormatModel fieldModel, ListingHighlightProvider provider,
|
||||
ToolOptions displayOptions, ToolOptions fieldOptions) {
|
||||
return new FunctionOpenCloseFieldFactory(fieldModel, provider, displayOptions,
|
||||
fieldOptions);
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,7 @@ public class ListingColors {
|
||||
public static final GColor EXT_REF_RESOLVED = new GColor("color.fg.listing.ext.ref.resolved");
|
||||
public static final GColor REGISTER = new GColor("color.fg.listing.register");
|
||||
public static final GColor PARALLEL_INSTRUCTION = new GColor("color.fg.listing.instruction.parallel");
|
||||
public static final GColor COLLAPSED_CODE = new GColor("color.fg.listing.collapsed");
|
||||
|
||||
|
||||
public static class XrefColors {
|
||||
|
||||
@@ -21,9 +21,13 @@ import ghidra.app.nav.Navigatable;
|
||||
import ghidra.framework.plugintool.ServiceProvider;
|
||||
import ghidra.program.util.ProgramLocation;
|
||||
|
||||
/**
|
||||
* Mouse handlers for open/close widgets
|
||||
*/
|
||||
public class OpenCloseFieldMouseHandler implements FieldMouseHandlerExtension {
|
||||
private final static Class<?>[] SUPPORTED_CLASSES =
|
||||
new Class[] { OpenCloseField.class, VariableOpenCloseField.class };
|
||||
new Class[] { OpenCloseField.class, VariableOpenCloseField.class,
|
||||
FunctionOpenCloseField.class };
|
||||
|
||||
@Override
|
||||
public boolean fieldElementClicked(Object clickedObject, Navigatable sourceNavigatable,
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -22,6 +22,7 @@ import docking.widgets.fieldpanel.support.FieldLocation;
|
||||
import ghidra.app.util.ListingHighlightProvider;
|
||||
import ghidra.app.util.viewer.format.FieldFormatModel;
|
||||
import ghidra.app.util.viewer.listingpanel.ListingModel;
|
||||
import ghidra.app.util.viewer.proxy.AddressProxy;
|
||||
import ghidra.app.util.viewer.proxy.ProxyObj;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.framework.options.ToolOptions;
|
||||
@@ -65,6 +66,9 @@ public class SeparatorFieldFactory extends FieldFactory {
|
||||
if (!enabled) {
|
||||
return null;
|
||||
}
|
||||
if (!(proxy instanceof AddressProxy)) {
|
||||
return null;
|
||||
}
|
||||
int numChars = width / getMetrics().charWidth(sepChar);
|
||||
sb.setLength(0);
|
||||
for (int i = 0; i < numChars; i++) {
|
||||
|
||||
@@ -23,7 +23,6 @@ import docking.widgets.fieldpanel.internal.FieldBackgroundColorManager;
|
||||
import docking.widgets.fieldpanel.internal.PaintContext;
|
||||
import docking.widgets.fieldpanel.support.RowColLocation;
|
||||
import generic.theme.GThemeDefaults.Colors.Palette;
|
||||
import generic.theme.Gui;
|
||||
import ghidra.app.util.viewer.proxy.ProxyObj;
|
||||
import ghidra.app.util.viewer.proxy.VariableProxy;
|
||||
import ghidra.program.model.address.Address;
|
||||
@@ -32,7 +31,6 @@ import ghidra.program.model.address.Address;
|
||||
* FactoryField class for displaying the open/close field widget for function variables.
|
||||
*/
|
||||
public class VariableOpenCloseField extends AbstractOpenCloseField {
|
||||
private static final Font HIDDEN_FONT = Gui.getFont("font.listing.base.hidden.field");
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
||||
@@ -384,15 +384,26 @@ public class FormatManager implements OptionsChangeListener {
|
||||
Element rowElem = new Element("ROW");
|
||||
|
||||
Element colElem = new Element("FIELD");
|
||||
|
||||
colElem.setAttribute("NAME", "Separator");
|
||||
colElem.setAttribute("WIDTH", "80");
|
||||
colElem.setAttribute("ENABLED", "true");
|
||||
|
||||
rowElem.addContent(colElem);
|
||||
root.addContent(rowElem);
|
||||
return root;
|
||||
|
||||
rowElem = new Element("ROW");
|
||||
colElem = new Element("FIELD");
|
||||
colElem.setAttribute("WIDTH", "150");
|
||||
colElem.setAttribute("ENABLED", "true");
|
||||
rowElem.addContent(colElem);
|
||||
|
||||
colElem = new Element("FIELD");
|
||||
colElem.setAttribute("NAME", "Collapsed Code");
|
||||
colElem.setAttribute("WIDTH", "200");
|
||||
colElem.setAttribute("ENABLED", "true");
|
||||
rowElem.addContent(colElem);
|
||||
|
||||
root.addContent(rowElem);
|
||||
return root;
|
||||
}
|
||||
|
||||
private Element getDefaultPlateFormat() {
|
||||
@@ -434,6 +445,12 @@ public class FormatManager implements OptionsChangeListener {
|
||||
Element rowElem = new Element("ROW");
|
||||
|
||||
Element colElem = new Element("FIELD");
|
||||
colElem.setAttribute("NAME", "+");
|
||||
colElem.setAttribute("WIDTH", "20");
|
||||
colElem.setAttribute("ENABLED", "true");
|
||||
rowElem.addContent(colElem);
|
||||
|
||||
colElem = new Element("FIELD");
|
||||
colElem.setAttribute("WIDTH", "200");
|
||||
colElem.setAttribute("ENABLED", "true");
|
||||
rowElem.addContent(colElem);
|
||||
@@ -961,7 +978,7 @@ public class FormatManager implements OptionsChangeListener {
|
||||
models[i].restoreFromXml(saveState.getXmlElement(models[i].getName()));
|
||||
// hack to make sure the new open/close variables field is present
|
||||
// If missing, we are just going to reset it to the default format
|
||||
checkForMissingOpenCloseField(models[i]);
|
||||
checkForMissingNewCriticalFields(models[i]);
|
||||
}
|
||||
else {
|
||||
models[i].restoreFromXml(getDefaultModel(i));
|
||||
@@ -971,21 +988,30 @@ public class FormatManager implements OptionsChangeListener {
|
||||
modelChanged(null);
|
||||
}
|
||||
|
||||
// This is a hack to make sure the new variables open/close field is present.
|
||||
// This was added in version 12.0 and can probably be removed in a few releases.
|
||||
private void checkForMissingOpenCloseField(FieldFormatModel model) {
|
||||
if (!model.getName().equals("Variable")) {
|
||||
return;
|
||||
// This is a hack to make sure the new variables and functions open/close field is present.
|
||||
// This was added in version 12.0/12.1 and can probably be removed in a few releases.
|
||||
private void checkForMissingNewCriticalFields(FieldFormatModel model) {
|
||||
if (model.getName().equals("Variable")) {
|
||||
if (!hasField(model, "+")) {
|
||||
model.restoreFromXml(getDefaultVariableFormat());
|
||||
}
|
||||
}
|
||||
if (!hasField(model, "+")) {
|
||||
model.restoreFromXml(getDefaultVariableFormat());
|
||||
if (model.getName().equals("Function")) {
|
||||
if (!hasField(model, "+")) {
|
||||
model.restoreFromXml(getDefaultFunctionFormat());
|
||||
}
|
||||
}
|
||||
if (model.getName().equals("Address Break")) {
|
||||
if (!hasField(model, "Collapsed Code")) {
|
||||
model.restoreFromXml(getDefaultDividerFormat());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasField(FieldFormatModel model, String fieldName) {
|
||||
FieldFactory[] unusedFactories = model.getUnusedFactories();
|
||||
for (FieldFactory fieldFactory : unusedFactories) {
|
||||
if (fieldFactory.getFieldName().equals("+")) {
|
||||
if (fieldFactory.getFieldName().equals(fieldName)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,4 +142,19 @@ public class EmptyListingModel implements ListingModel {
|
||||
public ListingModel copy() {
|
||||
return new EmptyListingModel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFunctionOpen(Address functionAddress) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFunctionOpen(Address functionAddress, boolean b) {
|
||||
// stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAllFunctionsOpen(boolean selected) {
|
||||
// stub
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,12 +38,39 @@ public interface ListingModel {
|
||||
FUNCTION_POINTER_OPTION_GROUP_NAME + Options.DELIMITER +
|
||||
"Display Non-External Function Pointer Header";
|
||||
|
||||
/**
|
||||
* {@return the address set of all addresses in the model}
|
||||
*/
|
||||
public AddressSetView getAddressSet();
|
||||
|
||||
/**
|
||||
* Returns the next address that has displayable information after the given address. This
|
||||
* allows the listing to efficiently skip over large sections of undisplayable addresses such
|
||||
* as those consumed by large data or addresses part of a closed function.
|
||||
* @param address the address from which to find the next address with displayable information
|
||||
* @return the next address with displayable information
|
||||
*/
|
||||
public Address getAddressAfter(Address address);
|
||||
|
||||
/**
|
||||
* Returns the previous address that has displayable information before the given address. This
|
||||
* allows the listing to efficiently skip over large sections of undisplayable addresses such
|
||||
* as those consumed by large data or addresses part of a closed function.
|
||||
* @param address the address from which to find the previous address with displayable
|
||||
* information
|
||||
* @return the previous address with displayable information
|
||||
*/
|
||||
public Address getAddressBefore(Address address);
|
||||
|
||||
/**
|
||||
* Returns a layout with displayable information for the given address.
|
||||
* @param address the address to get displayable information
|
||||
* @param isGapAddress true implies there is a gap of missing addresses before this address.
|
||||
* Note that this is different from addresses that are hidden due to collapsed functions or
|
||||
* closed data. These gaps are not even in consideration to display information such as
|
||||
* undefined memory or a fragmented program view.
|
||||
* @return a Layout with information to be displayed for the given address.
|
||||
*/
|
||||
public Layout getLayout(Address address, boolean isGapAddress);
|
||||
|
||||
/**
|
||||
@@ -181,4 +208,24 @@ public interface ListingModel {
|
||||
* @return a copy of this model.
|
||||
*/
|
||||
public ListingModel copy();
|
||||
|
||||
/**
|
||||
* Checks if the function at the given entry point is open or not.
|
||||
* @param functionAddress the entry point of the function to check for open
|
||||
* @return true if the function is open; false otherwise
|
||||
*/
|
||||
public boolean isFunctionOpen(Address functionAddress);
|
||||
|
||||
/**
|
||||
* Sets the function at the given address to be open or not
|
||||
* @param functionAddress the entry point of the function to set open or closed
|
||||
* @param open true to open the function, false to close it
|
||||
*/
|
||||
public void setFunctionOpen(Address functionAddress, boolean open);
|
||||
|
||||
/**
|
||||
* Sets all functions to open or closed.
|
||||
* @param open if true, opens all function; otherwise closes all functions
|
||||
*/
|
||||
public void setAllFunctionsOpen(boolean open);
|
||||
}
|
||||
|
||||
@@ -679,7 +679,7 @@ public class ListingPanel extends JPanel implements FieldMouseListener, FieldLoc
|
||||
return null;
|
||||
}
|
||||
|
||||
openDataAsNeeded(loc);
|
||||
openDataOrFunctionAsNeeded(loc);
|
||||
|
||||
FieldLocation floc = layoutModel.getFieldLocation(loc);
|
||||
if (floc != null) {
|
||||
@@ -719,15 +719,40 @@ public class ListingPanel extends JPanel implements FieldMouseListener, FieldLoc
|
||||
return layoutModel.getFieldLocation(new ProgramLocation(program, address));
|
||||
}
|
||||
|
||||
private void openDataAsNeeded(ProgramLocation location) {
|
||||
private void openDataOrFunctionAsNeeded(ProgramLocation location) {
|
||||
if (location instanceof CollapsedCodeLocation) {
|
||||
return;
|
||||
}
|
||||
Address address = location.getByteAddress();
|
||||
Program program = getProgram();
|
||||
CodeUnit cu = program.getListing().getCodeUnitContaining(address);
|
||||
if (!(cu instanceof Data)) {
|
||||
return;
|
||||
if (cu instanceof Data data) {
|
||||
openData(data, address);
|
||||
}
|
||||
else if (cu instanceof Instruction instruction) {
|
||||
openFunction(instruction);
|
||||
}
|
||||
|
||||
Data data = (Data) cu;
|
||||
}
|
||||
|
||||
private void openFunction(Instruction instruction) {
|
||||
Address address = instruction.getMinAddress();
|
||||
Program program = instruction.getProgram();
|
||||
Function function = program.getFunctionManager().getFunctionContaining(address);
|
||||
if (function == null) {
|
||||
return;
|
||||
}
|
||||
Address functionAddress = function.getEntryPoint();
|
||||
// don't auto-open entry point addresses
|
||||
if (address.equals(functionAddress)) {
|
||||
return;
|
||||
}
|
||||
if (!listingModel.isFunctionOpen(functionAddress)) {
|
||||
listingModel.setFunctionOpen(functionAddress, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void openData(Data data, Address address) {
|
||||
if (data.getComponent(0) == null) {
|
||||
// not sub data to open
|
||||
return;
|
||||
@@ -741,6 +766,7 @@ public class ListingPanel extends JPanel implements FieldMouseListener, FieldLoc
|
||||
if (openAllData(subData)) {
|
||||
layoutModel.dataChanged(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private FieldLocation getFieldLocationForDataAndOpenAsNeeded(Data data, Address address) {
|
||||
|
||||
@@ -43,7 +43,7 @@ public class ProgramBigListingModel implements ListingModel, FormatModelListener
|
||||
DomainObjectListener, ChangeListener, OptionsChangeListener {
|
||||
|
||||
protected final Program program;
|
||||
private ProgramOpenCloseManager openCloseMgr = new ProgramOpenCloseManager();
|
||||
private ProgramOpenCloseManager openCloseMgr;
|
||||
private FormatManager formatMgr;
|
||||
private ToolOptions fieldOptions;
|
||||
private boolean showExternalFunctionPointerFormat;
|
||||
@@ -59,6 +59,7 @@ public class ProgramBigListingModel implements ListingModel, FormatModelListener
|
||||
this.program = program;
|
||||
this.listing = program.getListing();
|
||||
this.formatMgr = formatMgr;
|
||||
openCloseMgr = new ProgramOpenCloseManager(program);
|
||||
dummyFactory = new DummyFieldFactory(formatMgr);
|
||||
formatMgr.addFormatModelListener(this);
|
||||
program.addListener(this);
|
||||
@@ -160,33 +161,43 @@ public class ProgramBigListingModel implements ListingModel, FormatModelListener
|
||||
addOpenData(dataList, data, addr);
|
||||
addUnionPostOpenData(dataList, data, addr);
|
||||
}
|
||||
boolean isClosedFunctionAddress = isClosedFunctionAddress(function, addr);
|
||||
|
||||
if (isGapAddress) {
|
||||
format = formatMgr.getDividerModel();
|
||||
format.addLayouts(list, 0, new AddressProxy(this, addr));
|
||||
}
|
||||
if (cu != null) {
|
||||
if (cu != null && function != null) {
|
||||
format = formatMgr.getPlateFormat();
|
||||
format.addLayouts(list, 0, new CodeUnitProxy(this, program, cu));
|
||||
}
|
||||
if (function != null) {
|
||||
format = formatMgr.getFunctionFormat();
|
||||
format.addLayouts(list, 0, new FunctionProxy(this, program, addr, function));
|
||||
format = formatMgr.getFunctionVarFormat();
|
||||
boolean variablesOpen = openCloseMgr.isFunctionVariablesOpen(function.getEntryPoint());
|
||||
if (variablesOpen) {
|
||||
addReturn(addr, list, format, function);
|
||||
addParameters(addr, list, format, function);
|
||||
addLocals(addr, list, format, function);
|
||||
if (!isClosedFunctionAddress) {
|
||||
format = formatMgr.getFunctionVarFormat();
|
||||
boolean variablesOpen =
|
||||
openCloseMgr.isFunctionVariablesOpen(function.getEntryPoint());
|
||||
if (variablesOpen) {
|
||||
addReturn(addr, list, format, function);
|
||||
addParameters(addr, list, format, function);
|
||||
addLocals(addr, list, format, function);
|
||||
}
|
||||
else {
|
||||
format.addLayouts(list, 0,
|
||||
new ClosedVariableProxy(this, program, addr, function));
|
||||
}
|
||||
}
|
||||
else {
|
||||
format.addLayouts(list, 0, new ClosedVariableProxy(this, program, addr, function));
|
||||
}
|
||||
|
||||
}
|
||||
if (cu != null) {
|
||||
format = formatMgr.getCodeUnitFormat();
|
||||
format.addLayouts(list, 0, new CodeUnitProxy(this, program, cu));
|
||||
if (isClosedFunctionAddress) {
|
||||
format = formatMgr.getDividerModel();
|
||||
}
|
||||
else {
|
||||
format = formatMgr.getCodeUnitFormat();
|
||||
}
|
||||
CodeUnitProxy proxy = new CodeUnitProxy(this, program, cu);
|
||||
format.addLayouts(list, 0, proxy);
|
||||
}
|
||||
|
||||
if (dataList != null) {
|
||||
@@ -213,6 +224,16 @@ public class ProgramBigListingModel implements ListingModel, FormatModelListener
|
||||
|
||||
}
|
||||
|
||||
private boolean isClosedFunctionAddress(Function function, Address addr) {
|
||||
if (function == null) {
|
||||
function = listing.getFunctionContaining(addr);
|
||||
}
|
||||
if (function == null) {
|
||||
return false;
|
||||
}
|
||||
return !openCloseMgr.isFunctionOpen(function.getEntryPoint());
|
||||
}
|
||||
|
||||
private void addReturn(Address addr, List<RowLayout> list, FieldFormatModel format,
|
||||
Function function) {
|
||||
format.addLayouts(list, 0,
|
||||
@@ -257,6 +278,35 @@ public class ProgramBigListingModel implements ListingModel, FormatModelListener
|
||||
return formatMgr.getMaxWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address getAddressBefore(Address addr) {
|
||||
CodeUnit cu = listing.getCodeUnitContaining(addr);
|
||||
if (cu instanceof Data && !addr.equals(cu.getMinAddress()) && isOpenData(cu)) {
|
||||
Address prevAddr = findOpenDataBefore(addr, (Data) cu);
|
||||
if (prevAddr != null) {
|
||||
return prevAddr;
|
||||
}
|
||||
return cu.getMinAddress();
|
||||
}
|
||||
|
||||
cu = listing.getCodeUnitBefore(addr);
|
||||
if (cu == null) {
|
||||
return null;
|
||||
}
|
||||
if (isOpenData(cu)) {
|
||||
return cu.getMaxAddress();
|
||||
}
|
||||
if (!isInClosedFunction(cu)) {
|
||||
return cu.getAddress();
|
||||
}
|
||||
Address firstAddress = getFirstAddressInClosedFunctionRange(cu);
|
||||
cu = listing.getCodeUnitAt(firstAddress);
|
||||
if (!isInClosedFunction(cu)) {
|
||||
return cu.getMinAddress();
|
||||
}
|
||||
return getAddressBefore(firstAddress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address getAddressAfter(Address address) {
|
||||
CodeUnit cu = listing.getCodeUnitContaining(address);
|
||||
@@ -272,7 +322,51 @@ public class ProgramBigListingModel implements ListingModel, FormatModelListener
|
||||
}
|
||||
}
|
||||
cu = listing.getCodeUnitAfter(address);
|
||||
return cu == null ? null : cu.getMinAddress();
|
||||
if (cu == null) {
|
||||
return null;
|
||||
}
|
||||
if (!isInClosedFunction(cu)) {
|
||||
return cu.getAddress();
|
||||
}
|
||||
Address lastAddress = getLastAddressInClosedFunctionRange(cu);
|
||||
return getAddressAfter(lastAddress);
|
||||
}
|
||||
|
||||
private Address getLastAddressInClosedFunctionRange(CodeUnit cu) {
|
||||
Address address = cu.getAddress();
|
||||
Function f = listing.getFunctionContaining(address);
|
||||
AddressSetView body = f.getBody();
|
||||
AddressRange range = body.getRangeContaining(address);
|
||||
return range.getMaxAddress();
|
||||
}
|
||||
|
||||
private Address getFirstAddressInClosedFunctionRange(CodeUnit cu) {
|
||||
Address address = cu.getAddress();
|
||||
Function f = listing.getFunctionContaining(address);
|
||||
AddressSetView body = f.getBody();
|
||||
AddressRange range = body.getRangeContaining(address);
|
||||
return range.getMinAddress();
|
||||
}
|
||||
|
||||
private boolean isInClosedFunction(CodeUnit cu) {
|
||||
Address a = cu.getAddress();
|
||||
Function f = listing.getFunctionContaining(a);
|
||||
if (f == null) {
|
||||
return false;
|
||||
}
|
||||
Address entryPoint = f.getEntryPoint();
|
||||
if (a.equals(entryPoint)) {
|
||||
return false;
|
||||
}
|
||||
AddressSetView body = f.getBody();
|
||||
AddressRange rangeContaining = body.getRangeContaining(a);
|
||||
if (rangeContaining.getMinAddress().equals(a)) {
|
||||
return false;
|
||||
}
|
||||
if (openCloseMgr.isFunctionOpen(entryPoint)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private Address findOpenDataAfter(Address address, Data parent) {
|
||||
@@ -344,25 +438,6 @@ public class ProgramBigListingModel implements ListingModel, FormatModelListener
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address getAddressBefore(Address addr) {
|
||||
CodeUnit cu = listing.getCodeUnitContaining(addr);
|
||||
if (cu == null || addr.equals(cu.getMinAddress())) {
|
||||
cu = listing.getCodeUnitBefore(addr);
|
||||
if (isOpenData(cu)) {
|
||||
return cu.getMaxAddress();
|
||||
}
|
||||
return cu == null ? null : cu.getMinAddress();
|
||||
}
|
||||
if (isOpenData(cu)) {
|
||||
Address prevAddr = findOpenDataBefore(addr, (Data) cu);
|
||||
if (prevAddr != null) {
|
||||
return prevAddr;
|
||||
}
|
||||
}
|
||||
return cu.getMinAddress();
|
||||
}
|
||||
|
||||
public boolean isOpenData(CodeUnit cu) {
|
||||
if (cu instanceof Data) {
|
||||
Data data = (Data) cu;
|
||||
@@ -491,8 +566,8 @@ public class ProgramBigListingModel implements ListingModel, FormatModelListener
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFunctionVariablesOpen(Address functionAddress, boolean open) {
|
||||
openCloseMgr.setFunctionVariablesOpen(functionAddress, open);
|
||||
public void setFunctionVariablesOpen(Address functionEntry, boolean open) {
|
||||
openCloseMgr.setFunctionVariablesOpen(functionEntry, open);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -501,8 +576,23 @@ public class ProgramBigListingModel implements ListingModel, FormatModelListener
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areFunctionVariablesOpen(Address FunctionAddress) {
|
||||
return openCloseMgr.isFunctionVariablesOpen(FunctionAddress);
|
||||
public boolean areFunctionVariablesOpen(Address functionEntry) {
|
||||
return openCloseMgr.isFunctionVariablesOpen(functionEntry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFunctionOpen(Address functionEntry) {
|
||||
return openCloseMgr.isFunctionOpen(functionEntry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFunctionOpen(Address functionEntry, boolean b) {
|
||||
openCloseMgr.setFunctionOpen(functionEntry, b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAllFunctionsOpen(boolean selected) {
|
||||
openCloseMgr.setAllFunctionsOpen(selected);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -647,4 +737,5 @@ public class ProgramBigListingModel implements ListingModel, FormatModelListener
|
||||
model.openCloseMgr = openCloseMgr;
|
||||
return model;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -212,4 +212,19 @@ public class ListingModelConverter implements ListingModel {
|
||||
return new ListingModelConverter(primaryModel.copy(), model.copy());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFunctionOpen(Address functionAddress) {
|
||||
return model.isFunctionOpen(functionAddress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFunctionOpen(Address functionAddress, boolean b) {
|
||||
model.setFunctionOpen(functionAddress, b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAllFunctionsOpen(boolean selected) {
|
||||
model.setAllFunctionsOpen(selected);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -352,6 +352,21 @@ public class MultiListingLayoutModel implements ListingModelListener, FormatMode
|
||||
return models[modelID].copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFunctionOpen(Address functionAddress) {
|
||||
return models[modelID].isFunctionOpen(functionAddress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFunctionOpen(Address functionAddress, boolean b) {
|
||||
models[modelID].setFunctionOpen(functionAddress, b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAllFunctionsOpen(boolean selected) {
|
||||
models[modelID].setAllFunctionsOpen(selected);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -61,7 +61,8 @@ public class ListingDisplayOptionsEditor implements OptionsEditor {
|
||||
options.registerThemeColorBinding(colorOptionName, element.getThemeColorId(), null,
|
||||
prefix + colorOptionName);
|
||||
String styleOptionName = element.getStyleOptionName();
|
||||
options.registerOption(styleOptionName, -1, null, prefix + styleOptionName);
|
||||
int style = element.getStyle();
|
||||
options.registerOption(styleOptionName, style, null, prefix + styleOptionName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -83,6 +83,7 @@ public class OptionsGui extends JPanel {
|
||||
public static final ScreenElement FLOW_ARROW_SELECTED = new ScreenElement("Flow Arrow, Selected", FlowArrowColors.SELECTED);
|
||||
public static final ScreenElement LABELS_PRIMARY = new ScreenElement("Labels, Primary", LabelColors.PRIMARY);
|
||||
public static final ScreenElement LABELS_NON_PRIMARY = new ScreenElement("Labels, Non-primary", LabelColors.NON_PRIMARY);
|
||||
public static final ScreenElement COLLAPSED_CODE = new ScreenElement("Collapsed Code", ListingColors.COLLAPSED_CODE, Font.ITALIC);
|
||||
public static final ScreenElement COMMENT_PLATE = new ScreenElement("Comment, Plate", "Plate Comment", CommentColors.PLATE);
|
||||
public static final ScreenElement COMMENT_POST = new ScreenElement("Comment, Post", "Post-Comment", CommentColors.POST);
|
||||
public static final ScreenElement COMMENT_PRE = new ScreenElement("Comment, Pre", "Pre-Comment", CommentColors.PRE);
|
||||
@@ -99,10 +100,9 @@ public class OptionsGui extends JPanel {
|
||||
public static final ScreenElement PCODE_ADDR_SPACE = new ScreenElement("P-code Address Space", PcodeColors.ADDRESS_SPACE);
|
||||
public static final ScreenElement PCODE_RAW_VARNODE = new ScreenElement("P-code Raw Varnode", PcodeColors.VARNODE);
|
||||
public static final ScreenElement PCODE_USEROP = new ScreenElement("P-code Userop", PcodeColors.USEROP);
|
||||
|
||||
static ScreenElement[] elements = {
|
||||
ADDRESS,
|
||||
BACKGROUND, BAD_REF_ADDR, BYTES,
|
||||
BACKGROUND, BAD_REF_ADDR, BYTES, COLLAPSED_CODE,
|
||||
COMMENT_AUTO, COMMENT_EOL, COMMENT_PLATE, COMMENT_POST, COMMENT_PRE, COMMENT_REPEATABLE,
|
||||
COMMENT_REF_REPEAT, CONSTANT,
|
||||
ENTRY_POINT, EXT_REF_RESOLVED, EXT_REF_UNRESOLVED,
|
||||
@@ -716,6 +716,26 @@ public class OptionsGui extends JPanel {
|
||||
lb.add(" ", null);
|
||||
list.add(lb.getLayout());
|
||||
|
||||
lb = new LayoutBuilder(1);
|
||||
lb.add(" /***********************************/", COMMENT_PLATE);
|
||||
list.add(lb.getLayout());
|
||||
lb = new LayoutBuilder(1);
|
||||
lb.add(" /* PLATE */", COMMENT_PLATE);
|
||||
list.add(lb.getLayout());
|
||||
lb = new LayoutBuilder(1);
|
||||
lb.add(" /***********************************/", COMMENT_PLATE);
|
||||
list.add(lb.getLayout());
|
||||
lb = new LayoutBuilder(4);
|
||||
lb.add(" ", null);
|
||||
lb.add("Word ", FUN_RET_TYPE);
|
||||
lb.add("AnotherFunc", FUN_NAME);
|
||||
lb.add("(", SEPARATOR);
|
||||
lb.add(")", SEPARATOR);
|
||||
list.add(lb.getLayout());
|
||||
lb = new LayoutBuilder(1);
|
||||
lb.add("<Collapsed Code: AnotherFunc>", COLLAPSED_CODE);
|
||||
list.add(lb.getLayout());
|
||||
|
||||
layouts = new Layout[list.size()];
|
||||
list.toArray(layouts);
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -27,15 +27,23 @@ public class ScreenElement {
|
||||
private int style;
|
||||
|
||||
ScreenElement(String name, GColor defaultColor) {
|
||||
this(name, name, defaultColor);
|
||||
this(name, name, defaultColor, -1);
|
||||
}
|
||||
|
||||
ScreenElement(String name, GColor defaultColor, int style) {
|
||||
this(name, name, defaultColor, style);
|
||||
}
|
||||
|
||||
ScreenElement(String name, String optionsName, GColor defaultColor) {
|
||||
this(name, optionsName, defaultColor, -1);
|
||||
}
|
||||
|
||||
ScreenElement(String name, String optionsName, GColor defaultColor, int style) {
|
||||
this.name = name;
|
||||
this.optionsName = optionsName;
|
||||
this.defaultColor = defaultColor;
|
||||
this.color = defaultColor;
|
||||
this.style = -1;
|
||||
this.style = style;
|
||||
}
|
||||
|
||||
public String getThemeColorId() {
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -109,4 +109,8 @@ public class FunctionProxy extends ProxyObj<Function> {
|
||||
}
|
||||
return f.getBody().contains(a);
|
||||
}
|
||||
|
||||
public Program getProgram() {
|
||||
return program;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ import ghidra.program.model.address.Address;
|
||||
* state can be set and then a set of address is kept for the locations that are the opposite
|
||||
* of the default.
|
||||
*/
|
||||
public class AddressBasedOpenCloseManager {
|
||||
public class InMemoryOpenCloseManager {
|
||||
private boolean openByDefault = true;
|
||||
private Set<Address> addresses = new HashSet<>();
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
/* ###
|
||||
* 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.app.util.viewer.util;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.listing.ProgramUserData;
|
||||
import ghidra.program.model.util.VoidPropertyMap;
|
||||
|
||||
/**
|
||||
* Address based open/close management that uses the {@link ProgramUserData} to persist the
|
||||
* open/close state for that address. Currently used for persisting the open/close state
|
||||
* of functions in the listing.
|
||||
*/
|
||||
public class PersistentOpenCloseManager {
|
||||
private boolean openByDefault = true;
|
||||
private VoidPropertyMap booleanProperty;
|
||||
private ProgramUserData programUserData;
|
||||
|
||||
// Often, isOpen will be called on the same function address many times in a row so cache
|
||||
// the last address and result
|
||||
private Address cachedAddress;
|
||||
private boolean cachedResult;
|
||||
private String defaultOpenClosePropertyname;
|
||||
|
||||
public PersistentOpenCloseManager(Program program, String owner, String propertyName) {
|
||||
this.defaultOpenClosePropertyname = propertyName + "Default";
|
||||
programUserData = program.getProgramUserData();
|
||||
|
||||
int tx = programUserData.startTransaction();
|
||||
try {
|
||||
booleanProperty =
|
||||
programUserData.getBooleanProperty(owner, propertyName, true);
|
||||
}
|
||||
finally {
|
||||
programUserData.endTransaction(tx);
|
||||
}
|
||||
|
||||
// Get the default open state. Only addresses different from default have properties stored.
|
||||
String functionState =
|
||||
programUserData.getStringProperty(defaultOpenClosePropertyname, "Open");
|
||||
openByDefault = functionState.equals("Open");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the state is "open" for the given address.
|
||||
* @param address the address to test
|
||||
* @return true if the state of the given address is "open"
|
||||
*/
|
||||
public boolean isOpen(Address address) {
|
||||
if (address.equals(cachedAddress)) {
|
||||
return cachedResult;
|
||||
}
|
||||
cachedAddress = address;
|
||||
boolean contains = booleanProperty.hasProperty(address);
|
||||
cachedResult = openByDefault ? !contains : contains;
|
||||
return cachedResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the state at the given address to be "open".
|
||||
* @param address the address to set "open"
|
||||
*/
|
||||
public void open(Address address) {
|
||||
cachedAddress = null;
|
||||
if (openByDefault) {
|
||||
removeAddressProperty(address);
|
||||
}
|
||||
else {
|
||||
addAddressProperty(address);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the state at the given address to be "closed".
|
||||
* @param address the address to set "closed"
|
||||
*/
|
||||
public void close(Address address) {
|
||||
cachedAddress = null;
|
||||
if (openByDefault) {
|
||||
addAddressProperty(address);
|
||||
}
|
||||
else {
|
||||
removeAddressProperty(address);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the default state is "open".
|
||||
* @return true if the default state for addresses is "open"
|
||||
*/
|
||||
public boolean isOpenByDefault() {
|
||||
return openByDefault;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all address to "open" (Makes "open" the default state and clears all individual
|
||||
* settings.
|
||||
*/
|
||||
public void openAll() {
|
||||
cachedAddress = null;
|
||||
openByDefault = true;
|
||||
clearProperties();
|
||||
programUserData.setStringProperty(defaultOpenClosePropertyname, "Open");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all address to "closed" (Makes "closed" the default state and clears all individual
|
||||
* settings.
|
||||
*/
|
||||
public void closeAll() {
|
||||
cachedAddress = null;
|
||||
openByDefault = false;
|
||||
clearProperties();
|
||||
programUserData.setStringProperty(defaultOpenClosePropertyname, "Closed");
|
||||
}
|
||||
|
||||
private void addAddressProperty(Address address) {
|
||||
int tx = programUserData.startTransaction();
|
||||
try {
|
||||
booleanProperty.add(address);
|
||||
}
|
||||
finally {
|
||||
programUserData.endTransaction(tx);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeAddressProperty(Address address) {
|
||||
int tx = programUserData.startTransaction();
|
||||
try {
|
||||
booleanProperty.remove(address);
|
||||
}
|
||||
finally {
|
||||
programUserData.endTransaction(tx);
|
||||
}
|
||||
}
|
||||
|
||||
private void clearProperties() {
|
||||
int tx = programUserData.startTransaction();
|
||||
try {
|
||||
booleanProperty.clear();
|
||||
}
|
||||
finally {
|
||||
programUserData.endTransaction(tx);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -33,30 +33,42 @@ import ghidra.util.task.TaskMonitor;
|
||||
public class ProgramOpenCloseManager {
|
||||
private DataOpenCloseManager dataOpenCloseManager = new DataOpenCloseManager();
|
||||
private List<ChangeListener> listeners = new ArrayList<>();
|
||||
private AddressBasedOpenCloseManager variablesOpenCloseManager = new AddressBasedOpenCloseManager();
|
||||
private InMemoryOpenCloseManager variablesOpenCloseManager;
|
||||
private PersistentOpenCloseManager functionsOpenCloseManager;
|
||||
|
||||
public ProgramOpenCloseManager(Program program) {
|
||||
// open/close functions states are persisted and specific to a program
|
||||
functionsOpenCloseManager = new PersistentOpenCloseManager(program,
|
||||
getClass().getSimpleName(), "Function Open State");
|
||||
|
||||
// open/close variables states are tool based so users can
|
||||
// choose whether to see them by default. They can be opened or closed
|
||||
// for specific functions in specific program, but this is not persisted for the program.
|
||||
variablesOpenCloseManager = new InMemoryOpenCloseManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether or not to display function variables at the given address.
|
||||
* @param functionAddress the address of the function
|
||||
* @param functionEntry the address of the function
|
||||
* @param open true to display function variables, false to to hide them
|
||||
*/
|
||||
public void setFunctionVariablesOpen(Address functionAddress, boolean open) {
|
||||
public void setFunctionVariablesOpen(Address functionEntry, boolean open) {
|
||||
if (open) {
|
||||
variablesOpenCloseManager.open(functionAddress);
|
||||
variablesOpenCloseManager.open(functionEntry);
|
||||
}
|
||||
else {
|
||||
variablesOpenCloseManager.close(functionAddress);
|
||||
variablesOpenCloseManager.close(functionEntry);
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the function variables are being shown at the given function address.
|
||||
* @param functionAddress the address of the function to check
|
||||
* @param functionEntry the address of the function to check
|
||||
* @return true if the variables are being displayed
|
||||
*/
|
||||
public boolean isFunctionVariablesOpen(Address functionAddress) {
|
||||
return variablesOpenCloseManager.isOpen(functionAddress);
|
||||
public boolean isFunctionVariablesOpen(Address functionEntry) {
|
||||
return variablesOpenCloseManager.isOpen(functionEntry);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,8 +86,42 @@ public class ProgramOpenCloseManager {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
public boolean isAllFunctionVariablesOpen() {
|
||||
return variablesOpenCloseManager.isOpenByDefault();
|
||||
/**
|
||||
* Returns true if the function at the given address is open.
|
||||
* @param functionEntry the function address to test if the function is open
|
||||
* @return true if the function at the given address is open
|
||||
*/
|
||||
public boolean isFunctionOpen(Address functionEntry) {
|
||||
return functionsOpenCloseManager.isOpen(functionEntry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the function at the given address to be open or closed.
|
||||
* @param functionEntry the address of the function to open or close
|
||||
* @param open true to open the function, false to close it
|
||||
*/
|
||||
public void setFunctionOpen(Address functionEntry, boolean open) {
|
||||
if (open) {
|
||||
functionsOpenCloseManager.open(functionEntry);
|
||||
}
|
||||
else {
|
||||
functionsOpenCloseManager.close(functionEntry);
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all functions to be open or closed.
|
||||
* @param open true to open all functions, false to close them
|
||||
*/
|
||||
public void setAllFunctionsOpen(boolean open) {
|
||||
if (open) {
|
||||
functionsOpenCloseManager.openAll();
|
||||
}
|
||||
else {
|
||||
functionsOpenCloseManager.closeAll();
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,4 +210,5 @@ public class ProgramOpenCloseManager {
|
||||
l.stateChanged(null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
/* ###
|
||||
* 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.app.util.viewer.util;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.*;
|
||||
|
||||
import ghidra.framework.model.*;
|
||||
import ghidra.program.database.ProgramBuilder;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||
import ghidra.test.TestEnv;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class PersistentOpenCloseManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
private DomainFile df;
|
||||
private AddressSpace space;
|
||||
private Program program;
|
||||
private PersistentOpenCloseManager openCloseMgr;
|
||||
private TestEnv env;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
env = new TestEnv();
|
||||
Project project = env.getProject();
|
||||
ProgramBuilder builder = new ProgramBuilder("Test", ProgramBuilder._TOY, this);
|
||||
ProjectData projectData = project.getProjectData();
|
||||
|
||||
DomainFolder rootFolder = projectData.getRootFolder();
|
||||
program = builder.getProgram();
|
||||
df = rootFolder.createFile("test", program, TaskMonitor.DUMMY);
|
||||
|
||||
space = program.getAddressFactory().getDefaultAddressSpace();
|
||||
openCloseMgr = new PersistentOpenCloseManager(program, "test", "test");
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
env.dispose();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOpenByDefaultCloseAllOpenAll() throws Exception {
|
||||
assertTrue(openCloseMgr.isOpen(addr(0)));
|
||||
assertTrue(openCloseMgr.isOpen(addr(100)));
|
||||
assertTrue(openCloseMgr.isOpenByDefault());
|
||||
|
||||
openCloseMgr.closeAll();
|
||||
|
||||
assertFalse(openCloseMgr.isOpen(addr(0)));
|
||||
assertFalse(openCloseMgr.isOpen(addr(100)));
|
||||
assertFalse(openCloseMgr.isOpenByDefault());
|
||||
|
||||
openCloseMgr.openAll();
|
||||
assertTrue(openCloseMgr.isOpen(addr(0)));
|
||||
assertTrue(openCloseMgr.isOpen(addr(100)));
|
||||
assertTrue(openCloseMgr.isOpenByDefault());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCloseAndOpenSpecificAddresses() throws Exception {
|
||||
assertTrue(openCloseMgr.isOpen(addr(0)));
|
||||
assertTrue(openCloseMgr.isOpen(addr(100)));
|
||||
|
||||
openCloseMgr.close(addr(0));
|
||||
|
||||
assertFalse(openCloseMgr.isOpen(addr(0)));
|
||||
assertTrue(openCloseMgr.isOpen(addr(100)));
|
||||
|
||||
openCloseMgr.open(addr(0));
|
||||
|
||||
assertTrue(openCloseMgr.isOpen(addr(0)));
|
||||
assertTrue(openCloseMgr.isOpen(addr(100)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOpenAndCloseSpecificAddressesWithDefaultClosed() throws Exception {
|
||||
openCloseMgr.closeAll();
|
||||
|
||||
assertFalse(openCloseMgr.isOpen(addr(0)));
|
||||
assertFalse(openCloseMgr.isOpen(addr(100)));
|
||||
|
||||
openCloseMgr.open(addr(0));
|
||||
|
||||
assertTrue(openCloseMgr.isOpen(addr(0)));
|
||||
assertFalse(openCloseMgr.isOpen(addr(100)));
|
||||
|
||||
openCloseMgr.close(addr(0));
|
||||
|
||||
assertFalse(openCloseMgr.isOpen(addr(0)));
|
||||
assertFalse(openCloseMgr.isOpen(addr(100)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPersistence() throws Exception {
|
||||
openCloseMgr.closeAll();
|
||||
assertFalse(openCloseMgr.isOpen(addr(0)));
|
||||
assertFalse(openCloseMgr.isOpen(addr(100)));
|
||||
|
||||
openCloseMgr.open(addr(0));
|
||||
assertTrue(openCloseMgr.isOpen(addr(0)));
|
||||
assertFalse(openCloseMgr.isOpen(addr(100)));
|
||||
|
||||
program.release(this);
|
||||
program = (Program) df.getDomainObject(this, false, false, TaskMonitor.DUMMY);
|
||||
space = program.getAddressFactory().getDefaultAddressSpace();
|
||||
openCloseMgr = new PersistentOpenCloseManager(program, "test", "test");
|
||||
|
||||
assertTrue(openCloseMgr.isOpen(addr(0)));
|
||||
assertFalse(openCloseMgr.isOpen(addr(100)));
|
||||
assertFalse(openCloseMgr.isOpenByDefault());
|
||||
}
|
||||
|
||||
private Address addr(long offset) {
|
||||
return space.getAddress(offset);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
/* ###
|
||||
* 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.app.util.viewer.listingpanel;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import generic.test.AbstractGenericTest;
|
||||
import ghidra.app.util.viewer.format.FormatManager;
|
||||
import ghidra.framework.options.SaveState;
|
||||
import ghidra.framework.options.ToolOptions;
|
||||
import ghidra.program.database.ProgramBuilder;
|
||||
import ghidra.program.database.ProgramDB;
|
||||
import ghidra.program.database.function.OverlappingFunctionException;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
public class ProgramBigListingModelTest extends AbstractGenericTest {
|
||||
|
||||
private ProgramDB program;
|
||||
private ProgramBigListingModel model;
|
||||
private AddressSpace space;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
ProgramBuilder builder = new ProgramBuilder("Test", ProgramBuilder._X86);
|
||||
program = builder.getProgram();
|
||||
space = program.getAddressFactory().getDefaultAddressSpace();
|
||||
builder.createMemory("block1", "0", 18);
|
||||
buildFun0(builder);
|
||||
|
||||
FormatManager formatManager =
|
||||
new FormatManager(new ToolOptions("display"), new ToolOptions("Listing Fields"));
|
||||
formatManager.readState(new SaveState()); // this will use default format
|
||||
model = new ProgramBigListingModel(program, formatManager);
|
||||
}
|
||||
|
||||
private void buildFun0(ProgramBuilder builder) throws OverlappingFunctionException {
|
||||
Function fun0 = builder.createFunction("0");
|
||||
AddressSet addrs = new AddressSet();
|
||||
addrs.add(addr(0), addr(3));
|
||||
addrs.add(addr(6), addr(9));
|
||||
addrs.add(addr(12), addr(15));
|
||||
program.withTransaction("test", () -> fun0.setBody(addrs));
|
||||
}
|
||||
|
||||
private Address addr(long offset) {
|
||||
return space.getAddress(offset);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetNextAddressWithFunctionOpen() {
|
||||
assertEquals(addr(1), model.getAddressAfter(addr(0)));
|
||||
assertEquals(addr(2), model.getAddressAfter(addr(1)));
|
||||
assertEquals(addr(3), model.getAddressAfter(addr(2)));
|
||||
assertEquals(addr(4), model.getAddressAfter(addr(3)));
|
||||
assertEquals(addr(5), model.getAddressAfter(addr(4)));
|
||||
assertEquals(addr(6), model.getAddressAfter(addr(5)));
|
||||
assertEquals(addr(7), model.getAddressAfter(addr(6)));
|
||||
assertEquals(addr(8), model.getAddressAfter(addr(7)));
|
||||
assertEquals(addr(9), model.getAddressAfter(addr(8)));
|
||||
assertEquals(addr(10), model.getAddressAfter(addr(9)));
|
||||
assertEquals(addr(11), model.getAddressAfter(addr(10)));
|
||||
assertEquals(addr(12), model.getAddressAfter(addr(11)));
|
||||
assertEquals(addr(13), model.getAddressAfter(addr(12)));
|
||||
assertEquals(addr(14), model.getAddressAfter(addr(13)));
|
||||
assertEquals(addr(15), model.getAddressAfter(addr(14)));
|
||||
assertEquals(addr(16), model.getAddressAfter(addr(15)));
|
||||
assertEquals(addr(17), model.getAddressAfter(addr(16)));
|
||||
assertNull(model.getAddressAfter(addr(17)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetNextAddressWithFunctionClosed() {
|
||||
model.setFunctionOpen(addr(0), false);
|
||||
|
||||
assertEquals(addr(4), model.getAddressAfter(addr(0)));
|
||||
assertEquals(addr(4), model.getAddressAfter(addr(1)));
|
||||
assertEquals(addr(4), model.getAddressAfter(addr(2)));
|
||||
assertEquals(addr(4), model.getAddressAfter(addr(3)));
|
||||
assertEquals(addr(5), model.getAddressAfter(addr(4)));
|
||||
assertEquals(addr(6), model.getAddressAfter(addr(5)));
|
||||
assertEquals(addr(10), model.getAddressAfter(addr(6)));
|
||||
assertEquals(addr(10), model.getAddressAfter(addr(7)));
|
||||
assertEquals(addr(10), model.getAddressAfter(addr(8)));
|
||||
assertEquals(addr(10), model.getAddressAfter(addr(9)));
|
||||
assertEquals(addr(11), model.getAddressAfter(addr(10)));
|
||||
assertEquals(addr(12), model.getAddressAfter(addr(11)));
|
||||
assertEquals(addr(16), model.getAddressAfter(addr(12)));
|
||||
assertEquals(addr(16), model.getAddressAfter(addr(13)));
|
||||
assertEquals(addr(16), model.getAddressAfter(addr(14)));
|
||||
assertEquals(addr(16), model.getAddressAfter(addr(15)));
|
||||
assertEquals(addr(17), model.getAddressAfter(addr(16)));
|
||||
assertNull(model.getAddressAfter(addr(17)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPreviousAddressWithFunctionOpen() {
|
||||
assertNull(model.getAddressBefore(addr(0)));
|
||||
assertEquals(addr(0), model.getAddressBefore(addr(1)));
|
||||
assertEquals(addr(1), model.getAddressBefore(addr(2)));
|
||||
assertEquals(addr(2), model.getAddressBefore(addr(3)));
|
||||
assertEquals(addr(3), model.getAddressBefore(addr(4)));
|
||||
assertEquals(addr(4), model.getAddressBefore(addr(5)));
|
||||
assertEquals(addr(5), model.getAddressBefore(addr(6)));
|
||||
assertEquals(addr(6), model.getAddressBefore(addr(7)));
|
||||
assertEquals(addr(7), model.getAddressBefore(addr(8)));
|
||||
assertEquals(addr(8), model.getAddressBefore(addr(9)));
|
||||
assertEquals(addr(9), model.getAddressBefore(addr(10)));
|
||||
assertEquals(addr(10), model.getAddressBefore(addr(11)));
|
||||
assertEquals(addr(11), model.getAddressBefore(addr(12)));
|
||||
assertEquals(addr(12), model.getAddressBefore(addr(13)));
|
||||
assertEquals(addr(13), model.getAddressBefore(addr(14)));
|
||||
assertEquals(addr(14), model.getAddressBefore(addr(15)));
|
||||
assertEquals(addr(15), model.getAddressBefore(addr(16)));
|
||||
assertEquals(addr(16), model.getAddressBefore(addr(17)));
|
||||
assertEquals(addr(17), model.getAddressBefore(addr(18)));
|
||||
assertEquals(addr(17), model.getAddressBefore(addr(19)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPreviousAddressWithFunctionClosed() {
|
||||
model.setFunctionOpen(addr(0), false);
|
||||
|
||||
assertNull(model.getAddressBefore(addr(0)));
|
||||
assertEquals(addr(0), model.getAddressBefore(addr(1)));
|
||||
assertEquals(addr(0), model.getAddressBefore(addr(2)));
|
||||
assertEquals(addr(0), model.getAddressBefore(addr(3)));
|
||||
assertEquals(addr(0), model.getAddressBefore(addr(4)));
|
||||
assertEquals(addr(4), model.getAddressBefore(addr(5)));
|
||||
assertEquals(addr(5), model.getAddressBefore(addr(6)));
|
||||
assertEquals(addr(6), model.getAddressBefore(addr(7)));
|
||||
assertEquals(addr(6), model.getAddressBefore(addr(8)));
|
||||
assertEquals(addr(6), model.getAddressBefore(addr(9)));
|
||||
assertEquals(addr(6), model.getAddressBefore(addr(10)));
|
||||
assertEquals(addr(10), model.getAddressBefore(addr(11)));
|
||||
assertEquals(addr(11), model.getAddressBefore(addr(12)));
|
||||
assertEquals(addr(12), model.getAddressBefore(addr(13)));
|
||||
assertEquals(addr(12), model.getAddressBefore(addr(14)));
|
||||
assertEquals(addr(12), model.getAddressBefore(addr(15)));
|
||||
assertEquals(addr(12), model.getAddressBefore(addr(16)));
|
||||
assertEquals(addr(16), model.getAddressBefore(addr(17)));
|
||||
assertEquals(addr(17), model.getAddressBefore(addr(18)));
|
||||
assertEquals(addr(17), model.getAddressBefore(addr(19)));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -213,6 +213,20 @@ public abstract class PropertyMapDB<T> extends DatabaseObject implements Propert
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
if (propertyTable == null) {
|
||||
return;
|
||||
}
|
||||
cache = new ObjectCache<>(DEFAULT_CACHE_SIZE);
|
||||
try {
|
||||
propertyTable.deleteAll();
|
||||
}
|
||||
catch (IOException e) {
|
||||
errHandler.dbError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust the size of the underlying read cache.
|
||||
* @param size the size of the cache.
|
||||
@@ -225,7 +239,6 @@ public abstract class PropertyMapDB<T> extends DatabaseObject implements Propert
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -79,6 +79,21 @@ public abstract class DefaultPropertyMap<T> implements PropertyMap<T> {
|
||||
return description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
if (getSize() == 0) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
long first = propertyMgr.getFirstPropertyIndex();
|
||||
long last = propertyMgr.getLastPropertyIndex();
|
||||
propertyMgr.removeRange(first, last);
|
||||
}
|
||||
catch (NoSuchIndexException e) {
|
||||
// can't happen since we checked it isn't empty
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean intersects(Address start, Address end) {
|
||||
return propertyMgr.intersects(addrMap.getKey(start), addrMap.getKey(end));
|
||||
|
||||
@@ -34,6 +34,11 @@ public interface PropertyMap<T> {
|
||||
*/
|
||||
public Class<T> getValueClass();
|
||||
|
||||
/**
|
||||
* Removes all properties from this map
|
||||
*/
|
||||
public void clear();
|
||||
|
||||
/**
|
||||
* Given two addresses, indicate whether there is an address in
|
||||
* that range (inclusive) having the property.
|
||||
@@ -45,7 +50,7 @@ public interface PropertyMap<T> {
|
||||
* has the property, false otherwise.
|
||||
*/
|
||||
public boolean intersects(Address start, Address end);
|
||||
|
||||
|
||||
/**
|
||||
* Indicate whether there is an address within
|
||||
* the set which exists within this map.
|
||||
@@ -55,7 +60,7 @@ public interface PropertyMap<T> {
|
||||
* has the property, false otherwise.
|
||||
*/
|
||||
public boolean intersects(AddressSetView set);
|
||||
|
||||
|
||||
/**
|
||||
* Removes all property values within a given range.
|
||||
* @param start begin range
|
||||
@@ -64,6 +69,7 @@ public interface PropertyMap<T> {
|
||||
* false otherwise.
|
||||
*/
|
||||
public boolean removeRange(Address start, Address end);
|
||||
|
||||
/**
|
||||
* Remove the property value at the given address.
|
||||
* @return true if the property value was removed, false
|
||||
@@ -71,7 +77,7 @@ public interface PropertyMap<T> {
|
||||
* @param addr the address where the property should be removed
|
||||
*/
|
||||
public boolean remove(Address addr);
|
||||
|
||||
|
||||
/**
|
||||
* returns whether there is a property value at addr.
|
||||
* @param addr the address in question
|
||||
@@ -86,7 +92,7 @@ public interface PropertyMap<T> {
|
||||
* @throws IllegalArgumentException if property value type is inappropriate for this map
|
||||
*/
|
||||
public void add(Address addr, Object value);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the property value stored at the specified
|
||||
* address or null if no property found.
|
||||
@@ -94,39 +100,39 @@ public interface PropertyMap<T> {
|
||||
* @return property value
|
||||
*/
|
||||
public T get(Address addr);
|
||||
|
||||
|
||||
/**
|
||||
* Get the next address where the property value exists.
|
||||
* @param addr the address from which to begin the search (exclusive).
|
||||
* @return property value location after specified {@code addr} or null if none found
|
||||
*/
|
||||
public Address getNextPropertyAddress(Address addr);
|
||||
|
||||
|
||||
/**
|
||||
* Get the previous Address where a property value exists.
|
||||
* @param addr the address from which to begin the search (exclusive).
|
||||
* @return property value location after specified {@code addr} or null if none found
|
||||
*/
|
||||
public Address getPreviousPropertyAddress(Address addr);
|
||||
|
||||
|
||||
/**
|
||||
* Get the first Address where a property value exists.
|
||||
* @return first property value location or null if none found
|
||||
*/
|
||||
public Address getFirstPropertyAddress();
|
||||
|
||||
|
||||
/**
|
||||
* Get the last Address where a property value exists.
|
||||
* @return last property value location or null if none found
|
||||
*/
|
||||
public Address getLastPropertyAddress();
|
||||
|
||||
|
||||
/**
|
||||
* Get the number of properties in the map.
|
||||
* @return number of stored property values
|
||||
*/
|
||||
public int getSize();
|
||||
|
||||
|
||||
/**
|
||||
* Returns an iterator over the indices having a property value.
|
||||
* @param start minimum address
|
||||
@@ -134,7 +140,7 @@ public interface PropertyMap<T> {
|
||||
* @return forward property address iterator
|
||||
*/
|
||||
public AddressIterator getPropertyIterator(Address start, Address end);
|
||||
|
||||
|
||||
/**
|
||||
* Returns an iterator over addresses that have a property value.
|
||||
* @param start minimum address
|
||||
@@ -144,7 +150,7 @@ public interface PropertyMap<T> {
|
||||
* @return property address iterator
|
||||
*/
|
||||
public AddressIterator getPropertyIterator(Address start, Address end, boolean forward);
|
||||
|
||||
|
||||
/**
|
||||
* Returns an iterator over the addresses that a property value.
|
||||
* @return forward property address iterator
|
||||
@@ -157,7 +163,7 @@ public interface PropertyMap<T> {
|
||||
* @param asv the set of addresses to iterate over.
|
||||
* @return forward property address iterator
|
||||
*/
|
||||
public AddressIterator getPropertyIterator(AddressSetView asv);
|
||||
public AddressIterator getPropertyIterator(AddressSetView asv);
|
||||
|
||||
/**
|
||||
* Returns an iterator over the addresses that have a property value and
|
||||
@@ -168,7 +174,7 @@ public interface PropertyMap<T> {
|
||||
* @return property address iterator
|
||||
*/
|
||||
public AddressIterator getPropertyIterator(AddressSetView asv, boolean forward);
|
||||
|
||||
|
||||
/**
|
||||
* Returns an iterator over the address having a property value.
|
||||
* @param start the starting address
|
||||
@@ -177,7 +183,7 @@ public interface PropertyMap<T> {
|
||||
* @return property address iterator
|
||||
*/
|
||||
public AddressIterator getPropertyIterator(Address start, boolean forward);
|
||||
|
||||
|
||||
/**
|
||||
* Moves the properties defined in the range from the start address thru the
|
||||
* end address to now be located beginning at the newStart address.
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/* ###
|
||||
* 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.util;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Program;
|
||||
|
||||
/**
|
||||
* <CODE>CollapsedCodeLocation</CODE> is program location generated when the cursor is on a field
|
||||
* representing code from a collapsed function.
|
||||
*/
|
||||
public class CollapsedCodeLocation extends ProgramLocation {
|
||||
|
||||
/**
|
||||
* Create a new DividerLocation.
|
||||
*
|
||||
* @param program the program of the location
|
||||
* @param addr address of bookmark
|
||||
* by its hierarchy names; this parameter may be null
|
||||
*/
|
||||
public CollapsedCodeLocation(Program program, Address addr) {
|
||||
super(program, addr, addr, null, null, 0, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default constructor needed for restoring
|
||||
* a program location from XML
|
||||
*/
|
||||
public CollapsedCodeLocation() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/* ###
|
||||
* 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.util;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Program;
|
||||
|
||||
/**
|
||||
* ProgramLocation that represents the cursor being on the function's open/close widget
|
||||
*/
|
||||
public class FunctionOpenCloseLocation extends CodeUnitLocation {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param program the program of the location
|
||||
* @param addr address of the location
|
||||
*/
|
||||
public FunctionOpenCloseLocation(Program program, Address addr) {
|
||||
super(program, addr, null, 0, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Required constructor for serialization
|
||||
*/
|
||||
public FunctionOpenCloseLocation() {
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user