mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-22 04:05:39 +00:00
Merge remote-tracking branch
'origin/GP-4855_ryanmkurtz_offset-fields--SQUASHED' (Closes #6794)
This commit is contained in:
commit
2e15f67384
@ -71,7 +71,7 @@ color.fg.listing.block.start = color.palette.indigo
|
||||
color.fg.listing.bytes.alignment = color.palette.gray
|
||||
color.fg.listing.bytes.entropy = color.fg
|
||||
color.fg.listing.disassembly.external = color.fg
|
||||
color.fg.listing.file.offset = color.fg
|
||||
color.fg.listing.field.offset = color.fg
|
||||
|
||||
color.fg.listing.instruction.parallel = color.palette.blue
|
||||
color.fg.listing.mask.bits = color.palette.navy
|
||||
|
@ -584,11 +584,11 @@
|
||||
<BLOCKQUOTE>
|
||||
<P>The File Offset field shows the filename and file offset of the original imported byte
|
||||
value for the given address. If the address's byte was not derived from an imported binary
|
||||
file, or file offset tracking is not supported by the binary file's importer, a value of
|
||||
"N/A" is shown.</P>
|
||||
<P><B>Show Filename -</B> Option to prefix the file offset with the source filename. This
|
||||
file, or file offset tracking is not supported by the binary file's importer, no offset is
|
||||
shown.</P>
|
||||
<P><B>Show Name -</B> Option to prefix the file offset with the source filename. This
|
||||
is useful if more than one binary file has been imported into a program.</P>
|
||||
<P><B>Show Numbers In Hex -</B> Option to display the file offset in hexadecimal rather than
|
||||
<P><B>Use Hex -</B> Option to display the file offset in hexadecimal rather than
|
||||
decimal.</P>
|
||||
<P><IMG src="help/shared/note.png" border="0">The File Offset field is disabled by default.
|
||||
To enable the field, see the <A HREF="Browser_Field_Formatter.htm#Enable_Field">Enable Field
|
||||
@ -596,6 +596,52 @@
|
||||
</P>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="Function_Offset_Field"></A>Function Offset Field</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>The Function Offset field shows the function name and function offset of the
|
||||
the given address. If the address is not in a function, no offset is shown.</P>
|
||||
<P><B>Show Name -</B> Option to prefix the function offset with the function name.</P>
|
||||
<P><B>Use Hex -</B> Option to display the function offset in hexadecimal rather than
|
||||
decimal.</P>
|
||||
<P><IMG src="help/shared/note.png" border="0">The Function Offset field is disabled by
|
||||
default. To enable the field, see the
|
||||
<A HREF="Browser_Field_Formatter.htm#Enable_Field">Enable Field</A> section.
|
||||
</P>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="Imagebase_Offset_Field"></A>Imagebase Offset Field</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>The Imagebase Offset field shows the imagebase offset of the given address. If the
|
||||
address and the imagebase are in different address spaces, no offset is shown.</P>
|
||||
<P><B>Show Name -</B> Option to prefix the imagebase offset with "imagebase".</P>
|
||||
<P><B>Use Hex -</B> Option to display the imagebase offset in hexadecimal rather than
|
||||
decimal.</P>
|
||||
<P><IMG src="help/shared/note.png" border="0">The Imagebase Offset field is disabled by
|
||||
default. To enable the field, see the
|
||||
<A HREF="Browser_Field_Formatter.htm#Enable_Field">Enable Field</A> section.
|
||||
</P>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="MemoryBlock_Offset_Field"></A>MemoryBlock Offset Field</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>The MemoryBlock Offset field shows the memory block name and memory block offset of the
|
||||
given address.</P>
|
||||
<P><B>Show Name -</B> Option to prefix the memory block offset with the memory block
|
||||
name.</P>
|
||||
<P><B>Use Hex -</B> Option to display the memory block offset in hexadecimal rather than
|
||||
decimal.</P>
|
||||
<P><IMG src="help/shared/note.png" border="0">The MemoryBlock Offset field is disabled by
|
||||
default. To enable the field, see the
|
||||
<A HREF="Browser_Field_Formatter.htm#Enable_Field">Enable Field</A> section.
|
||||
</P>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="Format_Code"></A>Format Code</H3>
|
||||
|
||||
|
@ -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.
|
||||
@ -42,7 +42,6 @@ import ghidra.app.plugin.core.codebrowser.CodeViewerActionContext;
|
||||
import ghidra.app.services.ClipboardContentProviderService;
|
||||
import ghidra.app.util.*;
|
||||
import ghidra.app.util.viewer.listingpanel.ListingModel;
|
||||
import ghidra.framework.cmd.Command;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.database.mem.AddressSourceInfo;
|
||||
@ -51,6 +50,7 @@ import ghidra.program.database.symbol.FunctionSymbol;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.Memory;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.program.util.*;
|
||||
import ghidra.util.Msg;
|
||||
@ -70,6 +70,12 @@ public class CodeBrowserClipboardProvider extends ByteCopier
|
||||
new ClipboardType(DataFlavor.stringFlavor, "Address w/ Offset");
|
||||
public static final ClipboardType BYTE_SOURCE_OFFSET_TYPE =
|
||||
new ClipboardType(DataFlavor.stringFlavor, "Byte Source Offset");
|
||||
public static final ClipboardType FUNCTION_OFFSET_TYPE =
|
||||
new ClipboardType(DataFlavor.stringFlavor, "Function Offset");
|
||||
public static final ClipboardType IMAGEBASE_OFFSET_TYPE =
|
||||
new ClipboardType(DataFlavor.stringFlavor, "Imagebase Offset");
|
||||
public static final ClipboardType BLOCK_OFFSET_TYPE =
|
||||
new ClipboardType(DataFlavor.stringFlavor, "Memory Block Offset");
|
||||
public static final ClipboardType CODE_TEXT_TYPE =
|
||||
new ClipboardType(DataFlavor.stringFlavor, "Formatted Code");
|
||||
public static final ClipboardType LABELS_COMMENTS_TYPE =
|
||||
@ -100,6 +106,9 @@ public class CodeBrowserClipboardProvider extends ByteCopier
|
||||
list.add(ADDRESS_TEXT_TYPE);
|
||||
list.add(ADDRESS_TEXT_WITH_OFFSET_TYPE);
|
||||
list.add(BYTE_SOURCE_OFFSET_TYPE);
|
||||
list.add(BLOCK_OFFSET_TYPE);
|
||||
list.add(FUNCTION_OFFSET_TYPE);
|
||||
list.add(IMAGEBASE_OFFSET_TYPE);
|
||||
|
||||
return list;
|
||||
}
|
||||
@ -230,6 +239,15 @@ public class CodeBrowserClipboardProvider extends ByteCopier
|
||||
else if (copyType == BYTE_SOURCE_OFFSET_TYPE) {
|
||||
return copyByteSourceOffset(monitor);
|
||||
}
|
||||
else if (copyType == BLOCK_OFFSET_TYPE) {
|
||||
return copyBlockSourceOffset(monitor);
|
||||
}
|
||||
else if (copyType == FUNCTION_OFFSET_TYPE) {
|
||||
return copyFunctionSourceOffset(monitor);
|
||||
}
|
||||
else if (copyType == IMAGEBASE_OFFSET_TYPE) {
|
||||
return copyImagebaseSourceOffset(monitor);
|
||||
}
|
||||
else if (copyType == CODE_TEXT_TYPE) {
|
||||
return copyCode(monitor);
|
||||
}
|
||||
@ -409,6 +427,48 @@ public class CodeBrowserClipboardProvider extends ByteCopier
|
||||
return createStringTransferable(String.join("\n", strings));
|
||||
}
|
||||
|
||||
private Transferable copyBlockSourceOffset(TaskMonitor monitor) {
|
||||
AddressSetView addrs = getSelectedAddresses();
|
||||
Memory mem = currentProgram.getMemory();
|
||||
List<String> strings = new ArrayList<>();
|
||||
AddressIterator addresses = addrs.getAddresses(true);
|
||||
while (addresses.hasNext() && !monitor.isCancelled()) {
|
||||
Address addr = addresses.next();
|
||||
MemoryBlock block = mem.getBlock(addr);
|
||||
strings.add(
|
||||
block != null ? "%x".formatted(addr.subtract(block.getStart())) : "<NO_OFFSET>");
|
||||
}
|
||||
return createStringTransferable(String.join("\n", strings));
|
||||
}
|
||||
|
||||
private Transferable copyFunctionSourceOffset(TaskMonitor monitor) {
|
||||
AddressSetView addrs = getSelectedAddresses();
|
||||
Listing listing = currentProgram.getListing();
|
||||
List<String> strings = new ArrayList<>();
|
||||
AddressIterator addresses = addrs.getAddresses(true);
|
||||
while (addresses.hasNext() && !monitor.isCancelled()) {
|
||||
Address addr = addresses.next();
|
||||
Function function = listing.getFunctionContaining(addr);
|
||||
strings.add(function != null ? "%x".formatted(addr.subtract(function.getEntryPoint()))
|
||||
: "<NO_OFFSET>");
|
||||
}
|
||||
return createStringTransferable(String.join("\n", strings));
|
||||
}
|
||||
|
||||
private Transferable copyImagebaseSourceOffset(TaskMonitor monitor) {
|
||||
AddressSetView addrs = getSelectedAddresses();
|
||||
List<String> strings = new ArrayList<>();
|
||||
AddressIterator addresses = addrs.getAddresses(true);
|
||||
while (addresses.hasNext() && !monitor.isCancelled()) {
|
||||
Address addr = addresses.next();
|
||||
Address imagebase = currentProgram.getImageBase();
|
||||
strings.add(
|
||||
addr.hasSameAddressSpace(imagebase) ? "%x".formatted(addr.subtract(imagebase))
|
||||
: "<NO_OFFSET>");
|
||||
}
|
||||
return createStringTransferable(String.join("\n", strings));
|
||||
}
|
||||
|
||||
protected Transferable copyCode(TaskMonitor monitor) {
|
||||
|
||||
AddressSetView addressSet = getSelectedAddresses();
|
||||
@ -480,8 +540,8 @@ public class CodeBrowserClipboardProvider extends ByteCopier
|
||||
List<?> list =
|
||||
(List<?>) pasteData.getTransferData(CodeUnitInfoTransferable.localDataTypeFlavor);
|
||||
List<CodeUnitInfo> infos = CollectionUtils.asList(list, CodeUnitInfo.class);
|
||||
Command cmd = new CodeUnitInfoPasteCmd(currentLocation.getAddress(), infos, pasteLabels,
|
||||
pasteComments);
|
||||
CodeUnitInfoPasteCmd cmd = new CodeUnitInfoPasteCmd(currentLocation.getAddress(), infos,
|
||||
pasteLabels, pasteComments);
|
||||
return tool.execute(cmd, currentProgram);
|
||||
}
|
||||
catch (Exception e) {
|
||||
|
@ -0,0 +1,185 @@
|
||||
/* ###
|
||||
* 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 generic.theme.GColor;
|
||||
import ghidra.app.util.ListingHighlightProvider;
|
||||
import ghidra.app.util.viewer.format.FieldFormatModel;
|
||||
import ghidra.app.util.viewer.proxy.ProxyObj;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.CodeUnit;
|
||||
import ghidra.program.model.listing.Data;
|
||||
import ghidra.program.util.*;
|
||||
import ghidra.util.HelpLocation;
|
||||
|
||||
/**
|
||||
* Generates Offset fields
|
||||
*/
|
||||
public abstract class AbstractOffsetFieldFactory extends FieldFactory {
|
||||
|
||||
public static final GColor COLOR = new GColor("color.fg.listing.field.offset");
|
||||
|
||||
private static final String SHOW_NAME = "Show Name";
|
||||
private static final String USE_HEX = "Use Hex";
|
||||
private static final boolean DEFAULT_SHOW_NAME = false;
|
||||
private static final boolean DEFAULT_USE_HEX = true;
|
||||
|
||||
protected boolean showName;
|
||||
protected boolean useHex;
|
||||
|
||||
protected String fieldName;
|
||||
protected String groupTitle;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new {@link AbstractOffsetFieldFactory}
|
||||
*
|
||||
* @param offsetDescription A description of the offset
|
||||
*/
|
||||
public AbstractOffsetFieldFactory(String offsetDescription) {
|
||||
super(offsetDescription + " Offset");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link AbstractOffsetFieldFactory}
|
||||
*
|
||||
* @param offsetDescription A description of the field offset
|
||||
* @param nameDescription A description of the name that can get prepended to the field offset
|
||||
* @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.
|
||||
*/
|
||||
protected AbstractOffsetFieldFactory(String offsetDescription, String nameDescription,
|
||||
FieldFormatModel model, ListingHighlightProvider hlProvider, Options displayOptions,
|
||||
Options fieldOptions) {
|
||||
super(offsetDescription + " Offset", model, hlProvider, displayOptions, fieldOptions);
|
||||
fieldName = offsetDescription + " Offset";
|
||||
groupTitle = offsetDescription + " Offset Field";
|
||||
initOptions(fieldOptions, offsetDescription, nameDescription);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the offset value
|
||||
*
|
||||
* @param codeUnit The {@link CodeUnit}
|
||||
* @return The offset value
|
||||
*/
|
||||
public abstract String getOffsetValue(CodeUnit codeUnit);
|
||||
|
||||
/**
|
||||
* Gets the {@link OffsetFieldType offset type}
|
||||
*
|
||||
* @return the {@link OffsetFieldType offset type}
|
||||
*/
|
||||
public abstract OffsetFieldType getOffsetFieldType();
|
||||
|
||||
private void initOptions(Options fieldOptions, String offsetDescription,
|
||||
String nameDescription) {
|
||||
HelpLocation helpLoc =
|
||||
new HelpLocation("CodeBrowserPlugin", offsetDescription + "_Offset_Field");
|
||||
fieldOptions.getOptions(groupTitle).setOptionsHelpLocation(helpLoc);
|
||||
|
||||
fieldOptions.registerOption(getFullOptionName(SHOW_NAME), DEFAULT_SHOW_NAME, helpLoc,
|
||||
"Prepends the %s name to the %s offset in the offset field."
|
||||
.formatted(nameDescription.toLowerCase(), offsetDescription));
|
||||
fieldOptions.registerOption(getFullOptionName(USE_HEX), DEFAULT_USE_HEX, helpLoc,
|
||||
"Toggles displaying offsets in hexadecimal/decimal in the offset field.");
|
||||
|
||||
showName = fieldOptions.getBoolean(getFullOptionName(SHOW_NAME), DEFAULT_SHOW_NAME);
|
||||
useHex = fieldOptions.getBoolean(getFullOptionName(USE_HEX), DEFAULT_USE_HEX);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListingField getField(ProxyObj<?> proxy, int varWidth) {
|
||||
Object obj = proxy.getObject();
|
||||
if (!enabled || !(obj instanceof CodeUnit)) {
|
||||
return null;
|
||||
}
|
||||
FieldElement fieldElement = new TextFieldElement(
|
||||
new AttributedString(getOffsetValue((CodeUnit) obj), COLOR, getMetrics()), 0, 0);
|
||||
ListingTextField listingTextField = ListingTextField.createSingleLineTextField(this, proxy,
|
||||
fieldElement, startX + varWidth, width, hlProvider);
|
||||
listingTextField.setPrimary(true);
|
||||
return listingTextField;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fieldOptionsChanged(Options options, String optionsName, Object oldValue,
|
||||
Object newValue) {
|
||||
if (optionsName.equals(getFullOptionName(SHOW_NAME))) {
|
||||
showName = ((Boolean) newValue).booleanValue();
|
||||
model.update();
|
||||
}
|
||||
else if (optionsName.equals(getFullOptionName(USE_HEX))) {
|
||||
useHex = ((Boolean) newValue).booleanValue();
|
||||
model.update();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldLocation getFieldLocation(ListingField lf, BigInteger index, int fieldNum,
|
||||
ProgramLocation loc) {
|
||||
if (loc instanceof OffsetFieldLocation offsetLoc &&
|
||||
offsetLoc.getType().equals(getOffsetFieldType())) {
|
||||
Object obj = lf.getProxy().getObject();
|
||||
|
||||
if (obj instanceof CodeUnit && hasSamePath(lf, offsetLoc)) {
|
||||
return new FieldLocation(index, fieldNum, 0, offsetLoc.getCharOffset());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProgramLocation getProgramLocation(int row, int col, ListingField lf) {
|
||||
Object obj = lf.getProxy().getObject();
|
||||
if (!(obj instanceof CodeUnit)) {
|
||||
return null;
|
||||
}
|
||||
CodeUnit cu = (CodeUnit) obj;
|
||||
Address addr = cu.getMinAddress();
|
||||
int[] cpath = null;
|
||||
if (cu instanceof Data) {
|
||||
cpath = ((Data) cu).getComponentPath();
|
||||
}
|
||||
return new OffsetFieldLocation(cu.getProgram(), addr, cpath, col, getOffsetFieldType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean acceptsType(int category, Class<?> proxyObjectClass) {
|
||||
if (!CodeUnit.class.isAssignableFrom(proxyObjectClass)) {
|
||||
return false;
|
||||
}
|
||||
return (category == FieldFormatModel.INSTRUCTION_OR_DATA ||
|
||||
category == FieldFormatModel.OPEN_DATA || category == FieldFormatModel.ARRAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the full option name, which includes the group and options delimiter
|
||||
*
|
||||
* @param shortName The short option name (no group or options delimiter)
|
||||
* @return The full option name, which includes the group and options delimiter
|
||||
*/
|
||||
private String getFullOptionName(String shortName) {
|
||||
return groupTitle + Options.DELIMITER + shortName;
|
||||
}
|
||||
}
|
@ -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.
|
||||
@ -15,82 +15,44 @@
|
||||
*/
|
||||
package ghidra.app.util.viewer.field;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import docking.widgets.fieldpanel.field.*;
|
||||
import docking.widgets.fieldpanel.support.FieldLocation;
|
||||
import generic.theme.GColor;
|
||||
import ghidra.app.util.ListingHighlightProvider;
|
||||
import ghidra.app.util.viewer.format.FieldFormatModel;
|
||||
import ghidra.app.util.viewer.proxy.ProxyObj;
|
||||
import ghidra.framework.options.*;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.framework.options.ToolOptions;
|
||||
import ghidra.program.database.mem.FileBytes;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.CodeUnit;
|
||||
import ghidra.program.model.listing.Data;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
import ghidra.program.model.mem.MemoryBlockSourceInfo;
|
||||
import ghidra.program.util.FileOffsetFieldLocation;
|
||||
import ghidra.program.util.ProgramLocation;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.exception.AssertException;
|
||||
import ghidra.program.util.OffsetFieldType;
|
||||
|
||||
/**
|
||||
* Generates File Offset fields
|
||||
* Generates Function Offset fields
|
||||
*/
|
||||
public class FileOffsetFieldFactory extends FieldFactory {
|
||||
public class FileOffsetFieldFactory extends AbstractOffsetFieldFactory {
|
||||
|
||||
public static final String FIELD_NAME = "File Offset";
|
||||
public static final GColor COLOR = new GColor("color.fg.listing.file.offset");
|
||||
public static final String GROUP_TITLE = "File Offset Field";
|
||||
public final static String FILE_OFFSET_DISPLAY_OPTIONS_NAME =
|
||||
GROUP_TITLE + Options.DELIMITER + "File Offset Display Options";
|
||||
|
||||
private boolean showFilename;
|
||||
private boolean useHex;
|
||||
private static final String FIELD_OFFSET_DESCRIPTION = "File";
|
||||
private static final String FIELD_NAME_DESCRIPTION = "File";
|
||||
|
||||
/**
|
||||
* Default Constructor
|
||||
* Creates a new default {@link FileOffsetFieldFactory}
|
||||
*/
|
||||
public FileOffsetFieldFactory() {
|
||||
super(FIELD_NAME);
|
||||
super(FIELD_OFFSET_DESCRIPTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* Creates a new {@link FileOffsetFieldFactory}
|
||||
*
|
||||
* @param model the {@link FieldFormatModel} that the field belongs to
|
||||
* @param hlProvider the {@link ListingHighlightProvider}
|
||||
* @param displayOptions the {@link Options} for display properties
|
||||
* @param fieldOptions the {@link Options} for field specific properties
|
||||
*/
|
||||
private FileOffsetFieldFactory(FieldFormatModel model, ListingHighlightProvider hlProvider,
|
||||
Options displayOptions, Options fieldOptions) {
|
||||
super(FIELD_NAME, model, hlProvider, displayOptions, fieldOptions);
|
||||
initOptions(fieldOptions);
|
||||
}
|
||||
|
||||
private void initOptions(Options fieldOptions) {
|
||||
HelpLocation helpLoc = new HelpLocation("CodeBrowserPlugin", "File_Offset_Field");
|
||||
|
||||
fieldOptions.registerOption(FILE_OFFSET_DISPLAY_OPTIONS_NAME, OptionType.CUSTOM_TYPE,
|
||||
new FileOffsetFieldOptionsWrappedOption(), helpLoc,
|
||||
"Adjusts the File Offset Field display",
|
||||
() -> new FileOffsetFieldOptionsPropertyEditor());
|
||||
|
||||
CustomOption customOption =
|
||||
fieldOptions.getCustomOption(FILE_OFFSET_DISPLAY_OPTIONS_NAME, null);
|
||||
|
||||
if (!(customOption instanceof FileOffsetFieldOptionsWrappedOption)) {
|
||||
throw new AssertException("Someone set an option for " +
|
||||
FILE_OFFSET_DISPLAY_OPTIONS_NAME + " that is not the expected " +
|
||||
FileOffsetFieldOptionsWrappedOption.class.getName() + " type.");
|
||||
}
|
||||
FileOffsetFieldOptionsWrappedOption fofowo =
|
||||
(FileOffsetFieldOptionsWrappedOption) customOption;
|
||||
showFilename = fofowo.showFilename();
|
||||
useHex = fofowo.useHex();
|
||||
|
||||
fieldOptions.getOptions(GROUP_TITLE).setOptionsHelpLocation(helpLoc);
|
||||
super(FIELD_OFFSET_DESCRIPTION, FIELD_NAME_DESCRIPTION, model, hlProvider, displayOptions,
|
||||
fieldOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -101,95 +63,28 @@ public class FileOffsetFieldFactory extends FieldFactory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fieldOptionsChanged(Options options, String optionsName, Object oldValue,
|
||||
Object newValue) {
|
||||
if (optionsName.equals(FILE_OFFSET_DISPLAY_OPTIONS_NAME)) {
|
||||
FileOffsetFieldOptionsWrappedOption fofowo =
|
||||
(FileOffsetFieldOptionsWrappedOption) newValue;
|
||||
showFilename = fofowo.showFilename();
|
||||
useHex = fofowo.useHex();
|
||||
model.update();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListingField getField(ProxyObj<?> proxy, int varWidth) {
|
||||
Object obj = proxy.getObject();
|
||||
if (!enabled || !(obj instanceof CodeUnit)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
CodeUnit cu = (CodeUnit) obj;
|
||||
public String getOffsetValue(CodeUnit cu) {
|
||||
Address addr = cu.getAddress();
|
||||
MemoryBlock block = cu.getProgram().getMemory().getBlock(addr);
|
||||
String text = "N/A";
|
||||
String text = "";
|
||||
for (MemoryBlockSourceInfo sourceInfo : block.getSourceInfos()) {
|
||||
if (sourceInfo.contains(addr)) {
|
||||
if (sourceInfo.getFileBytes().isPresent()) {
|
||||
FileBytes fileBytes = sourceInfo.getFileBytes().get();
|
||||
long offset = sourceInfo.getFileBytesOffset(addr);
|
||||
if (useHex) {
|
||||
text = String.format("0x%x", offset);
|
||||
}
|
||||
else {
|
||||
text = String.format("%d", offset);
|
||||
}
|
||||
if (showFilename) {
|
||||
text = fileBytes.getFilename() + ":" + text;
|
||||
text = String.format(useHex ? "0x%x" : "%d", offset);
|
||||
if (showName) {
|
||||
text = "%s:%s".formatted(fileBytes.getFilename(), text);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
FieldElement fieldElement =
|
||||
new TextFieldElement(new AttributedString(text, COLOR, getMetrics()), 0, 0);
|
||||
ListingTextField listingTextField = ListingTextField.createSingleLineTextField(this, proxy,
|
||||
fieldElement, startX + varWidth, width, hlProvider);
|
||||
listingTextField.setPrimary(true);
|
||||
|
||||
return listingTextField;
|
||||
return text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldLocation getFieldLocation(ListingField lf, BigInteger index, int fieldNum,
|
||||
ProgramLocation loc) {
|
||||
|
||||
if (loc instanceof FileOffsetFieldLocation) {
|
||||
FileOffsetFieldLocation fileOffsetFieldLoc = (FileOffsetFieldLocation) loc;
|
||||
Object obj = lf.getProxy().getObject();
|
||||
|
||||
if (obj instanceof CodeUnit && hasSamePath(lf, fileOffsetFieldLoc)) {
|
||||
return new FieldLocation(index, fieldNum, 0, fileOffsetFieldLoc.getCharOffset());
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProgramLocation getProgramLocation(int row, int col, ListingField lf) {
|
||||
Object obj = lf.getProxy().getObject();
|
||||
if (!(obj instanceof CodeUnit)) {
|
||||
return null;
|
||||
}
|
||||
CodeUnit cu = (CodeUnit) obj;
|
||||
|
||||
Address addr = cu.getMinAddress();
|
||||
|
||||
int[] cpath = null;
|
||||
if (cu instanceof Data) {
|
||||
cpath = ((Data) cu).getComponentPath();
|
||||
}
|
||||
|
||||
return new FileOffsetFieldLocation(cu.getProgram(), addr, cpath, col);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean acceptsType(int category, Class<?> proxyObjectClass) {
|
||||
if (!CodeUnit.class.isAssignableFrom(proxyObjectClass)) {
|
||||
return false;
|
||||
}
|
||||
return (category == FieldFormatModel.INSTRUCTION_OR_DATA ||
|
||||
category == FieldFormatModel.OPEN_DATA || category == FieldFormatModel.ARRAY);
|
||||
public OffsetFieldType getOffsetFieldType() {
|
||||
return OffsetFieldType.FILE;
|
||||
}
|
||||
}
|
||||
|
@ -1,136 +0,0 @@
|
||||
/* ###
|
||||
* 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.Component;
|
||||
import java.beans.PropertyEditorSupport;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.SwingConstants;
|
||||
|
||||
import docking.widgets.checkbox.GCheckBox;
|
||||
import docking.widgets.label.GDLabel;
|
||||
import ghidra.framework.options.CustomOptionsEditor;
|
||||
import ghidra.util.HTMLUtilities;
|
||||
import ghidra.util.layout.PairLayout;
|
||||
|
||||
/**
|
||||
* Provides a custom GUI layout for the File Offset field options
|
||||
*/
|
||||
public class FileOffsetFieldOptionsPropertyEditor extends PropertyEditorSupport
|
||||
implements CustomOptionsEditor {
|
||||
|
||||
private static final String SHOW_FILENAME_LABEL = "Show Filename";
|
||||
private static final String USE_HEX_LABEL = "Show Numbers In Hex";
|
||||
|
||||
private static final String[] NAMES = { SHOW_FILENAME_LABEL, USE_HEX_LABEL };
|
||||
|
||||
private static final String SHOW_FILENAME_TOOLTIP = HTMLUtilities.toWrappedHTML(
|
||||
"Prepends the filename to the file offset in the File Offset field.", 75);
|
||||
private static final String USE_HEX_TOOLTIP = HTMLUtilities.toWrappedHTML(
|
||||
"Toggles displaying file offsets in hexadecimal/decimal in the File Offset field.", 75);
|
||||
|
||||
private static final String[] DESCRIPTIONS = { SHOW_FILENAME_TOOLTIP, USE_HEX_TOOLTIP };
|
||||
|
||||
private FileOffsetFieldOptionsWrappedOption option;
|
||||
|
||||
private Component editorComponent;
|
||||
private GCheckBox showFilenameCheckbox;
|
||||
private GCheckBox useHexCheckbox;
|
||||
|
||||
/**
|
||||
* Creates a new {@link FileOffsetFieldOptionsPropertyEditor}
|
||||
*/
|
||||
public FileOffsetFieldOptionsPropertyEditor() {
|
||||
editorComponent = buildEditor();
|
||||
}
|
||||
|
||||
private Component buildEditor() {
|
||||
// we want to have a panel with our options so that we may group them together
|
||||
JPanel panel = new JPanel(new PairLayout(6, 10));
|
||||
|
||||
GDLabel showFilenameLabel = new GDLabel(SHOW_FILENAME_LABEL, SwingConstants.RIGHT);
|
||||
showFilenameLabel.setToolTipText(SHOW_FILENAME_TOOLTIP);
|
||||
panel.add(showFilenameLabel);
|
||||
showFilenameCheckbox = new GCheckBox();
|
||||
showFilenameCheckbox.setToolTipText(SHOW_FILENAME_TOOLTIP);
|
||||
panel.add(showFilenameCheckbox);
|
||||
|
||||
GDLabel useHexLabel = new GDLabel(USE_HEX_LABEL, SwingConstants.RIGHT);
|
||||
useHexLabel.setToolTipText(USE_HEX_TOOLTIP);
|
||||
panel.add(useHexLabel);
|
||||
useHexCheckbox = new GCheckBox();
|
||||
useHexCheckbox.setToolTipText(USE_HEX_TOOLTIP);
|
||||
panel.add(useHexCheckbox);
|
||||
|
||||
showFilenameCheckbox.addItemListener(evt -> firePropertyChange());
|
||||
useHexCheckbox.addItemListener(evt -> firePropertyChange());
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(Object value) {
|
||||
if (!(value instanceof FileOffsetFieldOptionsWrappedOption)) {
|
||||
return;
|
||||
}
|
||||
|
||||
option = (FileOffsetFieldOptionsWrappedOption) value;
|
||||
setLocalValues(option);
|
||||
firePropertyChange();
|
||||
}
|
||||
|
||||
private void setLocalValues(FileOffsetFieldOptionsWrappedOption option) {
|
||||
if (option.showFilename() != showFilenameCheckbox.isSelected()) {
|
||||
showFilenameCheckbox.setSelected(option.showFilename());
|
||||
}
|
||||
if (option.useHex() != useHexCheckbox.isSelected()) {
|
||||
useHexCheckbox.setSelected(option.useHex());
|
||||
}
|
||||
}
|
||||
|
||||
private FileOffsetFieldOptionsWrappedOption cloneFileOffsetValues() {
|
||||
FileOffsetFieldOptionsWrappedOption newOption = new FileOffsetFieldOptionsWrappedOption();
|
||||
newOption.setShowFilename(showFilenameCheckbox.isSelected());
|
||||
newOption.setUseHex(useHexCheckbox.isSelected());
|
||||
return newOption;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getOptionDescriptions() {
|
||||
return DESCRIPTIONS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getOptionNames() {
|
||||
return NAMES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return cloneFileOffsetValues();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getCustomEditor() {
|
||||
return editorComponent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsCustomEditor() {
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,115 +0,0 @@
|
||||
/* ###
|
||||
* 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 ghidra.framework.options.CustomOption;
|
||||
import ghidra.framework.options.GProperties;
|
||||
|
||||
/**
|
||||
* An option class that allows the user to edit a related group of options pertaining to
|
||||
* File Offset field display
|
||||
*/
|
||||
public class FileOffsetFieldOptionsWrappedOption implements CustomOption {
|
||||
|
||||
private static final String SHOW_FILENAME = "ShowFilename";
|
||||
private static final String USE_HEX = "UseHex";
|
||||
|
||||
private static final boolean DEFAULT_SHOW_FILENAME = false;
|
||||
private static final boolean DEFAULT_USE_HEX = true;
|
||||
|
||||
private boolean showFilename = DEFAULT_SHOW_FILENAME;
|
||||
private boolean useHex = DEFAULT_USE_HEX;
|
||||
|
||||
/**
|
||||
* Default constructor, required for persistence
|
||||
*/
|
||||
public FileOffsetFieldOptionsWrappedOption() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not to show the filename
|
||||
*
|
||||
* @return True if the filename is to be shown; otherwise, false
|
||||
*/
|
||||
public boolean showFilename() {
|
||||
return showFilename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether or not to show the filename
|
||||
*
|
||||
* @param showFilename True to show the filename, false to hide it
|
||||
*/
|
||||
public void setShowFilename(boolean showFilename) {
|
||||
this.showFilename = showFilename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not to display the file offset in hexadecimal
|
||||
*
|
||||
* @return True if the file offset is to be displayed in hexadecimal; otherwise, false
|
||||
*/
|
||||
public boolean useHex() {
|
||||
return useHex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether or not to display the file offset in hexadecimal
|
||||
*
|
||||
* @param useHex True to display the file offset in hexadecimal, false for decimal
|
||||
*/
|
||||
public void setUseHex(boolean useHex) {
|
||||
this.useHex = useHex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof FileOffsetFieldOptionsWrappedOption)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
FileOffsetFieldOptionsWrappedOption otherOption = (FileOffsetFieldOptionsWrappedOption) obj;
|
||||
return showFilename == otherOption.showFilename && useHex == otherOption.useHex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + (showFilename ? 1 : 0);
|
||||
result = prime * result + (useHex ? 1 : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
//Persistence
|
||||
//==================================================================================================
|
||||
@Override
|
||||
public void readState(GProperties properties) {
|
||||
showFilename = properties.getBoolean(SHOW_FILENAME, showFilename);
|
||||
useHex = properties.getBoolean(USE_HEX, useHex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeState(GProperties properties) {
|
||||
properties.putBoolean(SHOW_FILENAME, showFilename);
|
||||
properties.putBoolean(USE_HEX, useHex);
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
/* ###
|
||||
* 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 ghidra.app.util.ListingHighlightProvider;
|
||||
import ghidra.app.util.viewer.format.FieldFormatModel;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.framework.options.ToolOptions;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.CodeUnit;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.util.OffsetFieldType;
|
||||
|
||||
/**
|
||||
* Generates Function Offset fields
|
||||
*/
|
||||
public class FunctionOffsetFieldFactory extends AbstractOffsetFieldFactory {
|
||||
|
||||
private static final String FIELD_OFFSET_DESCRIPTION = "Function";
|
||||
private static final String FIELD_NAME_DESCRIPTION = "Function";
|
||||
|
||||
/**
|
||||
* Creates a new default {@link FunctionOffsetFieldFactory}
|
||||
*/
|
||||
public FunctionOffsetFieldFactory() {
|
||||
super(FIELD_OFFSET_DESCRIPTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link FunctionOffsetFieldFactory}
|
||||
*
|
||||
* @param model the {@link FieldFormatModel} that the field belongs to
|
||||
* @param hlProvider the {@link ListingHighlightProvider}
|
||||
* @param displayOptions the {@link Options} for display properties
|
||||
* @param fieldOptions the {@link Options} for field specific properties
|
||||
*/
|
||||
private FunctionOffsetFieldFactory(FieldFormatModel model, ListingHighlightProvider hlProvider,
|
||||
Options displayOptions, Options fieldOptions) {
|
||||
super(FIELD_OFFSET_DESCRIPTION, FIELD_NAME_DESCRIPTION, model, hlProvider, displayOptions,
|
||||
fieldOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldFactory newInstance(FieldFormatModel formatModel,
|
||||
ListingHighlightProvider highlightProvider, ToolOptions options,
|
||||
ToolOptions fieldOptions) {
|
||||
return new FunctionOffsetFieldFactory(formatModel, highlightProvider, options,
|
||||
fieldOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOffsetValue(CodeUnit cu) {
|
||||
Address addr = cu.getAddress();
|
||||
Function function = cu.getProgram().getListing().getFunctionContaining(addr);
|
||||
String text = "";
|
||||
if (function != null) {
|
||||
long offset = addr.subtract(function.getEntryPoint());
|
||||
text = String.format(useHex ? "0x%x" : "%d", offset);
|
||||
if (showName) {
|
||||
text = "%s:%s".formatted(function.getName(), text);
|
||||
}
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OffsetFieldType getOffsetFieldType() {
|
||||
return OffsetFieldType.FUNCTION;
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/* ###
|
||||
* 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 ghidra.app.util.ListingHighlightProvider;
|
||||
import ghidra.app.util.viewer.format.FieldFormatModel;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.framework.options.ToolOptions;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.CodeUnit;
|
||||
import ghidra.program.util.OffsetFieldType;
|
||||
|
||||
/**
|
||||
* Generates Imagebase Offset fields
|
||||
*/
|
||||
public class ImagebaseOffsetFieldFactory extends AbstractOffsetFieldFactory {
|
||||
|
||||
private static final String FIELD_OFFSET_DESCRIPTION = "Imagebase";
|
||||
private static final String FIELD_NAME_DESCRIPTION = "Field";
|
||||
|
||||
/**
|
||||
* Creates a new default {@link ImagebaseOffsetFieldFactory}
|
||||
*/
|
||||
public ImagebaseOffsetFieldFactory() {
|
||||
super(FIELD_OFFSET_DESCRIPTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link ImagebaseOffsetFieldFactory}
|
||||
*
|
||||
* @param model the {@link FieldFormatModel} that the field belongs to
|
||||
* @param hlProvider the {@link ListingHighlightProvider}
|
||||
* @param displayOptions the {@link Options} for display properties
|
||||
* @param fieldOptions the {@link Options} for field specific properties
|
||||
*/
|
||||
private ImagebaseOffsetFieldFactory(FieldFormatModel model, ListingHighlightProvider hlProvider,
|
||||
Options displayOptions, Options fieldOptions) {
|
||||
super(FIELD_OFFSET_DESCRIPTION, FIELD_NAME_DESCRIPTION, model, hlProvider, displayOptions,
|
||||
fieldOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldFactory newInstance(FieldFormatModel formatModel,
|
||||
ListingHighlightProvider highlightProvider, ToolOptions options,
|
||||
ToolOptions fieldOptions) {
|
||||
return new ImagebaseOffsetFieldFactory(formatModel, highlightProvider, options,
|
||||
fieldOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOffsetValue(CodeUnit cu) {
|
||||
Address addr = cu.getAddress();
|
||||
Address imagebase = cu.getProgram().getImageBase();
|
||||
String text = "";
|
||||
if (addr.hasSameAddressSpace(imagebase)) {
|
||||
long imagebaseOffset = addr.subtract(cu.getProgram().getImageBase());
|
||||
text = String.format(useHex ? "0x%x" : "%d", imagebaseOffset);
|
||||
if (showName) {
|
||||
text = "imagebase:%s".formatted(text);
|
||||
}
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OffsetFieldType getOffsetFieldType() {
|
||||
return OffsetFieldType.IMAGEBASE;
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
/* ###
|
||||
* 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 ghidra.app.util.ListingHighlightProvider;
|
||||
import ghidra.app.util.viewer.format.FieldFormatModel;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.framework.options.ToolOptions;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.CodeUnit;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
import ghidra.program.util.OffsetFieldType;
|
||||
|
||||
/**
|
||||
* Generates {@link MemoryBlock} Offset fields
|
||||
*/
|
||||
public class MemoryBlockOffsetFieldFactory extends AbstractOffsetFieldFactory {
|
||||
|
||||
private static final String FIELD_OFFSET_DESCRIPTION = "MemoryBlock";
|
||||
private static final String FIELD_NAME_DESCRIPTION = "Memory Block";
|
||||
|
||||
/**
|
||||
* Creates a new default {@link MemoryBlockOffsetFieldFactory}
|
||||
*/
|
||||
public MemoryBlockOffsetFieldFactory() {
|
||||
super(FIELD_OFFSET_DESCRIPTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link MemoryBlockOffsetFieldFactory}
|
||||
*
|
||||
* @param model the {@link FieldFormatModel} that the field belongs to
|
||||
* @param hlProvider the {@link ListingHighlightProvider}
|
||||
* @param displayOptions the {@link Options} for display properties
|
||||
* @param fieldOptions the {@link Options} for field specific properties
|
||||
*/
|
||||
private MemoryBlockOffsetFieldFactory(FieldFormatModel model,
|
||||
ListingHighlightProvider hlProvider, Options displayOptions, Options fieldOptions) {
|
||||
super(FIELD_OFFSET_DESCRIPTION, FIELD_NAME_DESCRIPTION, model, hlProvider, displayOptions,
|
||||
fieldOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldFactory newInstance(FieldFormatModel formatModel,
|
||||
ListingHighlightProvider highlightProvider, ToolOptions options,
|
||||
ToolOptions fieldOptions) {
|
||||
return new MemoryBlockOffsetFieldFactory(formatModel, highlightProvider, options,
|
||||
fieldOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOffsetValue(CodeUnit cu) {
|
||||
Address addr = cu.getAddress();
|
||||
String text = "";
|
||||
MemoryBlock block = cu.getProgram().getMemory().getBlock(addr);
|
||||
if (block != null) {
|
||||
long offset = addr.subtract(block.getStart());
|
||||
text = String.format(useHex ? "0x%x" : "%d", offset);
|
||||
if (showName) {
|
||||
text = "%s:%s".formatted(block.getName(), text);
|
||||
}
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OffsetFieldType getOffsetFieldType() {
|
||||
return OffsetFieldType.MEMORYBLOCK;
|
||||
}
|
||||
}
|
@ -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.
|
||||
@ -130,6 +130,9 @@ public class ToolOptions extends AbstractOptions {
|
||||
WrappedOption wo = (WrappedOption) constructor.newInstance();
|
||||
wo.readState(new SaveState(element));
|
||||
|
||||
if (wo instanceof WrappedCustomOption wrappedCustom && !wrappedCustom.isValid()) {
|
||||
continue;
|
||||
}
|
||||
if (wo instanceof WrappedKeyStroke wrappedKs) {
|
||||
wo = wrappedKs.toWrappedActionTrigger();
|
||||
}
|
||||
|
@ -1,13 +1,12 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* 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.
|
||||
@ -21,28 +20,40 @@ import ghidra.util.Msg;
|
||||
public class WrappedCustomOption implements WrappedOption {
|
||||
|
||||
private CustomOption value;
|
||||
private boolean valid;
|
||||
|
||||
public WrappedCustomOption(CustomOption value) {
|
||||
this();
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public WrappedCustomOption() {
|
||||
|
||||
this.valid = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readState(SaveState saveState) {
|
||||
String customOptionClassName = saveState.getString("CUSTOM OPTION CLASS", null);
|
||||
valid = false;
|
||||
try {
|
||||
Class<?> c = Class.forName(customOptionClassName);
|
||||
value = (CustomOption) c.newInstance();
|
||||
value = (CustomOption) c.getConstructor().newInstance();
|
||||
value.readState(saveState);
|
||||
valid = true;
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
Msg.info(this,
|
||||
"Custom option class '%s' does not exist".formatted(customOptionClassName));
|
||||
}
|
||||
catch (Exception e) {
|
||||
Msg.error(this, "Can't create customOption instance for: " + customOptionClassName, e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return valid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeState(SaveState saveState) {
|
||||
saveState.putString("CUSTOM OPTION CLASS", value.getClass().getName());
|
||||
|
@ -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.
|
||||
@ -19,28 +19,41 @@ import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Program;
|
||||
|
||||
/**
|
||||
* Provides specific information about a program location within the File Offset field
|
||||
* Provides specific information about a program location within an offset field
|
||||
*/
|
||||
public class FileOffsetFieldLocation extends CodeUnitLocation {
|
||||
public class OffsetFieldLocation extends CodeUnitLocation {
|
||||
|
||||
private OffsetFieldType type;
|
||||
|
||||
/**
|
||||
* Creates a new {@link FileOffsetFieldLocation} for the given address
|
||||
* Creates a new {@link OffsetFieldLocation} for the given address
|
||||
*
|
||||
* @param program the program
|
||||
* @param addr the address of the byte for this location
|
||||
* @param componentPath the path to data, or null
|
||||
* @param charOffset the position into the string representation indicating the exact
|
||||
* position within the field
|
||||
* @param type The {@link OffsetFieldType type} of offset field
|
||||
*/
|
||||
public FileOffsetFieldLocation(Program program, Address addr, int[] componentPath,
|
||||
int charOffset) {
|
||||
public OffsetFieldLocation(Program program, Address addr, int[] componentPath, int charOffset,
|
||||
OffsetFieldType type) {
|
||||
super(program, addr, componentPath, 0, 0, charOffset);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Default constructor needed for restoring the field location from XML
|
||||
*
|
||||
* @param type The {@link OffsetFieldType type} of offset field
|
||||
*/
|
||||
public FileOffsetFieldLocation() {
|
||||
public OffsetFieldLocation(OffsetFieldType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the type of offset field}
|
||||
*/
|
||||
public OffsetFieldType getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/* ###
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* The type of offset field
|
||||
*
|
||||
* @see OffsetFieldLocation
|
||||
*/
|
||||
public enum OffsetFieldType {
|
||||
FILE,
|
||||
FUNCTION,
|
||||
IMAGEBASE,
|
||||
MEMORYBLOCK
|
||||
}
|
Loading…
Reference in New Issue
Block a user