mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-31 21:37:54 +08:00
GP-1403 Added support for pointer-typedef settings, including support
for Archive use. Corrected settings stacking behavior. Unified two settings adapters into one shared implementation (upgrade and archive schema version still needed). Added ability to edit default settings for components from within the structure/union editor. Improved use of immutable settings. Improved array settings. Added PointerTypeDefBuilder and PointerTypeDefInspector. Added versioning support to DataTypeManagerDB to facilitate upgrades and compatibility detection. Initial improvements added for locking of datatype settings. Added support for auto-named pointer-typedefs.
This commit is contained in:
+1
-1
@@ -48,7 +48,7 @@ public class DBTraceDataSettingsAdapter
|
||||
static final String NAME_COLUMN_NAME = "Name";
|
||||
static final String LONG_VALUE_COLUMN_NAME = "LongValue";
|
||||
static final String STRING_VALUE_COLUMN_NAME = "StringValue";
|
||||
static final String BYTES_VALUE_COLUMN_NAME = "BytesValue";
|
||||
static final String BYTES_VALUE_COLUMN_NAME = "BytesValue"; // NOTE: Requirement dropped from Program API
|
||||
|
||||
@DBAnnotatedColumn(NAME_COLUMN_NAME)
|
||||
static DBObjectColumn NAME_COLUMN;
|
||||
|
||||
-13
@@ -120,19 +120,6 @@ public interface DBTraceDataSettingsOperations
|
||||
}
|
||||
}
|
||||
|
||||
default void setBytes(Range<Long> lifespan, Address address, String name, byte[] value) {
|
||||
try (LockHold hold = LockHold.lock(getLock().writeLock())) {
|
||||
doExactOrNew(lifespan, address, name).setBytes(value);
|
||||
}
|
||||
}
|
||||
|
||||
default byte[] getBytes(long snap, Address address, String name) {
|
||||
try (LockHold hold = LockHold.lock(getLock().readLock())) {
|
||||
DBTraceSettingsEntry entry = doGetEntry(snap, address, name);
|
||||
return entry == null ? null : entry.getBytes();
|
||||
}
|
||||
}
|
||||
|
||||
default void setValue(Range<Long> lifespan, Address address, String name, Object value) {
|
||||
assertKnownType(value);
|
||||
try (LockHold hold = LockHold.lock(getLock().writeLock())) {
|
||||
|
||||
+14
-3
@@ -21,7 +21,8 @@ import java.util.concurrent.locks.ReadWriteLock;
|
||||
|
||||
import db.DBHandle;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.program.database.data.DataTypeManagerDB;
|
||||
import ghidra.program.database.data.ProgramBasedDataTypeManagerDB;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.trace.database.DBTrace;
|
||||
import ghidra.trace.database.DBTraceManager;
|
||||
@@ -33,7 +34,7 @@ import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.VersionException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class DBTraceDataTypeManager extends DataTypeManagerDB
|
||||
public class DBTraceDataTypeManager extends ProgramBasedDataTypeManagerDB
|
||||
implements TraceBasedDataTypeManager, DBTraceManager {
|
||||
|
||||
protected final ReadWriteLock lock;
|
||||
@@ -43,10 +44,20 @@ public class DBTraceDataTypeManager extends DataTypeManagerDB
|
||||
TaskMonitor monitor, DBTrace trace)
|
||||
throws CancelledException, VersionException, IOException {
|
||||
super(dbh, null, openMode.toInteger(), trace, trace.getLock(), monitor);
|
||||
this.lock = lock;
|
||||
this.lock = lock; // TODO: nothing uses this local lock - not sure what its purpose is
|
||||
this.trace = trace;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dataSettingChanged(Address address) {
|
||||
// ignored - instance settings are not current supported (no AddressMap provided)
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowsDefaultBuiltInSettings() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCache(boolean all) {
|
||||
super.invalidateCache();
|
||||
|
||||
-25
@@ -119,31 +119,6 @@ public interface DBTraceDataAdapter extends DBTraceCodeUnitAdapter, DataAdapterM
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
default void setByteArray(String name, byte[] value) {
|
||||
try (LockHold hold = getTrace().lockWrite()) {
|
||||
getSettingsSpace(true).setBytes(getLifespan(), getAddress(), name, value);
|
||||
}
|
||||
getTrace().setChanged(new TraceChangeRecord<>(
|
||||
TraceCodeChangeType.DATA_TYPE_SETTINGS_CHANGED, getTraceSpace(), this.getBounds(), null,
|
||||
null));
|
||||
}
|
||||
|
||||
@Override
|
||||
default byte[] getByteArray(String name) {
|
||||
try (LockHold hold = getTrace().lockRead()) {
|
||||
DBTraceDataSettingsOperations space = getSettingsSpace(false);
|
||||
if (space != null) {
|
||||
byte[] value = space.getBytes(getStartSnap(), getAddress(), name);
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
Settings defaultSettings = getDefaultSettings();
|
||||
return defaultSettings == null ? null : defaultSettings.getByteArray(name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
default void setValue(String name, Object value) {
|
||||
try (LockHold hold = getTrace().lockWrite()) {
|
||||
|
||||
+11
-10
@@ -1533,7 +1533,7 @@ public class DBTraceCodeUnitTest extends AbstractGhidraHeadlessIntegrationTest
|
||||
Settings defs = myTypedef.getDefaultSettings();
|
||||
defs.setLong("myDefaultLong", 0x123456789L);
|
||||
defs.setString("myDefaultString", "Hello!");
|
||||
defs.setByteArray("myDefaultBytes", new byte[] { 4, 3, 2, 1 });
|
||||
//defs.setByteArray("myDefaultBytes", new byte[] { 4, 3, 2, 1 });
|
||||
|
||||
assertTrue(d4000.isEmpty()); // This is a terribly counter-intuitive method name
|
||||
assertArrayEquals(new String[] {}, d4000.getNames());
|
||||
@@ -1546,23 +1546,23 @@ public class DBTraceCodeUnitTest extends AbstractGhidraHeadlessIntegrationTest
|
||||
assertNull(u3fff.getLong("myLong"));
|
||||
assertNull(d4000.getLong("myLong"));
|
||||
assertNull(d4000.getString("myString"));
|
||||
assertNull(d4000.getByteArray("myBytes"));
|
||||
//assertNull(d4000.getByteArray("myBytes"));
|
||||
assertNull(d4000.getValue("myLong"));
|
||||
assertFalse(d4000.isConstant());
|
||||
assertFalse(d4000.isVolatile());
|
||||
|
||||
assertEquals(0x123456789L, d4000.getLong("myDefaultLong").longValue());
|
||||
assertEquals("Hello!", d4000.getString("myDefaultString"));
|
||||
assertArrayEquals(new byte[] { 4, 3, 2, 1 }, d4000.getByteArray("myDefaultBytes"));
|
||||
//assertArrayEquals(new byte[] { 4, 3, 2, 1 }, d4000.getByteArray("myDefaultBytes"));
|
||||
assertEquals("Hello!", d4000.getValue("myDefaultString"));
|
||||
|
||||
d4000.setLong("myLong", Long.MAX_VALUE);
|
||||
d4000.setString("myString", "Good bye!");
|
||||
d4000.setByteArray("myBytes", new byte[] { 8, 7, 6, 5 });
|
||||
//d4000.setByteArray("myBytes", new byte[] { 8, 7, 6, 5 });
|
||||
|
||||
assertFalse(d4000.isEmpty());
|
||||
// TODO: Figure out whether or not this includes defaultSettings?
|
||||
assertEquals(Set.of("myLong", "myString", "myBytes"), set(d4000.getNames()));
|
||||
assertEquals(Set.of("myLong", "myString" /*, "myBytes"*/), set(d4000.getNames()));
|
||||
|
||||
d4000.setLong("myDefaultLong", Long.MAX_VALUE);
|
||||
d4000.setString("myDefaultString", "Good bye!");
|
||||
@@ -1570,12 +1570,13 @@ public class DBTraceCodeUnitTest extends AbstractGhidraHeadlessIntegrationTest
|
||||
|
||||
assertEquals(Long.MAX_VALUE, d4000.getLong("myLong").longValue());
|
||||
assertEquals("Good bye!", d4000.getString("myString"));
|
||||
assertArrayEquals(new byte[] { 8, 7, 6, 5 }, d4000.getByteArray("myBytes"));
|
||||
assertArrayEquals(new byte[] { 8, 7, 6, 5 }, (byte[]) d4000.getValue("myBytes"));
|
||||
//assertArrayEquals(new byte[] { 8, 7, 6, 5 }, d4000.getByteArray("myBytes"));
|
||||
//assertArrayEquals(new byte[] { 8, 7, 6, 5 }, (byte[]) d4000.getValue("myBytes"));
|
||||
|
||||
assertEquals(Long.MAX_VALUE, d4000.getLong("myDefaultLong").longValue());
|
||||
assertEquals("Good bye!", d4000.getString("myDefaultString"));
|
||||
assertArrayEquals(new byte[] { 8, 7, 6, 5 }, d4000.getByteArray("myDefaultBytes"));
|
||||
//assertArrayEquals(new byte[] { 8, 7, 6, 5 }, d4000.getByteArray("myDefaultBytes"));
|
||||
assertArrayEquals(new byte[] { 8, 7, 6, 5 }, (byte[]) d4000.getValue("myDefaultBytes"));
|
||||
|
||||
d4000.clearSetting("myDefaultLong");
|
||||
assertEquals(0x123456789L, d4000.getLong("myDefaultLong").longValue());
|
||||
@@ -1587,11 +1588,11 @@ public class DBTraceCodeUnitTest extends AbstractGhidraHeadlessIntegrationTest
|
||||
|
||||
assertNull(d4000.getLong("myLong"));
|
||||
assertNull(d4000.getString("myString"));
|
||||
assertNull(d4000.getByteArray("myBytes"));
|
||||
//assertNull(d4000.getByteArray("myBytes"));
|
||||
|
||||
assertEquals(0x123456789L, d4000.getLong("myDefaultLong").longValue());
|
||||
assertEquals("Hello!", d4000.getString("myDefaultString"));
|
||||
assertArrayEquals(new byte[] { 4, 3, 2, 1 }, d4000.getByteArray("myDefaultBytes"));
|
||||
//assertArrayEquals(new byte[] { 4, 3, 2, 1 }, d4000.getByteArray("myDefaultBytes"));
|
||||
assertNull(d4000.getValue("myLong"));
|
||||
|
||||
assertFalse(d4000.isConstant());
|
||||
|
||||
@@ -218,11 +218,11 @@
|
||||
<TD colspan="4" bgcolor="#c0c0c0" height="21" align="left">
|
||||
Settings
|
||||
<ul>
|
||||
<li>Endian (*default, big, little)
|
||||
<li>Format (*hex, decimal, octal, binary, ascii)
|
||||
<li>Mnemonic-style (default, *assembly, C)
|
||||
<li>Endian (default, big, little)
|
||||
<li>Format (hex, decimal, octal, binary, ascii)
|
||||
<li>Mnemonic-style (default, assembly, C)
|
||||
<li>Mutability (normal, volatile, constant)
|
||||
<li>Padding (*unpadded, padded)
|
||||
<li>Padding (unpadded, padded)
|
||||
</ul>
|
||||
</TD>
|
||||
|
||||
@@ -294,6 +294,18 @@
|
||||
<TH width="50%">Name</TD>
|
||||
<TH width="50%">Signed/Unsigned</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD align="left">char</TD>
|
||||
<TD align="left">(determined by data organziation)*</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD align="left">schar</TD>
|
||||
<TD align="left">Signed*</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD align="left">uchar</TD>
|
||||
<TD align="left">Unsigned*</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD align="left">short</TD>
|
||||
<TD align="left">Signed</TD>
|
||||
@@ -332,11 +344,16 @@
|
||||
<TD colspan="4" bgcolor="#c0c0c0" height="21" align="left">
|
||||
Settings <i>(may vary)</i>
|
||||
<ul>
|
||||
<li>Endian (*default, big, little)
|
||||
<li>Format (*hex, decimal, octal, binary, ascii)
|
||||
<li>Mnemonic-style (default, *assembly, C)
|
||||
<li>Mutability (normal, volatile, constant)
|
||||
<li>Padding (*unpadded, padded)
|
||||
<li>Endian (default, big, little)</li>
|
||||
<li>Format (hex, decimal, octal, binary, ascii)</li>
|
||||
<li>Mnemonic-style (default, assembly, C)</li>
|
||||
<li>Mutability (normal, volatile, constant)</li>
|
||||
<li>Padding (unpadded, padded)</li>
|
||||
</ul>
|
||||
*Additional character type <A href="#StringSettings">Settings</A>:
|
||||
<ul>
|
||||
<li>Charset (defaults to US-ASCII if user settable)</li>
|
||||
<li>Render non-ASCII Unicode (all, byte sequence, escape sequence)</li>
|
||||
</ul>
|
||||
</TD>
|
||||
|
||||
@@ -360,17 +377,9 @@
|
||||
<TH width="25%">Name</TD>
|
||||
<TH width="75%">Description</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD align="left">char</TD>
|
||||
<TD>Signed ASCII character</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD align="left">uchar</TD>
|
||||
<TD>Unsigned ASCII character</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD align="left">wchar_t</TD>
|
||||
<TD>Signed Wide Character</TD>
|
||||
<TD>Signed Wide Character*</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD align="left">pointer</TD>
|
||||
@@ -391,9 +400,9 @@
|
||||
<TR>
|
||||
|
||||
<TD colspan="4" bgcolor="#c0c0c0" height="21" align="left">
|
||||
Settings
|
||||
Settings <i>(may vary)</i>
|
||||
<ul>
|
||||
<li>Mutability (normal, volatile, constant)
|
||||
<li>Mutability (normal, volatile, constant)</li>
|
||||
</ul>
|
||||
</TD>
|
||||
|
||||
@@ -483,7 +492,7 @@
|
||||
<A href="#StringSettings">Settings</A>
|
||||
<ul>
|
||||
<li>Charset (defaults to US-ASCII if user settable)
|
||||
<li>Render Unicode (all, byte sequence, escape sequence)
|
||||
<li>Render non-ASCII Unicode (all, byte sequence, escape sequence)
|
||||
<li>Translation
|
||||
<li>Mutability (normal, volatile, constant)
|
||||
</ul>
|
||||
@@ -770,7 +779,7 @@
|
||||
press <B>OK</B>. To reset a setting to its default value, set the <B>Use Default</B>
|
||||
checkbox.</P>
|
||||
|
||||
<P><A name="Default_Data_Settings"></A>The <I>default</I> settings for a given data type can
|
||||
<P><A name="Default_Settings"></A>The <I>default</I> settings for a given data type can
|
||||
be changed. When a default setting has been changed, every data item <I>currently</I>
|
||||
using the default setting for that data type will use the new default value. Data items
|
||||
that have a modified value for that setting will not be affected.</P>
|
||||
@@ -1173,9 +1182,14 @@
|
||||
<BLOCKQUOTE>
|
||||
<P>A typedef is an alias for another data type. It is useful for giving a more meaningful
|
||||
name to a data type. For example, you might typedef <I>dword</I> to be
|
||||
<I>int</I>. Typedefs are <A href=
|
||||
"../DataTypeManagerPlugin/data_type_manager_description.htm#CreateDataTypes">created</A>
|
||||
using the Data Type Manager and applied like any other data type.</P>
|
||||
<I>int</I>.
|
||||
In addition, a typedef may be based upon a pointer with additional Settings which can influence
|
||||
how such a pointer should be interpretted.
|
||||
Typedefs are created</A>
|
||||
using the Data Type Manager and applied like any other data type (See
|
||||
<A href="../DataTypeManagerPlugin/data_type_manager_description.htm#CreateDataTypes">Creating New
|
||||
User Defined Data Types</A>).</P>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3>Void</H3>
|
||||
|
||||
+53
-8
@@ -785,24 +785,24 @@
|
||||
signature editor for function definitions) for creating the new desired data type.</P>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<H4>Creating a Typedef</H4>
|
||||
<P>Creating a new <B>typedef</B> is even easier. Right-click on the data type to be
|
||||
typedef'ed and select the <I><B>New<IMG src="../../shared/arrow.gif" alt=""> Typedef on
|
||||
XYZ</B></I> action. A new typedef will be created on the <I>XYZ</I> data type in the
|
||||
same category as the original data type.<BR>
|
||||
</P>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>
|
||||
Alternatively, you can click <I><B>New<IMG src="../../shared/arrow.gif" alt="">
|
||||
<P>Alternatively, you can click <I><B>New<IMG src="../../shared/arrow.gif" alt="">
|
||||
Typedef...</B></I>, which will show a dialog that allows you to choose a typedef name
|
||||
and the data type from which the typedef will be created.<SUP>*</SUP> This action can
|
||||
also be executed from any folder instead of directly on another data type.
|
||||
</P>
|
||||
</BLOCKQUOTE>
|
||||
<BR>
|
||||
<BR>
|
||||
|
||||
<P>A Typedef created with a Pointer base type will allow additional Settings to be made
|
||||
which can influence how such a pointer should be interpretted
|
||||
(see <A href="#Pointer_Typedef_Settings">Pointer-Typedef Settings</A>).</P>
|
||||
|
||||
|
||||
<H4>Creating a Pointer</H4>
|
||||
<P>To create a <B>pointer</B>, you can click <I><B>New<IMG src="../../shared/arrow.gif"
|
||||
alt=""> Pointer to XYZ</B></I>. A new pointer will be created to the <I>XYZ</I> data
|
||||
type in the same category as the original data type.<SUP>*</SUP></P>
|
||||
@@ -1056,8 +1056,53 @@
|
||||
part of your tool's state when you close the Project or exit Ghidra. Your list of
|
||||
favorites is restored when you re-open your project or restart Ghidra.</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="Pointer_Typedef_Settings"></A>Pointer-Typedef Settings</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>On occasion there may be the need to add stipulate additional attributes on a pointer
|
||||
type to stipulate how the associated pointer should be interpreted or processed during analysis.
|
||||
Such pointer attributes may only be specified when such a pointer in in the form of a Typedef
|
||||
which enables the datatype to preserve these attributes during type resolution and propogation.
|
||||
This includes preservation of such Typedef Settings within a data type archive, and through
|
||||
merge processing, which normal Data Settings do not support.</P>
|
||||
|
||||
<P>The Typedef Settings may be modified via the Settings dialog in the same way data type Default Settings
|
||||
are changed for listing Data (see <A href="../DataPlugin/Data.htm#Default_Settings">Changing Default Settings for Data</A>).
|
||||
In addition to this popup action on listing Data, the dialog may be displayed from the <I>Data Type Manager</I>
|
||||
tree by right-clicking on a data type and selecting the <B>Settings...</B> action. Typedef-specific settings
|
||||
are only supported as default settings for a typedef and may not be overriden at the component or data level.</A>
|
||||
|
||||
<P>The following Pointer-Typedef settings are currently supported:</P>
|
||||
<UL>
|
||||
<LI><B>Address Space</B> (case-sensitive string) - Allows a specific address space to be associated with a pointer.
|
||||
If an unknown name is used it will be silently ignored. </LI>
|
||||
<LI><B>Component Offset</B> (signed value) - Allows a base-relative offset to be specified. When applied
|
||||
to memory an Offset Reference will be generated. I addition, type analysis may use the offset to identify
|
||||
a component relative to the pointer's base-datatype (e.g., structure).</LI>
|
||||
<LI><B>Offset Mask</B> (64-bit mask) - Allows a bit-mask to be applied to a stored value when computing the
|
||||
absolute memory offset. This bit-mask will be applied prior to any applied bit-shift.</LI>
|
||||
<LI><B>Offset Shift</B> (-64..0..64) - Allows a bit-shift (left=negative, right=positive) to be applied to a
|
||||
stored value when computing the absolute memory offset.</LI>
|
||||
<LI><B>Pointer Type</B> (<I>default, IBO, relative, file-offset</I>) - allows the overall interpretation of a
|
||||
pointer to be specified. The <I>relative</I> pointer type has limited applicabaility and is only
|
||||
intended to be applied to pointers stored in memory since their storage location is used in computing
|
||||
the absolute address that the pointer refers to. (IBO: Image Base Offset Relative).</LI>
|
||||
</UL>
|
||||
|
||||
<P><IMG src="../../shared/note.png" alt="" border="0">All Typedef Settings must be established on
|
||||
a Typedef before such a type is applied to Data or referenced by other types. This is highly recommended
|
||||
since the side-affects of using such a modified typedef will not be updated to reflect subsequent changes.
|
||||
</P>
|
||||
|
||||
<P><IMG src="../../shared/note.png" alt="" border="0"> Full support for the above Pointer-Typedef
|
||||
Settings within analysis and decompilation will evolve over time. We also hope to improve
|
||||
naming concerns for such typedefs and to replace the use of custom BuiltIn data types which would
|
||||
be better modeled as a Pointer.</P>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<P class="providedbyplugin">Provided by: <I>DataTypeManagerPlugin</I></P>
|
||||
|
||||
|
||||
@@ -664,7 +664,7 @@ xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-
|
||||
<BLOCKQUOTE>
|
||||
<P>Display options for <I>individual</I> data items in Ghidra. For example one byte can be
|
||||
displayed as decimal while another is displayed as hex. Also see <A href=
|
||||
"help/topics/DataPlugin/Data.htm#Default_Data_Settings">Data Type Default Settings</A>.</P>
|
||||
"help/topics/DataPlugin/Data.htm#Default_Settings">Data Type Default Settings</A>.</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H2><A name="Instruction"></A>Instruction</H2>
|
||||
|
||||
-3
@@ -1791,9 +1791,6 @@ public class DataTypeMergeManager implements MergeResolver {
|
||||
Composite c2 = (Composite) dt2;
|
||||
return compositeDataTypeWasChanged(c1, c2);
|
||||
}
|
||||
if (dt1 instanceof TypeDef) {
|
||||
return false;
|
||||
}
|
||||
return !dt1.isEquivalent(dt2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ import javax.swing.JTextPane;
|
||||
import javax.swing.text.*;
|
||||
|
||||
import ghidra.app.merge.MergeConstants;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.docking.settings.SettingsDefinition;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.Enum;
|
||||
import ghidra.program.model.listing.FunctionSignature;
|
||||
@@ -76,6 +78,9 @@ class DataTypePanel extends JPanel {
|
||||
else {
|
||||
formatDataType(dataType);
|
||||
}
|
||||
if (dataType != null) {
|
||||
formatDataTypeSettings(dataType);
|
||||
}
|
||||
textPane.setCaretPosition(0);
|
||||
}
|
||||
|
||||
@@ -318,7 +323,23 @@ class DataTypePanel extends JPanel {
|
||||
formatPath(td);
|
||||
insertString(td.getDisplayName(), nameAttrSet);
|
||||
insertString("\n", contentAttrSet);
|
||||
insertString(" TypeDef on " + td.getDataType().getDisplayName(), contentAttrSet);
|
||||
insertString(" TypeDef on " + td.getDataType().getDisplayName(), contentAttrSet);
|
||||
}
|
||||
|
||||
private void formatDataTypeSettings(DataType dt) {
|
||||
Settings settings = dt.getDefaultSettings();
|
||||
SettingsDefinition[] defs =
|
||||
SettingsDefinition.filterSettingsDefinitions(dt.getSettingsDefinitions(), def -> {
|
||||
return (def instanceof TypeDefSettingsDefinition) && def.hasValue(settings);
|
||||
});
|
||||
if (defs.length == 0) {
|
||||
return;
|
||||
}
|
||||
insertString("\n\nSettings\n", sourceAttrSet);
|
||||
for (SettingsDefinition def : defs) {
|
||||
insertString(" " + def.getName() + ": " + def.getValueString(settings) + "\n",
|
||||
contentAttrSet);
|
||||
}
|
||||
}
|
||||
|
||||
private void formatFunctionDef(FunctionDefinition fd) {
|
||||
|
||||
+131
-130
@@ -51,7 +51,7 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
*/
|
||||
@Override
|
||||
public void load(Composite dataType) {
|
||||
super.load(dataType, true);
|
||||
super.load(dataType);
|
||||
fixSelection();
|
||||
selectionChanged();
|
||||
}
|
||||
@@ -116,11 +116,12 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
}
|
||||
originalDt.setDescription(getDescription());
|
||||
replaceOriginalComponents();
|
||||
load(originalDt, true);
|
||||
updateOriginalComponentSettings(viewComposite, originalDt);
|
||||
load(originalDt);
|
||||
}
|
||||
else {
|
||||
Composite dt = (Composite) originalDTM.resolve(viewComposite, null);
|
||||
load(dt, true);
|
||||
load(dt);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1310,81 +1311,88 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
public void dataTypeChanged(DataTypeManager dtm, DataTypePath path) {
|
||||
try {
|
||||
|
||||
if (isLoaded()) {
|
||||
// If we don't currently have any modifications that need applying and
|
||||
// the structure in the editor just changed, then show the changed
|
||||
// structure.
|
||||
if (originalDataTypePath == null) {
|
||||
if (dtm instanceof CompositeViewerDataTypeManager) {
|
||||
// required to detect settings changes
|
||||
componentEdited();
|
||||
return;
|
||||
}
|
||||
|
||||
DataTypeManager originalDTM = getOriginalDataTypeManager();
|
||||
if (dtm != originalDTM) {
|
||||
return; // Different DTM than the one for this data type.
|
||||
}
|
||||
|
||||
if (!isLoaded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we don't currently have any modifications that need applying and
|
||||
// the structure in the editor just changed, then show the changed
|
||||
// structure.
|
||||
String oldName = path.getDataTypeName();
|
||||
if (path.equals(originalDataTypePath)) {
|
||||
if (consideringReplacedDataType) {
|
||||
return;
|
||||
}
|
||||
String oldName = path.getDataTypeName();
|
||||
if (path.equals(originalDataTypePath)) {
|
||||
if (consideringReplacedDataType) {
|
||||
return;
|
||||
}
|
||||
// Return if the original is already changing. Need this since there
|
||||
// can be multiple change notifications from a single data type update
|
||||
// event due to replaceWith(), setLastChangeTime() and
|
||||
// setLastChangeTimeInSource() each firing dataTypeChanged().
|
||||
if (originalIsChanging) {
|
||||
return;
|
||||
}
|
||||
originalIsChanging = true;
|
||||
try {
|
||||
if (hadChanges) {
|
||||
String message = "<html>" + HTMLUtilities.escapeHTML(oldName) +
|
||||
" has changed outside the editor.<br>" +
|
||||
"Discard edits & reload the " + getTypeName() + "?";
|
||||
String title = "Reload " + getTypeName() + " Editor?";
|
||||
int response = OptionDialog.showYesNoDialogWithNoAsDefaultButton(
|
||||
provider.getComponent(), title, message);
|
||||
if (response == OptionDialog.OPTION_ONE) {
|
||||
load(getOriginalComposite());
|
||||
}
|
||||
originalComponentsChanged();
|
||||
}
|
||||
else {
|
||||
Composite changedComposite = getOriginalComposite();
|
||||
if ((changedComposite != null) &&
|
||||
!viewComposite.isEquivalent(changedComposite)) {
|
||||
load(getOriginalComposite());
|
||||
setStatus(
|
||||
viewComposite.getPathName() + " changed outside the editor.",
|
||||
false);
|
||||
}
|
||||
// Return if the original is already changing. Need this since there
|
||||
// can be multiple change notifications from a single data type update
|
||||
// event due to replaceWith(), setLastChangeTime() and
|
||||
// setLastChangeTimeInSource() each firing dataTypeChanged().
|
||||
if (originalIsChanging) {
|
||||
return;
|
||||
}
|
||||
originalIsChanging = true;
|
||||
try {
|
||||
if (hadChanges) {
|
||||
String message = "<html>" + HTMLUtilities.escapeHTML(oldName) +
|
||||
" has changed outside the editor.<br>" + "Discard edits & reload the " +
|
||||
getTypeName() + "?";
|
||||
String title = "Reload " + getTypeName() + " Editor?";
|
||||
int response = OptionDialog.showYesNoDialogWithNoAsDefaultButton(
|
||||
provider.getComponent(), title, message);
|
||||
if (response == OptionDialog.OPTION_ONE) {
|
||||
load(getOriginalComposite());
|
||||
}
|
||||
}
|
||||
finally {
|
||||
originalIsChanging = false;
|
||||
else {
|
||||
Composite changedComposite = getOriginalComposite();
|
||||
if ((changedComposite != null) &&
|
||||
!viewComposite.isEquivalent(changedComposite)) {
|
||||
load(getOriginalComposite());
|
||||
setStatus(viewComposite.getPathName() + " changed outside the editor.",
|
||||
false);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
DataType viewDt = viewDTM.getDataType(path);
|
||||
if (viewDt == null) {
|
||||
return;
|
||||
}
|
||||
int origDtLen = viewDt.getLength();
|
||||
DataType changedDt = dtm.getDataType(path);
|
||||
if (changedDt != null) {
|
||||
if ((viewDt instanceof Composite) && (changedDt instanceof Composite)) {
|
||||
Composite comp = (Composite) changedDt;
|
||||
Composite origDt = getOriginalComposite();
|
||||
if ((origDt != null) && comp.isPartOf(origDt)) {
|
||||
removeDtFromComponents(comp);
|
||||
}
|
||||
finally {
|
||||
originalIsChanging = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DataType viewDt = viewDTM.getDataType(path);
|
||||
if (viewDt == null) {
|
||||
return;
|
||||
}
|
||||
int origDtLen = viewDt.getLength();
|
||||
DataType changedDt = dtm.getDataType(path);
|
||||
if (changedDt != null) {
|
||||
if ((viewDt instanceof Composite) && (changedDt instanceof Composite)) {
|
||||
Composite comp = (Composite) changedDt;
|
||||
Composite origDt = getOriginalComposite();
|
||||
if ((origDt != null) && comp.isPartOf(origDt)) {
|
||||
removeDtFromComponents(comp);
|
||||
}
|
||||
|
||||
((Composite) viewDt).setDescription(
|
||||
((Composite) changedDt).getDescription());
|
||||
}
|
||||
viewDt =
|
||||
viewDTM.resolve(changedDt, DataTypeConflictHandler.REPLACE_HANDLER);
|
||||
if (origDtLen != viewDt.getLength()) {
|
||||
viewComposite.dataTypeSizeChanged(viewDt);
|
||||
}
|
||||
((Composite) viewDt)
|
||||
.setDescription(((Composite) changedDt).getDescription());
|
||||
}
|
||||
viewDt = viewDTM.resolve(changedDt, DataTypeConflictHandler.REPLACE_HANDLER);
|
||||
if (origDtLen != viewDt.getLength()) {
|
||||
viewComposite.dataTypeSizeChanged(viewDt);
|
||||
}
|
||||
fireTableDataChanged();
|
||||
componentDataChanged();
|
||||
}
|
||||
fireTableDataChanged();
|
||||
componentDataChanged();
|
||||
}
|
||||
}
|
||||
catch (ConcurrentModificationException e) {
|
||||
@@ -1397,78 +1405,74 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
@Override
|
||||
public void dataTypeReplaced(DataTypeManager dtm, DataTypePath oldPath, DataTypePath newPath,
|
||||
DataType newDataType) {
|
||||
if (newDataType == null) {
|
||||
|
||||
DataTypeManager originalDTM = getOriginalDataTypeManager();
|
||||
if (dtm != originalDTM) {
|
||||
return; // Different DTM than the one for this data type.
|
||||
}
|
||||
|
||||
if (!isLoaded()) {
|
||||
return;
|
||||
}
|
||||
if (isLoaded()) {
|
||||
DataTypeManager originalDataTypeManager = getOriginalDataTypeManager();
|
||||
if (originalDataTypeManager != dtm) {
|
||||
return;
|
||||
}
|
||||
if (originalDataTypePath == null) {
|
||||
return;
|
||||
}
|
||||
String dtName = oldPath.getDataTypeName();
|
||||
DataTypePath dtPath = new DataTypePath(newDataType.getCategoryPath(), dtName);
|
||||
if (!dtPath.equals(originalDataTypePath)) {
|
||||
DataType dt = viewDTM.getDataType(dtPath);
|
||||
if (dt != null) {
|
||||
if (hasSubDt(viewComposite, dtPath)) {
|
||||
String msg = "Replaced data type \"" + dtPath +
|
||||
"\", which is a sub-component of \"" + getOriginalDataTypeName() +
|
||||
"\".";
|
||||
setStatus(msg, true);
|
||||
}
|
||||
// NOTE: depending upon event sequence and handling a
|
||||
// re-load may have occured and replcement may be uneccessary
|
||||
try {
|
||||
viewDTM.replaceDataType(dt, newDataType, true);
|
||||
}
|
||||
catch (DataTypeDependencyException e) {
|
||||
throw new AssertException(e);
|
||||
}
|
||||
fireTableDataChanged();
|
||||
componentDataChanged();
|
||||
|
||||
String dtName = oldPath.getDataTypeName();
|
||||
DataTypePath dtPath = new DataTypePath(newDataType.getCategoryPath(), dtName);
|
||||
if (!dtPath.equals(originalDataTypePath)) {
|
||||
DataType dt = viewDTM.getDataType(dtPath);
|
||||
if (dt != null) {
|
||||
if (hasSubDt(viewComposite, dtPath)) {
|
||||
String msg = "Replaced data type \"" + dtPath +
|
||||
"\", which is a sub-component of \"" + getOriginalDataTypeName() + "\".";
|
||||
setStatus(msg, true);
|
||||
}
|
||||
// NOTE: depending upon event sequence and handling a
|
||||
// re-load may have occured and replcement may be uneccessary
|
||||
try {
|
||||
viewDTM.replaceDataType(dt, newDataType, true);
|
||||
}
|
||||
catch (DataTypeDependencyException e) {
|
||||
throw new AssertException(e);
|
||||
}
|
||||
fireTableDataChanged();
|
||||
componentDataChanged();
|
||||
}
|
||||
else {
|
||||
if (this.hadChanges) {
|
||||
if (originalDataTypePath.equals(oldPath)) {
|
||||
if (hadChanges) {
|
||||
consideringReplacedDataType = true;
|
||||
try {
|
||||
String message =
|
||||
"<html>" + HTMLUtilities.escapeHTML(oldPath.getPath()) +
|
||||
" has changed outside the editor.<br>" +
|
||||
"Discard edits & reload the " + getTypeName() + "?";
|
||||
String title = "Reload " + getTypeName() + " Editor?";
|
||||
int response = OptionDialog.showYesNoDialogWithNoAsDefaultButton(
|
||||
provider.getComponent(), title, message);
|
||||
if (response == OptionDialog.OPTION_ONE) {
|
||||
load(getOriginalComposite());
|
||||
}
|
||||
originalComponentsChanged();
|
||||
}
|
||||
finally {
|
||||
consideringReplacedDataType = false;
|
||||
}
|
||||
else {
|
||||
if (this.hadChanges) {
|
||||
if (originalDataTypePath.equals(oldPath)) {
|
||||
if (hadChanges) {
|
||||
consideringReplacedDataType = true;
|
||||
try {
|
||||
String message =
|
||||
"<html>" + HTMLUtilities.escapeHTML(oldPath.getPath()) +
|
||||
" has changed outside the editor.<br>" +
|
||||
"Discard edits & reload the " + getTypeName() + "?";
|
||||
String title = "Reload " + getTypeName() + " Editor?";
|
||||
int response = OptionDialog.showYesNoDialogWithNoAsDefaultButton(
|
||||
provider.getComponent(), title, message);
|
||||
if (response == OptionDialog.OPTION_ONE) {
|
||||
load(getOriginalComposite());
|
||||
}
|
||||
}
|
||||
else {
|
||||
load(getOriginalComposite());
|
||||
setStatus(viewComposite.getPathName() + " changed outside the editor.",
|
||||
false);
|
||||
finally {
|
||||
consideringReplacedDataType = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
String msg = "\"" + oldPath.getPath() + "\" was replaced with " +
|
||||
newDataType.getPathName() + " in the data type manager.";
|
||||
setStatus(msg, true);
|
||||
load(getOriginalComposite());
|
||||
setStatus(viewComposite.getPathName() + " changed outside the editor.",
|
||||
false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
load((Composite) newDataType);
|
||||
String msg = "\"" + oldPath.getPath() + "\" was replaced with " +
|
||||
newDataType.getPathName() + " in the data type manager.";
|
||||
setStatus(msg, true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
load((Composite) newDataType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1701,9 +1705,6 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
|
||||
public int getActualAlignment() {
|
||||
return viewComposite.getAlignment();
|
||||
// return viewDTM.getDataOrganization().getAlignment(viewComposite, getLength());
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/* ###
|
||||
* 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.plugin.core.compositeeditor;
|
||||
|
||||
import ghidra.program.model.data.*;
|
||||
|
||||
/**
|
||||
* <code>ComponentContext</code> provides a selected component context when editing a structure/union
|
||||
*/
|
||||
public interface ComponentContext {
|
||||
|
||||
/**
|
||||
* Get editor's data type manager
|
||||
* @return editor's datatype manager
|
||||
*/
|
||||
DataTypeManager getDataTypeManager();
|
||||
|
||||
/**
|
||||
* Get the editor's selected component's parent composite (structure or union)
|
||||
* @return editor's selected component's parent composite
|
||||
*/
|
||||
Composite getCompositeDataType();
|
||||
|
||||
/**
|
||||
* Get the editor's selected component
|
||||
* @return editor's selected component
|
||||
*/
|
||||
DataTypeComponent getDataTypeComponent();
|
||||
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/* ###
|
||||
* 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.plugin.core.compositeeditor;
|
||||
|
||||
import ghidra.app.context.ProgramActionContext;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
|
||||
/**
|
||||
* <code>ComponentProgramActionContext</code> provides an action context when editing a
|
||||
* composite with a single selected component, and the composite is associated with a program.
|
||||
*/
|
||||
public class ComponentProgramActionContext extends ProgramActionContext
|
||||
implements ComponentContext {
|
||||
|
||||
private DataTypeComponent component;
|
||||
private Composite composite;
|
||||
|
||||
public ComponentProgramActionContext(CompositeEditorProvider compositeEditorProvider,
|
||||
Program program, DataTypeComponent component) {
|
||||
super(compositeEditorProvider, program);
|
||||
this.component = component;
|
||||
DataType parent = component.getParent();
|
||||
if (!(parent instanceof Composite)) {
|
||||
throw new IllegalArgumentException("Only Composite components allowed");
|
||||
}
|
||||
this.composite = (Composite) parent;
|
||||
if (parent.getDataTypeManager() == null) {
|
||||
throw new IllegalArgumentException("Component's parent must have a DataTypeManager");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeManager getDataTypeManager() {
|
||||
// Pass target datatype manager - not intended to be modified!
|
||||
return program.getDataTypeManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Composite getCompositeDataType() {
|
||||
return composite;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeComponent getDataTypeComponent() {
|
||||
return component;
|
||||
}
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/* ###
|
||||
* 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.plugin.core.compositeeditor;
|
||||
|
||||
import docking.ActionContext;
|
||||
import ghidra.program.model.data.*;
|
||||
|
||||
/**
|
||||
* <code>ComponentStandAloneActionContext</code> provides an action context when editing a
|
||||
* composite with a single selected component, and the composite is associated with a
|
||||
* stand-alone archive.
|
||||
*/
|
||||
public class ComponentStandAloneActionContext extends ActionContext
|
||||
implements ComponentContext {
|
||||
|
||||
private DataTypeComponent component;
|
||||
private Composite composite;
|
||||
|
||||
public ComponentStandAloneActionContext(CompositeEditorProvider compositeEditorProvider,
|
||||
DataTypeComponent component) {
|
||||
super(compositeEditorProvider);
|
||||
this.component = component;
|
||||
DataType parent = component.getParent();
|
||||
if (!(parent instanceof Composite)) {
|
||||
throw new IllegalArgumentException("Only Composite components allowed");
|
||||
}
|
||||
this.composite = (Composite) parent;
|
||||
if (parent.getDataTypeManager() == null) {
|
||||
throw new IllegalArgumentException("Component's parent must have a DataTypeManager");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeManager getDataTypeManager() {
|
||||
return composite.getDataTypeManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Composite getCompositeDataType() {
|
||||
return composite;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeComponent getDataTypeComponent() {
|
||||
return component;
|
||||
}
|
||||
}
|
||||
+126
-60
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package ghidra.app.plugin.core.compositeeditor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.*;
|
||||
|
||||
import docking.widgets.dialogs.NumberInputDialog;
|
||||
import docking.widgets.fieldpanel.support.FieldRange;
|
||||
@@ -31,6 +31,7 @@ import docking.widgets.fieldpanel.support.FieldSelection;
|
||||
*/
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.util.DataTypeUtils;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.Enum;
|
||||
import ghidra.util.*;
|
||||
@@ -58,7 +59,6 @@ public abstract class CompositeEditorModel extends CompositeViewerModel implemen
|
||||
protected int lastNumElements = 1;
|
||||
protected int lastNumBytes = 1;
|
||||
|
||||
private boolean offline = true;
|
||||
protected boolean hadChanges = false;
|
||||
protected boolean originalIsChanging = false;
|
||||
|
||||
@@ -68,34 +68,27 @@ public abstract class CompositeEditorModel extends CompositeViewerModel implemen
|
||||
super(provider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(Composite dataType, boolean useOffLineCategory) {
|
||||
this.offline = useOffLineCategory;
|
||||
if (dataType == null) {
|
||||
/**
|
||||
* Loads the specified composite into the model replacing
|
||||
* whatever composite is there.
|
||||
*
|
||||
* @param dataType the new composite data type.
|
||||
*/
|
||||
public void load(Composite dataType) {
|
||||
if (dataType == null) { // TODO: Why is this needed? Use case?
|
||||
return;
|
||||
// throw new NullPointerException();
|
||||
}
|
||||
DataTypeManager dataTypeManager = dataType.getDataTypeManager();
|
||||
if (dataTypeManager == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Datatype " + dataType.getName() + " doesn't have a data type manager specified.");
|
||||
}
|
||||
CategoryPath categoryPath = dataType.getCategoryPath();
|
||||
Category cat = dataTypeManager.getCategory(categoryPath);
|
||||
if (cat == null && !useOffLineCategory) {
|
||||
throw new IllegalArgumentException(
|
||||
"Datatype " + dataType.getName() + " category not found: " +
|
||||
categoryPath.getPath());
|
||||
}
|
||||
|
||||
if (isEditingField()) {
|
||||
endFieldEditing();
|
||||
}
|
||||
DataTypeManager originalDTM = getOriginalDataTypeManager();
|
||||
|
||||
if (isLoaded()) {
|
||||
// No longer want to listen for changes to previous category.
|
||||
if (originalDTM != null) {
|
||||
originalDTM.removeDataTypeManagerListener(this);
|
||||
}
|
||||
unload();
|
||||
}
|
||||
|
||||
@@ -103,32 +96,54 @@ public abstract class CompositeEditorModel extends CompositeViewerModel implemen
|
||||
originalComposite = dataType;
|
||||
originalDataTypePath = originalComposite.getDataTypePath();
|
||||
currentName = dataType.getName();
|
||||
originalDTM = dataTypeManager;
|
||||
if (useOffLineCategory) {
|
||||
viewDTM = new CompositeViewerDataTypeManager(originalDTM.getName(), dataType);
|
||||
viewComposite = (Composite) viewDTM.resolve(dataType, null);
|
||||
}
|
||||
else {
|
||||
viewDTM = originalDTM;
|
||||
viewComposite = (Composite) dataType.clone(viewDTM);
|
||||
}
|
||||
DataTypeManager originalDTM = dataTypeManager;
|
||||
|
||||
viewComposite = createViewCompositeFromOriginalComposite(originalComposite);
|
||||
viewDTM = viewComposite.getDataTypeManager();
|
||||
|
||||
// Listen so we can update editor if name changes for this structure.
|
||||
originalCompositeId = DataTypeManager.NULL_DATATYPE_ID;
|
||||
if (originalDTM.contains(dataType)) {
|
||||
compositeID = originalDTM.getID(dataType); // Get the id if editing an existing data type.
|
||||
originalCompositeId = originalDTM.getID(dataType); // Get the id if editing an existing data type.
|
||||
}
|
||||
originalDTM.addDataTypeManagerListener(this);
|
||||
|
||||
hadChanges = false;
|
||||
setSelection(new FieldSelection());
|
||||
clearStatus();
|
||||
originalNameChanged();
|
||||
originalCategoryChanged();
|
||||
compositeInfoChanged();
|
||||
fireTableDataChanged();
|
||||
componentDataChanged();
|
||||
|
||||
editorStateChanged(CompositeEditorModelListener.COMPOSITE_LOADED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create view composite with the appropriate datatype manager and
|
||||
* changes listener(s) if required.
|
||||
*
|
||||
* @param original original composite being loaded
|
||||
* @return view composite to used by model
|
||||
*/
|
||||
protected Composite createViewCompositeFromOriginalComposite(Composite original) {
|
||||
|
||||
// Use temporary standalone view datatype manager
|
||||
DataTypeManager dtm =
|
||||
new CompositeViewerDataTypeManager(original.getDataTypeManager().getName(), original);
|
||||
Composite composite = (Composite) dtm.resolve(original, null);
|
||||
|
||||
// Clone all settings some of which do not get resolved.
|
||||
|
||||
// NOTE: It is important to note that the editor will allow modification of component
|
||||
// default settings, however the underlying datatype default settings may not get copied
|
||||
// as they get resolved into the view datatype manager. This may result in the incorrect
|
||||
// underlying datatype default setting value being presented when adjusting component
|
||||
// default settings.
|
||||
cloneAllComponentSettings(original, composite);
|
||||
|
||||
dtm.addDataTypeManagerListener(this); // listen to view datatype manager changes
|
||||
return composite;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
@@ -544,22 +559,6 @@ public abstract class CompositeEditorModel extends CompositeViewerModel implemen
|
||||
return validName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this composite editor model is editing the composite in
|
||||
* an offline data type manager instance. In other words, changes to the data type
|
||||
* being edited don't directly affect the original data type manager is unaffected
|
||||
* until editor changes are applied.
|
||||
*
|
||||
* <p>If this returns false, then the editor directly affects the original
|
||||
* data type manager. For example, as data types are added to the composite data type,
|
||||
* they are also added to the original data type manager if not already there.
|
||||
*
|
||||
* @return true if editing offline
|
||||
*/
|
||||
public boolean isOffline() {
|
||||
return offline;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasChanges() {
|
||||
return hadChanges;
|
||||
@@ -582,6 +581,7 @@ public abstract class CompositeEditorModel extends CompositeViewerModel implemen
|
||||
boolean noCompChanges = false;
|
||||
if (oldComposite != null) {
|
||||
noCompChanges = (viewComposite.isEquivalent(oldComposite) &&
|
||||
hasSameComponentSettings(viewComposite, oldComposite) &&
|
||||
!hasCompPathNameChanges(viewComposite, oldComposite));
|
||||
}
|
||||
else {
|
||||
@@ -591,6 +591,74 @@ public abstract class CompositeEditorModel extends CompositeViewerModel implemen
|
||||
return hadChanges;
|
||||
}
|
||||
|
||||
private boolean hasSameComponentSettings(Composite currentViewComposite,
|
||||
Composite oldComposite) {
|
||||
DataTypeComponent[] viewComps = currentViewComposite.getDefinedComponents();
|
||||
DataTypeComponent[] oldComps = oldComposite.getDefinedComponents();
|
||||
if (viewComps.length != oldComps.length) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < viewComps.length; i++) {
|
||||
if (!hasSameSettings(viewComps[i], oldComps[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean hasSameSettings(DataTypeComponent viewDtc, DataTypeComponent oldDtc) {
|
||||
Settings viewDtcSettings = viewDtc.getDefaultSettings();
|
||||
Settings oldDtcSettings = oldDtc.getDefaultSettings();
|
||||
String[] viewSettingsNames = viewDtcSettings.getNames();
|
||||
String[] oldSettingsNames = oldDtcSettings.getNames();
|
||||
if (viewSettingsNames.length != oldSettingsNames.length) {
|
||||
return false;
|
||||
}
|
||||
Arrays.sort(viewSettingsNames);
|
||||
Arrays.sort(oldSettingsNames);
|
||||
if (!Arrays.equals(viewSettingsNames, oldSettingsNames)) {
|
||||
return false;
|
||||
}
|
||||
for (String name : viewSettingsNames) {
|
||||
if (!Objects.equals(viewDtcSettings.getValue(name), oldDtcSettings.getValue(name))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void cloneAllComponentSettings(Composite sourceComposite, Composite destComposite) {
|
||||
DataTypeComponent[] sourceComps = sourceComposite.getDefinedComponents();
|
||||
DataTypeComponent[] destComps = destComposite.getDefinedComponents();
|
||||
assert (sourceComps.length == destComps.length);
|
||||
for (int i = 0; i < sourceComps.length; i++) {
|
||||
Settings sourceDtcSettings = sourceComps[i].getDefaultSettings();
|
||||
Settings destDtcSettings = destComps[i].getDefaultSettings();
|
||||
destDtcSettings.clearAllSettings();
|
||||
for (String name : sourceDtcSettings.getNames()) {
|
||||
destDtcSettings.setValue(name, sourceDtcSettings.getValue(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateOriginalComponentSettings(Composite sourceComposite,
|
||||
Composite destComposite) {
|
||||
DataTypeComponent[] sourceComps = sourceComposite.getDefinedComponents();
|
||||
DataTypeComponent[] destComps = destComposite.getDefinedComponents();
|
||||
assert (sourceComps.length == destComps.length);
|
||||
for (int i = 0; i < sourceComps.length; i++) {
|
||||
if (hasSameSettings(sourceComps[i], destComps[i])) {
|
||||
continue;
|
||||
}
|
||||
Settings sourceDtcSettings = sourceComps[i].getDefaultSettings();
|
||||
Settings destDtcSettings = destComps[i].getDefaultSettings();
|
||||
destDtcSettings.clearAllSettings();
|
||||
for (String name : sourceDtcSettings.getNames()) {
|
||||
destDtcSettings.setValue(name, sourceDtcSettings.getValue(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasCompPathNameChanges(Composite currentViewComposite, Composite oldComposite) {
|
||||
// Check component data type pathnames.
|
||||
DataTypeComponent[] comps = currentViewComposite.getDefinedComponents();
|
||||
@@ -899,20 +967,27 @@ public abstract class CompositeEditorModel extends CompositeViewerModel implemen
|
||||
|
||||
@Override
|
||||
public void dataTypeRenamed(DataTypeManager dtm, DataTypePath oldPath, DataTypePath newPath) {
|
||||
|
||||
DataTypeManager originalDTM = getOriginalDataTypeManager();
|
||||
if (dtm != originalDTM) {
|
||||
return; // Different DTM than the one for this data type.
|
||||
}
|
||||
|
||||
if (!isLoaded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldPath.getDataTypeName().equals(newPath.getDataTypeName())) {
|
||||
return;
|
||||
}
|
||||
if (originalDataTypePath == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String newName = newPath.getDataTypeName();
|
||||
String oldName = oldPath.getDataTypeName();
|
||||
|
||||
// Does the old name match our original name.
|
||||
if (originalDataTypePath.equals(oldPath)) {
|
||||
// Check originalCompositeId to ensure original type is managed
|
||||
if (originalCompositeId != DataTypeManager.NULL_DATATYPE_ID &&
|
||||
oldPath.equals(originalDataTypePath)) {
|
||||
originalDataTypePath = newPath;
|
||||
try {
|
||||
if (viewComposite.getName().equals(oldName)) {
|
||||
@@ -926,7 +1001,6 @@ public abstract class CompositeEditorModel extends CompositeViewerModel implemen
|
||||
catch (InvalidNameException e) {
|
||||
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
|
||||
}
|
||||
originalNameChanged();
|
||||
}
|
||||
else {
|
||||
DataType dt = viewDTM.getDataType(oldPath);
|
||||
@@ -1005,14 +1079,6 @@ public abstract class CompositeEditorModel extends CompositeViewerModel implemen
|
||||
// End of methods for determining if a type of edit action is allowed
|
||||
//==================================================================================================
|
||||
|
||||
@Override
|
||||
protected Composite getOriginalComposite() {
|
||||
if (!offline) {
|
||||
return originalComposite;
|
||||
}
|
||||
return super.getOriginalComposite();
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the current selection in the structure components viewing area.
|
||||
*
|
||||
|
||||
+1
-1
@@ -540,7 +540,7 @@ public abstract class CompositeEditorPanel extends JPanel
|
||||
}
|
||||
if (reload) {
|
||||
cancelCellEditing(); // Make sure a field isn't being edited.
|
||||
model.load(originalDt, model.isOffline()); // reload the structure
|
||||
model.load(originalDt); // reload the structure
|
||||
model.updateAndCheckChangeState();
|
||||
}
|
||||
}
|
||||
|
||||
+13
@@ -174,11 +174,24 @@ public abstract class CompositeEditorProvider extends ComponentProviderAdapter
|
||||
|
||||
@Override
|
||||
public ActionContext getActionContext(MouseEvent event) {
|
||||
|
||||
DataTypeComponent componentAt = null;
|
||||
int[] selectedComponentRows = editorModel.getSelectedComponentRows();
|
||||
if (selectedComponentRows.length == 1) {
|
||||
componentAt = editorModel.getComponent(selectedComponentRows[0]);
|
||||
}
|
||||
|
||||
DataTypeManager originalDTM = editorModel.getOriginalDataTypeManager();
|
||||
if (originalDTM instanceof ProgramBasedDataTypeManager) {
|
||||
Program program = ((ProgramBasedDataTypeManager) originalDTM).getProgram();
|
||||
if (componentAt != null) {
|
||||
return new ComponentProgramActionContext(this, program, componentAt);
|
||||
}
|
||||
return new ProgramActionContext(this, program);
|
||||
}
|
||||
else if (componentAt != null && (originalDTM instanceof StandAloneDataTypeManager)) {
|
||||
return new ComponentStandAloneActionContext(this, componentAt);
|
||||
}
|
||||
return new ActionContext(this, null);
|
||||
}
|
||||
|
||||
|
||||
+6
@@ -25,6 +25,7 @@ public class CompositeViewerDataTypeManager extends StandAloneDataTypeManager {
|
||||
*/
|
||||
private DataTypeManager originalDTM;
|
||||
private int transactionID;
|
||||
|
||||
/**
|
||||
* Creates a data type manager that the structure editor will use
|
||||
* internally for updating the structure being edited.
|
||||
@@ -50,4 +51,9 @@ public class CompositeViewerDataTypeManager extends StandAloneDataTypeManager {
|
||||
return originalDTM.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowsDefaultBuiltInSettings() {
|
||||
return originalDTM.allowsDefaultBuiltInSettings();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+139
-247
File diff suppressed because it is too large
Load Diff
+2
-26
@@ -23,15 +23,8 @@ import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public interface EditorModel {
|
||||
|
||||
/**
|
||||
* Loads the specified composite into the model replacing
|
||||
* whatever composite is there.
|
||||
*
|
||||
* @param dataType the new composite data type.
|
||||
* @param offline false indicates don't try to keep the composite itself
|
||||
* in the editor's data type manager.
|
||||
*/
|
||||
public void load(Composite dataType, boolean offline);
|
||||
// TODO: This model interface serves no real purpose and could be collapsed into the
|
||||
// abstract class CompositeEditorModel implementation.
|
||||
|
||||
/**
|
||||
* Called when the model is no longer needed.
|
||||
@@ -397,23 +390,6 @@ public interface EditorModel {
|
||||
*/
|
||||
public boolean moveDown() throws UsrException;
|
||||
|
||||
// /**
|
||||
// *
|
||||
// * @param dataType
|
||||
// * @return
|
||||
// * @throws UsrException
|
||||
// */
|
||||
// public DataTypeComponent replace(DataType dataType) throws UsrException;
|
||||
//
|
||||
// /**
|
||||
// *
|
||||
// * @param rowIndex
|
||||
// * @param dataType
|
||||
// * @return
|
||||
// * @throws UsrException
|
||||
// */
|
||||
// public DataTypeComponent replace(int rowIndex, DataType dataType) throws UsrException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param rowIndex
|
||||
|
||||
+1
-7
@@ -24,7 +24,6 @@ import docking.widgets.dialogs.InputDialog;
|
||||
import docking.widgets.dialogs.InputDialogListener;
|
||||
import docking.widgets.fieldpanel.support.FieldRange;
|
||||
import docking.widgets.fieldpanel.support.FieldSelection;
|
||||
import ghidra.docking.settings.SettingsImpl;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.lang.InsufficientBytesException;
|
||||
import ghidra.util.Msg;
|
||||
@@ -80,11 +79,6 @@ class StructureEditorModel extends CompEditorModel {
|
||||
return COMMENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(Composite dataType, boolean useOffLineCategory) {
|
||||
super.load(dataType, useOffLineCategory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(Composite dataType) {
|
||||
super.load(dataType);
|
||||
@@ -143,7 +137,7 @@ class StructureEditorModel extends CompEditorModel {
|
||||
}
|
||||
else if (columnIndex == getMnemonicColumn()) {
|
||||
DataType dt = dtc.getDataType();
|
||||
value = dt.getMnemonic(new SettingsImpl());
|
||||
value = dt.getMnemonic(dtc.getDefaultSettings());
|
||||
int compLen = dtc.getLength();
|
||||
int dtLen = dt.isZeroLength() ? 0 : dt.getLength();
|
||||
if (dtLen > compLen) {
|
||||
|
||||
+750
File diff suppressed because it is too large
Load Diff
+9
-13
@@ -19,9 +19,10 @@ import java.awt.event.KeyEvent;
|
||||
|
||||
import javax.swing.KeyStroke;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.*;
|
||||
import docking.action.KeyBindingData;
|
||||
import docking.action.KeyBindingType;
|
||||
import ghidra.app.context.ListingActionContext;
|
||||
import ghidra.app.context.ListingContextAction;
|
||||
import ghidra.app.util.datatype.DataTypeSelectionDialog;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.data.DataType;
|
||||
@@ -31,7 +32,7 @@ import ghidra.util.data.DataTypeParser.AllowedDataTypes;
|
||||
/**
|
||||
* An action that allows the user to change or select a data type.
|
||||
*/
|
||||
public class ChooseDataTypeAction extends DockingAction {
|
||||
public class ChooseDataTypeAction extends ListingContextAction {
|
||||
|
||||
private DataPlugin plugin;
|
||||
private static final KeyStroke KEY_BINDING = KeyStroke.getKeyStroke(KeyEvent.VK_T, 0);
|
||||
@@ -53,11 +54,10 @@ public class ChooseDataTypeAction extends DockingAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
ListingActionContext listingContext = (ListingActionContext) context.getContextObject();
|
||||
DataType dataType = getDataType(listingContext);
|
||||
protected void actionPerformed(ListingActionContext context) {
|
||||
DataType dataType = getDataType(context);
|
||||
if (dataType != null) {
|
||||
plugin.createData(dataType, listingContext, false, true);
|
||||
plugin.createData(dataType, context, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,11 +74,7 @@ public class ChooseDataTypeAction extends DockingAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
Object contextObject = context.getContextObject();
|
||||
if (contextObject instanceof ListingActionContext) {
|
||||
return plugin.isCreateDataAllowed(((ListingActionContext) contextObject));
|
||||
}
|
||||
return false;
|
||||
protected boolean isEnabledForContext(ListingActionContext context) {
|
||||
return plugin.isCreateDataAllowed(context);
|
||||
}
|
||||
}
|
||||
|
||||
+8
-14
@@ -19,13 +19,13 @@ import java.awt.event.KeyEvent;
|
||||
|
||||
import javax.swing.KeyStroke;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.*;
|
||||
import docking.widgets.OptionDialog;
|
||||
import docking.widgets.dialogs.NumberInputDialog;
|
||||
import ghidra.app.cmd.data.CreateArrayCmd;
|
||||
import ghidra.app.cmd.data.CreateArrayInStructureCmd;
|
||||
import ghidra.app.context.ListingActionContext;
|
||||
import ghidra.app.context.ListingContextAction;
|
||||
import ghidra.framework.cmd.Command;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.address.*;
|
||||
@@ -34,7 +34,7 @@ import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
import ghidra.program.util.*;
|
||||
|
||||
class CreateArrayAction extends DockingAction {
|
||||
class CreateArrayAction extends ListingContextAction {
|
||||
|
||||
private static final KeyStroke DEFAULT_KEY_STROKE =
|
||||
KeyStroke.getKeyStroke(KeyEvent.VK_OPEN_BRACKET, 0);
|
||||
@@ -62,12 +62,10 @@ class CreateArrayAction extends DockingAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
ListingActionContext programActionContext =
|
||||
(ListingActionContext) context.getContextObject();
|
||||
Program program = programActionContext.getProgram();
|
||||
ProgramLocation loc = programActionContext.getLocation();
|
||||
ProgramSelection sel = programActionContext.getSelection();
|
||||
protected void actionPerformed(ListingActionContext context) {
|
||||
Program program = context.getProgram();
|
||||
ProgramLocation loc = context.getLocation();
|
||||
ProgramSelection sel = context.getSelection();
|
||||
|
||||
if (sel != null && !sel.isEmpty()) {
|
||||
InteriorSelection interiorSel = sel.getInteriorSelection();
|
||||
@@ -322,12 +320,8 @@ class CreateArrayAction extends DockingAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
Object contextObject = context.getContextObject();
|
||||
if (contextObject instanceof ListingActionContext) {
|
||||
return plugin.isCreateDataAllowed(((ListingActionContext) contextObject));
|
||||
}
|
||||
return false;
|
||||
protected boolean isEnabledForContext(ListingActionContext context) {
|
||||
return plugin.isCreateDataAllowed(context);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+8
-20
@@ -17,10 +17,11 @@ package ghidra.app.plugin.core.data;
|
||||
|
||||
import javax.swing.KeyStroke;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.*;
|
||||
import docking.action.KeyBindingData;
|
||||
import docking.action.KeyBindingType;
|
||||
import ghidra.app.cmd.data.*;
|
||||
import ghidra.app.context.ListingActionContext;
|
||||
import ghidra.app.context.ListingContextAction;
|
||||
import ghidra.framework.cmd.BackgroundCommand;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.CycleGroup;
|
||||
@@ -34,7 +35,7 @@ import ghidra.util.Msg;
|
||||
* <code>CycleGroupAction</code> cycles data through a series of data types
|
||||
* defined by a <code>CycleGroup</code>.
|
||||
*/
|
||||
public class CycleGroupAction extends DockingAction {
|
||||
public class CycleGroupAction extends ListingContextAction {
|
||||
|
||||
private DataPlugin plugin;
|
||||
private CycleGroup cycleGroup;
|
||||
@@ -63,26 +64,13 @@ public class CycleGroupAction extends DockingAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
Object contextObject = context.getContextObject();
|
||||
if (contextObject instanceof ListingActionContext) {
|
||||
return plugin.isCreateDataAllowed((ListingActionContext) contextObject);
|
||||
}
|
||||
return false;
|
||||
protected boolean isEnabledForContext(ListingActionContext context) {
|
||||
return plugin.isCreateDataAllowed(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
|
||||
if (context != null) {
|
||||
Object contextObject = context.getContextObject();
|
||||
|
||||
if (contextObject instanceof ListingActionContext) {
|
||||
ListingActionContext programContextObject = (ListingActionContext) contextObject;
|
||||
cycleData(programContextObject);
|
||||
return;
|
||||
}
|
||||
}
|
||||
protected void actionPerformed(ListingActionContext context) {
|
||||
cycleData(context);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,21 +17,31 @@ package ghidra.app.plugin.core.data;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import docking.ActionContext;
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
import docking.action.DockingAction;
|
||||
import docking.action.MenuData;
|
||||
import docking.action.builder.ActionBuilder;
|
||||
import docking.widgets.OptionDialog;
|
||||
import docking.widgets.tree.GTree;
|
||||
import ghidra.app.CorePluginPackage;
|
||||
import ghidra.app.cmd.data.*;
|
||||
import ghidra.app.context.ListingActionContext;
|
||||
import ghidra.app.events.ProgramActivatedPluginEvent;
|
||||
import ghidra.app.plugin.PluginCategoryNames;
|
||||
import ghidra.app.plugin.core.compositeeditor.*;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypesActionContext;
|
||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeNode;
|
||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeTreeNode;
|
||||
import ghidra.app.services.DataService;
|
||||
import ghidra.app.services.DataTypeManagerService;
|
||||
import ghidra.docking.settings.SettingsDefinition;
|
||||
import ghidra.framework.cmd.BackgroundCommand;
|
||||
import ghidra.framework.cmd.Command;
|
||||
import ghidra.framework.plugintool.*;
|
||||
import ghidra.framework.plugintool.util.PluginStatus;
|
||||
import ghidra.program.database.data.DataTypeManagerDB;
|
||||
import ghidra.program.database.data.ProgramDataTypeManager;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
@@ -76,18 +86,17 @@ public class DataPlugin extends Plugin implements DataService {
|
||||
{ DATA_MENU_POPUP_PATH, "Edit Data Type..." };
|
||||
private static final String[] DATA_SETTINGS_POPUP_PATH =
|
||||
{ DATA_MENU_POPUP_PATH, "Settings..." };
|
||||
private static final String[] DEFAULT_DATA_SETTINGS_POPUP_PATH =
|
||||
private static final String[] DEFAULT_SETTINGS_POPUP_PATH =
|
||||
{ DATA_MENU_POPUP_PATH, "Default Settings..." };
|
||||
private static final String[] DATATYPE_SETTINGS_POPUP_PATH = { "Settings..." };
|
||||
private static final String[] CHOOSE_DATA_TYPE_POPUP_PATH =
|
||||
{ DATA_MENU_POPUP_PATH, "Choose Data Type..." };
|
||||
|
||||
private DataTypeManagerService dtmService;
|
||||
|
||||
private DockingAction settingsAction;
|
||||
private DockingAction defaultSettingsAction;
|
||||
private DataAction pointerAction;
|
||||
private DataAction recentlyUsedAction;
|
||||
private DockingAction editDataTypeAction; // Edit a data type action
|
||||
private DockingAction editDataTypeAction;
|
||||
private CreateStructureAction createStructureAction;
|
||||
private CreateArrayAction createArrayAction;
|
||||
private RenameDataFieldAction renameDataFieldAction;
|
||||
@@ -143,77 +152,72 @@ public class DataPlugin extends Plugin implements DataService {
|
||||
pointerAction = new PointerDataAction(this);
|
||||
tool.addAction(pointerAction);
|
||||
|
||||
settingsAction = new DockingAction("Data Settings", getName()) {
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
dataSettingsCallback((ListingActionContext) context.getContextObject());
|
||||
}
|
||||
// Data instance settings action based upon data selection in listing
|
||||
new ActionBuilder("Data Settings", getName())
|
||||
.sharedKeyBinding()
|
||||
.popupMenuPath(DATA_SETTINGS_POPUP_PATH)
|
||||
.popupMenuGroup("Settings")
|
||||
.withContext(ListingActionContext.class)
|
||||
.enabledWhen(context -> isDataTypeSettingsAllowed(context, false))
|
||||
.onAction(context -> dataSettingsCallback(context))
|
||||
.buildAndInstall(tool);
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
Object contextObject = context.getContextObject();
|
||||
if (contextObject instanceof ListingActionContext) {
|
||||
return isDataTypeSettingsAllowed((ListingActionContext) context, false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
// Default settings action based upon data selection in listing
|
||||
new ActionBuilder("Default Settings", getName())
|
||||
.sharedKeyBinding()
|
||||
.popupMenuPath(DEFAULT_SETTINGS_POPUP_PATH)
|
||||
.popupMenuGroup("Settings")
|
||||
.withContext(ListingActionContext.class)
|
||||
.enabledWhen(context -> isDataTypeSettingsAllowed(context, true))
|
||||
.onAction(context -> editDefaultDataSettings(context))
|
||||
.buildAndInstall(tool);
|
||||
|
||||
settingsAction.setPopupMenuData(new MenuData(DATA_SETTINGS_POPUP_PATH, null, "Settings"));
|
||||
// Default settings action for selected datatypes from datatype manager
|
||||
new ActionBuilder("Default Settings", getName())
|
||||
.sharedKeyBinding()
|
||||
.popupMenuPath(DATATYPE_SETTINGS_POPUP_PATH)
|
||||
.popupMenuGroup("Settings")
|
||||
.withContext(DataTypesActionContext.class)
|
||||
.enabledWhen(context -> isDefaultDataTypeSettingsAllowed(context))
|
||||
.onAction(context -> editDefaultDataTypeSettings(context))
|
||||
.buildAndInstall(tool);
|
||||
|
||||
settingsAction.setEnabled(true);
|
||||
tool.addAction(settingsAction);
|
||||
// Default settings action for composite editor components (Program-based)
|
||||
new ActionBuilder("Default Settings", getName())
|
||||
.sharedKeyBinding()
|
||||
.popupMenuPath(DATATYPE_SETTINGS_POPUP_PATH)
|
||||
.popupMenuGroup("Settings")
|
||||
.withContext(ComponentProgramActionContext.class)
|
||||
.enabledWhen(context -> isDefaultComponentSettingsAllowed(context))
|
||||
.onAction(context -> editDefaultComponentSettings(context))
|
||||
.buildAndInstall(tool);
|
||||
|
||||
defaultSettingsAction = new DockingAction("Default Data Settings", getName()) {
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
defaultDataSettingsCallback((ListingActionContext) context.getContextObject());
|
||||
}
|
||||
// Default settings action for composite editor components (stand-alone archive)
|
||||
new ActionBuilder("Default Settings", getName())
|
||||
.sharedKeyBinding()
|
||||
.popupMenuPath(DATATYPE_SETTINGS_POPUP_PATH)
|
||||
.popupMenuGroup("Settings")
|
||||
.withContext(ComponentStandAloneActionContext.class)
|
||||
.enabledWhen(context -> isDefaultComponentSettingsAllowed(context))
|
||||
.onAction(context -> editDefaultComponentSettings(context))
|
||||
.buildAndInstall(tool);
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
Object contextObject = context.getContextObject();
|
||||
if (contextObject instanceof ListingActionContext) {
|
||||
return isDataTypeSettingsAllowed((ListingActionContext) context, true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
defaultSettingsAction.setPopupMenuData(
|
||||
new MenuData(DEFAULT_DATA_SETTINGS_POPUP_PATH, null, "Settings"));
|
||||
|
||||
defaultSettingsAction.setEnabled(true);
|
||||
tool.addAction(defaultSettingsAction);
|
||||
|
||||
editDataTypeAction = new DockingAction("Edit Data Type", getName()) {
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
editDataTypeCallback((ListingActionContext) context.getContextObject());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
Object contextObject = context.getContextObject();
|
||||
if (contextObject instanceof ListingActionContext) {
|
||||
DataType editableDt =
|
||||
getEditableDataTypeFromContext((ListingActionContext) contextObject);
|
||||
editDataTypeAction = new ActionBuilder("Edit Data Type", getName())
|
||||
.popupMenuPath(EDIT_DATA_TYPE_POPUP_PATH)
|
||||
.popupMenuGroup("BasicData")
|
||||
.withContext(ListingActionContext.class)
|
||||
.enabledWhen(c -> {
|
||||
DataType editableDt = getEditableDataTypeFromContext(c);
|
||||
if (editableDt != null) {
|
||||
editDataTypeAction.setHelpLocation(
|
||||
dtmService.getEditorHelpLocation(editableDt));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
editDataTypeAction.setPopupMenuData(
|
||||
new MenuData(EDIT_DATA_TYPE_POPUP_PATH, null, "BasicData"));
|
||||
|
||||
editDataTypeAction.setEnabled(true);
|
||||
editDataTypeAction.setHelpLocation(new HelpLocation("DataTypeEditors", "Structure_Editor"));
|
||||
tool.addAction(editDataTypeAction);
|
||||
return false;
|
||||
})
|
||||
.onAction(c -> editDataTypeCallback(c))
|
||||
.helpLocation(new HelpLocation("DataTypeEditors", "Structure_Editor"))
|
||||
.buildAndInstall(tool);
|
||||
|
||||
chooseDataTypeAction = new ChooseDataTypeAction(this);
|
||||
chooseDataTypeAction.setEnabled(false);
|
||||
@@ -605,12 +609,105 @@ public class DataPlugin extends Plugin implements DataService {
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
dialog = new DataSettingsDialog(context.getProgram(), data);
|
||||
dialog = new DataSettingsDialog(data);
|
||||
}
|
||||
tool.showDialog(dialog);
|
||||
dialog.dispose();
|
||||
}
|
||||
|
||||
DataType getSelectedDataType(DataTypesActionContext context) {
|
||||
Object contextObject = context.getContextObject();
|
||||
GTree gtree = (GTree) contextObject;
|
||||
TreePath[] selectionPaths = gtree.getSelectionPaths();
|
||||
if (selectionPaths == null || selectionPaths.length != 1) {
|
||||
return null;
|
||||
}
|
||||
DataTypeTreeNode node = (DataTypeTreeNode) selectionPaths[0].getLastPathComponent();
|
||||
if (!(node instanceof DataTypeNode)) {
|
||||
return null;
|
||||
}
|
||||
DataTypeNode dataTypeNode = (DataTypeNode) node;
|
||||
DataType dataType = dataTypeNode.getDataType();
|
||||
if (dataType.getDataTypeManager() instanceof DataTypeManagerDB) {
|
||||
return dataType;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void editDefaultDataTypeSettings(DataTypesActionContext context) {
|
||||
DataType dataType = getSelectedDataType(context);
|
||||
if (dataType == null) {
|
||||
return;
|
||||
}
|
||||
DataTypeManager dtm = dataType.getDataTypeManager();
|
||||
if (!(dtm instanceof DataTypeManagerDB)) {
|
||||
return;
|
||||
}
|
||||
|
||||
SettingsDefinition[] settingsDefinitions = dataType.getSettingsDefinitions();
|
||||
if (!(dtm instanceof ProgramDataTypeManager)) {
|
||||
// Non-Program use limited to TypeDefSettingsDefinition only
|
||||
settingsDefinitions =
|
||||
SettingsDefinition.filterSettingsDefinitions(settingsDefinitions, def -> {
|
||||
return (def instanceof TypeDefSettingsDefinition);
|
||||
});
|
||||
}
|
||||
|
||||
DataTypeSettingsDialog dialog = new DataTypeSettingsDialog(dataType, settingsDefinitions);
|
||||
tool.showDialog(dialog);
|
||||
dialog.dispose();
|
||||
}
|
||||
|
||||
private void editDefaultComponentSettings(ComponentContext context) {
|
||||
DataTypeSettingsDialog dialog = new DataTypeSettingsDialog(context.getDataTypeComponent());
|
||||
tool.showDialog(dialog);
|
||||
dialog.dispose();
|
||||
dialog = null;
|
||||
}
|
||||
|
||||
protected boolean isDefaultDataTypeSettingsAllowed(DataTypesActionContext context) {
|
||||
DataType dt = getSelectedDataType(context);
|
||||
if (dt == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DataTypeManager dtm = dt.getDataTypeManager();
|
||||
if (dtm instanceof BuiltInDataTypeManager) {
|
||||
return false; // no settings modifications are permitted
|
||||
}
|
||||
if ((dt instanceof BuiltIn) && !dtm.allowsDefaultBuiltInSettings()) {
|
||||
// prevent BuiltIn settings modification when not allowed
|
||||
return false;
|
||||
}
|
||||
|
||||
SettingsDefinition[] settingsDefinitions = dt.getSettingsDefinitions();
|
||||
if (dtm instanceof ProgramBasedDataTypeManager) {
|
||||
// Any defined setting may be modified within a Program
|
||||
return settingsDefinitions.length != 0;
|
||||
}
|
||||
|
||||
// Non-Program use limited to TypeDefSettingsDefinition modification only
|
||||
for (SettingsDefinition def : settingsDefinitions) {
|
||||
if (def instanceof TypeDefSettingsDefinition) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean isDefaultComponentSettingsAllowed(ComponentContext context) {
|
||||
// Note: targetDtm should not be modified and reflects the ultimate target.
|
||||
// This context is intended to be used by composite editors where the component
|
||||
// parent datatype resides within a temporary datatype manager and not the targetDtm
|
||||
// until a subsequent save/apply is performed when the settings will get copied.
|
||||
DataTypeManager targetDtm = context.getDataTypeManager();
|
||||
if (targetDtm.allowsDefaultComponentSettings()) {
|
||||
DataType dt = context.getDataTypeComponent().getDataType();
|
||||
return dt.getSettingsDefinitions().length != 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean isDataTypeSettingsAllowed(ListingActionContext context, boolean editDefaults) {
|
||||
ProgramSelection selection = context.getSelection();
|
||||
Data data = getDataUnit(context);
|
||||
@@ -624,7 +721,7 @@ public class DataPlugin extends Plugin implements DataService {
|
||||
return data.getDataType().getSettingsDefinitions().length != 0;
|
||||
}
|
||||
|
||||
private void defaultDataSettingsCallback(ListingActionContext context) {
|
||||
private void editDefaultDataSettings(ListingActionContext context) {
|
||||
|
||||
// get the structure dt we are over
|
||||
Data data = getDataUnit(context);
|
||||
@@ -632,23 +729,19 @@ public class DataPlugin extends Plugin implements DataService {
|
||||
return;
|
||||
}
|
||||
|
||||
DataSettingsDialog dialog = null;
|
||||
Program program = context.getProgram();
|
||||
DataTypeSettingsDialog dialog = null;
|
||||
Data parent = data.getParent();
|
||||
if (parent != null) {
|
||||
DataType parentDT = parent.getDataType();
|
||||
if (parentDT instanceof Composite) {
|
||||
int[] path = context.getLocation().getComponentPath();
|
||||
|
||||
dialog = new DataSettingsDialog(program,
|
||||
dialog = new DataTypeSettingsDialog(
|
||||
((Composite) parentDT).getComponent(path[path.length - 1]));
|
||||
}
|
||||
else {
|
||||
dialog = new DataSettingsDialog(program, data.getDataType());
|
||||
}
|
||||
}
|
||||
else {
|
||||
dialog = new DataSettingsDialog(program, data.getDataType());
|
||||
if (dialog == null) {
|
||||
DataType dt = data.getDataType();
|
||||
dialog = new DataTypeSettingsDialog(dt, dt.getSettingsDefinitions());
|
||||
}
|
||||
|
||||
tool.showDialog(dialog);
|
||||
|
||||
+135
-555
File diff suppressed because it is too large
Load Diff
+154
@@ -0,0 +1,154 @@
|
||||
/* ###
|
||||
* 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.plugin.core.data;
|
||||
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.docking.settings.SettingsDefinition;
|
||||
import ghidra.program.database.data.DataTypeManagerDB;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.HelpLocation;
|
||||
|
||||
public class DataTypeSettingsDialog extends AbstractSettingsDialog {
|
||||
|
||||
private DataType dataType; // not set for data selection mode
|
||||
private DataTypeComponent dtc; // Only set for single data-type component mode
|
||||
|
||||
/**
|
||||
* Construct for data type default settings
|
||||
* @param dataType data type (must be resolved to program)
|
||||
* @param settingsDefinitions settings definitions to be displayed (may be a restricted set)
|
||||
*/
|
||||
public DataTypeSettingsDialog(DataType dataType, SettingsDefinition[] settingsDefinitions) {
|
||||
super(constructTitle(null, dataType, true), settingsDefinitions,
|
||||
dataType.getDefaultSettings());
|
||||
checkDataType(dataType);
|
||||
this.dataType = dataType;
|
||||
setHelpLocation(new HelpLocation("DataPlugin", "Default_Settings"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct for structure component default settings
|
||||
* @param dtc data type component (must belong to program-resolved structure)
|
||||
*/
|
||||
DataTypeSettingsDialog(DataTypeComponent dtc) {
|
||||
super(constructTitle(dtc, dtc.getDataType(), true),
|
||||
DataSettingsDialog.getAllowedDataInstanceSettingsDefinitions(dtc.getDataType()),
|
||||
dtc.getDefaultSettings());
|
||||
// NOTE: component default settings currently use the same restricted set of definitions
|
||||
checkDataType(dtc.getParent());
|
||||
this.dtc = dtc;
|
||||
this.dataType = dtc.getDataType();
|
||||
setHelpLocation(new HelpLocation("DataPlugin", "SettingsOnStructureComponents"));
|
||||
}
|
||||
|
||||
private static void checkDataType(DataType dt) {
|
||||
DataTypeManager dtm = dt.getDataTypeManager();
|
||||
if (dtm instanceof BuiltInDataTypeManager) {
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported use for datatype from BuiltInDataTypeManager");
|
||||
}
|
||||
if (dtm instanceof DataTypeManagerDB) {
|
||||
long id = dtm.getID(dt);
|
||||
if (id > 0) {
|
||||
if (dt == dtm.getDataType(id)) {
|
||||
return; // valid original instance
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Invalid data type instance");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
dataType = null;
|
||||
dtc = null;
|
||||
}
|
||||
|
||||
static String constructTitle(DataTypeComponent dtc, DataType dataType, boolean isDefault) {
|
||||
// TODO: May need to truncate names which could be very long
|
||||
StringBuffer nameBuf = new StringBuffer();
|
||||
if (isDefault) {
|
||||
nameBuf.append("Default ");
|
||||
}
|
||||
String name = dataType.getDisplayName();
|
||||
// default array settings defer to base type
|
||||
if (dtc == null) {
|
||||
name = getSettingsBaseType(dataType).getDisplayName();
|
||||
}
|
||||
nameBuf.append(name);
|
||||
nameBuf.append(" Settings");
|
||||
if (dtc != null) {
|
||||
nameBuf.append(" (");
|
||||
nameBuf.append(dtc.getParent().getDisplayName());
|
||||
nameBuf.append('.');
|
||||
String fname = dtc.getFieldName();
|
||||
if (fname == null) {
|
||||
fname = dtc.getDefaultFieldName();
|
||||
}
|
||||
nameBuf.append(fname);
|
||||
nameBuf.append(')');
|
||||
}
|
||||
return nameBuf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get base datatype associated with any array (include typedef of array)
|
||||
* @param dt datatype
|
||||
* @return base array datatype or specified dt if not an array type
|
||||
*/
|
||||
private static DataType getSettingsBaseType(DataType dt) {
|
||||
while (true) {
|
||||
if (dt instanceof TypeDef) {
|
||||
DataType baseDt = ((TypeDef) dt).getBaseDataType();
|
||||
if (baseDt instanceof Array) {
|
||||
dt = baseDt;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (dt instanceof Array) {
|
||||
dt = ((Array) dt).getDataType();
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return dt;
|
||||
}
|
||||
|
||||
protected void applySettings() {
|
||||
DataTypeManager dtm = dataType.getDataTypeManager();
|
||||
int txId = dtm.startTransaction(getTitle());
|
||||
try {
|
||||
Settings origDefSettings = null;
|
||||
if (dtc != null) {
|
||||
origDefSettings = dtc.getDefaultSettings();
|
||||
}
|
||||
else {
|
||||
origDefSettings = dataType.getDefaultSettings();
|
||||
}
|
||||
Settings modifiedSettings = getSettings();
|
||||
for (SettingsDefinition settingsDef : getSettingsDefinitions()) {
|
||||
settingsDef.copySetting(modifiedSettings, origDefSettings);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
dtm.endTransaction(txId, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
-26
@@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* 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.
|
||||
@@ -16,7 +15,12 @@
|
||||
*/
|
||||
package ghidra.app.plugin.core.data;
|
||||
|
||||
import java.awt.event.KeyEvent;
|
||||
|
||||
import docking.action.KeyBindingData;
|
||||
import docking.action.MenuData;
|
||||
import ghidra.app.context.ListingActionContext;
|
||||
import ghidra.app.context.ListingContextAction;
|
||||
import ghidra.app.util.PluginConstants;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.data.*;
|
||||
@@ -24,27 +28,19 @@ import ghidra.program.model.listing.Data;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.util.FieldNameFieldLocation;
|
||||
import ghidra.program.util.ProgramLocation;
|
||||
|
||||
import java.awt.event.KeyEvent;
|
||||
|
||||
import javax.swing.KeyStroke;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.*;
|
||||
|
||||
/**
|
||||
* Base class for comment actions to edit and delete comments.
|
||||
*/
|
||||
class RenameDataFieldAction extends DockingAction {
|
||||
class RenameDataFieldAction extends ListingContextAction {
|
||||
|
||||
private static final KeyStroke KEY_BINDING = KeyStroke.getKeyStroke(KeyEvent.VK_N,0);
|
||||
private DataPlugin plugin;
|
||||
private RenameDataFieldDialog dialog;
|
||||
|
||||
public RenameDataFieldAction(DataPlugin plugin) {
|
||||
super("Rename Data Field", plugin.getName());
|
||||
dialog = new RenameDataFieldDialog(plugin);
|
||||
// ACTIONS - auto generated
|
||||
|
||||
setPopupMenuData(
|
||||
new MenuData(
|
||||
new String[] {"Data", "Rename Field"},null,"BasicData" ) );
|
||||
@@ -56,11 +52,8 @@ class RenameDataFieldAction extends DockingAction {
|
||||
setEnabled(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method called when the action is invoked.
|
||||
*/
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
protected void actionPerformed(ListingActionContext context) {
|
||||
ListingActionContext programActionContext = (ListingActionContext) context.getContextObject();
|
||||
PluginTool tool = plugin.getTool();
|
||||
Program program = programActionContext.getProgram();
|
||||
@@ -87,17 +80,9 @@ class RenameDataFieldAction extends DockingAction {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @see docking.DockableAction#isValidContext(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
Object contextObject = context.getContextObject();
|
||||
if (!(contextObject instanceof ListingActionContext)) {
|
||||
return false;
|
||||
}
|
||||
ListingActionContext programActionContext = (ListingActionContext) contextObject;
|
||||
return (programActionContext.getLocation() instanceof FieldNameFieldLocation);
|
||||
@Override
|
||||
protected boolean isEnabledForContext(ListingActionContext context) {
|
||||
return (context.getLocation() instanceof FieldNameFieldLocation);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
-1
@@ -125,6 +125,11 @@ class OpenDomainFileTask extends Task {
|
||||
return version == otherVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open archive in an immutable fashion. Unlike ProgramDB, we do not want to
|
||||
* allow upgrade or modification of a read-only archve (e.g., not-checked-out).
|
||||
* @param monitor task monitor
|
||||
*/
|
||||
private void openReadOnlyFile(TaskMonitor monitor) {
|
||||
String fileDescr =
|
||||
((version != DomainFile.DEFAULT_VERSION) ? "version " + version + " of " : "") +
|
||||
@@ -134,7 +139,7 @@ class OpenDomainFileTask extends Task {
|
||||
monitor.setMessage("Opening " + fileDescr);
|
||||
contentType = domainFile.getContentType();
|
||||
dtArchive =
|
||||
(DataTypeArchive) domainFile.getReadOnlyDomainObject(this, version, monitor);
|
||||
(DataTypeArchive) domainFile.getImmutableDomainObject(this, version, monitor);
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
// we don't care, the task has been canceled
|
||||
|
||||
+2
-2
@@ -22,8 +22,8 @@ import java.util.List;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
|
||||
import ghidra.app.services.DataTypeQueryService;
|
||||
import ghidra.app.services.DataTypeManagerService;
|
||||
import ghidra.app.services.DataTypeQueryService;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.Enum;
|
||||
import ghidra.util.Msg;
|
||||
@@ -382,7 +382,7 @@ public class DataTypeUtils {
|
||||
* <br>If "INT" is a typedef on a "dword" then INT[7][3] would have a base data type of dword.
|
||||
* If you wanted to get the INT from INT[7][3]
|
||||
* you should call getNamedBasedDataType(DataType) instead.
|
||||
* @param baseDataType the data type whose base data type is to be determined.
|
||||
* @param dt the data type whose base data type is to be determined.
|
||||
* @return the base data type.
|
||||
*/
|
||||
public static DataType getBaseDataType(DataType dt) {
|
||||
|
||||
+1
-2
@@ -18,7 +18,6 @@
|
||||
*/
|
||||
package ghidra.app.plugin.core.datapreview;
|
||||
|
||||
import ghidra.docking.settings.SettingsImpl;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.mem.*;
|
||||
@@ -71,7 +70,7 @@ class DataTypeComponentPreview implements Preview {
|
||||
addr = addr.add(dtc.getOffset());
|
||||
MemBuffer mb = new DumbMemBufferImpl(memory, addr);
|
||||
DataType dt = dtc.getDataType();
|
||||
return dt.getRepresentation(mb, new SettingsImpl(), dtc.getLength());
|
||||
return dt.getRepresentation(mb, dtc.getDefaultSettings(), dtc.getLength());
|
||||
}
|
||||
catch (Exception e) {
|
||||
return "ERROR: unable to create preview";
|
||||
|
||||
+1
-2
@@ -18,7 +18,6 @@
|
||||
*/
|
||||
package ghidra.app.plugin.core.datapreview;
|
||||
|
||||
import ghidra.docking.settings.SettingsImpl;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.DataTypeInstance;
|
||||
@@ -48,7 +47,7 @@ class DataTypePreview implements Preview {
|
||||
}
|
||||
|
||||
int length = Math.min(dti.getLength(), MAX_PREVIEW_LENGTH);
|
||||
return dt.getRepresentation(mb, new SettingsImpl(), length);
|
||||
return dt.getRepresentation(mb, dt.getDefaultSettings(), length);
|
||||
}
|
||||
catch (Exception e) {
|
||||
|
||||
|
||||
+1
-1
@@ -239,7 +239,7 @@ class EditMemoryReferencePanel extends EditReferencePanel {
|
||||
populateRefTypes(rt);
|
||||
refTypes.setSelectedItem(rt);
|
||||
|
||||
if (fromSubIndex < 0) {
|
||||
if (fromOpIndex < 0) {
|
||||
Program program = plugin.getCurrentProgram();
|
||||
ProgramLocation location = plugin.getCurrentLocation();
|
||||
Address toAddr = null;
|
||||
|
||||
+11
-10
@@ -22,7 +22,6 @@ import javax.swing.JOptionPane;
|
||||
import docking.widgets.OptionDialog;
|
||||
import docking.widgets.fieldpanel.support.FieldRange;
|
||||
import docking.widgets.fieldpanel.support.FieldSelection;
|
||||
|
||||
/**
|
||||
* Function stack editor model for maintaining information about the edits to
|
||||
* a function stack frame. Updates the stack frame with the edit changes.
|
||||
@@ -33,7 +32,6 @@ import docking.widgets.fieldpanel.support.FieldSelection;
|
||||
* When edit actions occur and there is a selection, the listener's are notified
|
||||
* of the new selection via the listener's overrideSelection method.
|
||||
*/
|
||||
|
||||
import ghidra.app.plugin.core.compositeeditor.CompositeEditorModel;
|
||||
import ghidra.app.plugin.core.compositeeditor.DataTypeHelper;
|
||||
import ghidra.app.util.datatype.EmptyCompositeException;
|
||||
@@ -89,7 +87,7 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||
return false;
|
||||
}
|
||||
|
||||
void stackChangedExcternally(boolean changed) {
|
||||
void stackChangedExternally(boolean changed) {
|
||||
stackChangedExternally = changed;
|
||||
}
|
||||
|
||||
@@ -97,13 +95,17 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||
originalStack = function.getStackFrame();
|
||||
StackFrameDataType stackFrameDataType = new StackFrameDataType(originalStack, dtm);
|
||||
stackFrameDataType.setCategoryPath(dtm.getRootCategory().getCategoryPath());
|
||||
load(stackFrameDataType, false);
|
||||
load(stackFrameDataType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(Composite dataType, boolean useOffLineCategory) {
|
||||
stackChangedExcternally(false);
|
||||
super.load(dataType, useOffLineCategory);
|
||||
public void load(Composite dataType) {
|
||||
stackChangedExternally(false);
|
||||
super.load(dataType);
|
||||
}
|
||||
|
||||
protected Composite createViewCompositeFromOriginalComposite(Composite original) {
|
||||
return (Composite) original.copy(original.getDataTypeManager());
|
||||
}
|
||||
|
||||
StackFrameDataType getViewComposite() {
|
||||
@@ -1023,7 +1025,7 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||
newSv.setComment(comment);
|
||||
}
|
||||
}
|
||||
load(new StackFrameDataType(original, dtm), false);
|
||||
load(new StackFrameDataType(original, dtm));
|
||||
clearStatus();
|
||||
return true;
|
||||
}
|
||||
@@ -1183,7 +1185,6 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||
originalDataTypePath.getDataTypeName().equals(newPath.getDataTypeName()) &&
|
||||
originalDataTypePath.getCategoryPath().equals(oldPath.getCategoryPath())) {
|
||||
originalDataTypePath = newPath;
|
||||
originalCategoryChanged();
|
||||
compositeInfoChanged();
|
||||
}
|
||||
}
|
||||
@@ -1241,7 +1242,7 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||
@Override
|
||||
protected Composite getOriginalComposite() {
|
||||
// This is to allow the stack editor panel to have access.
|
||||
return super.getOriginalComposite();
|
||||
return originalComposite; // not contained within datatype manager
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -303,7 +303,7 @@ public class StackEditorPanel extends CompositeEditorPanel {
|
||||
cancelCellEditing();
|
||||
// TODO
|
||||
// boolean lockState = model.isLocked(); // save the lock state
|
||||
model.load(originalDt, model.isOffline()); // reload the structure
|
||||
model.load(originalDt); // reload the structure
|
||||
// model.setLocked(lockState); // restore the lock state
|
||||
model.updateAndCheckChangeState();
|
||||
}
|
||||
|
||||
+10
-1
@@ -15,6 +15,10 @@
|
||||
*/
|
||||
package ghidra.app.plugin.core.stackeditor;
|
||||
|
||||
import java.awt.event.MouseEvent;
|
||||
|
||||
import docking.ActionContext;
|
||||
import ghidra.app.context.ProgramActionContext;
|
||||
import ghidra.app.plugin.core.compositeeditor.*;
|
||||
import ghidra.framework.model.*;
|
||||
import ghidra.framework.plugintool.Plugin;
|
||||
@@ -104,6 +108,11 @@ public class StackEditorProvider extends CompositeEditorProvider implements Doma
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionContext getActionContext(MouseEvent event) {
|
||||
return new ProgramActionContext(this, program);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the function name for the function stack frame being edited.
|
||||
* @return the name
|
||||
@@ -240,7 +249,7 @@ public class StackEditorProvider extends CompositeEditorProvider implements Doma
|
||||
stackModel.load(function);
|
||||
}
|
||||
else {
|
||||
stackModel.stackChangedExcternally(true);
|
||||
stackModel.stackChangedExternally(true);
|
||||
editorPanel.setStatus("Stack may have been changed externally--data may be stale.");
|
||||
}
|
||||
}
|
||||
|
||||
+8
-1
@@ -68,7 +68,6 @@ public class StackFrameDataType extends BiDirectionDataType {
|
||||
this.growsNegative = stackDt.growsNegative;
|
||||
this.returnAddressOffset = stackDt.returnAddressOffset;
|
||||
this.stack = stackDt.stack;
|
||||
this.defaultSettings = stackDt.defaultSettings;
|
||||
for (DataTypeComponentImpl dtc : stackDt.components) {
|
||||
replaceAtOffset(dtc.getOffset(), dtc.getDataType(), dtc.getLength(), dtc.getFieldName(),
|
||||
dtc.getComment());
|
||||
@@ -150,6 +149,14 @@ public class StackFrameDataType extends BiDirectionDataType {
|
||||
|
||||
@Override
|
||||
public StackFrameDataType clone(DataTypeManager dtm) {
|
||||
if (dtm == dataMgr) {
|
||||
return this;
|
||||
}
|
||||
return new StackFrameDataType(this, dtm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType copy(DataTypeManager dtm) {
|
||||
return new StackFrameDataType(this, dtm);
|
||||
}
|
||||
|
||||
|
||||
+35
-20
@@ -23,11 +23,13 @@ import ghidra.app.CorePluginPackage;
|
||||
import ghidra.app.plugin.PluginCategoryNames;
|
||||
import ghidra.app.plugin.ProgramPlugin;
|
||||
import ghidra.app.plugin.core.data.DataSettingsDialog;
|
||||
import ghidra.app.plugin.core.data.DataTypeSettingsDialog;
|
||||
import ghidra.app.services.GoToService;
|
||||
import ghidra.framework.model.*;
|
||||
import ghidra.framework.plugintool.PluginInfo;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.framework.plugintool.util.PluginStatus;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.listing.Data;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.util.*;
|
||||
@@ -62,8 +64,6 @@ public class ViewStringsPlugin extends ProgramPlugin implements DomainObjectList
|
||||
ResourceManager.getDisabledIcon(Icons.REFRESH_ICON, 60);
|
||||
|
||||
private DockingAction refreshAction;
|
||||
private DockingAction showSettingsAction;
|
||||
private DockingAction showDefaultSettingsAction;
|
||||
private SelectionNavigationAction linkNavigationAction;
|
||||
private ViewStringsProvider provider;
|
||||
private SwingUpdateManager reloadUpdateMgr;
|
||||
@@ -111,13 +111,14 @@ public class ViewStringsPlugin extends ProgramPlugin implements DomainObjectList
|
||||
linkNavigationAction = new SelectionNavigationAction(this, provider.getTable());
|
||||
tool.addLocalAction(provider, linkNavigationAction);
|
||||
|
||||
showSettingsAction = new DockingAction("Settings", getName()) {
|
||||
DockingAction editDataSettingsAction =
|
||||
new DockingAction("Data Settings", getName(), KeyBindingType.SHARED) {
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
try {
|
||||
DataSettingsDialog dialog = provider.getSelectedRowCount() == 1
|
||||
? new DataSettingsDialog(currentProgram, provider.getSelectedData())
|
||||
: new DataSettingsDialog(currentProgram, provider.selectData());
|
||||
? new DataSettingsDialog(provider.getSelectedData())
|
||||
: new DataSettingsDialog(currentProgram, provider.getProgramSelection());
|
||||
|
||||
tool.showDialog(dialog);
|
||||
dialog.dispose();
|
||||
@@ -128,33 +129,47 @@ public class ViewStringsPlugin extends ProgramPlugin implements DomainObjectList
|
||||
}
|
||||
|
||||
};
|
||||
showSettingsAction.setPopupMenuData(new MenuData(new String[] { "Settings..." }, "R"));
|
||||
showSettingsAction.setDescription("Shows settings for the selected strings");
|
||||
showSettingsAction.setHelpLocation(new HelpLocation("DataPlugin", "Data_Settings"));
|
||||
showDefaultSettingsAction = new DockingAction("Default Settings", getName()) {
|
||||
editDataSettingsAction.setPopupMenuData(new MenuData(new String[] { "Settings..." }, "R"));
|
||||
editDataSettingsAction.setHelpLocation(new HelpLocation("DataPlugin", "Data_Settings"));
|
||||
|
||||
DockingAction editDefaultSettingsAction =
|
||||
new DockingAction("Default Settings", getName(), KeyBindingType.SHARED) {
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
Data data = provider.getSelectedData();
|
||||
DataSettingsDialog dataSettingsDialog =
|
||||
new DataSettingsDialog(getCurrentProgram(), data.getDataType());
|
||||
DataType dt = getSelectedDataType();
|
||||
if (dt == null) {
|
||||
return;
|
||||
}
|
||||
DataTypeSettingsDialog dataSettingsDialog =
|
||||
new DataTypeSettingsDialog(dt, dt.getSettingsDefinitions());
|
||||
tool.showDialog(dataSettingsDialog);
|
||||
dataSettingsDialog.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
return provider.getSelectedRowCount() == 1;
|
||||
if (provider.getSelectedRowCount() != 1) {
|
||||
return false;
|
||||
}
|
||||
DataType dt = getSelectedDataType();
|
||||
if (dt == null) {
|
||||
return false;
|
||||
}
|
||||
return dt.getSettingsDefinitions().length != 0;
|
||||
}
|
||||
|
||||
private DataType getSelectedDataType() {
|
||||
Data data = provider.getSelectedData();
|
||||
return data != null ? data.getDataType() : null;
|
||||
}
|
||||
};
|
||||
showDefaultSettingsAction.setPopupMenuData(
|
||||
editDefaultSettingsAction.setPopupMenuData(
|
||||
new MenuData(new String[] { "Default Settings..." }, "R"));
|
||||
showDefaultSettingsAction.setDescription(
|
||||
"Shows settings for the selected string data type");
|
||||
showDefaultSettingsAction.setHelpLocation(
|
||||
new HelpLocation("DataPlugin", "Default_Data_Settings"));
|
||||
editDefaultSettingsAction.setHelpLocation(
|
||||
new HelpLocation("DataPlugin", "Default_Settings"));
|
||||
|
||||
tool.addLocalAction(provider, showSettingsAction);
|
||||
tool.addLocalAction(provider, showDefaultSettingsAction);
|
||||
tool.addLocalAction(provider, editDataSettingsAction);
|
||||
tool.addLocalAction(provider, editDefaultSettingsAction);
|
||||
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -176,7 +176,7 @@ public class ViewStringsProvider extends ComponentProviderAdapter {
|
||||
tool.contextChanged(this);
|
||||
}
|
||||
|
||||
ProgramSelection selectData() {
|
||||
ProgramSelection getProgramSelection() {
|
||||
return table.getProgramSelection();
|
||||
}
|
||||
|
||||
|
||||
@@ -319,7 +319,7 @@ public class GuidUtil {
|
||||
}
|
||||
GuidDataType dt = new GuidDataType();
|
||||
String guidRep = dt.getRepresentation(new DumbMemBufferImpl(program.getMemory(), address),
|
||||
new SettingsImpl(), -1);
|
||||
SettingsImpl.NO_SETTINGS, -1);
|
||||
return guidRep.endsWith(guidString);
|
||||
}
|
||||
|
||||
|
||||
+1
-11
@@ -175,8 +175,7 @@ public class CompositeDataTypeHTMLRepresentation extends HTMLDataTypeRepresentat
|
||||
BR);
|
||||
append(fullHtml, truncatedHtml, lineCount, LENGTH_PREFIX,
|
||||
footerText.getText(),
|
||||
BR);
|
||||
append(fullHtml, truncatedHtml, lineCount, BR, BR);
|
||||
BR, BR);
|
||||
//@formatter:on
|
||||
|
||||
// header
|
||||
@@ -343,15 +342,6 @@ public class CompositeDataTypeHTMLRepresentation extends HTMLDataTypeRepresentat
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
protected static StringBuilder addAlignmentValue(String alignmentValueString,
|
||||
StringBuilder buffer) {
|
||||
|
||||
buffer.append(BR);
|
||||
buffer.append(ALIGNMENT_VALUE_PREFIX + alignmentValueString);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// overridden to return truncated text by default
|
||||
@Override
|
||||
public String getHTMLString() {
|
||||
|
||||
+5
-1
@@ -45,7 +45,7 @@ public class PointerDataTypeHTMLRepresentation extends HTMLDataTypeRepresentatio
|
||||
return truncatedHtmlData;
|
||||
}
|
||||
|
||||
private static String buildHTMLText(Pointer pointer, boolean trim) {
|
||||
static String buildHTMLText(Pointer pointer, boolean trim) {
|
||||
|
||||
DataType baseDataType = pointer;
|
||||
while (baseDataType instanceof Pointer) {
|
||||
@@ -116,6 +116,10 @@ public class PointerDataTypeHTMLRepresentation extends HTMLDataTypeRepresentatio
|
||||
description = Character.toUpperCase(firstChar) + description.substring(1);
|
||||
}
|
||||
|
||||
int length = pointer.getLength();
|
||||
description += BR;
|
||||
description += "Size: " + (length >= 0 ? length : "default");
|
||||
|
||||
return description;
|
||||
}
|
||||
|
||||
|
||||
+46
@@ -21,6 +21,8 @@ import java.util.*;
|
||||
import ghidra.app.util.ToolTipUtils;
|
||||
import ghidra.app.util.html.diff.DataTypeDiff;
|
||||
import ghidra.app.util.html.diff.DataTypeDiffBuilder;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.docking.settings.SettingsDefinition;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.HTMLUtilities;
|
||||
import ghidra.util.StringUtilities;
|
||||
@@ -127,6 +129,47 @@ public class TypeDefDataTypeHTMLRepresentation extends HTMLDataTypeRepresentatio
|
||||
baseDataType = ((Pointer) baseDataType).getDataType();
|
||||
}
|
||||
}
|
||||
|
||||
// Show modified default settings details
|
||||
StringBuilder buffy = new StringBuilder();
|
||||
Settings defaultSettings = typeDef.getDefaultSettings();
|
||||
HashSet<Class<?>> ignoredSettings = new HashSet<>();
|
||||
|
||||
for (SettingsDefinition settingsDef : typeDef.getSettingsDefinitions()) {
|
||||
if (!(settingsDef instanceof TypeDefSettingsDefinition) ||
|
||||
!settingsDef.hasValue(defaultSettings)) {
|
||||
continue;
|
||||
}
|
||||
if (settingsDef instanceof PointerTypeSettingsDefinition) {
|
||||
ignoredSettings.add(AddressSpaceSettingsDefinition.class);
|
||||
}
|
||||
}
|
||||
|
||||
for (SettingsDefinition settingsDef : typeDef.getSettingsDefinitions()) {
|
||||
if (!(settingsDef instanceof TypeDefSettingsDefinition) ||
|
||||
!settingsDef.hasValue(defaultSettings)) {
|
||||
continue;
|
||||
}
|
||||
boolean ignored = ignoredSettings.contains(settingsDef.getClass());
|
||||
if (buffy.length() == 0) {
|
||||
buffy.append(INDENT_OPEN);
|
||||
}
|
||||
else {
|
||||
buffy.append(BR);
|
||||
}
|
||||
buffy.append(TT_OPEN)
|
||||
.append(settingsDef.getName())
|
||||
.append(": ")
|
||||
.append(settingsDef.getValueString(defaultSettings));
|
||||
if (ignored) {
|
||||
buffy.append(" (ignored)");
|
||||
}
|
||||
buffy.append(TT_CLOSE);
|
||||
}
|
||||
if (buffy.length() != 0) {
|
||||
buffy.append(INDENT_CLOSE);
|
||||
lines.add(new TextLine(buffy.toString()));
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
@@ -168,6 +211,9 @@ public class TypeDefDataTypeHTMLRepresentation extends HTMLDataTypeRepresentatio
|
||||
|
||||
// body
|
||||
buffy.append(BR);
|
||||
if (typeDef.isPointer()) {
|
||||
buffy.append("Pointer-");
|
||||
}
|
||||
buffy.append("TypeDef Base Data Type: ").append(BR);
|
||||
|
||||
iterator = bodyLines.iterator();
|
||||
|
||||
@@ -1169,13 +1169,38 @@ public class CodeUnitFormat {
|
||||
}
|
||||
}
|
||||
|
||||
if (ref.isMemoryReference() && (ref instanceof OffsetReference)) {
|
||||
return getOffsetReferenceRepresentation(cu, (OffsetReference) ref);
|
||||
}
|
||||
|
||||
if (ref.isMemoryReference() || ref.isExternalReference()) {
|
||||
return getMemoryReferenceLabel(cu, ref);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
private Object getOffsetReferenceRepresentation(CodeUnit cu, OffsetReference offsetRef) {
|
||||
Reference baseRef =
|
||||
new MemReferenceImpl(offsetRef.getFromAddress(), offsetRef.getBaseAddress(),
|
||||
RefType.DATA,
|
||||
offsetRef.getSource(), offsetRef.getOperandIndex(), offsetRef.isPrimary());
|
||||
Object baseRefObj = getMemoryReferenceLabel(cu, baseRef);
|
||||
long offset = offsetRef.getOffset();
|
||||
String sign = "+";
|
||||
if (offset < 0) {
|
||||
offset = -offset;
|
||||
sign = "-";
|
||||
}
|
||||
Scalar offsetScalar = new Scalar(64, offsetRef.getOffset(), true);
|
||||
OperandRepresentationList list = new OperandRepresentationList();
|
||||
list.add(baseRefObj);
|
||||
list.add(sign);
|
||||
list.add(offsetScalar);
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a LabelString object which corresponds to the specified memory
|
||||
* reference from the specified code unit. Format options are considered
|
||||
|
||||
+6
-1
@@ -37,12 +37,17 @@ public class ByteCountSettingsDefinition implements EnumSettingsDefinition {
|
||||
return DEFAULT;
|
||||
}
|
||||
Long value = settings.getLong(BYTE_COUNT);
|
||||
if (value == null) {
|
||||
if (value == null || value < 0 || value >= choices.length) {
|
||||
return DEFAULT;
|
||||
}
|
||||
return value.intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValueString(Settings settings) {
|
||||
return choices[getChoice(settings)];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChoice(Settings settings, int value) {
|
||||
if (value < DEFAULT) {
|
||||
|
||||
+6
-1
@@ -52,12 +52,17 @@ public class CodeUnitCountSettingsDefinition implements EnumSettingsDefinition {
|
||||
return 0;
|
||||
}
|
||||
Long value = settings.getLong(CODE_UNIT_COUNT);
|
||||
if (value == null) {
|
||||
if (value == null || value < 0 || value >= choices.length) {
|
||||
return 0;
|
||||
}
|
||||
return value.intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValueString(Settings settings) {
|
||||
return choices[getChoice(settings)];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChoice(Settings settings, int value) {
|
||||
if (value < 0) {
|
||||
|
||||
+6
-1
@@ -56,12 +56,17 @@ public class CodeUnitOffsetSettingsDefinition implements EnumSettingsDefinition
|
||||
return DEFAULT_CHOICE;
|
||||
}
|
||||
Long value = settings.getLong(MEMORY_OFFSET);
|
||||
if (value == null) {
|
||||
if (value == null || value < 0 || value >= choices.length) {
|
||||
return DEFAULT_CHOICE;
|
||||
}
|
||||
return value.intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValueString(Settings settings) {
|
||||
return choices[getChoice(settings)];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChoice(Settings settings, int value) {
|
||||
if (value < 0) {
|
||||
|
||||
+6
-1
@@ -26,7 +26,7 @@ public class FunctionInlineSettingsDefinition implements BooleanSettingsDefiniti
|
||||
private static final String INLINE = "Show inline";
|
||||
private static final String NAME = INLINE;
|
||||
private static final String DESCRIPTION =
|
||||
"On siganls to show the inline " + "function attribute when present";
|
||||
"On signals to show the inline " + "function attribute when present";
|
||||
private static final boolean DEFAULT = false;
|
||||
|
||||
@Override
|
||||
@@ -41,6 +41,11 @@ public class FunctionInlineSettingsDefinition implements BooleanSettingsDefiniti
|
||||
return Boolean.parseBoolean(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValueString(Settings settings) {
|
||||
return Boolean.toString(getValue(settings));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(Settings settings, boolean value) {
|
||||
settings.setString(INLINE, Boolean.toString(value));
|
||||
|
||||
+5
@@ -41,6 +41,11 @@ public class FunctionNoReturnSettingsDefinition implements BooleanSettingsDefini
|
||||
return Boolean.parseBoolean(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValueString(Settings settings) {
|
||||
return Boolean.toString(getValue(settings));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(Settings settings, boolean value) {
|
||||
settings.setString(NORETURN, Boolean.toString(value));
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user