mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
GP-1403 Improved support for auto-named typedefs. Updated create
typedef action from pointer to use auto-naming. Replaced old ImageBaseOffsetDataType 32/64-bit BuiltIn types with new pointer-typedef based implementations. Improved settings modification restrictions. Resolved various bugs.
This commit is contained in:
parent
ec5b6aada7
commit
8f0589a6d8
103 changed files with 2226 additions and 1156 deletions
|
@ -20,6 +20,7 @@ import java.util.Collection;
|
|||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.docking.settings.SettingsDefinition;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.TypeDefSettingsDefinition;
|
||||
import ghidra.program.model.symbol.RefType;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.trace.database.data.DBTraceDataSettingsOperations;
|
||||
|
@ -68,6 +69,15 @@ public interface DBTraceDataAdapter extends DBTraceCodeUnitAdapter, DataAdapterM
|
|||
|
||||
DBTraceDataSettingsOperations getSettingsSpace(boolean createIfAbsent);
|
||||
|
||||
@Override
|
||||
default boolean isChangeAllowed(SettingsDefinition settingsDefinition) {
|
||||
if (settingsDefinition instanceof TypeDefSettingsDefinition) {
|
||||
return false;
|
||||
}
|
||||
// assume instance setting allowed if default setting allowed
|
||||
return getDefaultSettings().isChangeAllowed(settingsDefinition);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void setLong(String name, long value) {
|
||||
try (LockHold hold = getTrace().lockWrite()) {
|
||||
|
|
|
@ -65,6 +65,7 @@ dependencies {
|
|||
testImplementation project(path: ':Generic', configuration: 'testArtifacts')
|
||||
testImplementation project(path: ':Project', configuration: 'testArtifacts')
|
||||
testImplementation project(path: ':SoftwareModeling', configuration: 'testArtifacts')
|
||||
testImplementation project(path: ':DB', configuration: 'testArtifacts')
|
||||
|
||||
javacc 'net.java.dev.javacc:javacc:5.0'
|
||||
}
|
||||
|
|
|
@ -800,7 +800,16 @@
|
|||
|
||||
<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>
|
||||
(see <A href="#Pointer_Typedef_Settings">Pointer-Typedef Settings</A>).
|
||||
If no name is assigned to a new Pointer-Typedef is will be treated as an "auto-typedef"
|
||||
where a dynamic name will be assigned based upon the underlying pointer and assigned
|
||||
typedef attribute settings. Examples:
|
||||
<ul>
|
||||
<li><i>char * __((space(ram)))</i></li>
|
||||
<li><i>int * __((offset(0x8)))</i></li>
|
||||
<li><i>pointer __((image-base-relative))</i></li>
|
||||
</ul>
|
||||
</P>
|
||||
|
||||
<H4>Creating a Pointer</H4>
|
||||
<P>To create a <B>pointer</B>, you can click <I><B>New<IMG src="../../shared/arrow.gif"
|
||||
|
@ -1076,18 +1085,18 @@
|
|||
<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>
|
||||
If an unknown name is used it will be silently ignored. Auto name attribute format: __((space(<i>name</i>))</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>
|
||||
a component relative to the pointer's base-datatype (e.g., structure). Auto name attribute format: __((offset(<i>signed_value</i>))</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>
|
||||
absolute memory offset. This bit-mask will be applied prior to any applied bit-shift. Auto name attribute format: __((mask(<i>hex_mask</i>))</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
|
||||
stored value when computing the absolute memory offset. Auto name attribute format: __((shift(<i>bitshift_amount</i>))</LI>
|
||||
<LI><B>Pointer Type</B> (<I>default, image-base-relative, 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>
|
||||
the absolute address that the pointer refers to.</LI>
|
||||
</UL>
|
||||
|
||||
<P><IMG src="../../shared/note.png" alt="" border="0">All Typedef Settings must be established on
|
||||
|
|
|
@ -665,7 +665,6 @@ public class DataTypeMergeManager implements MergeResolver {
|
|||
* in RESULT; false if the data type did not have to be added
|
||||
*/
|
||||
private boolean dataTypeRenamedOrMoved(long id) {
|
||||
|
||||
DataType newDt = null;
|
||||
|
||||
switch (conflictOption) {
|
||||
|
@ -700,7 +699,7 @@ public class DataTypeMergeManager implements MergeResolver {
|
|||
DataType resultDt = dtms[RESULT].getDataType(id);
|
||||
DataType newDt = null;
|
||||
if (resultDt != null) {
|
||||
setDataTypeName(resultDt, dt.getName());
|
||||
setDataTypeName(resultDt, dt);
|
||||
setCategoryPath(resultDt, dt.getCategoryPath());
|
||||
}
|
||||
else {
|
||||
|
@ -1645,8 +1644,12 @@ public class DataTypeMergeManager implements MergeResolver {
|
|||
return;
|
||||
}
|
||||
}
|
||||
String name = category.getName();
|
||||
String newName = name;
|
||||
String newName = category.getName();
|
||||
String baseName = newName;
|
||||
int index = newName.indexOf(DataType.CONFLICT_SUFFIX);
|
||||
if (index > 0) {
|
||||
baseName = newName.substring(0, index);
|
||||
}
|
||||
int oneUpNumber = 0;
|
||||
while (true) {
|
||||
try {
|
||||
|
@ -1656,7 +1659,7 @@ public class DataTypeMergeManager implements MergeResolver {
|
|||
return;
|
||||
}
|
||||
++oneUpNumber;
|
||||
newName = name + DataType.CONFLICT_SUFFIX + oneUpNumber;
|
||||
newName = baseName + DataType.CONFLICT_SUFFIX + oneUpNumber;
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
throw new AssertException("Got DuplicateNameException");
|
||||
|
@ -1673,6 +1676,11 @@ public class DataTypeMergeManager implements MergeResolver {
|
|||
return;
|
||||
}
|
||||
String name = newName;
|
||||
String baseName = newName;
|
||||
int index = newName.indexOf(DataType.CONFLICT_SUFFIX);
|
||||
if (index > 0) {
|
||||
baseName = newName.substring(0, index);
|
||||
}
|
||||
int oneUpNumber = 0;
|
||||
while (true) {
|
||||
try {
|
||||
|
@ -1681,7 +1689,7 @@ public class DataTypeMergeManager implements MergeResolver {
|
|||
}
|
||||
catch (DuplicateNameException e) {
|
||||
++oneUpNumber;
|
||||
name = newName + DataType.CONFLICT_SUFFIX + oneUpNumber;
|
||||
name = baseName + DataType.CONFLICT_SUFFIX + oneUpNumber;
|
||||
}
|
||||
catch (InvalidNameException e) {
|
||||
throw new AssertException("Got InvalidNameException: " + e);
|
||||
|
@ -1689,20 +1697,31 @@ public class DataTypeMergeManager implements MergeResolver {
|
|||
}
|
||||
}
|
||||
|
||||
private void setDataTypeName(DataType dt, String newName) {
|
||||
private void setDataTypeName(DataType dt, DataType dtToCopy) {
|
||||
if (isAutoNamedTypedef(dtToCopy)) {
|
||||
if (dt instanceof TypeDef) {
|
||||
((TypeDef) dt).enableAutoNaming();
|
||||
return;
|
||||
}
|
||||
}
|
||||
String newName = dtToCopy.getName();
|
||||
if (dt.getName().equals(newName)) {
|
||||
return;
|
||||
}
|
||||
String name = newName;
|
||||
String baseName = newName;
|
||||
int index = newName.indexOf(DataType.CONFLICT_SUFFIX);
|
||||
if (index > 0) {
|
||||
baseName = newName.substring(0, index);
|
||||
}
|
||||
int oneUpNumber = 0;
|
||||
while (true) {
|
||||
try {
|
||||
dt.setName(name);
|
||||
dt.setName(newName);
|
||||
return;
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
++oneUpNumber;
|
||||
name = newName + DataType.CONFLICT_SUFFIX + oneUpNumber;
|
||||
newName = baseName + DataType.CONFLICT_SUFFIX + oneUpNumber;
|
||||
}
|
||||
catch (InvalidNameException e) {
|
||||
throw new AssertException("Got InvalidNameException: " + e);
|
||||
|
@ -1710,6 +1729,7 @@ public class DataTypeMergeManager implements MergeResolver {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean categoryWasMoved(long id, DataTypeManager dtm1, DataTypeManager dtm2) {
|
||||
Category cat1 = dtm1.getCategory(id);
|
||||
Category cat2 = dtm2.getCategory(id);
|
||||
|
@ -1765,10 +1785,24 @@ public class DataTypeMergeManager implements MergeResolver {
|
|||
return dataTypeWasRenamed(id, dtms[ORIGINAL], dtm);
|
||||
}
|
||||
|
||||
private boolean isAutoNamedTypedef(DataType dt) {
|
||||
if (dt instanceof TypeDef) {
|
||||
TypeDef td = (TypeDef) dt;
|
||||
return td.isAutoNamed();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean dataTypeWasRenamed(long id, DataTypeManager dtm1, DataTypeManager dtm2) {
|
||||
DataType dt1 = dtm1.getDataType(id);
|
||||
DataType dt2 = dtm2.getDataType(id);
|
||||
if (dt1 != null && dt2 != null) {
|
||||
if (isAutoNamedTypedef(dt1)) {
|
||||
return isAutoNamedTypedef(dt2);
|
||||
}
|
||||
else if (isAutoNamedTypedef(dt2)) {
|
||||
return false;
|
||||
}
|
||||
String name1 = dt1.getName();
|
||||
String name2 = dt2.getName();
|
||||
return !name1.equals(name2);
|
||||
|
@ -2695,7 +2729,7 @@ public class DataTypeMergeManager implements MergeResolver {
|
|||
DataType dt = dtms[RESULT].getDataType(id);
|
||||
if (dataTypeWasRenamed(id, dtms[MY])) {
|
||||
if (dt != null) {
|
||||
setDataTypeName(dt, myDt.getName());
|
||||
setDataTypeName(dt, myDt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,7 +57,6 @@ public class PropertyListMergeManager implements MergeResolver {
|
|||
private int currentConflict;
|
||||
private int totalConflictCount;
|
||||
private ProgramMultiUserMergeManager mergeManager;
|
||||
private int progressIndex;
|
||||
private int propertyListChoice = ASK_USER;
|
||||
|
||||
/**
|
||||
|
@ -157,7 +156,7 @@ public class PropertyListMergeManager implements MergeResolver {
|
|||
}
|
||||
}
|
||||
mergeManager.updateProgress(100);
|
||||
currentMonitor.initialize(myNamesCount);
|
||||
|
||||
try {
|
||||
processConflicts();
|
||||
commit = true;
|
||||
|
@ -193,7 +192,6 @@ public class PropertyListMergeManager implements MergeResolver {
|
|||
return;
|
||||
}
|
||||
addProperty(list, resultList, optionName);
|
||||
currentMonitor.setProgress(++progressIndex);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -251,7 +249,6 @@ public class PropertyListMergeManager implements MergeResolver {
|
|||
|
||||
if (latestValue.equals(origValue)) {
|
||||
latestList.removeOption(propertyName);
|
||||
currentMonitor.setProgress(++progressIndex);
|
||||
}
|
||||
else {
|
||||
String listName = latestList.getName();
|
||||
|
@ -275,25 +272,28 @@ public class PropertyListMergeManager implements MergeResolver {
|
|||
Object resultValue = getValue(resultList, propertyName);
|
||||
Object origValue = getValue(origList, propertyName);
|
||||
|
||||
if (!SystemUtilities.isEqual(resultValue, myValue)) {
|
||||
if (propertyName.equals(Program.ANALYZED) && (myValue instanceof Boolean)) {
|
||||
// If latest or my version sets "Analyzed" to true, then it should result in true.
|
||||
setValue(resultList, propertyName, myList.getType(propertyName), Boolean.TRUE);
|
||||
currentMonitor.setProgress(++progressIndex);
|
||||
return;
|
||||
}
|
||||
if (SystemUtilities.isEqual(resultValue, origValue)) {
|
||||
setValue(resultList, propertyName, myList.getType(propertyName), myValue);
|
||||
currentMonitor.setProgress(++progressIndex);
|
||||
}
|
||||
else {
|
||||
String listName = resultList.getName();
|
||||
ArrayList<ConflictInfo> mapList = getConflictList(listName);
|
||||
mapList.add(new ConflictInfo(listName, propertyName,
|
||||
resultList.getType(propertyName), myList.getType(propertyName),
|
||||
origList.getType(propertyName), resultValue, myValue, origValue));
|
||||
++totalConflictCount;
|
||||
}
|
||||
if (SystemUtilities.isEqual(origValue, myValue) ||
|
||||
SystemUtilities.isEqual(resultValue, myValue)) {
|
||||
// value was not modified in my program or it was changed the same as in latest
|
||||
return;
|
||||
}
|
||||
if (propertyName.equals(Program.ANALYZED) && Boolean.TRUE.equals(myValue)) {
|
||||
// If my version sets "Analyzed" to true, then it should result in true.
|
||||
setValue(resultList, propertyName, myList.getType(propertyName), Boolean.TRUE);
|
||||
return;
|
||||
}
|
||||
if (SystemUtilities.isEqual(resultValue, origValue)) {
|
||||
// no change by latest - use my value
|
||||
setValue(resultList, propertyName, myList.getType(propertyName), myValue);
|
||||
}
|
||||
else {
|
||||
// my change conflicts with latest change
|
||||
String listName = resultList.getName();
|
||||
ArrayList<ConflictInfo> mapList = getConflictList(listName);
|
||||
mapList.add(new ConflictInfo(listName, propertyName,
|
||||
resultList.getType(propertyName), myList.getType(propertyName),
|
||||
origList.getType(propertyName), resultValue, myValue, origValue));
|
||||
++totalConflictCount;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -322,7 +322,6 @@ public class PropertyListMergeManager implements MergeResolver {
|
|||
|
||||
if (!myValue.equals(origValue)) {
|
||||
setValue(resultList, propertyName, myList.getType(propertyName), myValue);
|
||||
currentMonitor.setProgress(++progressIndex);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -412,7 +411,7 @@ public class PropertyListMergeManager implements MergeResolver {
|
|||
String currentListName) throws CancelledException {
|
||||
|
||||
for (int i = 0; i < conflictList.size(); i++) {
|
||||
currentMonitor.setProgress(++progressIndex);
|
||||
currentMonitor.setProgress(i);
|
||||
|
||||
ConflictInfo info = conflictList.get(i);
|
||||
|
||||
|
|
|
@ -67,7 +67,11 @@ public abstract class AbstractSettingsDialog extends DialogComponentProvider {
|
|||
Settings originalSettings) {
|
||||
super(title, true, false, true, false);
|
||||
this.settingsDefinitions = settingDefinitions;
|
||||
settings = new SettingsImpl(originalSettings);
|
||||
settings = new SettingsImpl(originalSettings) {
|
||||
public boolean isChangeAllowed(SettingsDefinition settingsDefinition) {
|
||||
return originalSettings.isChangeAllowed(settingsDefinition);
|
||||
}
|
||||
};
|
||||
defaultSettings = settings.getDefaultSettings();
|
||||
if (originalSettings != null && defaultSettings == null) {
|
||||
// ensure we have defaults to facilitate revert to default
|
||||
|
@ -206,6 +210,17 @@ public abstract class AbstractSettingsDialog extends DialogComponentProvider {
|
|||
|
||||
workPanel.add(scrollpane, BorderLayout.CENTER);
|
||||
|
||||
boolean hasImmutableSettings = false;
|
||||
for (SettingsDefinition def : settingsDefinitions) {
|
||||
if (!settings.isChangeAllowed(def)) {
|
||||
hasImmutableSettings = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasImmutableSettings) {
|
||||
workPanel.add(new JLabel("* Immutable setting"), BorderLayout.SOUTH);
|
||||
}
|
||||
|
||||
return workPanel;
|
||||
}
|
||||
|
||||
|
@ -366,6 +381,10 @@ public abstract class AbstractSettingsDialog extends DialogComponentProvider {
|
|||
return definition.getName();
|
||||
}
|
||||
|
||||
boolean isEditable() {
|
||||
return settings.isChangeAllowed(definition);
|
||||
}
|
||||
|
||||
Object getSettingsObject() {
|
||||
if (definition instanceof EnumSettingsDefinition) {
|
||||
StringChoices choices = getChoices((EnumSettingsDefinition) definition);
|
||||
|
@ -464,7 +483,11 @@ public abstract class AbstractSettingsDialog extends DialogComponentProvider {
|
|||
|
||||
@Override
|
||||
public boolean isCellEditable(int row, int col) {
|
||||
return col != 0;
|
||||
if (col == 0) {
|
||||
return false;
|
||||
}
|
||||
SettingsRowObject rowObject = rows.get(row);
|
||||
return rowObject.isEditable();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -503,7 +526,11 @@ public abstract class AbstractSettingsDialog extends DialogComponentProvider {
|
|||
public Object getColumnValueForRow(SettingsRowObject t, int columnIndex) {
|
||||
switch (columnIndex) {
|
||||
case 0:
|
||||
return t.getName();
|
||||
String name = t.getName();
|
||||
if (!t.isEditable()) {
|
||||
name += "*"; // append immutable indicator
|
||||
}
|
||||
return name;
|
||||
case 1:
|
||||
return t.getSettingsObject();
|
||||
case 2:
|
||||
|
|
|
@ -63,6 +63,8 @@ public class DataTypeSettingsDialog extends AbstractSettingsDialog {
|
|||
if (dtm instanceof DataTypeManagerDB) {
|
||||
long id = dtm.getID(dt);
|
||||
if (id > 0) {
|
||||
// FIXME: this does not handle re-mapped BuiltIn datatypes
|
||||
// since multiple instances may be defined
|
||||
if (dt == dtm.getDataType(id)) {
|
||||
return; // valid original instance
|
||||
}
|
||||
|
|
|
@ -144,7 +144,7 @@ public class DataTypeSyncInfo {
|
|||
}
|
||||
|
||||
public String getRefDtPath() {
|
||||
return refDt.getPathName();
|
||||
return refDt.getCategoryPath().getPath();
|
||||
}
|
||||
|
||||
public long getLastChangeTime(boolean useSource) {
|
||||
|
|
|
@ -119,7 +119,7 @@ public class DataTypeSynchronizer {
|
|||
long lastChangeTime = refDT.getLastChangeTime();
|
||||
DataType sourceDT = sourceDTM.resolve(refDT, DataTypeConflictHandler.REPLACE_HANDLER);
|
||||
if (!namesAreEquivalent(refDT, sourceDT)) {
|
||||
renameDataType(sourceDTM, sourceDT, refDT.getName());
|
||||
renameDataType(sourceDTM, sourceDT, refDT);
|
||||
}
|
||||
if (!StringUtils.equals(refDT.getDescription(), sourceDT.getDescription())) {
|
||||
sourceDT.setDescription(refDT.getDescription());
|
||||
|
@ -132,7 +132,7 @@ public class DataTypeSynchronizer {
|
|||
long lastChangeTime = sourceDT.getLastChangeTime();
|
||||
DataType refDT = refDTM.resolve(sourceDT, DataTypeConflictHandler.REPLACE_HANDLER);
|
||||
if (!namesAreEquivalent(refDT, sourceDT)) {
|
||||
renameDataType(refDTM, refDT, sourceDT.getName());
|
||||
renameDataType(refDTM, refDT, sourceDT);
|
||||
}
|
||||
if (!StringUtils.equals(sourceDT.getDescription(), refDT.getDescription())) {
|
||||
refDT.setDescription(sourceDT.getDescription());
|
||||
|
@ -231,7 +231,15 @@ public class DataTypeSynchronizer {
|
|||
}
|
||||
}
|
||||
|
||||
private static void renameDataType(DataTypeManager sourceDTM, DataType sourceDT, String name) {
|
||||
private static void renameDataType(DataTypeManager sourceDTM, DataType sourceDT,
|
||||
DataType dtToCopy) {
|
||||
if (isAutoNamedTypedef(dtToCopy)) {
|
||||
if (sourceDT instanceof TypeDef) {
|
||||
((TypeDef) sourceDT).enableAutoNaming();
|
||||
return;
|
||||
}
|
||||
}
|
||||
String name = dtToCopy.getName();
|
||||
int index = name.indexOf(DataType.CONFLICT_SUFFIX);
|
||||
if (index > 0) {
|
||||
name = name.substring(0, index);
|
||||
|
@ -254,7 +262,21 @@ public class DataTypeSynchronizer {
|
|||
}
|
||||
}
|
||||
|
||||
private static boolean isAutoNamedTypedef(DataType dt) {
|
||||
if (dt instanceof TypeDef) {
|
||||
TypeDef td = (TypeDef) dt;
|
||||
return td.isAutoNamed();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean namesAreEquivalent(DataType dt1, DataType dt2) {
|
||||
if (isAutoNamedTypedef(dt1)) {
|
||||
return isAutoNamedTypedef(dt2);
|
||||
}
|
||||
else if (isAutoNamedTypedef(dt2)) {
|
||||
return false;
|
||||
}
|
||||
String name1 = dt1.getName();
|
||||
String name2 = dt2.getName();
|
||||
if (name1.equals(name2)) {
|
||||
|
|
|
@ -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,16 +15,17 @@
|
|||
*/
|
||||
package ghidra.app.plugin.core.datamgr.actions;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeArchiveGTree;
|
||||
import ghidra.program.model.data.*;
|
||||
|
||||
import java.awt.Component;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.ComponentProvider;
|
||||
import docking.action.DockingAction;
|
||||
import docking.widgets.tree.GTreeNode;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeArchiveGTree;
|
||||
import ghidra.program.model.data.*;
|
||||
|
||||
abstract class AbstractTypeDefAction extends DockingAction {
|
||||
|
||||
|
@ -55,15 +55,27 @@ abstract class AbstractTypeDefAction extends DockingAction {
|
|||
return null;
|
||||
}
|
||||
|
||||
return createNewDataType(gTree, dataType, categoryPath, dataTypeManager, typeDefName);
|
||||
if (StringUtils.isBlank(typeDefName)) {
|
||||
// use auto-naming for pointer-typedef
|
||||
if (dataType instanceof Pointer) {
|
||||
// category ignored
|
||||
TypeDef typedef = new PointerTypedef(null, (Pointer) dataType, dataTypeManager);
|
||||
return createNewTypeDef(gTree, typedef, categoryPath, dataTypeManager);
|
||||
}
|
||||
// generate default typedef name
|
||||
String baseName = getBaseName(dataType) + "Typedef";
|
||||
typeDefName = dataTypeManager.getUniqueName(dataType.getCategoryPath(), baseName);
|
||||
}
|
||||
|
||||
TypeDef typedef = new TypedefDataType(categoryPath, typeDefName, dataType);
|
||||
return createNewTypeDef(gTree, typedef, categoryPath, dataTypeManager);
|
||||
}
|
||||
|
||||
private DataType createNewDataType(Component parentComponent, DataType dataType,
|
||||
CategoryPath categoryPath, DataTypeManager dataTypeManager, String name) {
|
||||
private DataType createNewTypeDef(Component parentComponent, TypeDef typedef,
|
||||
CategoryPath categoryPath, DataTypeManager dataTypeManager) {
|
||||
DataType newdt = null;
|
||||
int transactionID = dataTypeManager.startTransaction("Create Typedef");
|
||||
try {
|
||||
DataType typedef = new TypedefDataType(categoryPath, name, dataType);
|
||||
newdt = dataTypeManager.addDataType(typedef, plugin.getConflictHandler());
|
||||
}
|
||||
finally {
|
||||
|
@ -72,4 +84,16 @@ abstract class AbstractTypeDefAction extends DockingAction {
|
|||
|
||||
return newdt;
|
||||
}
|
||||
|
||||
protected static String getBaseName(DataType dt) {
|
||||
if (dt instanceof Pointer) {
|
||||
DataType dataType = ((Pointer) dt).getDataType();
|
||||
if (dataType == null) {
|
||||
// must be a generic pointer type
|
||||
return dt.getName();
|
||||
}
|
||||
return getBaseName(dataType) + "Ptr";
|
||||
}
|
||||
return dt.getDisplayName();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,16 +113,15 @@ public class CreateTypeDefAction extends AbstractTypeDefAction {
|
|||
DataTypeNode dataTypeNode = (DataTypeNode) selectionPaths[0].getLastPathComponent();
|
||||
DataType dataType = dataTypeNode.getDataType();
|
||||
|
||||
String baseName = getBaseName(dataType) + "Typedef";
|
||||
|
||||
DerivativeDataTypeInfo info =
|
||||
new DerivativeDataTypeInfo(plugin, gTree, dataTypeNode, dataType);
|
||||
|
||||
DataTypeManager dataTypeManager = info.getDataTypeManager();
|
||||
String name = dataTypeManager.getUniqueName(dataType.getCategoryPath(), baseName);
|
||||
|
||||
CategoryPath categoryPath = info.getCategoryPath();
|
||||
DataType newTypeDef = createTypeDef(dataTypeManager, dataType, categoryPath, context,
|
||||
dataTypeNode.getParent(), name);
|
||||
dataTypeNode.getParent(), null);
|
||||
if (newTypeDef == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -133,15 +132,5 @@ public class CreateTypeDefAction extends AbstractTypeDefAction {
|
|||
gTree.startEditing(finalParentNode, newNodeName);
|
||||
}
|
||||
|
||||
private static String getBaseName(DataType dt) {
|
||||
if (dt instanceof Pointer) {
|
||||
DataType dataType = ((Pointer) dt).getDataType();
|
||||
if (dataType == null) {
|
||||
// must be a generic pointer type
|
||||
return dt.getName();
|
||||
}
|
||||
return getBaseName(dataType) + "Ptr";
|
||||
}
|
||||
return dt.getDisplayName();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -176,6 +176,13 @@ public abstract class AbstractReferenceHover extends AbstractConfigurableHover {
|
|||
return null;
|
||||
}
|
||||
|
||||
if (programLocation instanceof MnemonicFieldLocation) {
|
||||
CodeUnit cu = program.getListing().getCodeUnitAt(programLocation.getAddress());
|
||||
if (!(cu instanceof Instruction)) {
|
||||
return null; // defer to mnemonic hover for Data
|
||||
}
|
||||
}
|
||||
|
||||
Address refAddr = programLocation.getRefAddress();
|
||||
if (refAddr != null && refAddr.isExternalAddress()) {
|
||||
return createExternalToolTipComponent(program, refAddr);
|
||||
|
|
|
@ -118,7 +118,6 @@ class DbViewerComponent extends JPanel {
|
|||
if (dbh == null) {
|
||||
return;
|
||||
}
|
||||
Msg.info(this, "Updating dbViewer...");
|
||||
synchronized (dbh) {
|
||||
updateTableChoices((TableItem) combo.getSelectedItem());
|
||||
updateTable();
|
||||
|
|
|
@ -70,11 +70,11 @@ public interface StructConverter {
|
|||
/**
|
||||
* Reusable 32-bit image base offset datatype.
|
||||
*/
|
||||
public final static DataType IBO32 = new ImageBaseOffset32DataType();
|
||||
public final static DataType IBO32 = IBO32DataType.dataType;
|
||||
/**
|
||||
* Reusable 64-bit image base offset datatype.
|
||||
*/
|
||||
public final static DataType IBO64 = new ImageBaseOffset64DataType();
|
||||
public final static DataType IBO64 = IBO64DataType.dataType;
|
||||
|
||||
/**
|
||||
* Returns a structure datatype representing the
|
||||
|
|
|
@ -173,7 +173,7 @@ public class ControlFlowGuard {
|
|||
IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_MASK) >> IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_SHIFT;
|
||||
|
||||
// Pre-define base data types used to define table entry data type
|
||||
DataType ibo32 = new ImageBaseOffset32DataType();
|
||||
DataType ibo32 = new IBO32DataType();
|
||||
DataType byteType = ByteDataType.dataType;
|
||||
|
||||
CategoryPath categoryPath = new CategoryPath(CategoryPath.ROOT, "CFG");
|
||||
|
@ -255,7 +255,7 @@ public class ControlFlowGuard {
|
|||
program.getSymbolTable()
|
||||
.createLabel(tableAddr, GuardCFAddressTakenIatTableName, SourceType.IMPORTED);
|
||||
// Each table entry is an RVA (32-bit image base offset)
|
||||
DataType ibo32 = new ImageBaseOffset32DataType();
|
||||
DataType ibo32 = new IBO32DataType();
|
||||
for (long i = 0; i < functionCount; i++) {
|
||||
Data d =
|
||||
PeUtils.createData(program, tableAddr.add(i * ibo32.getLength()), ibo32, log);
|
||||
|
|
|
@ -299,7 +299,7 @@ public class DelayImportDescriptor implements StructConverter {
|
|||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
DataType ibo32 = new ImageBaseOffset32DataType();
|
||||
DataType ibo32 = new IBO32DataType();
|
||||
StructureDataType struct = new StructureDataType(NAME, 0);
|
||||
struct.add(DWORD, "grAttrs", null);
|
||||
struct.add(ibo32, "szName", null);
|
||||
|
|
|
@ -84,7 +84,8 @@ public class LoadConfigDataDirectory extends DataDirectory {
|
|||
if (monitor.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
DataType dt = ntHeader.getOptionalHeader().is64bit() ? new ImageBaseOffset64DataType() : new ImageBaseOffset32DataType();
|
||||
DataType dt = ntHeader.getOptionalHeader().is64bit() ? IBO64DataType.dataType
|
||||
: IBO32DataType.dataType;
|
||||
|
||||
PeUtils.createData(program, addr, dt, log);
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ public class PEx64UnwindInfoDataType extends DynamicDataType {
|
|||
private final static int UNWIND_OP_INFO_FIELD_LENGTH = 0x04;
|
||||
|
||||
private final static DataType BYTE = ByteDataType.dataType;
|
||||
private final static DataType IBO32 = new ImageBaseOffset32DataType();
|
||||
private final static DataType IBO32 = new IBO32DataType();
|
||||
|
||||
public PEx64UnwindInfoDataType() {
|
||||
this(null);
|
||||
|
|
|
@ -273,7 +273,7 @@ public class MSDataTypeUtils {
|
|||
*/
|
||||
public static DataType getReferenceDataType(Program program, DataType referredToDataType) {
|
||||
DataTypeManager dtm = program.getDataTypeManager();
|
||||
return is64Bit(program) ? new ImageBaseOffset32DataType(dtm)
|
||||
return is64Bit(program) ? new IBO32DataType(dtm)
|
||||
: new PointerDataType(referredToDataType);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,9 +86,6 @@ public class TypeDefDataTypeHTMLRepresentation extends HTMLDataTypeRepresentatio
|
|||
DataType basedataType = dataType;
|
||||
while (basedataType instanceof TypeDef) {
|
||||
basedataType = ((TypeDef) basedataType).getDataType();
|
||||
while (basedataType instanceof Pointer) {
|
||||
basedataType = ((Pointer) basedataType).getDataType();
|
||||
}
|
||||
}
|
||||
return basedataType;
|
||||
}
|
||||
|
|
|
@ -71,6 +71,11 @@ public class ByteCountSettingsDefinition implements EnumSettingsDefinition {
|
|||
return BYTE_COUNT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStorageKey() {
|
||||
return BYTE_COUNT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Selects the number of bytes to display";
|
||||
|
|
|
@ -90,6 +90,11 @@ public class CodeUnitCountSettingsDefinition implements EnumSettingsDefinition {
|
|||
return CODE_UNIT_COUNT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStorageKey() {
|
||||
return CODE_UNIT_COUNT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Selects the number of bytes to display";
|
||||
|
|
|
@ -92,6 +92,11 @@ public class CodeUnitOffsetSettingsDefinition implements EnumSettingsDefinition
|
|||
return MEMORY_OFFSET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStorageKey() {
|
||||
return MEMORY_OFFSET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Selects the relative byte offset from which to display";
|
||||
|
|
|
@ -77,6 +77,11 @@ public class FunctionInlineSettingsDefinition implements BooleanSettingsDefiniti
|
|||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStorageKey() {
|
||||
return INLINE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasValue(Settings settings) {
|
||||
return settings.getValue(INLINE) != null;
|
||||
|
|
|
@ -77,6 +77,11 @@ public class FunctionNoReturnSettingsDefinition implements BooleanSettingsDefini
|
|||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStorageKey() {
|
||||
return NORETURN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasValue(Settings settings) {
|
||||
return settings.getValue(NORETURN) != null;
|
||||
|
|
|
@ -76,6 +76,11 @@ public class FunctionThunkSettingsDefinition implements BooleanSettingsDefinitio
|
|||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStorageKey() {
|
||||
return THUNK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasValue(Settings settings) {
|
||||
return settings.getValue(THUNK) != null;
|
||||
|
|
|
@ -91,6 +91,11 @@ public class MemoryOffsetSettingsDefinition implements EnumSettingsDefinition {
|
|||
return MEMORY_OFFSET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStorageKey() {
|
||||
return MEMORY_OFFSET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Selects the relative byte offset from which to display";
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.junit.Test;
|
|||
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.program.database.*;
|
||||
import ghidra.program.database.data.DataTypeUtilities;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.Enum;
|
||||
import ghidra.util.InvalidNameException;
|
||||
|
@ -1433,7 +1434,7 @@ public class DataTypeMerge5Test extends AbstractDataTypeMergeTest {
|
|||
// NOTE: these are not viable settings but are intended to exercise all of them
|
||||
Settings settings = td.getDefaultSettings();
|
||||
PointerTypeSettingsDefinition.DEF.setType(settings,
|
||||
PointerType.IBO);
|
||||
PointerType.IMAGE_BASE_RELATIVE);
|
||||
AddressSpaceSettingsDefinition.DEF.setValue(settings, "ROM");
|
||||
ComponentOffsetSettingsDefinition.DEF.setValue(settings, 0x10);
|
||||
OffsetMaskSettingsDefinition.DEF.setValue(settings, 0x1234);
|
||||
|
@ -1515,6 +1516,211 @@ public class DataTypeMerge5Test extends AbstractDataTypeMergeTest {
|
|||
checkConflictCount(0);
|
||||
}
|
||||
|
||||
private static String formatAttributes(String attrs) {
|
||||
StringBuilder buf = new StringBuilder(DataType.TYPEDEF_ATTRIBUTE_PREFIX);
|
||||
buf.append(attrs);
|
||||
buf.append(DataType.TYPEDEF_ATTRIBUTE_SUFFIX);
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTypeDefs11() throws Exception {
|
||||
|
||||
// Exercise pointer-typedef auto-naming with setting changes
|
||||
|
||||
mtf.initialize("notepad2", new OriginalProgramModifierListener() {
|
||||
|
||||
@Override
|
||||
public void modifyOriginal(ProgramDB program) throws Exception {
|
||||
boolean commit = false;
|
||||
DataTypeManager dtm = program.getDataTypeManager();
|
||||
int transactionID = program.startTransaction("test");
|
||||
try {
|
||||
// must specify datatype manager when constructing to allow for settings to be made
|
||||
Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
|
||||
PointerTypedef td =
|
||||
new PointerTypedef(null, foo, -1, dtm, PointerType.IMAGE_BASE_RELATIVE);
|
||||
DataType dt = dtm.resolve(td, DataTypeConflictHandler.DEFAULT_HANDLER);
|
||||
assertEquals("Foo * " + formatAttributes("image-base-relative"), dt.getName());
|
||||
commit = true;
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, commit);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
DataTypeManager dtm = program.getDataTypeManager();
|
||||
int transactionID = program.startTransaction("test");
|
||||
try {
|
||||
TypeDef td = (TypeDef) dtm.getDataType(new CategoryPath("/MISC"),
|
||||
"Foo * " + formatAttributes("image-base-relative"));
|
||||
assertNotNull(td);
|
||||
td.setName("Bob_Ptr_Td");
|
||||
|
||||
Settings settings = td.getDefaultSettings();
|
||||
PointerTypeSettingsDefinition.DEF.setType(settings,
|
||||
PointerType.RELATIVE);
|
||||
|
||||
Structure st = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
|
||||
st.setName("Bob");
|
||||
|
||||
commit = true;
|
||||
}
|
||||
catch (InvalidNameException | DuplicateNameException e) {
|
||||
failWithException("unexpected", e);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, commit);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
DataTypeManager dtm = program.getDataTypeManager();
|
||||
int transactionID = program.startTransaction("test");
|
||||
try {
|
||||
TypeDef td = (TypeDef) dtm.getDataType(new CategoryPath("/MISC"),
|
||||
"Foo * " + formatAttributes("image-base-relative"));
|
||||
assertNotNull(td);
|
||||
|
||||
Settings settings = td.getDefaultSettings();
|
||||
ComponentOffsetSettingsDefinition.DEF.setValue(settings, 0x123);
|
||||
|
||||
Structure st = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
|
||||
st.setName("Bill");
|
||||
|
||||
commit = true;
|
||||
}
|
||||
catch (InvalidNameException | DuplicateNameException e) {
|
||||
failWithException("unexpected", e);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, commit);
|
||||
}
|
||||
}
|
||||
});
|
||||
executeMerge();
|
||||
|
||||
chooseOption(DataTypeMergeManager.OPTION_MY); // choose Bill rename of Foo
|
||||
chooseOption(DataTypeMergeManager.OPTION_LATEST); // choose RELATIVE setting and Bob_Ptr_Td rename
|
||||
|
||||
waitForCompletion();
|
||||
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
TypeDef td = (TypeDef) dtm.getDataType(new CategoryPath("/MISC"), "Bob_Ptr_Td");
|
||||
assertNotNull(td);
|
||||
|
||||
DataType dt = DataTypeUtilities.getBaseDataType(td.getDataType());
|
||||
assertTrue(dt instanceof Structure);
|
||||
assertEquals("Bill", dt.getName());
|
||||
|
||||
Settings settings = td.getDefaultSettings();
|
||||
assertEquals(
|
||||
"Expected pointer-typedef type: relative",
|
||||
PointerType.RELATIVE, PointerTypeSettingsDefinition.DEF.getType(settings));
|
||||
assertFalse(
|
||||
"Unexpected setting: " +
|
||||
ComponentOffsetSettingsDefinition.DEF.getAttributeSpecification(settings),
|
||||
ComponentOffsetSettingsDefinition.DEF.hasValue(settings));
|
||||
|
||||
checkConflictCount(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTypeDefs12() throws Exception {
|
||||
|
||||
// Exercise pointer-typedef auto-naming with setting changes
|
||||
|
||||
mtf.initialize("notepad2", new OriginalProgramModifierListener() {
|
||||
|
||||
@Override
|
||||
public void modifyOriginal(ProgramDB program) throws Exception {
|
||||
boolean commit = false;
|
||||
DataTypeManager dtm = program.getDataTypeManager();
|
||||
int transactionID = program.startTransaction("test");
|
||||
try {
|
||||
// must specify datatype manager when constructing to allow for settings to be made
|
||||
Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
|
||||
PointerTypedef td =
|
||||
new PointerTypedef(null, foo, -1, dtm, PointerType.IMAGE_BASE_RELATIVE);
|
||||
DataType dt = dtm.resolve(td, DataTypeConflictHandler.DEFAULT_HANDLER);
|
||||
assertEquals("Foo * " + formatAttributes("image-base-relative"), dt.getName());
|
||||
commit = true;
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, commit);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
DataTypeManager dtm = program.getDataTypeManager();
|
||||
int transactionID = program.startTransaction("test");
|
||||
try {
|
||||
TypeDef td = (TypeDef) dtm.getDataType(new CategoryPath("/MISC"),
|
||||
"Foo * " + formatAttributes("image-base-relative"));
|
||||
assertNotNull(td);
|
||||
td.setName("Bob_Ptr_Td");
|
||||
|
||||
Settings settings = td.getDefaultSettings();
|
||||
PointerTypeSettingsDefinition.DEF.setType(settings,
|
||||
PointerType.RELATIVE);
|
||||
|
||||
commit = true;
|
||||
}
|
||||
catch (InvalidNameException | DuplicateNameException e) {
|
||||
failWithException("unexpected", e);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, commit);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
boolean commit = false;
|
||||
DataTypeManager dtm = program.getDataTypeManager();
|
||||
int transactionID = program.startTransaction("test");
|
||||
try {
|
||||
Structure st = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
|
||||
st.setName("Bill");
|
||||
commit = true;
|
||||
}
|
||||
catch (InvalidNameException | DuplicateNameException e) {
|
||||
failWithException("unexpected", e);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, commit);
|
||||
}
|
||||
}
|
||||
});
|
||||
executeMerge(true);
|
||||
|
||||
DataTypeManager dtm = resultProgram.getDataTypeManager();
|
||||
TypeDef td = (TypeDef) dtm.getDataType(new CategoryPath("/MISC"), "Bob_Ptr_Td");
|
||||
assertNotNull(td);
|
||||
|
||||
DataType dt = DataTypeUtilities.getBaseDataType(td.getDataType());
|
||||
assertTrue(dt instanceof Structure);
|
||||
assertEquals("Bill", dt.getName());
|
||||
|
||||
Settings settings = td.getDefaultSettings();
|
||||
assertEquals(
|
||||
"Expected pointer-typedef type: relative",
|
||||
PointerType.RELATIVE, PointerTypeSettingsDefinition.DEF.getType(settings));
|
||||
assertFalse(
|
||||
"Unexpected setting: " +
|
||||
ComponentOffsetSettingsDefinition.DEF.getAttributeSpecification(settings),
|
||||
ComponentOffsetSettingsDefinition.DEF.hasValue(settings));
|
||||
|
||||
checkConflictCount(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArrays() throws Exception {
|
||||
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
*/
|
||||
package ghidra.app.merge.listing;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.awt.Window;
|
||||
import java.math.BigInteger;
|
||||
|
@ -1165,7 +1164,7 @@ public class ProgramContextMergeManagerTest extends AbstractListingMergeManagerT
|
|||
*/
|
||||
@Override
|
||||
public Address addr(String address) {
|
||||
return mtf.getResultProgram().getAddressFactory().getAddress(address);
|
||||
return mtf.getOriginalProgram().getAddressFactory().getAddress(address);
|
||||
}
|
||||
|
||||
private void setRegValue(ProgramContext pc, Address start, Address end, Register reg,
|
||||
|
|
|
@ -522,19 +522,7 @@ public class PropertyListMergeManager2Test extends AbstractMergeTest {
|
|||
|
||||
@Test
|
||||
public void testAnalyzedFalseInLatest() throws Exception {
|
||||
mtf.initialize("notepad", new OriginalProgramModifierListener() {
|
||||
|
||||
@Override
|
||||
public void modifyOriginal(ProgramDB program) throws Exception {
|
||||
int transactionID = program.startTransaction("test");
|
||||
try {
|
||||
Options list = program.getOptions("Program Information");
|
||||
list.setBoolean("Analyzed", false);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
}
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
|
@ -605,19 +593,7 @@ public class PropertyListMergeManager2Test extends AbstractMergeTest {
|
|||
|
||||
@Test
|
||||
public void testAnalyzedFalseInMy() throws Exception {
|
||||
mtf.initialize("notepad", new OriginalProgramModifierListener() {
|
||||
|
||||
@Override
|
||||
public void modifyOriginal(ProgramDB program) throws Exception {
|
||||
int transactionID = program.startTransaction("test");
|
||||
try {
|
||||
Options list = program.getOptions("Program Information");
|
||||
list.setBoolean("Analyzed", false);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
}
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
|
@ -734,10 +710,20 @@ public class PropertyListMergeManager2Test extends AbstractMergeTest {
|
|||
public void testAnalyzedTrueInLatestFalseInMy() throws Exception {
|
||||
// test case: conflict because both values changed
|
||||
// Choose 'latest'
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
mtf.initialize("notepad", new OriginalProgramModifierListener() {
|
||||
|
||||
@Override
|
||||
public void modifyOriginal(ProgramDB program) throws Exception {
|
||||
int transactionID = program.startTransaction("test");
|
||||
try {
|
||||
Options list = program.getOptions("Program Information");
|
||||
list.setBoolean("Analyzed", false); // revert to default state
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
int transactionID = program.startTransaction("test");
|
||||
|
@ -777,10 +763,20 @@ public class PropertyListMergeManager2Test extends AbstractMergeTest {
|
|||
public void testAnalyzedFalseInLatestTrueInMy() throws Exception {
|
||||
// test case: conflict because both values changed
|
||||
// Choose 'latest'
|
||||
mtf.initialize("notepad", new ProgramModifierListener() {
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
mtf.initialize("notepad", new OriginalProgramModifierListener() {
|
||||
|
||||
@Override
|
||||
public void modifyOriginal(ProgramDB program) throws Exception {
|
||||
int transactionID = program.startTransaction("test");
|
||||
try {
|
||||
Options list = program.getOptions("Program Information");
|
||||
list.setBoolean("Analyzed", false); // revert to default value
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
int transactionID = program.startTransaction("test");
|
||||
|
@ -793,9 +789,6 @@ public class PropertyListMergeManager2Test extends AbstractMergeTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB)
|
||||
*/
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
int transactionID = program.startTransaction("test");
|
||||
|
|
|
@ -25,6 +25,8 @@ import ghidra.program.database.ProgramBuilder;
|
|||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.data.ProgramBasedDataTypeManager;
|
||||
import ghidra.program.model.data.StringDataType;
|
||||
import ghidra.program.model.listing.Data;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||
|
@ -44,6 +46,10 @@ public class MoveBlockModelTest extends AbstractGhidraHeadedIntegrationTest
|
|||
private volatile boolean success;
|
||||
private volatile String errMsg;
|
||||
|
||||
// Suitable settings allowed for StringDataType data
|
||||
private static String LONG_SETTING_NAME = "mutability";
|
||||
private static String STRING_SETTING_NAME = "charset";
|
||||
|
||||
private Program buildProgram1(String programName) throws Exception {
|
||||
ProgramBuilder builder = new ProgramBuilder(programName, ProgramBuilder._TOY);
|
||||
builder.createMemory(".text", Long.toHexString(0x1001000), 0x6600);
|
||||
|
@ -80,11 +86,13 @@ public class MoveBlockModelTest extends AbstractGhidraHeadedIntegrationTest
|
|||
model.initialize(block);
|
||||
|
||||
int transactionID = x8051.startTransaction("Set settings");
|
||||
|
||||
ProgramBasedDataTypeManager dtm = x8051.getDataTypeManager();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Address a = getAddr(x8051, "BITS", i);
|
||||
dtm.setStringSettingsValue(a, "color", "red" + i);
|
||||
dtm.setLongSettingsValue(a, "someLongValue", i);
|
||||
Data d = x8051.getListing().createData(a, StringDataType.dataType, 1);
|
||||
dtm.setStringSettingsValue(d, STRING_SETTING_NAME, "red" + i);
|
||||
dtm.setLongSettingsValue(d, LONG_SETTING_NAME, i);
|
||||
}
|
||||
x8051.endTransaction(transactionID, true);
|
||||
}
|
||||
|
@ -198,11 +206,13 @@ public class MoveBlockModelTest extends AbstractGhidraHeadedIntegrationTest
|
|||
ProgramBasedDataTypeManager dtm = x8051.getDataTypeManager();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Address a = getAddr(x8051, "CODE", 0x2000 + i);
|
||||
Data d = x8051.getListing().getDataAt(a);
|
||||
assertNotNull(d);
|
||||
|
||||
String s = dtm.getStringSettingsValue(a, "color");
|
||||
String s = dtm.getStringSettingsValue(d, STRING_SETTING_NAME);
|
||||
assertEquals("red" + i, s);
|
||||
|
||||
Long lvalue = dtm.getLongSettingsValue(a, "someLongValue");
|
||||
Long lvalue = dtm.getLongSettingsValue(d, LONG_SETTING_NAME);
|
||||
assertEquals(i, lvalue.longValue());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@ package ghidra.program.database.data;
|
|||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.*;
|
||||
|
||||
import ghidra.docking.settings.SettingsDefinition;
|
||||
import ghidra.program.database.ProgramBuilder;
|
||||
import ghidra.program.database.ProgramDB;
|
||||
|
@ -29,8 +31,6 @@ import ghidra.program.model.mem.Memory;
|
|||
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||
import ghidra.util.task.TaskMonitorAdapter;
|
||||
|
||||
import org.junit.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* To change the template for this generated type comment go to
|
||||
|
@ -171,15 +171,15 @@ public class ArrayTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Data comp = data.getComponent(i);
|
||||
assertEquals(null, comp.getLong("MySetting"));
|
||||
assertEquals(null, comp.getLong("format"));
|
||||
}
|
||||
|
||||
Data component4 = data.getComponent(4);
|
||||
component4.setLong("MySetting", 10L);
|
||||
component4.setLong("format", 10L);
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Data comp = data.getComponent(i);
|
||||
assertEquals((Long) 10L, comp.getLong("MySetting"));
|
||||
assertEquals((Long) 10L, comp.getLong("format"));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -199,15 +199,15 @@ public class ArrayTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Data comp = subData.getComponent(i);
|
||||
assertEquals(null, comp.getLong("MySetting"));
|
||||
assertEquals(null, comp.getLong("format"));
|
||||
}
|
||||
|
||||
Data component4 = subData.getComponent(4);
|
||||
component4.setLong("MySetting", 10L);
|
||||
component4.setLong("format", 10L);
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Data comp = subData.getComponent(i);
|
||||
assertEquals((Long) 10L, comp.getLong("MySetting"));
|
||||
assertEquals((Long) 10L, comp.getLong("format"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import ghidra.program.database.ProgramDB;
|
|||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.DataUtilities.ClearDataMode;
|
||||
import ghidra.program.model.listing.Data;
|
||||
import ghidra.program.model.listing.Listing;
|
||||
import ghidra.program.model.mem.Memory;
|
||||
|
@ -47,6 +48,10 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
private AddressSpace space;
|
||||
private int transactionID;
|
||||
|
||||
// Suitable settings allowed for StringDataType data
|
||||
private static String LONG_SETTING_NAME = "mutability";
|
||||
private static String STRING_SETTING_NAME = "charset";
|
||||
|
||||
// NOTE: Datatypes must be resolved before settings may be changed
|
||||
// with the exception of TypeDefDataType which does permit
|
||||
// TypeDefSettingsDefinition settings defined by the base-datatype.
|
||||
|
@ -63,6 +68,16 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
listing = program.getListing();
|
||||
transactionID = program.startTransaction("Test");
|
||||
addBlock();
|
||||
// pointer-typedef has the largest
|
||||
// System.out.println("Defined string settings:");
|
||||
// for (SettingsDefinition def : StringDataType.dataType.getSettingsDefinitions()) {
|
||||
// System.out.println(def.getStorageKey());
|
||||
// }
|
||||
|
||||
for (int i = 0; i < 40; i++) {
|
||||
DataUtilities.createData(program, addr(i), StringDataType.dataType, 1, false,
|
||||
ClearDataMode.CLEAR_ALL_CONFLICT_DATA);
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
|
@ -76,31 +91,33 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
@Test
|
||||
public void testSetDefaultSettings() throws Exception {
|
||||
|
||||
DataType dt = ByteDataType.dataType;
|
||||
DataType dt = StringDataType.dataType;
|
||||
|
||||
Settings defaultSettings = dt.getDefaultSettings();
|
||||
defaultSettings.setString("color", "red");
|
||||
defaultSettings.setLong("someLongValue", 10);
|
||||
|
||||
assertNull(defaultSettings.getString("color"));
|
||||
assertNull(defaultSettings.getLong("someLongValue"));
|
||||
// immutable warnings expected
|
||||
defaultSettings.setString(STRING_SETTING_NAME, "red");
|
||||
defaultSettings.setLong(LONG_SETTING_NAME, 10);
|
||||
|
||||
assertNull(defaultSettings.getString(STRING_SETTING_NAME));
|
||||
assertNull(defaultSettings.getLong(LONG_SETTING_NAME));
|
||||
|
||||
// May modify byte default settings after resolve
|
||||
dt = dataMgr.resolve(dt, null);
|
||||
|
||||
defaultSettings = dt.getDefaultSettings();
|
||||
defaultSettings.setString("color", "red");
|
||||
defaultSettings.setLong("someLongValue", 10);
|
||||
defaultSettings.setString(STRING_SETTING_NAME, "red");
|
||||
defaultSettings.setLong(LONG_SETTING_NAME, 10);
|
||||
|
||||
assertEquals("red", defaultSettings.getString("color"));
|
||||
Long lv = defaultSettings.getLong("someLongValue");
|
||||
assertEquals("red", defaultSettings.getString(STRING_SETTING_NAME));
|
||||
Long lv = defaultSettings.getLong(LONG_SETTING_NAME);
|
||||
assertNotNull(lv);
|
||||
assertEquals(10, lv.longValue());
|
||||
|
||||
defaultSettings.setValue("long", 10L);
|
||||
Object obj = defaultSettings.getValue("long");
|
||||
assertNotNull(obj);
|
||||
assertEquals(10, ((Long) obj).longValue());
|
||||
defaultSettings.setValue(LONG_SETTING_NAME, 20L);
|
||||
Object obj = defaultSettings.getValue(LONG_SETTING_NAME);
|
||||
assertTrue(obj instanceof Long);
|
||||
assertEquals(20, ((Long) obj).longValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -112,31 +129,32 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
assertEquals(0, ByteDataType.dataType.getTypeDefSettingsDefinitions().length);
|
||||
|
||||
Settings defaultSettings = typeDef.getDefaultSettings();
|
||||
defaultSettings.setString("color", "red");
|
||||
defaultSettings.setLong("someLongValue", 10);
|
||||
|
||||
assertNull(defaultSettings.getString("color"));
|
||||
assertNull(defaultSettings.getLong("someLongValue"));
|
||||
// immutable warnings expected
|
||||
FormatSettingsDefinition.DEF.setChoice(defaultSettings, FormatSettingsDefinition.CHAR);
|
||||
EndianSettingsDefinition.DEF.setBigEndian(defaultSettings, false);
|
||||
PaddingSettingsDefinition.DEF.setPadded(defaultSettings, true);
|
||||
|
||||
assertNull(defaultSettings.getLong("format"));
|
||||
assertNull(defaultSettings.getLong("endian"));
|
||||
assertNull(defaultSettings.getLong("padding"));
|
||||
|
||||
// May modify arbitrary typedef default settings after resolve
|
||||
typeDef = (TypeDef) dataMgr.resolve(typeDef, null);
|
||||
|
||||
defaultSettings = typeDef.getDefaultSettings();
|
||||
defaultSettings.setString("color", "red");
|
||||
defaultSettings.setLong("someLongValue", 10);
|
||||
FormatSettingsDefinition.DEF.setChoice(defaultSettings, FormatSettingsDefinition.CHAR);
|
||||
EndianSettingsDefinition.DEF.setBigEndian(defaultSettings, false);
|
||||
PaddingSettingsDefinition.DEF.setPadded(defaultSettings, true);
|
||||
|
||||
assertEquals("red", defaultSettings.getString("color"));
|
||||
Long lv = defaultSettings.getLong("someLongValue");
|
||||
assertNotNull(lv);
|
||||
assertEquals(10, lv.longValue());
|
||||
|
||||
defaultSettings.setValue("long", 10L);
|
||||
Object obj = defaultSettings.getValue("long");
|
||||
assertNotNull(obj);
|
||||
assertEquals(10, ((Long) obj).longValue());
|
||||
assertEquals(FormatSettingsDefinition.CHAR, defaultSettings.getLong("format").longValue());
|
||||
assertEquals(EndianSettingsDefinition.LITTLE,
|
||||
defaultSettings.getLong("endian").longValue());
|
||||
assertEquals(PaddingSettingsDefinition.PADDED_VALUE,
|
||||
defaultSettings.getLong("padded").longValue());
|
||||
|
||||
try {
|
||||
defaultSettings.setValue("color", Color.RED);
|
||||
defaultSettings.setValue("format", Color.RED);
|
||||
Assert.fail("Should not be able to set arbitrary objects");
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
|
@ -147,10 +165,10 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
@Test
|
||||
public void testIsEmpty() throws Exception {
|
||||
|
||||
DataType dt = dataMgr.resolve(ByteDataType.dataType, null);
|
||||
Settings defaultSettings = dt.getDefaultSettings();
|
||||
defaultSettings.setString("color", "red");
|
||||
defaultSettings.setLong("someLongValue", 10);
|
||||
Data data = listing.getDataAt(addr(10));
|
||||
Settings defaultSettings = data.getDataType().getDefaultSettings();
|
||||
defaultSettings.setString(STRING_SETTING_NAME, "red");
|
||||
defaultSettings.setLong(LONG_SETTING_NAME, 10);
|
||||
|
||||
assertTrue(!defaultSettings.isEmpty());
|
||||
|
||||
|
@ -161,107 +179,99 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
@Test
|
||||
public void testGetNames() throws Exception {
|
||||
|
||||
DataType dt = dataMgr.resolve(ByteDataType.dataType, null);
|
||||
DataType dt = dataMgr.resolve(StringDataType.dataType, null);
|
||||
Settings defaultSettings = dt.getDefaultSettings();
|
||||
defaultSettings.setString("color", "red");
|
||||
defaultSettings.setLong("someLongValue", 10);
|
||||
defaultSettings.setString("endian", "big Endian");
|
||||
defaultSettings.setString(STRING_SETTING_NAME, "red");
|
||||
defaultSettings.setLong(LONG_SETTING_NAME, 10);
|
||||
|
||||
String[] names = defaultSettings.getNames();
|
||||
assertEquals(3, names.length);
|
||||
assertEquals(2, names.length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClearSetting() throws Exception {
|
||||
|
||||
DataType dt = dataMgr.resolve(ByteDataType.dataType, null);
|
||||
DataType dt = dataMgr.resolve(StringDataType.dataType, null);
|
||||
Settings defaultSettings = dt.getDefaultSettings();
|
||||
defaultSettings.setString("color", "red");
|
||||
defaultSettings.setLong("someLongValue", 10);
|
||||
defaultSettings.setString(STRING_SETTING_NAME, "red");
|
||||
defaultSettings.setLong(LONG_SETTING_NAME, 10);
|
||||
|
||||
defaultSettings.clearSetting("color");
|
||||
assertNull(defaultSettings.getString("color"));
|
||||
defaultSettings.clearSetting(STRING_SETTING_NAME);
|
||||
assertNull(defaultSettings.getString(STRING_SETTING_NAME));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInstanceSettings() throws Exception {
|
||||
|
||||
listing.createData(addr(10), new ByteDataType(), 1);
|
||||
Data data = listing.getDataAt(addr(10));
|
||||
ByteDataType dt = (ByteDataType) data.getDataType();
|
||||
Data data = DataUtilities.createData(program, addr(10), ByteDataType.dataType, 1, false,
|
||||
ClearDataMode.CLEAR_ALL_CONFLICT_DATA);
|
||||
|
||||
DataType dt = data.getDataType();
|
||||
Settings defaultSettings = dt.getDefaultSettings();
|
||||
defaultSettings.setLong("format", FormatSettingsDefinition.CHAR);
|
||||
defaultSettings.setLong("signed", 0);
|
||||
defaultSettings.setLong("padded", 1);
|
||||
FormatSettingsDefinition.DEF.setChoice(defaultSettings, FormatSettingsDefinition.CHAR);
|
||||
EndianSettingsDefinition.DEF.setBigEndian(defaultSettings, false);
|
||||
PaddingSettingsDefinition.DEF.setPadded(defaultSettings, true);
|
||||
|
||||
SettingsDefinition[] defs = dt.getSettingsDefinitions();
|
||||
for (int i = 0; i < defs.length; i++) {
|
||||
assertEquals(FormatSettingsDefinition.CHAR, data.getLong("format").longValue());
|
||||
FormatSettingsDefinition.DEF.setChoice(data, FormatSettingsDefinition.DECIMAL);
|
||||
assertEquals(FormatSettingsDefinition.DECIMAL, data.getLong("format").longValue());
|
||||
|
||||
if (defs[i] instanceof EnumSettingsDefinition) {
|
||||
EnumSettingsDefinition enumDef = (EnumSettingsDefinition) defs[i];
|
||||
int value = enumDef.getChoice(data);
|
||||
enumDef.setChoice(data, value);
|
||||
if (i == 0) {
|
||||
assertEquals(FormatSettingsDefinition.CHAR, data.getLong("format").longValue());
|
||||
}
|
||||
else if (i == 1) {
|
||||
assertEquals(0, data.getLong("signed").longValue());
|
||||
}
|
||||
else if (i == 2) {
|
||||
assertEquals(1, data.getLong("padded").longValue());
|
||||
}
|
||||
assertEquals(EndianSettingsDefinition.LITTLE, data.getLong("endian").longValue());
|
||||
EndianSettingsDefinition.DEF.setChoice(data, EndianSettingsDefinition.BIG);
|
||||
assertEquals(EndianSettingsDefinition.BIG, data.getLong("endian").longValue());
|
||||
|
||||
}
|
||||
}
|
||||
assertEquals(PaddingSettingsDefinition.PADDED_VALUE, data.getLong("padded").longValue());
|
||||
PaddingSettingsDefinition.DEF.setChoice(data, PaddingSettingsDefinition.UNPADDED_VALUE);
|
||||
assertEquals(PaddingSettingsDefinition.UNPADDED_VALUE, data.getLong("padded").longValue());
|
||||
|
||||
FormatSettingsDefinition.DEF.setChoice(defaultSettings, FormatSettingsDefinition.HEX);
|
||||
EndianSettingsDefinition.DEF.clear(defaultSettings);
|
||||
PaddingSettingsDefinition.DEF.clear(defaultSettings);
|
||||
|
||||
assertEquals(FormatSettingsDefinition.DECIMAL, data.getLong("format").longValue());
|
||||
assertEquals(EndianSettingsDefinition.BIG, data.getLong("endian").longValue());
|
||||
assertEquals(PaddingSettingsDefinition.UNPADDED_VALUE, data.getLong("padded").longValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetInstanceNames() throws Exception {
|
||||
listing.createData(addr(10), new ByteDataType(), 1);
|
||||
Data data = listing.getDataAt(addr(10));
|
||||
data.setString("color", "red");
|
||||
data.setLong("someLongValue", 10);
|
||||
data.setString("endian", "big Endian");
|
||||
data.setString(STRING_SETTING_NAME, "red");
|
||||
data.setLong(LONG_SETTING_NAME, 10);
|
||||
|
||||
String[] names = data.getNames();
|
||||
assertEquals(3, names.length);
|
||||
assertEquals(2, names.length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClearInstanceSettings() throws Exception {
|
||||
listing.createData(addr(10), new ByteDataType(), 1);
|
||||
Data data = listing.getDataAt(addr(10));
|
||||
|
||||
data.setString("color", "red");
|
||||
data.setLong("someLongValue", 10);
|
||||
data.setString(STRING_SETTING_NAME, "red");
|
||||
data.setLong(LONG_SETTING_NAME, 10);
|
||||
|
||||
data.clearSetting("color");
|
||||
assertNull(data.getString("color"));
|
||||
data.clearSetting(STRING_SETTING_NAME);
|
||||
assertNull(data.getString(STRING_SETTING_NAME));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClearAllInstanceSettings() throws Exception {
|
||||
listing.createData(addr(10), new ByteDataType(), 1);
|
||||
Data data = listing.getDataAt(addr(10));
|
||||
|
||||
data.setString("color", "red");
|
||||
data.setLong("someLongValue", 10);
|
||||
data.setString("endian", "big Endian");
|
||||
data.setString(STRING_SETTING_NAME, "red");
|
||||
data.setLong(LONG_SETTING_NAME, 10);
|
||||
|
||||
data.clearAllSettings();
|
||||
assertNull(data.getString("color"));
|
||||
assertNull(data.getLong("someLongValue"));
|
||||
assertNull(data.getString("endian"));
|
||||
assertNull(data.getString(STRING_SETTING_NAME));
|
||||
assertNull(data.getLong(LONG_SETTING_NAME));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsEmptyInstanceSettings() throws Exception {
|
||||
listing.createData(addr(10), new ByteDataType(), 1);
|
||||
Data data = listing.getDataAt(addr(10));
|
||||
|
||||
data.setString("color", "red");
|
||||
data.setLong("someLongValue", 10);
|
||||
data.setString("endian", "big Endian");
|
||||
data.setString(STRING_SETTING_NAME, "red");
|
||||
data.setLong(LONG_SETTING_NAME, 10);
|
||||
|
||||
assertTrue(!data.isEmpty());
|
||||
data.clearAllSettings();
|
||||
|
@ -269,23 +279,29 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
assertTrue(data.isEmpty());
|
||||
}
|
||||
|
||||
private Data getDataAt(long offset) {
|
||||
Data data = listing.getDataAt(addr(offset));
|
||||
assertNotNull("expected data at address 0x" + Long.toHexString(offset));
|
||||
return data;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveSettings() throws Exception {
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Address a = addr(i);
|
||||
dataMgr.setStringSettingsValue(a, "color", "red" + i);
|
||||
dataMgr.setLongSettingsValue(a, "someLongValue", i);
|
||||
Data d = getDataAt(i);
|
||||
dataMgr.setStringSettingsValue(d, STRING_SETTING_NAME, "red" + i);
|
||||
dataMgr.setLongSettingsValue(d, LONG_SETTING_NAME, i);
|
||||
}
|
||||
dataMgr.moveAddressRange(addr(0), addr(20), 10, TaskMonitor.DUMMY);
|
||||
int j = 0;
|
||||
for (int i = 20; i < 30; i++, j++) {
|
||||
Address a = addr(i);
|
||||
Data d = getDataAt(i);
|
||||
|
||||
String s = dataMgr.getStringSettingsValue(a, "color");
|
||||
String s = dataMgr.getStringSettingsValue(d, STRING_SETTING_NAME);
|
||||
assertEquals("red" + j, s);
|
||||
|
||||
Long lvalue = dataMgr.getLongSettingsValue(a, "someLongValue");
|
||||
Long lvalue = dataMgr.getLongSettingsValue(d, LONG_SETTING_NAME);
|
||||
assertEquals(j, lvalue.longValue());
|
||||
}
|
||||
}
|
||||
|
@ -294,9 +310,9 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
public void testMoveSettings2() {
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Address a = addr(i);
|
||||
dataMgr.setStringSettingsValue(a, "color", "red" + i);
|
||||
dataMgr.setLongSettingsValue(a, "someLongValue", i);
|
||||
Data d = getDataAt(i);
|
||||
dataMgr.setStringSettingsValue(d, STRING_SETTING_NAME, "red" + i);
|
||||
dataMgr.setLongSettingsValue(d, LONG_SETTING_NAME, i);
|
||||
}
|
||||
try {
|
||||
dataMgr.moveAddressRange(addr(0), addr(5), 10, TaskMonitor.DUMMY);
|
||||
|
@ -307,12 +323,12 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
int j = 0;
|
||||
for (int i = 5; i < 15; i++, j++) {
|
||||
Address a = addr(i);
|
||||
Data d = getDataAt(i);
|
||||
|
||||
String s = dataMgr.getStringSettingsValue(a, "color");
|
||||
String s = dataMgr.getStringSettingsValue(d, STRING_SETTING_NAME);
|
||||
assertEquals("red" + j, s);
|
||||
|
||||
Long lvalue = dataMgr.getLongSettingsValue(a, "someLongValue");
|
||||
Long lvalue = dataMgr.getLongSettingsValue(d, LONG_SETTING_NAME);
|
||||
assertEquals(j, lvalue.longValue());
|
||||
}
|
||||
}
|
||||
|
@ -322,9 +338,9 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
int j = 20;
|
||||
for (int i = 20; i < 30; i++, j++) {
|
||||
Address a = addr(i);
|
||||
dataMgr.setStringSettingsValue(a, "color", "red" + i);
|
||||
dataMgr.setLongSettingsValue(a, "someLongValue", i);
|
||||
Data d = getDataAt(i);
|
||||
dataMgr.setStringSettingsValue(d, STRING_SETTING_NAME, "red" + i);
|
||||
dataMgr.setLongSettingsValue(d, LONG_SETTING_NAME, i);
|
||||
}
|
||||
j = 20;
|
||||
try {
|
||||
|
@ -334,12 +350,12 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
Assert.fail("Unexpected cancelled exception");
|
||||
}
|
||||
for (int i = 5; i < 15; i++, j++) {
|
||||
Address a = addr(i);
|
||||
Data d = getDataAt(i);
|
||||
|
||||
String s = dataMgr.getStringSettingsValue(a, "color");
|
||||
String s = dataMgr.getStringSettingsValue(d, STRING_SETTING_NAME);
|
||||
assertEquals("red" + j, s);
|
||||
|
||||
Long lvalue = dataMgr.getLongSettingsValue(a, "someLongValue");
|
||||
Long lvalue = dataMgr.getLongSettingsValue(d, LONG_SETTING_NAME);
|
||||
assertEquals(j, lvalue.longValue());
|
||||
}
|
||||
|
||||
|
@ -378,8 +394,7 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
DataType byteDT = dataMgr.resolve(new ByteDataType(), null);
|
||||
SettingsDefinition[] settingsDefinitions = byteDT.getSettingsDefinitions();
|
||||
Settings settings = byteDT.getDefaultSettings();
|
||||
settings.setLong("format", FormatSettingsDefinition.OCTAL);
|
||||
settings.setString("color", "red");
|
||||
FormatSettingsDefinition.DEF.setChoice(settings, FormatSettingsDefinition.OCTAL);
|
||||
|
||||
TypedefDataType tdt = new TypedefDataType("ByteTypedef", byteDT);
|
||||
TypeDef td = (TypeDef) dataMgr.addDataType(tdt, null);
|
||||
|
@ -388,11 +403,18 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
assertTrue(sdefs.length >= settingsDefinitions.length); // TypeDef may add some of its own
|
||||
|
||||
Settings defSettings = td.getDefaultSettings();
|
||||
defSettings.setLong("someLongValue", 10);
|
||||
assertEquals(FormatSettingsDefinition.OCTAL,
|
||||
FormatSettingsDefinition.DEF.getChoice(defSettings));
|
||||
|
||||
FormatSettingsDefinition.DEF.setChoice(defSettings, FormatSettingsDefinition.DECIMAL);
|
||||
assertEquals(FormatSettingsDefinition.DECIMAL,
|
||||
FormatSettingsDefinition.DEF.getChoice(defSettings));
|
||||
|
||||
FormatSettingsDefinition.DEF.setChoice(settings, FormatSettingsDefinition.HEX);
|
||||
|
||||
assertEquals(FormatSettingsDefinition.DECIMAL,
|
||||
FormatSettingsDefinition.DEF.getChoice(defSettings)); // unchanged
|
||||
|
||||
assertEquals((long) FormatSettingsDefinition.OCTAL, defSettings.getValue("format")); // inherits from byteDt
|
||||
assertEquals("red", defSettings.getValue("color")); // inherits from byteDt
|
||||
assertEquals(10L, defSettings.getValue("someLongValue"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -19,6 +19,8 @@ import static org.junit.Assert.*;
|
|||
|
||||
import org.junit.*;
|
||||
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.program.database.DatabaseObject;
|
||||
import ghidra.program.database.ProgramBuilder;
|
||||
import ghidra.program.database.data.PointerTypedefInspector;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
|
@ -52,7 +54,7 @@ public class PointerTypedefDataTypeTest extends AbstractGhidraHeadedIntegrationT
|
|||
program = buildProgram("notepad");
|
||||
dtm = program.getDataTypeManager();
|
||||
builtInDtm = BuiltInDataTypeManager.getDataTypeManager();
|
||||
|
||||
|
||||
program.startTransaction("TEST");
|
||||
}
|
||||
|
||||
|
@ -63,75 +65,241 @@ public class PointerTypedefDataTypeTest extends AbstractGhidraHeadedIntegrationT
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testIBOBuiltIn() throws Exception {
|
||||
public void testBuiltInIBODataTypes() throws Exception {
|
||||
|
||||
DataType dt = builtInDtm.getDataType(CategoryPath.ROOT, IBO32DataType.NAME);
|
||||
assertTrue(dt instanceof TypeDef);
|
||||
assertFalse(dt instanceof BuiltIn); // transforms from BuiltIn to DataTypeDB
|
||||
assertTrue(dt instanceof IBO32DataType);
|
||||
assertEquals(IBO32DataType.NAME, dt.getName());
|
||||
assertFalse(dt.hasLanguageDependantLength());
|
||||
assertTrue(dt.isEquivalent(dtm.resolve(dt, null)));
|
||||
|
||||
dt = new IBO32DataType(CharDataType.dataType, dtm);
|
||||
assertTrue(dt instanceof TypeDef);
|
||||
assertTrue(dt instanceof BuiltIn);
|
||||
assertEquals("char *32 __attribute__((image-base-relative))", dt.getName());
|
||||
DataType dbDt = dtm.resolve(dt, null);
|
||||
assertTrue(dbDt instanceof TypeDef);
|
||||
assertFalse(dbDt instanceof BuiltIn); // transforms from BuiltIn to DataTypeDB
|
||||
assertTrue(dbDt instanceof IBO32DataType);
|
||||
assertTrue(dt.isEquivalent(dbDt));
|
||||
assertEquals(dt.getName(), dbDt.getName());
|
||||
|
||||
dt = builtInDtm.getDataType(CategoryPath.ROOT, IBO64DataType.NAME);
|
||||
assertTrue(dt instanceof TypeDef);
|
||||
assertFalse(dt instanceof BuiltIn); // transforms from BuiltIn to DataTypeDB
|
||||
assertTrue(dt instanceof IBO64DataType);
|
||||
assertEquals(IBO64DataType.NAME, dt.getName());
|
||||
assertFalse(dt.hasLanguageDependantLength());
|
||||
assertTrue(dt.isEquivalent(dtm.resolve(dt, null)));
|
||||
|
||||
dt = new IBO64DataType(CharDataType.dataType, dtm);
|
||||
assertTrue(dt instanceof TypeDef);
|
||||
assertTrue(dt instanceof BuiltIn);
|
||||
assertEquals("char *64 __attribute__((image-base-relative))", dt.getName());
|
||||
dbDt = dtm.resolve(dt, null);
|
||||
assertTrue(dbDt instanceof TypeDef);
|
||||
assertFalse(dbDt instanceof BuiltIn); // transforms from BuiltIn to DataTypeDB
|
||||
assertTrue(dbDt instanceof IBO64DataType);
|
||||
assertTrue(dt.isEquivalent(dbDt));
|
||||
assertEquals(dt.getName(), dbDt.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPointerTypedef() throws Exception {
|
||||
|
||||
DataType dt = new PointerTypedef(null, CharDataType.dataType, -1, dtm,
|
||||
program.getAddressFactory().getRegisterSpace());
|
||||
DataType dt = new PointerTypedef(null, CharDataType.dataType, -1, dtm, 0x8);
|
||||
assertTrue(dt.hasLanguageDependantLength());
|
||||
assertEquals(4, dt.getLength());
|
||||
assertTrue(dt instanceof TypeDef);
|
||||
assertTrue(dt instanceof BuiltIn);
|
||||
assertEquals("char * __attribute__((space(register)))", dt.getName());
|
||||
assertEquals("char * " + formatAttributes("offset(0x8)"), dt.getName());
|
||||
DataType dbDt = dtm.resolve(dt, null);
|
||||
assertTrue(dbDt instanceof TypeDef);
|
||||
assertFalse(dbDt instanceof BuiltIn); // transforms from BuiltIn to DataTypeDB
|
||||
assertTrue(dbDt instanceof DatabaseObject); // transforms to TypedefDB
|
||||
assertTrue(dt.isEquivalent(dbDt));
|
||||
assertEquals(dt.getName(), dbDt.getName());
|
||||
|
||||
AddressSpace space = PointerTypedefInspector.getPointerAddressSpace((TypeDef) dbDt,
|
||||
program.getAddressFactory());
|
||||
assertTrue(program.getAddressFactory().getRegisterSpace().equals(space));
|
||||
assertNull(space);
|
||||
|
||||
dt = new PointerTypedef(null, CharDataType.dataType, -1, dtm,
|
||||
PointerType.RELATIVE);
|
||||
assertTrue(dt.hasLanguageDependantLength());
|
||||
assertEquals(4, dt.getLength());
|
||||
assertTrue(dt instanceof TypeDef);
|
||||
assertTrue(dt instanceof BuiltIn);
|
||||
assertEquals("char * __attribute__((relative))", dt.getName());
|
||||
assertEquals("char * " + formatAttributes("relative"), dt.getName());
|
||||
dbDt = dtm.resolve(dt, null);
|
||||
assertTrue(dbDt instanceof TypeDef);
|
||||
assertFalse(dbDt instanceof BuiltIn); // transforms from BuiltIn to DataTypeDB
|
||||
assertTrue(dbDt instanceof DatabaseObject); // transforms to TypedefDB
|
||||
assertTrue(dt.isEquivalent(dbDt));
|
||||
assertEquals(dt.getName(), dbDt.getName());
|
||||
|
||||
assertEquals(PointerType.RELATIVE, PointerTypedefInspector.getPointerType((TypeDef) dbDt));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPointerTypedefWithAddrSpace() throws Exception {
|
||||
|
||||
DataType dt = new PointerTypedef(null, CharDataType.dataType, -1, dtm,
|
||||
program.getAddressFactory().getRegisterSpace());
|
||||
assertFalse(dt.hasLanguageDependantLength());
|
||||
assertEquals(2, dt.getLength());
|
||||
assertTrue(dt instanceof TypeDef);
|
||||
assertEquals("char *16 " + formatAttributes("space(register)"), dt.getName());
|
||||
DataType dbDt = dtm.resolve(dt, null);
|
||||
assertTrue(dbDt instanceof TypeDef);
|
||||
assertTrue(dbDt instanceof DatabaseObject); // transforms to TypedefDB
|
||||
assertTrue(dt.isEquivalent(dbDt));
|
||||
assertEquals(dt.getName(), dbDt.getName());
|
||||
|
||||
AddressSpace space = PointerTypedefInspector.getPointerAddressSpace((TypeDef) dbDt,
|
||||
program.getAddressFactory());
|
||||
assertTrue(program.getAddressFactory().getRegisterSpace().equals(space));
|
||||
|
||||
dt = new PointerTypedef(null, CharDataType.dataType, 4, dtm,
|
||||
program.getAddressFactory().getRegisterSpace());
|
||||
assertFalse(dt.hasLanguageDependantLength());
|
||||
assertEquals(4, dt.getLength());
|
||||
assertTrue(dt instanceof TypeDef);
|
||||
assertEquals("char *32 " + formatAttributes("space(register)"), dt.getName());
|
||||
dbDt = dtm.resolve(dt, null);
|
||||
assertTrue(dbDt instanceof TypeDef);
|
||||
assertTrue(dbDt instanceof DatabaseObject); // transforms to TypedefDB
|
||||
assertTrue(dt.isEquivalent(dbDt));
|
||||
assertEquals(dt.getName(), dbDt.getName());
|
||||
|
||||
space = PointerTypedefInspector.getPointerAddressSpace((TypeDef) dbDt,
|
||||
program.getAddressFactory());
|
||||
assertTrue(program.getAddressFactory().getRegisterSpace().equals(space));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPointerTypedefAutoNaming() throws Exception {
|
||||
|
||||
DataType st = dtm.resolve(new StructureDataType("foo", 10), null);
|
||||
|
||||
DataType dt = new PointerTypedef(null, st, -1, dtm,
|
||||
program.getAddressFactory().getRegisterSpace());
|
||||
assertFalse(dt.hasLanguageDependantLength());
|
||||
assertEquals(2, dt.getLength());
|
||||
assertTrue(dt instanceof TypeDef);
|
||||
assertEquals("foo *16 " + formatAttributes("space(register)"), dt.getName());
|
||||
DataType dbDt = dtm.resolve(dt, null);
|
||||
assertTrue(dbDt instanceof TypeDef);
|
||||
assertTrue(dbDt instanceof DatabaseObject); // transforms to TypedefDB
|
||||
assertTrue(dt.isEquivalent(dbDt));
|
||||
assertEquals(dt.getName(), dbDt.getName());
|
||||
|
||||
st.setName("bob");
|
||||
|
||||
// auto-name should update
|
||||
assertEquals("bob *16 " + formatAttributes("space(register)"), dbDt.getName());
|
||||
|
||||
Settings settings = dbDt.getDefaultSettings();
|
||||
|
||||
OffsetMaskSettingsDefinition.DEF.setValue(settings, 0x123456789abcdef0L);
|
||||
assertEquals("bob *16 " + formatAttributes("space(register),mask(0x123456789abcdef0)"),
|
||||
dbDt.getName());
|
||||
|
||||
ComponentOffsetSettingsDefinition.DEF.setValue(settings, 0x123);
|
||||
assertEquals(
|
||||
"bob *16 " + formatAttributes("space(register),mask(0x123456789abcdef0),offset(0x123)"),
|
||||
dbDt.getName());
|
||||
|
||||
OffsetShiftSettingsDefinition.DEF.setValue(settings, 16);
|
||||
assertEquals(
|
||||
"bob *16 " + formatAttributes(
|
||||
"space(register),mask(0x123456789abcdef0),shift(16),offset(0x123)"),
|
||||
dbDt.getName());
|
||||
|
||||
PointerTypeSettingsDefinition.DEF.setType(settings, PointerType.IMAGE_BASE_RELATIVE);
|
||||
assertEquals(
|
||||
"bob *16 " + formatAttributes(
|
||||
"image-base-relative,space(register),mask(0x123456789abcdef0),shift(16),offset(0x123)"),
|
||||
dbDt.getName());
|
||||
|
||||
st.setName("bill");
|
||||
assertEquals(
|
||||
"bill *16 " + formatAttributes(
|
||||
"image-base-relative,space(register),mask(0x123456789abcdef0),shift(16),offset(0x123)"),
|
||||
dbDt.getName());
|
||||
|
||||
PointerTypeSettingsDefinition.DEF.clear(settings);
|
||||
assertEquals(
|
||||
"bill *16 " + formatAttributes(
|
||||
"space(register),mask(0x123456789abcdef0),shift(16),offset(0x123)"),
|
||||
dbDt.getName());
|
||||
|
||||
ComponentOffsetSettingsDefinition.DEF.clear(settings);
|
||||
assertEquals(
|
||||
"bill *16 " + formatAttributes("space(register),mask(0x123456789abcdef0),shift(16)"),
|
||||
dbDt.getName());
|
||||
|
||||
// NOTE: Changing address space setting will not alter pointer size
|
||||
|
||||
AddressSpaceSettingsDefinition.DEF.clear(settings);
|
||||
assertEquals(
|
||||
"bill *16 " + formatAttributes("mask(0x123456789abcdef0),shift(16)"),
|
||||
dbDt.getName());
|
||||
|
||||
OffsetShiftSettingsDefinition.DEF.clear(settings);
|
||||
assertEquals(
|
||||
"bill *16 " + formatAttributes("mask(0x123456789abcdef0)"),
|
||||
dbDt.getName());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPointerTypedefEquivalence() throws Exception {
|
||||
|
||||
DataType st = dtm.resolve(new StructureDataType("foo", 10), null);
|
||||
|
||||
TypeDef dt = new PointerTypedef(null, st, -1, dtm,
|
||||
program.getAddressFactory().getRegisterSpace());
|
||||
assertTrue(dt.isAutoNamed());
|
||||
assertFalse(dt.hasLanguageDependantLength());
|
||||
assertEquals(2, dt.getLength());
|
||||
assertEquals("foo *16 " + formatAttributes("space(register)"), dt.getName());
|
||||
TypeDef dbDt = (TypeDef) dtm.resolve(dt, null);
|
||||
assertTrue(dbDt instanceof DatabaseObject); // transforms to TypedefDB
|
||||
assertTrue(dt.isEquivalent(dbDt));
|
||||
assertEquals(dt.getName(), dbDt.getName());
|
||||
|
||||
dt = (TypeDef) dt.copy(dtm);
|
||||
assertTrue(dbDt == dtm.resolve(dt, null)); // should resolve to same instance
|
||||
|
||||
dt = (TypeDef) dt.copy(dtm);
|
||||
PointerTypeSettingsDefinition.DEF.setType(dt.getDefaultSettings(), PointerType.IMAGE_BASE_RELATIVE);
|
||||
TypeDef dbDt2 = (TypeDef) dtm.resolve(dt, null); // should resolve to new instance
|
||||
assertTrue(dbDt != dbDt2);
|
||||
assertEquals("foo *16 " + formatAttributes("image-base-relative,space(register)"),
|
||||
dbDt2.getName());
|
||||
|
||||
PointerTypeSettingsDefinition.DEF.clear(dbDt2.getDefaultSettings());
|
||||
assertEquals("foo *16 " + formatAttributes("space(register)") + DataType.CONFLICT_SUFFIX,
|
||||
dbDt2.getName());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPointerTypedefEquivalence2() throws Exception {
|
||||
|
||||
DataType st = dtm.resolve(new StructureDataType("foo", 10), null);
|
||||
|
||||
TypeDef dt = new PointerTypedef(null, st, -1, dtm,
|
||||
program.getAddressFactory().getRegisterSpace());
|
||||
assertTrue(dt.isAutoNamed());
|
||||
assertFalse(dt.hasLanguageDependantLength());
|
||||
assertEquals(2, dt.getLength());
|
||||
assertEquals("foo *16 " + formatAttributes("space(register)"), dt.getName());
|
||||
TypeDef dbDt = (TypeDef) dtm.resolve(dt, null);
|
||||
assertTrue(dbDt instanceof DatabaseObject); // transforms to TypedefDB
|
||||
assertTrue(dt.isEquivalent(dbDt));
|
||||
assertEquals(dt.getName(), dbDt.getName());
|
||||
|
||||
TypeDef dt2 = new PointerTypedef("john", st, -1, dtm,
|
||||
program.getAddressFactory().getRegisterSpace());
|
||||
assertFalse(dt2.isAutoNamed());
|
||||
assertFalse(dt2.hasLanguageDependantLength());
|
||||
assertEquals(2, dt.getLength());
|
||||
assertEquals("john", dt2.getName());
|
||||
TypeDef dbDt2 = (TypeDef) dtm.resolve(dt2, null);
|
||||
assertTrue(dbDt != dbDt2);
|
||||
assertFalse(dbDt.isEquivalent(dbDt2));
|
||||
assertFalse(dbDt2.isEquivalent(dbDt));
|
||||
assertTrue(dbDt2 instanceof DatabaseObject); // transforms to TypedefDB
|
||||
assertTrue(dt2.isEquivalent(dbDt2));
|
||||
assertEquals(dt2.getName(), dbDt2.getName());
|
||||
|
||||
}
|
||||
|
||||
private static String formatAttributes(String attrs) {
|
||||
StringBuilder buf = new StringBuilder(DataType.TYPEDEF_ATTRIBUTE_PREFIX);
|
||||
buf.append(attrs);
|
||||
buf.append(DataType.TYPEDEF_ATTRIBUTE_SUFFIX);
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ package ghidra.program.database;
|
|||
|
||||
import java.io.IOException;
|
||||
|
||||
import db.*;
|
||||
import db.buffers.BufferFile;
|
||||
import generic.test.AbstractGenericTest;
|
||||
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
|
||||
|
@ -28,6 +29,7 @@ import ghidra.program.model.listing.ProgramChangeSet;
|
|||
import ghidra.test.TestEnv;
|
||||
import ghidra.util.InvalidNameException;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.VersionException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
|
@ -105,7 +107,7 @@ public abstract class AbstractMTFModel {
|
|||
return privateChangeSet;
|
||||
}
|
||||
|
||||
public ProgramChangeSet getResultChangeSet() {
|
||||
public ProgramChangeSet getLatestChangeSet() {
|
||||
return latestChangeSet;
|
||||
}
|
||||
|
||||
|
@ -113,7 +115,7 @@ public abstract class AbstractMTFModel {
|
|||
return env;
|
||||
}
|
||||
|
||||
protected void disableAutoAnalysis(Program p) {
|
||||
protected static void disableAutoAnalysis(Program p) {
|
||||
// Disable all analysis
|
||||
AutoAnalysisManager analysisMgr = AutoAnalysisManager.getAnalysisManager(p);
|
||||
AbstractGenericTest.setInstanceField("isEnabled", analysisMgr, Boolean.FALSE);
|
||||
|
@ -169,4 +171,25 @@ public abstract class AbstractMTFModel {
|
|||
throws Exception;
|
||||
|
||||
public abstract void initialize(String programName, ProgramModifierListener l) throws Exception;
|
||||
|
||||
/**
|
||||
* Clone a program to a new instance. The new instance will be assigned an empty change-set.
|
||||
* @param prog program to be cloned
|
||||
* @param consumer new program consumer
|
||||
* @return new program instance
|
||||
* @throws IOException if a file IO error occurs
|
||||
*/
|
||||
public static ProgramDB cloneProgram(ProgramDB prog, Object consumer) throws IOException {
|
||||
try {
|
||||
DBHandle newDbh = DBTestUtils.cloneDbHandle(prog.getDBHandle());
|
||||
ProgramDB newProg =
|
||||
new ProgramDB(newDbh, DBConstants.UPDATE, TaskMonitor.DUMMY, consumer);
|
||||
newProg.setChangeSet(new ProgramDBChangeSet(newProg.getAddressMap(), 20));
|
||||
disableAutoAnalysis(newProg);
|
||||
return newProg;
|
||||
}
|
||||
catch (CancelledException | VersionException e) {
|
||||
throw new RuntimeException(e); // unexpected
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,7 +90,7 @@ public class MergeTestFacilitator {
|
|||
* Get the change set for Result program.
|
||||
*/
|
||||
public ProgramChangeSet getResultChangeSet() {
|
||||
return model.getResultChangeSet();
|
||||
return model.getLatestChangeSet();
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
|
|
|
@ -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.
|
||||
|
@ -30,11 +29,7 @@ import ghidra.util.exception.AssertException;
|
|||
// TODO rename--this is no longer using real programs
|
||||
public class RealProgramMTFModel extends AbstractMTFModel {
|
||||
|
||||
/**
|
||||
* We install our test ID generator to ensure that all datatypes we create will share the
|
||||
* same ID across all versions of the programs we create. If we do not do this, then they will
|
||||
* be different, which breaks many tests.
|
||||
*/
|
||||
// Use simple ID generation
|
||||
private TestUniversalIdGenerator universalIdGenerator = new TestUniversalIdGenerator();
|
||||
|
||||
RealProgramMTFModel(TestEnv env) {
|
||||
|
@ -46,12 +41,15 @@ public class RealProgramMTFModel extends AbstractMTFModel {
|
|||
cleanup();
|
||||
|
||||
MergeProgramGenerator programGenerator = createProgramGenerator(programName);
|
||||
generatePrograms(programName, programGenerator);
|
||||
originalProgram = programGenerator.generateProgram(programName);
|
||||
|
||||
disableAutoAnalysis();
|
||||
latestProgram = cloneProgram(originalProgram, this);
|
||||
modifier.modifyLatest(latestProgram);
|
||||
|
||||
makeIncomingChanges(modifier);
|
||||
makeLocalChanges(modifier);
|
||||
resultProgram = cloneProgram(latestProgram, this);
|
||||
|
||||
privateProgram = cloneProgram(originalProgram, this);
|
||||
modifier.modifyPrivate(privateProgram);
|
||||
|
||||
recordChanges();
|
||||
clearChanges();
|
||||
|
@ -63,36 +61,21 @@ public class RealProgramMTFModel extends AbstractMTFModel {
|
|||
cleanup();
|
||||
|
||||
MergeProgramGenerator programGenerator = createProgramGenerator(programName);
|
||||
generatePrograms(programName, programGenerator);
|
||||
originalProgram = programGenerator.generateProgram(programName);
|
||||
modifier.modifyOriginal(originalProgram);
|
||||
|
||||
disableAutoAnalysis();
|
||||
privateProgram = cloneProgram(originalProgram, this);
|
||||
modifier.modifyPrivate(privateProgram);
|
||||
|
||||
createCustomStartingProgram(modifier);
|
||||
clearChanges();
|
||||
latestProgram = cloneProgram(originalProgram, this);
|
||||
modifier.modifyLatest(latestProgram);
|
||||
|
||||
makeIncomingChanges(modifier);
|
||||
makeLocalChanges(modifier);
|
||||
resultProgram = cloneProgram(latestProgram, this);
|
||||
|
||||
recordChanges();
|
||||
clearChanges();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that use this method are creating a new 'original' program, rather than using
|
||||
* a pre-fabricated one from a program builder.
|
||||
*/
|
||||
private void createCustomStartingProgram(OriginalProgramModifierListener modifier)
|
||||
throws Exception {
|
||||
universalIdGenerator.checkpoint();
|
||||
modifier.modifyOriginal(originalProgram);
|
||||
universalIdGenerator.restore();
|
||||
modifier.modifyOriginal(privateProgram);
|
||||
universalIdGenerator.restore();
|
||||
modifier.modifyOriginal(latestProgram);
|
||||
universalIdGenerator.restore();
|
||||
modifier.modifyOriginal(resultProgram);
|
||||
}
|
||||
|
||||
private MergeProgramGenerator createProgramGenerator(String programName) {
|
||||
if (programName.toLowerCase().contains("notepad")) {
|
||||
return new MergeProgramGenerator_Notepads(this);
|
||||
|
@ -117,35 +100,6 @@ public class RealProgramMTFModel extends AbstractMTFModel {
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
private void disableAutoAnalysis() {
|
||||
disableAutoAnalysis(privateProgram);
|
||||
disableAutoAnalysis(resultProgram);
|
||||
disableAutoAnalysis(latestProgram);
|
||||
}
|
||||
|
||||
private void makeLocalChanges(ProgramModifierListener modifier) throws Exception {
|
||||
modifier.modifyPrivate(privateProgram);
|
||||
}
|
||||
|
||||
private void makeIncomingChanges(ProgramModifierListener modifier) throws Exception {
|
||||
universalIdGenerator.checkpoint();
|
||||
modifier.modifyLatest(latestProgram);
|
||||
universalIdGenerator.restore();
|
||||
modifier.modifyLatest(resultProgram);
|
||||
}
|
||||
|
||||
private void generatePrograms(String programName, MergeProgramGenerator programGenerator)
|
||||
throws Exception {
|
||||
universalIdGenerator.checkpoint();
|
||||
privateProgram = programGenerator.generateProgram(programName);
|
||||
universalIdGenerator.restore();
|
||||
originalProgram = programGenerator.generateProgram(programName);
|
||||
universalIdGenerator.restore();
|
||||
resultProgram = programGenerator.generateProgram(programName);
|
||||
universalIdGenerator.restore();
|
||||
latestProgram = programGenerator.generateProgram(programName);
|
||||
}
|
||||
|
||||
private void recordChanges() {
|
||||
// ...keep track of the changes we've made
|
||||
latestChangeSet = latestProgram.getChanges();
|
||||
|
|
|
@ -581,8 +581,8 @@ public class ExtendedFlatProgramAPI extends FlatProgramAPI {
|
|||
|
||||
int addressSize = address.getSize();
|
||||
if (addressSize == 64 && getIboIf64bit) {
|
||||
ImageBaseOffset32DataType ibo32 =
|
||||
new ImageBaseOffset32DataType(currentProgram.getDataTypeManager());
|
||||
IBO32DataType ibo32 =
|
||||
new IBO32DataType(currentProgram.getDataTypeManager());
|
||||
int length = ibo32.getLength();
|
||||
DumbMemBufferImpl compMemBuffer =
|
||||
new DumbMemBufferImpl(currentProgram.getMemory(), address);
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
package ghidra.app.cmd.data.exceptionhandling;
|
||||
|
||||
import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.getAlignedPack4Structure;
|
||||
import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.*;
|
||||
|
||||
import ghidra.app.cmd.data.*;
|
||||
import ghidra.app.util.datatype.microsoft.DataValidationOptions;
|
||||
|
@ -116,7 +116,7 @@ public class EHCatchHandlerModel extends AbstractCreateDataTypeModel {
|
|||
|
||||
/* comps[1] */
|
||||
if (isRelative) {
|
||||
compDt = new ImageBaseOffset32DataType(dataTypeManager);
|
||||
compDt = new IBO32DataType(dataTypeManager);
|
||||
struct.add(compDt, "dispType", null);
|
||||
}
|
||||
else {
|
||||
|
@ -136,7 +136,7 @@ public class EHCatchHandlerModel extends AbstractCreateDataTypeModel {
|
|||
|
||||
/* comps[3] */
|
||||
if (isRelative) {
|
||||
compDt = new ImageBaseOffset32DataType(dataTypeManager);
|
||||
compDt = new IBO32DataType(dataTypeManager);
|
||||
struct.add(compDt, "dispOfHandler", null);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
package ghidra.app.cmd.data.exceptionhandling;
|
||||
|
||||
import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.getAlignedPack4Structure;
|
||||
import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.*;
|
||||
|
||||
import ghidra.app.cmd.data.AbstractCreateDataTypeModel;
|
||||
import ghidra.app.cmd.data.EHDataTypeUtilities;
|
||||
|
@ -101,7 +101,7 @@ public class EHESTypeListModel extends AbstractCreateDataTypeModel {
|
|||
|
||||
/* comps[1] */
|
||||
if (isRelative) {
|
||||
compDt = new ImageBaseOffset32DataType(dataTypeManager);
|
||||
compDt = new IBO32DataType(dataTypeManager);
|
||||
struct.add(compDt, "dispTypeArray", null);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
package ghidra.app.cmd.data.exceptionhandling;
|
||||
|
||||
import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.getAlignedPack4Structure;
|
||||
import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.*;
|
||||
|
||||
import ghidra.app.cmd.data.AbstractCreateDataTypeModel;
|
||||
import ghidra.app.cmd.data.EHDataTypeUtilities;
|
||||
|
@ -150,7 +150,7 @@ public class EHFunctionInfoModel extends AbstractCreateDataTypeModel {
|
|||
DataTypeManager dataTypeManager = getProgram().getDataTypeManager();
|
||||
int intSize = new IntegerDataType(dataTypeManager).getLength();
|
||||
int uintSize = new UnsignedIntegerDataType(dataTypeManager).getLength();
|
||||
int ibo32Size = new ImageBaseOffset32DataType(dataTypeManager).getLength();
|
||||
int ibo32Size = new IBO32DataType(dataTypeManager).getLength();
|
||||
int defaultPointerSize = getDefaultPointerSize();
|
||||
int size20;
|
||||
int additional21;
|
||||
|
@ -316,7 +316,7 @@ public class EHFunctionInfoModel extends AbstractCreateDataTypeModel {
|
|||
|
||||
/* comps[2] */
|
||||
if (isRelative) {
|
||||
compDt = new ImageBaseOffset32DataType(dataTypeManager);
|
||||
compDt = new IBO32DataType(dataTypeManager);
|
||||
struct.add(compDt, "dispUnwindMap", null);
|
||||
}
|
||||
else {
|
||||
|
@ -330,7 +330,7 @@ public class EHFunctionInfoModel extends AbstractCreateDataTypeModel {
|
|||
|
||||
/* comps[4] */
|
||||
if (isRelative) {
|
||||
compDt = new ImageBaseOffset32DataType(dataTypeManager);
|
||||
compDt = new IBO32DataType(dataTypeManager);
|
||||
struct.add(compDt, "dispTryBlockMap", null);
|
||||
}
|
||||
else {
|
||||
|
@ -344,7 +344,7 @@ public class EHFunctionInfoModel extends AbstractCreateDataTypeModel {
|
|||
|
||||
/* comps[6] */
|
||||
if (isRelative) {
|
||||
compDt = new ImageBaseOffset32DataType(dataTypeManager);
|
||||
compDt = new IBO32DataType(dataTypeManager);
|
||||
struct.add(compDt, "dispIPToStateMap", null);
|
||||
}
|
||||
else {
|
||||
|
@ -359,7 +359,7 @@ public class EHFunctionInfoModel extends AbstractCreateDataTypeModel {
|
|||
|
||||
if (isV2 || isV3) {
|
||||
if (isRelative) { /* comps[8] */
|
||||
compDt = new ImageBaseOffset32DataType(dataTypeManager);
|
||||
compDt = new IBO32DataType(dataTypeManager);
|
||||
struct.add(compDt, "dispESTypeList", null);
|
||||
}
|
||||
else { /* comps[7] */
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
package ghidra.app.cmd.data.exceptionhandling;
|
||||
|
||||
import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.getAlignedPack4Structure;
|
||||
import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.*;
|
||||
|
||||
import ghidra.app.cmd.data.AbstractCreateDataTypeModel;
|
||||
import ghidra.app.cmd.data.EHDataTypeUtilities;
|
||||
|
@ -102,7 +102,7 @@ public class EHIPToStateModel extends AbstractCreateDataTypeModel {
|
|||
|
||||
/* comps[0] */
|
||||
if (isRelative) {
|
||||
compDt = new ImageBaseOffset32DataType(dataTypeManager);
|
||||
compDt = new IBO32DataType(dataTypeManager);
|
||||
}
|
||||
else {
|
||||
DataType dwordDt = new TypedefDataType(new CategoryPath("/WinDef.h"), "DWORD",
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
package ghidra.app.cmd.data.exceptionhandling;
|
||||
|
||||
import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.getAlignedPack4Structure;
|
||||
import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.*;
|
||||
|
||||
import ghidra.app.cmd.data.AbstractCreateDataTypeModel;
|
||||
import ghidra.app.cmd.data.EHDataTypeUtilities;
|
||||
|
@ -114,7 +114,7 @@ public class EHTryBlockModel extends AbstractCreateDataTypeModel {
|
|||
|
||||
/* comps[4] */
|
||||
if (isRelative) {
|
||||
compDt = new ImageBaseOffset32DataType(dataTypeManager);
|
||||
compDt = new IBO32DataType(dataTypeManager);
|
||||
struct.add(compDt, "dispHandlerArray", null);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
package ghidra.app.cmd.data.exceptionhandling;
|
||||
|
||||
import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.getAlignedPack4Structure;
|
||||
import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.*;
|
||||
|
||||
import ghidra.app.cmd.data.AbstractCreateDataTypeModel;
|
||||
import ghidra.app.cmd.data.EHDataTypeUtilities;
|
||||
|
@ -106,7 +106,7 @@ public class EHUnwindModel extends AbstractCreateDataTypeModel {
|
|||
|
||||
/* comps[1] */
|
||||
if (isRelative) {
|
||||
compDt = new ImageBaseOffset32DataType(dataTypeManager);
|
||||
compDt = new IBO32DataType(dataTypeManager);
|
||||
}
|
||||
else {
|
||||
|
||||
|
|
|
@ -232,7 +232,7 @@ public class Rtti1Model extends AbstractCreateRttiDataModel {
|
|||
boolean is64Bit = MSDataTypeUtils.is64Bit(program);
|
||||
Structure rtti1Struct = (Structure) DataTypeUtils.getBaseDataType(rtti1Dt);
|
||||
DataType rtti3RefDt =
|
||||
is64Bit ? new ImageBaseOffset32DataType(dataTypeManager) : new PointerDataType(rtti3Dt);
|
||||
is64Bit ? new IBO32DataType(dataTypeManager) : new PointerDataType(rtti3Dt);
|
||||
rtti1Struct.replace(CLASS_HIERARCHY_POINTER_ORDINAL, rtti3RefDt, rtti3RefDt.getLength(),
|
||||
"pClassHierarchyDescriptor", "ref to ClassHierarchyDescriptor (RTTI 3) for class");
|
||||
}
|
||||
|
@ -248,9 +248,9 @@ public class Rtti1Model extends AbstractCreateRttiDataModel {
|
|||
boolean is64Bit = MSDataTypeUtils.is64Bit(program);
|
||||
DataType rtti0Dt = TypeDescriptorModel.getDataType(program);
|
||||
DataType rtti0RefDt =
|
||||
is64Bit ? new ImageBaseOffset32DataType(dataTypeManager) : new PointerDataType(rtti0Dt);
|
||||
is64Bit ? new IBO32DataType(dataTypeManager) : new PointerDataType(rtti0Dt);
|
||||
DataType rtti3RefDt =
|
||||
is64Bit ? new ImageBaseOffset32DataType(dataTypeManager) : new PointerDataType();
|
||||
is64Bit ? new IBO32DataType(dataTypeManager) : new PointerDataType();
|
||||
|
||||
CategoryPath categoryPath = new CategoryPath(CATEGORY_PATH);
|
||||
StructureDataType struct =
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
package ghidra.app.cmd.data.rtti;
|
||||
|
||||
import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.getReferencedAddress;
|
||||
import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -145,11 +145,8 @@ public class Rtti2Model extends AbstractCreateRttiDataModel {
|
|||
|
||||
DataTypeManager dataTypeManager = program.getDataTypeManager();
|
||||
|
||||
if (MSDataTypeUtils.is64Bit(program)) {
|
||||
return new ImageBaseOffset32DataType(dataTypeManager);
|
||||
}
|
||||
|
||||
return new PointerDataType(rtti1Dt, dataTypeManager);
|
||||
return MSDataTypeUtils.is64Bit(program) ? IBO32DataType.createIBO32PointerTypedef(rtti1Dt)
|
||||
: new PointerDataType(rtti1Dt, dataTypeManager);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -162,11 +159,8 @@ public class Rtti2Model extends AbstractCreateRttiDataModel {
|
|||
|
||||
DataTypeManager dataTypeManager = program.getDataTypeManager();
|
||||
|
||||
if (MSDataTypeUtils.is64Bit(program)) {
|
||||
return new ImageBaseOffset32DataType(dataTypeManager);
|
||||
}
|
||||
|
||||
return new PointerDataType(dataTypeManager);
|
||||
return MSDataTypeUtils.is64Bit(program) ? IBO32DataType.dataType
|
||||
: new PointerDataType(dataTypeManager);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -15,9 +15,6 @@
|
|||
*/
|
||||
package ghidra.app.cmd.data.rtti;
|
||||
|
||||
import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.getAlignedPack4Structure;
|
||||
import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.getReferencedAddress;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.cmd.data.EHDataTypeUtilities;
|
||||
|
@ -147,8 +144,8 @@ public class Rtti3Model extends AbstractCreateRttiDataModel {
|
|||
boolean is64Bit = MSDataTypeUtils.is64Bit(program);
|
||||
Structure rtti3Struct = (Structure) DataTypeUtils.getBaseDataType(rtti3Dt);
|
||||
DataType individualRtti2EntryDt = Rtti2Model.getIndividualEntryDataType(program, rtti1Dt);
|
||||
DataType rtti2RefDt = is64Bit ? new ImageBaseOffset32DataType(dataTypeManager)
|
||||
: new PointerDataType(individualRtti2EntryDt);
|
||||
DataType rtti2RefDt = is64Bit ? IBO32DataType.createIBO32PointerTypedef(individualRtti2EntryDt)
|
||||
: new PointerDataType(individualRtti2EntryDt, dataTypeManager);
|
||||
rtti3Struct.replace(BASE_ARRAY_PTR_ORDINAL, rtti2RefDt, rtti2RefDt.getLength(),
|
||||
"pBaseClassArray", "ref to BaseClassArray (RTTI 2)");
|
||||
}
|
||||
|
@ -165,7 +162,7 @@ public class Rtti3Model extends AbstractCreateRttiDataModel {
|
|||
|
||||
CategoryPath categoryPath = new CategoryPath(CATEGORY_PATH);
|
||||
StructureDataType struct =
|
||||
getAlignedPack4Structure(dataTypeManager, categoryPath, STRUCTURE_NAME);
|
||||
MSDataTypeUtils.getAlignedPack4Structure(dataTypeManager, categoryPath, STRUCTURE_NAME);
|
||||
|
||||
// Add the components.
|
||||
DWordDataType dWordDataType = new DWordDataType(dataTypeManager);
|
||||
|
@ -174,8 +171,10 @@ public class Rtti3Model extends AbstractCreateRttiDataModel {
|
|||
struct.add(dWordDataType, "numBaseClasses", "number of base classes (i.e. rtti1Count)");
|
||||
|
||||
DataType rtti2Dt = Rtti2Model.getSimpleIndividualEntryDataType(program);
|
||||
// FIXME! I don't think we should be making a pointer-to-pointer
|
||||
DataType rtti2RefDt =
|
||||
is64Bit ? new ImageBaseOffset32DataType(dataTypeManager) : new PointerDataType(rtti2Dt);
|
||||
is64Bit ? IBO32DataType.createIBO32PointerTypedef(rtti2Dt)
|
||||
: new PointerDataType(rtti2Dt, dataTypeManager);
|
||||
struct.add(rtti2RefDt, "pBaseClassArray", "ref to BaseClassArray (RTTI 2)");
|
||||
|
||||
return new TypedefDataType(categoryPath, DATA_TYPE_NAME, struct, dataTypeManager);
|
||||
|
@ -264,7 +263,7 @@ public class Rtti3Model extends AbstractCreateRttiDataModel {
|
|||
Memory memory = program.getMemory();
|
||||
|
||||
Address rtti2CompAddress = rtti3Address.add(BASE_ARRAY_PTR_OFFSET);
|
||||
Address pointedToAddress = getReferencedAddress(program, rtti2CompAddress);
|
||||
Address pointedToAddress = MSDataTypeUtils.getReferencedAddress(program, rtti2CompAddress);
|
||||
if (pointedToAddress == null || !memory.contains(pointedToAddress)) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -15,9 +15,8 @@
|
|||
*/
|
||||
package ghidra.app.cmd.data.rtti;
|
||||
|
||||
import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.getAbsoluteAddress;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static ghidra.app.util.datatype.microsoft.MSDataTypeUtils.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import ghidra.app.cmd.data.AbstractCreateDataTypeModelTest;
|
||||
import ghidra.app.cmd.data.TypeDescriptorModel;
|
||||
|
@ -591,10 +590,10 @@ class AbstractRttiTest extends AbstractCreateDataTypeModelTest {
|
|||
}
|
||||
|
||||
protected void checkRtti2Data(ProgramDB program, long address, int numEntries) {
|
||||
DataType rtti1Dt = Rtti1Model.getDataType(program);
|
||||
DataType expectedDataType =
|
||||
MSDataTypeUtils.is64Bit(program) ? new ImageBaseOffset32DataType()
|
||||
: new PointerDataType(Rtti1Model.getDataType(program),
|
||||
program.getDataTypeManager());
|
||||
MSDataTypeUtils.is64Bit(program) ? IBO32DataType.createIBO32PointerTypedef(rtti1Dt)
|
||||
: new PointerDataType(rtti1Dt, program.getDataTypeManager());
|
||||
checkArrayData(program, address, expectedDataType, numEntries);
|
||||
}
|
||||
|
||||
|
|
|
@ -679,11 +679,16 @@ public class DBHandle {
|
|||
* @param outFile buffer file open for writing
|
||||
* @param newDatabaseId database ID to be forced for new database or null to generate
|
||||
* new database ID
|
||||
* @param associateWithNewFile if true the outFile will be associated with this DBHandle as the
|
||||
* current source file, if false no change will be made to this DBHandle's state and the outFile
|
||||
* will be written and set as read-only. The caller is responsbile for disposing the outFile if
|
||||
* this parameter is false.
|
||||
* @param monitor progress monitor
|
||||
* @throws IOException if IO error occurs
|
||||
* @throws CancelledException if monitor cancels operation
|
||||
*/
|
||||
protected synchronized void saveAs(BufferFile outFile, Long newDatabaseId, TaskMonitor monitor)
|
||||
protected synchronized void saveAs(BufferFile outFile, Long newDatabaseId,
|
||||
boolean associateWithNewFile, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
|
||||
if (txStarted) {
|
||||
|
@ -704,7 +709,7 @@ public class DBHandle {
|
|||
endTransaction(txId, true); // saved file may be corrupt on IOException
|
||||
}
|
||||
|
||||
bufferMgr.saveAs(outFile, true, monitor);
|
||||
bufferMgr.saveAs(outFile, associateWithNewFile, monitor);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -23,8 +23,9 @@ import java.util.Random;
|
|||
|
||||
import org.junit.Assert;
|
||||
|
||||
import db.buffers.BufferFileManager;
|
||||
import db.buffers.DummyBufferFileMgr;
|
||||
import db.buffers.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -803,6 +804,30 @@ public class DBTestUtils {
|
|||
static BufferFileManager getBufferFileManager(File dir, String dbName) {
|
||||
return new DummyBufferFileMgr(dir, dbName, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone a DBHandle backed by a new temporary source buffer file.
|
||||
* The specified dbh will remain associated with its original source buffer file.
|
||||
* @param dbh DBHandle to clone
|
||||
* @return new DBhandle
|
||||
* @throws IOException if a file IO error occurs
|
||||
*/
|
||||
public static DBHandle cloneDbHandle(DBHandle dbh) throws IOException {
|
||||
|
||||
try {
|
||||
File tmpFile = File.createTempFile("tmp", ".db");
|
||||
tmpFile.delete();
|
||||
|
||||
LocalBufferFile bf = new LocalBufferFile(tmpFile, dbh.getBufferSize());
|
||||
dbh.saveAs(bf, dbh.getDatabaseId(), false, TaskMonitor.DUMMY);
|
||||
tmpFile.deleteOnExit();
|
||||
|
||||
return new DBHandle(bf);
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
throw new IOException(e); // unexpected
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class DuplicateKeyException extends Exception {
|
||||
|
|
|
@ -92,6 +92,11 @@ public class FloatingPointPrecisionSettingsDefinition implements EnumSettingsDef
|
|||
return PRECISION_DIGITS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStorageKey() {
|
||||
return PRECISION_DIGITS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Selects the number of digits of precision to display";
|
||||
|
|
|
@ -114,6 +114,11 @@ public class FormatSettingsDefinition implements EnumSettingsDefinition {
|
|||
return "Format";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStorageKey() {
|
||||
return FORMAT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Selects the display format";
|
||||
|
|
|
@ -113,6 +113,11 @@ public class IntegerSignednessFormattingModeSettingsDefinition implements EnumSe
|
|||
return "Signedness Mode";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStorageKey() {
|
||||
return SIGN_FORMAT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Selects the display mode for signed values";
|
||||
|
|
|
@ -80,7 +80,7 @@ public class JavaEnumSettingsDefinition<T extends Enum<T>> implements EnumSettin
|
|||
* @return Enum<T> value, or the specified defaultValueOveride if not present.
|
||||
*/
|
||||
public T getEnumValue(Settings settings, T defaultValueOverride) {
|
||||
Long lvalue = settings.getLong(getSettingName());
|
||||
Long lvalue = settings.getLong(settingName);
|
||||
if (lvalue == null) {
|
||||
return defaultValueOverride;
|
||||
}
|
||||
|
@ -126,38 +126,34 @@ public class JavaEnumSettingsDefinition<T extends Enum<T>> implements EnumSettin
|
|||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of this setting as it is stored in a {@link Settings} object.
|
||||
*
|
||||
* @return String name.
|
||||
*/
|
||||
public String getSettingName() {
|
||||
return settingName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasValue(Settings setting) {
|
||||
return setting.getValue(getSettingName()) != null;
|
||||
return setting.getValue(settingName) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
public final String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
public final String getStorageKey() {
|
||||
return settingName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear(Settings settings) {
|
||||
settings.clearSetting(getSettingName());
|
||||
settings.clearSetting(settingName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copySetting(Settings srcSettings, Settings destSettings) {
|
||||
Long l = srcSettings.getLong(getSettingName());
|
||||
Long l = srcSettings.getLong(settingName);
|
||||
if (l == null) {
|
||||
clear(destSettings);
|
||||
}
|
||||
|
@ -168,7 +164,7 @@ public class JavaEnumSettingsDefinition<T extends Enum<T>> implements EnumSettin
|
|||
|
||||
@Override
|
||||
public int getChoice(Settings settings) {
|
||||
Long lvalue = settings.getLong(getSettingName());
|
||||
Long lvalue = settings.getLong(settingName);
|
||||
|
||||
int value = (lvalue != null) ? (int) (long) lvalue : defaultValue.ordinal();
|
||||
return Math.min(Math.max(value, 0), values.length - 1);
|
||||
|
@ -181,7 +177,7 @@ public class JavaEnumSettingsDefinition<T extends Enum<T>> implements EnumSettin
|
|||
|
||||
@Override
|
||||
public void setChoice(Settings settings, int value) {
|
||||
settings.setLong(getSettingName(), value);
|
||||
settings.setLong(settingName, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -22,6 +22,14 @@ package ghidra.docking.settings;
|
|||
*/
|
||||
public interface Settings {
|
||||
|
||||
/**
|
||||
* Determine if a settings change corresponding to the specified
|
||||
* settingsDefinition is permitted.
|
||||
* @param settingsDefinition settings definition
|
||||
* @return true if change permitted else false
|
||||
*/
|
||||
boolean isChangeAllowed(SettingsDefinition settingsDefinition);
|
||||
|
||||
/**
|
||||
* Gets the Long value associated with the given name
|
||||
* @param name the key used to retrieve a value
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package ghidra.docking.settings;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
|
@ -26,8 +27,7 @@ public interface SettingsDefinition {
|
|||
|
||||
/**
|
||||
* Create a new list of {@link SettingsDefinition}s by concat'ing a base list with
|
||||
* a var-arg'ish additional list of setting defs.
|
||||
*
|
||||
* a var-arg'ish additional list of setting defs. Any additional duplicates are discarded.
|
||||
* @param settings List of settings defs.
|
||||
* @param additional More settings defs to add
|
||||
* @return new array with all the settings defs joined together.
|
||||
|
@ -40,11 +40,14 @@ public interface SettingsDefinition {
|
|||
if (settings == null) {
|
||||
return additional;
|
||||
}
|
||||
|
||||
SettingsDefinition[] result = new SettingsDefinition[settings.length + additional.length];
|
||||
System.arraycopy(settings, 0, result, 0, settings.length);
|
||||
System.arraycopy(additional, 0, result, settings.length, additional.length);
|
||||
return result;
|
||||
ArrayList<SettingsDefinition> list = new ArrayList<>();
|
||||
list.addAll(Arrays.asList(settings));
|
||||
for (SettingsDefinition def : additional) {
|
||||
if (!list.contains(def)) {
|
||||
list.add(def);
|
||||
}
|
||||
}
|
||||
return list.toArray(new SettingsDefinition[list.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -81,11 +84,17 @@ public interface SettingsDefinition {
|
|||
public String getValueString(Settings settings);
|
||||
|
||||
/**
|
||||
* Returns the name of this SettingsDefinition
|
||||
* Returns the display name of this SettingsDefinition
|
||||
* @return display name for setting
|
||||
*/
|
||||
public String getName();
|
||||
|
||||
/**
|
||||
* Get the {@link Settings} key which is used when storing a key/value entry.
|
||||
* @return settings storage key
|
||||
*/
|
||||
String getStorageKey();
|
||||
|
||||
/**
|
||||
* Returns a description of this settings definition
|
||||
* @return setting description
|
||||
|
|
|
@ -65,31 +65,19 @@ public class SettingsImpl implements Settings, Serializable {
|
|||
}
|
||||
|
||||
/**
|
||||
* Check for immutable settings and log error of modification not permitted
|
||||
* @param type setting type or null
|
||||
* @param name setting name or null
|
||||
* @return true if change permitted
|
||||
* Construct a new SettingsImpl object. If settings object is specified this
|
||||
* settings will copy all name/value pairs and underlying defaults.
|
||||
* @param settings the settings object to copy
|
||||
*/
|
||||
private boolean checkSetting(String type, String name) {
|
||||
if (immutable) {
|
||||
String typeStr = "";
|
||||
if (type != null) {
|
||||
typeStr = type + " ";
|
||||
public SettingsImpl(Settings settings) {
|
||||
this();
|
||||
if (settings != null) {
|
||||
String[] names = settings.getNames();
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
map.put(names[i], settings.getValue(names[i]));
|
||||
}
|
||||
String nameStr = ": " + name;
|
||||
if (name == null) {
|
||||
nameStr = "s";
|
||||
}
|
||||
Msg.warn(SettingsImpl.class,
|
||||
"Ignored invalid attempt to modify immutable " + typeStr + "component setting" +
|
||||
nameStr);
|
||||
return false;
|
||||
defaultSettings = settings.getDefaultSettings();
|
||||
}
|
||||
if (allowedSettingPredicate != null && !allowedSettingPredicate.apply(name)) {
|
||||
Msg.warn(this, "Ignored disallowed setting '" + name + "'");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -113,20 +101,45 @@ public class SettingsImpl implements Settings, Serializable {
|
|||
this.changeSourceObj = changeSourceObj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new SettingsImpl object. If settings object is specified this
|
||||
* settings will copy all name/value pairs and underlying defaults.
|
||||
* @param settings the settings object to copy
|
||||
*/
|
||||
public SettingsImpl(Settings settings) {
|
||||
this();
|
||||
if (settings != null) {
|
||||
String[] names = settings.getNames();
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
map.put(names[i], settings.getValue(names[i]));
|
||||
}
|
||||
defaultSettings = settings.getDefaultSettings();
|
||||
@Override
|
||||
public boolean isChangeAllowed(SettingsDefinition settingsDefinition) {
|
||||
if (immutable) {
|
||||
return false;
|
||||
}
|
||||
if (allowedSettingPredicate != null &&
|
||||
!allowedSettingPredicate.apply(settingsDefinition.getStorageKey())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for immutable settings and log error of modification not permitted
|
||||
* @param type setting type or null
|
||||
* @param name setting name or null
|
||||
* @return true if change permitted
|
||||
*/
|
||||
private boolean checkSetting(String type, String name) {
|
||||
if (immutable) {
|
||||
String typeStr = "";
|
||||
if (type != null) {
|
||||
typeStr = type + " ";
|
||||
}
|
||||
String nameStr = ": " + name;
|
||||
if (name == null) {
|
||||
nameStr = "s";
|
||||
}
|
||||
Msg.warn(SettingsImpl.class,
|
||||
"Ignored invalid attempt to modify immutable " + typeStr + "component setting" +
|
||||
nameStr);
|
||||
return false;
|
||||
}
|
||||
if (name != null && allowedSettingPredicate != null &&
|
||||
!allowedSettingPredicate.apply(name)) {
|
||||
Msg.warn(this, "Ignored disallowed setting '" + name + "'");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -82,9 +82,10 @@ public class PackedDBHandle extends DBHandle {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void saveAs(BufferFile outFile, Long newDatabaseId, TaskMonitor monitor)
|
||||
protected synchronized void saveAs(BufferFile outFile, Long newDatabaseId,
|
||||
boolean associateWithNewFile, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
super.saveAs(outFile, newDatabaseId, monitor);
|
||||
super.saveAs(outFile, newDatabaseId, associateWithNewFile, monitor);
|
||||
if (pdb != null) {
|
||||
pdb.dispose();
|
||||
pdb = null;
|
||||
|
|
|
@ -179,7 +179,7 @@ public class PackedDatabase extends Database {
|
|||
|
||||
LocalManagedBufferFile bfile = new LocalManagedBufferFile(dbHandle.getBufferSize(),
|
||||
bfMgr, FolderItem.DEFAULT_CHECKOUT_ID);
|
||||
dbHandle.saveAs(bfile, newDatabaseId, monitor);
|
||||
dbHandle.saveAs(bfile, newDatabaseId, true, monitor);
|
||||
packDatabase(monitor);
|
||||
addInstance(this);
|
||||
success = true;
|
||||
|
|
|
@ -18,6 +18,7 @@ package ghidra.app.util;
|
|||
import java.util.*;
|
||||
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.docking.settings.SettingsDefinition;
|
||||
import ghidra.program.database.ProgramDB;
|
||||
import ghidra.program.database.data.ProgramDataTypeManager;
|
||||
import ghidra.program.model.address.Address;
|
||||
|
@ -228,7 +229,12 @@ public class PseudoData extends PseudoCodeUnit implements Data {
|
|||
|
||||
@Override
|
||||
public Long getLong(String name) {
|
||||
return null;
|
||||
return getDefaultSettings().getLong(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChangeAllowed(SettingsDefinition settingsDefinition) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -238,15 +244,12 @@ public class PseudoData extends PseudoCodeUnit implements Data {
|
|||
|
||||
@Override
|
||||
public String getString(String name) {
|
||||
return null;
|
||||
return getDefaultSettings().getString(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(String name) {
|
||||
if (baseDataType != null) {
|
||||
return baseDataType.getValue(this, this, length);
|
||||
}
|
||||
return null;
|
||||
return getDefaultSettings().getValue(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -369,41 +372,6 @@ public class PseudoData extends PseudoCodeUnit implements Data {
|
|||
return null;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @see ghidra.program.model.listing.Data#getComponents()
|
||||
// */
|
||||
// public Data[] getComponents() {
|
||||
// if (length < dataType.getLength()) {
|
||||
// return null;
|
||||
// }
|
||||
// Data[] retData = EMPTY_COMPONENTS;
|
||||
// if (baseDataType instanceof Composite) {
|
||||
// Composite composite = (Composite)baseDataType;
|
||||
// int n = composite.getNumComponents();
|
||||
// retData = new Data[n];
|
||||
// for(int i=0;i<n;i++) {
|
||||
// retData[i] = getComponent(i);
|
||||
// }
|
||||
// }
|
||||
// else if (baseDataType instanceof Array) {
|
||||
// Array array = (Array)baseDataType;
|
||||
// int n = array.getNumElements();
|
||||
// retData = new Data[n];
|
||||
// for(int i=0;i<n;i++) {
|
||||
// retData[i] = getComponent(i);
|
||||
// }
|
||||
// }
|
||||
// else if (baseDataType instanceof DynamicDataType) {
|
||||
// DynamicDataType ddt = (DynamicDataType)baseDataType;
|
||||
// int n = ddt.getNumComponents(this);
|
||||
// retData = new Data[n];
|
||||
// for(int i=0;i<n;i++) {
|
||||
// retData[i] = getComponent(i);
|
||||
// }
|
||||
// }
|
||||
// return retData;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public DataType getDataType() {
|
||||
return dataType;
|
||||
|
@ -542,7 +510,7 @@ public class PseudoData extends PseudoCodeUnit implements Data {
|
|||
if (dataMgr == null) {
|
||||
return true;
|
||||
}
|
||||
return dataMgr.isEmptySetting(address);
|
||||
return dataMgr.isEmptySetting(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -38,7 +38,6 @@ class PseudoDataComponent extends PseudoData {
|
|||
private int indexInParent;
|
||||
private int offset;
|
||||
private int[] path;
|
||||
private Settings defaultSettings;
|
||||
|
||||
PseudoDataComponent(Program program, Address address, PseudoData parent,
|
||||
DataTypeComponent component, MemBuffer memBuffer)
|
||||
|
@ -170,60 +169,6 @@ class PseudoDataComponent extends PseudoData {
|
|||
return super.equals(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getLong(String name) {
|
||||
if (dataMgr == null) {
|
||||
return null;
|
||||
}
|
||||
Long value = dataMgr.getLongSettingsValue(address, name);
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
if (component == null) {
|
||||
return null;
|
||||
}
|
||||
if (defaultSettings == null) {
|
||||
defaultSettings = component.getDefaultSettings();
|
||||
}
|
||||
return defaultSettings.getLong(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString(String name) {
|
||||
if (dataMgr == null) {
|
||||
return null;
|
||||
}
|
||||
String value = dataMgr.getStringSettingsValue(address, name);
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
if (component == null) {
|
||||
return null;
|
||||
}
|
||||
if (defaultSettings == null) {
|
||||
defaultSettings = component.getDefaultSettings();
|
||||
}
|
||||
return defaultSettings.getString(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(String name) {
|
||||
if (dataMgr == null) {
|
||||
return null;
|
||||
}
|
||||
Object value = dataMgr.getSettings(address, name);
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
if (component == null) {
|
||||
return null;
|
||||
}
|
||||
if (defaultSettings == null) {
|
||||
defaultSettings = component.getDefaultSettings();
|
||||
}
|
||||
return defaultSettings.getValue(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized String getComment(int commentType) {
|
||||
String cmt = super.getComment(commentType);
|
||||
|
@ -238,7 +183,7 @@ class PseudoDataComponent extends PseudoData {
|
|||
if (component != null) {
|
||||
return component.getDefaultSettings();
|
||||
}
|
||||
return dataType.getDefaultSettings();
|
||||
return super.getDefaultSettings();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -283,12 +283,4 @@ class DataComponent extends DataDB {
|
|||
return super.getDefaultSettings();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Address getDataSettingsAddress() {
|
||||
if (parent.getBaseDataType() instanceof Array) {
|
||||
return parent.getDataSettingsAddress();
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -373,17 +373,22 @@ class DataDB extends CodeUnitDB implements Data {
|
|||
return hasMutability(MutabilitySettingsDefinition.VOLATILE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChangeAllowed(SettingsDefinition settingsDefinition) {
|
||||
refreshIfNeeded();
|
||||
return dataMgr.isChangeAllowed(this, settingsDefinition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearSetting(String name) {
|
||||
refreshIfNeeded();
|
||||
Address cuAddr = getDataSettingsAddress();
|
||||
dataMgr.clearSetting(cuAddr, name);
|
||||
dataMgr.clearSetting(this, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getLong(String name) {
|
||||
refreshIfNeeded();
|
||||
Long value = dataMgr.getLongSettingsValue(getDataSettingsAddress(), name);
|
||||
Long value = dataMgr.getLongSettingsValue(this, name);
|
||||
if (value == null) {
|
||||
value = getDefaultSettings().getLong(name);
|
||||
}
|
||||
|
@ -393,13 +398,13 @@ class DataDB extends CodeUnitDB implements Data {
|
|||
@Override
|
||||
public String[] getNames() {
|
||||
refreshIfNeeded();
|
||||
return dataMgr.getInstanceSettingsNames(getDataSettingsAddress());
|
||||
return dataMgr.getInstanceSettingsNames(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString(String name) {
|
||||
refreshIfNeeded();
|
||||
String value = dataMgr.getStringSettingsValue(getDataSettingsAddress(), name);
|
||||
String value = dataMgr.getStringSettingsValue(this, name);
|
||||
if (value == null) {
|
||||
value = getDefaultSettings().getString(name);
|
||||
}
|
||||
|
@ -409,7 +414,7 @@ class DataDB extends CodeUnitDB implements Data {
|
|||
@Override
|
||||
public Object getValue(String name) {
|
||||
refreshIfNeeded();
|
||||
Object value = dataMgr.getSettings(getDataSettingsAddress(), name);
|
||||
Object value = dataMgr.getSettings(this, name);
|
||||
if (value == null) {
|
||||
value = getDefaultSettings().getValue(name);
|
||||
}
|
||||
|
@ -419,22 +424,19 @@ class DataDB extends CodeUnitDB implements Data {
|
|||
@Override
|
||||
public void setLong(String name, long value) {
|
||||
refreshIfNeeded();
|
||||
Address cuAddr = getDataSettingsAddress();
|
||||
dataMgr.setLongSettingsValue(cuAddr, name, value);
|
||||
dataMgr.setLongSettingsValue(this, name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setString(String name, String value) {
|
||||
refreshIfNeeded();
|
||||
Address cuAddr = getDataSettingsAddress();
|
||||
dataMgr.setStringSettingsValue(cuAddr, name, value);
|
||||
dataMgr.setStringSettingsValue(this, name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(String name, Object value) {
|
||||
refreshIfNeeded();
|
||||
Address cuAddr = getDataSettingsAddress();
|
||||
dataMgr.setSettings(cuAddr, name, value);
|
||||
dataMgr.setSettings(this, name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -758,14 +760,13 @@ class DataDB extends CodeUnitDB implements Data {
|
|||
@Override
|
||||
public void clearAllSettings() {
|
||||
refreshIfNeeded();
|
||||
Address cuAddr = getDataSettingsAddress();
|
||||
dataMgr.clearAllSettings(cuAddr);
|
||||
dataMgr.clearAllSettings(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
refreshIfNeeded();
|
||||
return dataMgr.isEmptySetting(getDataSettingsAddress());
|
||||
return dataMgr.isEmptySetting(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -789,7 +790,4 @@ class DataDB extends CodeUnitDB implements Data {
|
|||
return dataType.getDefaultSettings();
|
||||
}
|
||||
|
||||
protected Address getDataSettingsAddress() {
|
||||
return address;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,8 +18,7 @@ package ghidra.program.database.data;
|
|||
import java.io.IOException;
|
||||
|
||||
import db.DBRecord;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.docking.settings.SettingsImpl;
|
||||
import ghidra.docking.settings.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.SystemUtilities;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
@ -433,6 +432,19 @@ class DataTypeComponentDB implements InternalDataTypeComponent {
|
|||
dataMgr.dataTypeChanged(getParent(), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChangeAllowed(SettingsDefinition settingsDefinition) {
|
||||
if (settingsDefinition instanceof TypeDefSettingsDefinition) {
|
||||
return false;
|
||||
}
|
||||
for (SettingsDefinition def : getDataType().getSettingsDefinitions()) {
|
||||
if (def.equals(settingsDefinition)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getLong(String name) {
|
||||
SettingDB settingDB = dataMgr.getSetting(record.getKey(), name);
|
||||
|
|
|
@ -26,6 +26,8 @@ import db.*;
|
|||
import db.util.ErrorHandler;
|
||||
import generic.jar.ResourceFile;
|
||||
import ghidra.app.plugin.core.datamgr.archive.BuiltInSourceArchive;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.docking.settings.SettingsDefinition;
|
||||
import ghidra.framework.store.db.PackedDBHandle;
|
||||
import ghidra.framework.store.db.PackedDatabase;
|
||||
import ghidra.graph.*;
|
||||
|
@ -63,8 +65,9 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
*
|
||||
* Due to the frequent use of read-only mode for certain archives, read-only
|
||||
* mode must always be allowed when opening older versions.
|
||||
* - version 1 - legacy prior to overall DTM versioning (not stored)
|
||||
* 12-Jan-2022 - version 2 - introduced DataTypeManager data map table and overall DTM version
|
||||
* - version 1 - Legacy prior to overall DTM versioning (not stored)
|
||||
* 12-Jan-2022 - version 2 - Introduced DataTypeManager data map table and overall DTM version.
|
||||
* Also added typedef flags and auto-naming support.
|
||||
*/
|
||||
static final int DB_VERSION = 2;
|
||||
|
||||
|
@ -869,7 +872,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
return name;
|
||||
}
|
||||
|
||||
public String getUniqueName(CategoryPath path1, CategoryPath path2, String baseName) {
|
||||
String getUniqueName(CategoryPath path1, CategoryPath path2, String baseName) {
|
||||
int pos = baseName.lastIndexOf('_');
|
||||
int oneUpNumber = 0;
|
||||
String name = baseName;
|
||||
|
@ -893,6 +896,9 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
|
||||
@Override
|
||||
public Category getCategory(CategoryPath path) {
|
||||
if (path == null) {
|
||||
return null;
|
||||
}
|
||||
if (path.equals(CategoryPath.ROOT)) {
|
||||
return root;
|
||||
}
|
||||
|
@ -2166,7 +2172,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
|
||||
@Override
|
||||
public DataType getDataType(CategoryPath path, String name) {
|
||||
if (path.equals(DataType.DEFAULT.getCategoryPath()) &&
|
||||
if (CategoryPath.ROOT.equals(path) &&
|
||||
name.equals(DataType.DEFAULT.getName())) {
|
||||
return DataType.DEFAULT;
|
||||
}
|
||||
|
@ -2279,16 +2285,13 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
private DataType getBuiltInDataType(long dataTypeID, DBRecord record) {
|
||||
lock.acquire();
|
||||
try {
|
||||
Long key = dataTypeID;
|
||||
DataType dt = builtInMap.get(key);
|
||||
|
||||
DataType dt = builtInMap.get(dataTypeID);
|
||||
if (dt != null) {
|
||||
return dt;
|
||||
}
|
||||
|
||||
if (record == null) {
|
||||
record = builtinAdapter.getRecord(dataTypeID);
|
||||
|
||||
if (record == null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -2301,7 +2304,6 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
String name = record.getString(BuiltinDBAdapter.BUILT_IN_NAME_COL);
|
||||
try { // TODO: !! Can we look for alternate constructor which takes DTM argument
|
||||
Class<?> c;
|
||||
|
||||
try {
|
||||
c = Class.forName(classPath);
|
||||
}
|
||||
|
@ -2322,18 +2324,41 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
BuiltInDataType bdt = (BuiltInDataType) c.getDeclaredConstructor().newInstance();
|
||||
bdt.setName(name);
|
||||
bdt.setCategoryPath(catPath);
|
||||
bdt = (BuiltInDataType) bdt.clone(this);
|
||||
if (allowsDefaultBuiltInSettings() && bdt.getSettingsDefinitions().length != 0) {
|
||||
bdt.setDefaultSettings(new DataTypeSettingsDB(this, bdt, dataTypeID));
|
||||
|
||||
final BuiltInDataType builtInDt = (BuiltInDataType) bdt.clone(this);
|
||||
|
||||
// check for prior instantiation with different id
|
||||
Long id = builtIn2IdMap.get(builtInDt);
|
||||
if (id != null) {
|
||||
DataType datatype = builtInMap.get(id);
|
||||
if (datatype != null) {
|
||||
builtInMap.put(dataTypeID, datatype);
|
||||
return datatype;
|
||||
}
|
||||
}
|
||||
dt = bdt;
|
||||
|
||||
if (allowsDefaultBuiltInSettings() &&
|
||||
builtInDt.getSettingsDefinitions().length != 0) {
|
||||
DataTypeSettingsDB settings =
|
||||
new DataTypeSettingsDB(this, builtInDt, dataTypeID);
|
||||
if (builtInDt instanceof TypeDef) {
|
||||
// Copy default immutable builtin typedef settings
|
||||
Settings typedefSettings = builtInDt.getDefaultSettings();
|
||||
for (String n : typedefSettings.getNames()) {
|
||||
settings.setValue(n, typedefSettings.getValue(n));
|
||||
}
|
||||
}
|
||||
settings.setAllowedSettingPredicate(n -> isBuiltInSettingAllowed(builtInDt, n));
|
||||
builtInDt.setDefaultSettings(settings);
|
||||
}
|
||||
dt = builtInDt;
|
||||
}
|
||||
catch (Exception e) {
|
||||
Msg.error(this, e);
|
||||
dt = new MissingBuiltInDataType(catPath, name, classPath, this);
|
||||
}
|
||||
builtInMap.put(key, dt);
|
||||
builtIn2IdMap.put(dt, key);
|
||||
builtInMap.put(dataTypeID, dt);
|
||||
builtIn2IdMap.put(dt, dataTypeID);
|
||||
return dt;
|
||||
}
|
||||
catch (IOException e) {
|
||||
|
@ -2345,6 +2370,18 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
return null;
|
||||
}
|
||||
|
||||
private boolean isBuiltInSettingAllowed(BuiltInDataType bdt, String settingName) {
|
||||
SettingsDefinition def = null;
|
||||
for (SettingsDefinition sd : bdt.getSettingsDefinitions()) {
|
||||
if (sd.getStorageKey().equals(settingName)) {
|
||||
def = sd;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// restrict to non-TypeDefSettingsDefinitions which are defined for the datatype
|
||||
return def != null && !(def instanceof TypeDefSettingsDefinition);
|
||||
}
|
||||
|
||||
private Enum getEnumDataType(long dataTypeID, DBRecord record) {
|
||||
lock.acquire();
|
||||
try {
|
||||
|
@ -2526,6 +2563,10 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
int len = ptr.hasLanguageDependantLength() ? -1 : ptr.getLength();
|
||||
newDataType = createPointer(ptr.getDataType(), cat, (byte) len, handler);
|
||||
}
|
||||
else if (dt instanceof BuiltInDataType) {
|
||||
BuiltInDataType builtInDataType = (BuiltInDataType) dt;
|
||||
newDataType = createBuiltIn(builtInDataType, cat);
|
||||
}
|
||||
else if (dt instanceof StructureInternal) {
|
||||
StructureInternal structure = (StructureInternal) dt;
|
||||
newDataType = createStructure(structure, name, cat, sourceArchiveIdValue,
|
||||
|
@ -2550,10 +2591,6 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
newDataType = createFunctionDefinition(funDef, name, cat, sourceArchiveIdValue,
|
||||
id.getValue());
|
||||
}
|
||||
else if (dt instanceof BuiltInDataType) {
|
||||
BuiltInDataType builtInDataType = (BuiltInDataType) dt;
|
||||
newDataType = createBuiltIn(builtInDataType, cat);
|
||||
}
|
||||
else if (dt instanceof MissingBuiltInDataType) {
|
||||
MissingBuiltInDataType missingBuiltInDataType = (MissingBuiltInDataType) dt;
|
||||
newDataType = createMissingBuiltIn(missingBuiltInDataType, cat);
|
||||
|
@ -2621,7 +2658,13 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
throw new IllegalArgumentException("Data type must have a valid name");
|
||||
}
|
||||
DataType dataType = resolve(typedef.getDataType(), getDependencyConflictHandler());
|
||||
DBRecord record = typedefAdapter.createRecord(getID(dataType), name, cat.getID(),
|
||||
boolean isAutoNamed = typedef.isAutoNamed();
|
||||
short flags = 0;
|
||||
if (isAutoNamed) {
|
||||
flags = (short) TypedefDBAdapter.TYPEDEF_FLAG_AUTONAME;
|
||||
cat = getCategory(dataType.getCategoryPath()); // force category
|
||||
}
|
||||
DBRecord record = typedefAdapter.createRecord(getID(dataType), name, flags, cat.getID(),
|
||||
sourceArchiveIdValue, universalIdValue, typedef.getLastChangeTime());
|
||||
TypedefDB typedefDB = new TypedefDB(this, dtCache, typedefAdapter, record);
|
||||
|
||||
|
@ -2631,6 +2674,8 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
TypedefDataType.copyTypeDefSettings(typedef, typedefDB, false);
|
||||
settings.setLock(wasLocked);
|
||||
|
||||
typedefDB.updateAutoName(false);
|
||||
|
||||
dataType.addParent(typedefDB);
|
||||
return typedefDB;
|
||||
}
|
||||
|
@ -3047,8 +3092,9 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
* @param oldCatId the old category's record id
|
||||
*/
|
||||
void dataTypeCategoryPathChanged(DataTypeDB dt, CategoryPath oldPath, long oldCatId) {
|
||||
if (!(dt instanceof Array) && !(dt instanceof Pointer)) {
|
||||
try {
|
||||
|
||||
try {
|
||||
if (!(dt instanceof Array) && !(dt instanceof Pointer)) {
|
||||
for (Field arrayId : arrayAdapter.getRecordIdsInCategory(oldCatId)) {
|
||||
long id = arrayId.getLongValue();
|
||||
DBRecord rec = arrayAdapter.getRecord(id);
|
||||
|
@ -3062,10 +3108,18 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
ptr.updatePath(dt);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
dbError(e);
|
||||
|
||||
// only affects those with auto-naming which must follow category change
|
||||
for (Field ptrId : typedefAdapter.getRecordIdsInCategory(oldCatId)) {
|
||||
long id = ptrId.getLongValue();
|
||||
DBRecord rec = typedefAdapter.getRecord(id);
|
||||
TypedefDB td = (TypedefDB) getDataType(id, rec);
|
||||
td.updatePath(dt);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
dbError(e);
|
||||
}
|
||||
|
||||
dataTypeMoved(dt, new DataTypePath(oldPath, dt.getName()), dt.getDataTypePath());
|
||||
}
|
||||
|
@ -3341,7 +3395,12 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
return creatingDataType != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Notification when data type is changed.
|
||||
* @param dt data type that is changed
|
||||
* @param isAutoChange true if change was an automatic change in response to
|
||||
* another datatype's change (e.g., size, alignment).
|
||||
*/
|
||||
public void dataTypeChanged(DataType dt, boolean isAutoChange) {
|
||||
if (dt instanceof Enum) {
|
||||
enumValueMap = null;
|
||||
|
@ -3353,6 +3412,22 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
defaultListener.dataTypeChanged(this, dt.getDataTypePath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification when data type settings have changed.
|
||||
* @param dt data type that is changed
|
||||
*/
|
||||
public void dataTypeSettingsChanged(DataType dt) {
|
||||
if (dt instanceof TypedefDB) {
|
||||
TypedefDB td = (TypedefDB) dt;
|
||||
td.updateAutoName(true);
|
||||
if (creatingDataType == 0) {
|
||||
td.setLastChangeTime(System.currentTimeMillis());
|
||||
setDirtyFlag(dt);
|
||||
}
|
||||
}
|
||||
defaultListener.dataTypeChanged(this, dt.getDataTypePath());
|
||||
}
|
||||
|
||||
protected void dataTypeAdded(DataType newDt, DataType originalDataType) {
|
||||
CategoryDB category = (CategoryDB) getCategory(newDt.getCategoryPath());
|
||||
category.dataTypeAdded(newDt);
|
||||
|
|
|
@ -17,8 +17,7 @@ package ghidra.program.database.data;
|
|||
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.docking.settings.SettingsImpl;
|
||||
import ghidra.docking.settings.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
|
@ -78,6 +77,18 @@ class DataTypeSettingsDB implements Settings {
|
|||
return wasLocked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChangeAllowed(SettingsDefinition settingsDefinition) {
|
||||
if (locked) {
|
||||
return false;
|
||||
}
|
||||
if (allowedSettingPredicate != null &&
|
||||
!allowedSettingPredicate.apply(settingsDefinition.getStorageKey())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set predicate for settings modification
|
||||
* @param allowedSettingPredicate callback for checking an allowed setting modification
|
||||
|
@ -107,7 +118,8 @@ class DataTypeSettingsDB implements Settings {
|
|||
nameStr);
|
||||
return false;
|
||||
}
|
||||
if (allowedSettingPredicate != null && !allowedSettingPredicate.apply(name)) {
|
||||
if (name != null && allowedSettingPredicate != null &&
|
||||
!allowedSettingPredicate.apply(name)) {
|
||||
Msg.warn(this, "Ignored disallowed setting '" + name + "'");
|
||||
return false;
|
||||
}
|
||||
|
@ -118,7 +130,7 @@ class DataTypeSettingsDB implements Settings {
|
|||
// NOTE: Merge currently only supports TypeDefDB default settings changes which correspond
|
||||
// to TypeDefSettingsDefinition established by the base datatype
|
||||
// and does not consider DataTypeComponent default settings changes or other setting types.
|
||||
dataMgr.dataTypeChanged(dataType, false);
|
||||
dataMgr.dataTypeSettingsChanged(dataType);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -52,8 +52,8 @@ public class PointerTypedefInspector {
|
|||
* its default settings.
|
||||
* @param pointerTypeDef Pointer TypeDef
|
||||
* @param addrFactory target address factory
|
||||
* @return referenced address space or null if not applicable
|
||||
* or the space setting is not defined within the addrFactory.
|
||||
* @return referenced address space or null if not specified or address space
|
||||
* lookup fails.
|
||||
*/
|
||||
public static AddressSpace getPointerAddressSpace(TypeDef pointerTypeDef,
|
||||
AddressFactory addrFactory) {
|
||||
|
|
|
@ -20,11 +20,14 @@ import java.util.List;
|
|||
|
||||
import db.*;
|
||||
import db.util.ErrorHandler;
|
||||
import ghidra.docking.settings.SettingsDefinition;
|
||||
import ghidra.program.database.map.AddressMap;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.KeyRange;
|
||||
import ghidra.program.model.data.ProgramBasedDataTypeManager;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.Data;
|
||||
import ghidra.util.Lock;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.VersionException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
@ -91,22 +94,36 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
|
|||
abstract protected void dataSettingChanged(Address address);
|
||||
|
||||
@Override
|
||||
public boolean setLongSettingsValue(Address dataAddr, String name, long value) {
|
||||
return updateInstanceSettings(dataAddr, name, null, value);
|
||||
public boolean isChangeAllowed(Data data,
|
||||
SettingsDefinition settingsDefinition) {
|
||||
if (settingsDefinition instanceof TypeDefSettingsDefinition) {
|
||||
return false;
|
||||
}
|
||||
for (SettingsDefinition def : data.getDataType().getSettingsDefinitions()) {
|
||||
if (def.equals(settingsDefinition)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setStringSettingsValue(Address dataAddr, String name, String value) {
|
||||
return updateInstanceSettings(dataAddr, name, value, -1);
|
||||
public boolean setLongSettingsValue(Data data, String name, long value) {
|
||||
return updateInstanceSettings(data, name, null, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setSettings(Address dataAddr, String name, Object value) {
|
||||
public boolean setStringSettingsValue(Data data, String name, String value) {
|
||||
return updateInstanceSettings(data, name, value, -1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setSettings(Data data, String name, Object value) {
|
||||
if (value instanceof String) {
|
||||
return updateInstanceSettings(dataAddr, name, (String) value, -1);
|
||||
return updateInstanceSettings(data, name, (String) value, -1);
|
||||
}
|
||||
else if (isAllowedNumberType(value)) {
|
||||
return updateInstanceSettings(dataAddr, name, null, ((Number) value).longValue());
|
||||
return updateInstanceSettings(data, name, null, ((Number) value).longValue());
|
||||
}
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupportd Settings Value: " + (value == null ? "null" : value.getClass().getName()));
|
||||
|
@ -129,8 +146,8 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
|
|||
}
|
||||
|
||||
@Override
|
||||
public Long getLongSettingsValue(Address dataAddr, String name) {
|
||||
SettingDB settings = getSettingDB(dataAddr, name);
|
||||
public Long getLongSettingsValue(Data data, String name) {
|
||||
SettingDB settings = getSettingDB(data, name);
|
||||
if (settings != null) {
|
||||
return settings.getLongValue();
|
||||
}
|
||||
|
@ -138,8 +155,8 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getStringSettingsValue(Address dataAddr, String name) {
|
||||
SettingDB settings = getSettingDB(dataAddr, name);
|
||||
public String getStringSettingsValue(Data data, String name) {
|
||||
SettingDB settings = getSettingDB(data, name);
|
||||
if (settings != null) {
|
||||
return settings.getStringValue();
|
||||
}
|
||||
|
@ -147,21 +164,22 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object getSettings(Address dataAddr, String name) {
|
||||
Object obj = getStringSettingsValue(dataAddr, name);
|
||||
public Object getSettings(Data data, String name) {
|
||||
Object obj = getStringSettingsValue(data, name);
|
||||
if (obj != null) {
|
||||
return obj;
|
||||
}
|
||||
return getLongSettingsValue(dataAddr, name);
|
||||
return getLongSettingsValue(data, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean clearSetting(Address dataAddr, String name) {
|
||||
public boolean clearSetting(Data data, String name) {
|
||||
if (instanceSettingsAdapter == null) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
lock.acquire();
|
||||
try {
|
||||
Address dataAddr = getDataSettingsAddress(data);
|
||||
instanceSettingsCache.remove(dataAddr, name);
|
||||
long addr = addrMap.getKey(dataAddr, false);
|
||||
if (instanceSettingsAdapter.removeSettingsRecord(addr, name)) {
|
||||
|
@ -180,7 +198,7 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
|
|||
}
|
||||
|
||||
@Override
|
||||
public void clearAllSettings(Address dataAddr) {
|
||||
public void clearAllSettings(Data data) {
|
||||
if (instanceSettingsAdapter == null) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
@ -188,6 +206,7 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
|
|||
try {
|
||||
instanceSettingsCache.clear();
|
||||
boolean changed = false;
|
||||
Address dataAddr = getDataSettingsAddress(data);
|
||||
Field[] keys = instanceSettingsAdapter.getSettingsKeys(addrMap.getKey(dataAddr, false));
|
||||
for (Field key : keys) {
|
||||
instanceSettingsAdapter.removeSettingsRecord(key.getLongValue());
|
||||
|
@ -267,12 +286,13 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
|
|||
}
|
||||
|
||||
@Override
|
||||
public String[] getInstanceSettingsNames(Address dataAddr) {
|
||||
public String[] getInstanceSettingsNames(Data data) {
|
||||
if (instanceSettingsAdapter == null) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
lock.acquire();
|
||||
try {
|
||||
Address dataAddr = getDataSettingsAddress(data);
|
||||
return instanceSettingsAdapter.getSettingsNames(addrMap.getKey(dataAddr, false));
|
||||
}
|
||||
catch (IOException e) {
|
||||
|
@ -285,11 +305,12 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmptySetting(Address dataAddr) {
|
||||
public boolean isEmptySetting(Data data) {
|
||||
if (instanceSettingsAdapter == null) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
try {
|
||||
Address dataAddr = getDataSettingsAddress(data);
|
||||
return instanceSettingsAdapter
|
||||
.getSettingsKeys(addrMap.getKey(dataAddr, false)).length == 0;
|
||||
}
|
||||
|
@ -299,7 +320,7 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
|
|||
return true;
|
||||
}
|
||||
|
||||
private boolean updateInstanceSettings(Address dataAddr, String name, String strValue,
|
||||
private boolean updateInstanceSettings(Data data, String name, String strValue,
|
||||
long longValue) {
|
||||
|
||||
boolean wasChanged = false;
|
||||
|
@ -309,6 +330,10 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
|
|||
if (instanceSettingsAdapter == null) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
if (!checkSetting(data, name)) {
|
||||
return false;
|
||||
}
|
||||
Address dataAddr = getDataSettingsAddress(data);
|
||||
long addrKey = addrMap.getKey(dataAddr, true);
|
||||
DBRecord rec =
|
||||
instanceSettingsAdapter.updateSettingsRecord(addrKey, name, strValue, longValue);
|
||||
|
@ -330,12 +355,31 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
|
|||
return wasChanged;
|
||||
}
|
||||
|
||||
private SettingDB getSettingDB(Address dataAddr, String name) {
|
||||
private boolean checkSetting(Data data, String name) {
|
||||
SettingsDefinition settingsDefinition = null;
|
||||
for (SettingsDefinition def : data.getDataType().getSettingsDefinitions()) {
|
||||
if (def.getStorageKey().equals(name)) {
|
||||
settingsDefinition = def;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (settingsDefinition == null) {
|
||||
Msg.warn(this, "Ignored unrecognized setting '" + name + "'");
|
||||
return false;
|
||||
}
|
||||
if (settingsDefinition instanceof TypeDefSettingsDefinition) {
|
||||
Msg.warn(this, "Ignored disallowed instance setting '" + name + "'");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private SettingDB getSettingDB(Data data, String name) {
|
||||
lock.acquire();
|
||||
try {
|
||||
if (instanceSettingsAdapter == null) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
Address dataAddr = getDataSettingsAddress(data);
|
||||
SettingDB settings = instanceSettingsCache.get(dataAddr, name);
|
||||
if (settings != null) {
|
||||
return settings;
|
||||
|
@ -380,4 +424,15 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
|
|||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
private static Address getDataSettingsAddress(Data data) {
|
||||
Data parent = data.getParent();
|
||||
if (parent != null) {
|
||||
DataType dataType = parent.getDataType();
|
||||
if (dataType instanceof Array) {
|
||||
return getDataSettingsAddress(parent);
|
||||
}
|
||||
}
|
||||
return data.getAddress();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,8 +55,8 @@ class SettingsDBAdapterV1 extends SettingsDBAdapter {
|
|||
private Table settingsTable;
|
||||
private Table settingsNameTable;
|
||||
|
||||
private HashMap<Short, String> nameIndexMap = new HashMap<>();
|
||||
private HashMap<String, Short> nameStringMap = new HashMap<>();
|
||||
private HashMap<Short, String> nameIndexMap;
|
||||
private HashMap<String, Short> nameStringMap;
|
||||
|
||||
SettingsDBAdapterV1(String tableName, DBHandle handle, boolean create)
|
||||
throws VersionException, IOException {
|
||||
|
|
|
@ -24,6 +24,7 @@ import ghidra.program.database.DBObjectCache;
|
|||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
import ghidra.util.UniversalID;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
/**
|
||||
* Database implementation for a Typedef data type.
|
||||
|
@ -49,6 +50,73 @@ class TypedefDB extends DataTypeDB implements TypeDef {
|
|||
this.defaultSettings = null; // ensure lazy initialization
|
||||
}
|
||||
|
||||
private void setFlags(int flags) {
|
||||
record.setShortValue(TypedefDBAdapter.TYPEDEF_FLAGS_COL, (short) flags);
|
||||
}
|
||||
|
||||
private int getFlags() {
|
||||
return record.getShortValue(TypedefDBAdapter.TYPEDEF_FLAGS_COL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableAutoNaming() {
|
||||
if (isAutoNamed()) {
|
||||
return;
|
||||
}
|
||||
lock.acquire();
|
||||
try {
|
||||
checkDeleted();
|
||||
|
||||
String oldName = getName();
|
||||
|
||||
setFlags(getFlags() | TypedefDBAdapter.TYPEDEF_FLAG_AUTONAME);
|
||||
adapter.updateRecord(record, true);
|
||||
|
||||
// auto-named typedef follows category of associated datatype
|
||||
CategoryPath oldPath = getCategoryPath();
|
||||
CategoryPath currentPath = getDataType().getCategoryPath();
|
||||
|
||||
String newName = generateTypedefName(currentPath);
|
||||
record.setString(TypedefDBAdapter.TYPEDEF_NAME_COL, newName);
|
||||
adapter.updateRecord(record, true);
|
||||
refreshName();
|
||||
|
||||
if (!currentPath.equals(oldPath)) {
|
||||
// update category for typedef
|
||||
try {
|
||||
super.setCategoryPath(currentPath);
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
// should not happen
|
||||
}
|
||||
}
|
||||
|
||||
notifyNameChanged(oldName);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoNamed() {
|
||||
int flags = getFlags();
|
||||
if (isInvalid()) {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
flags = getFlags();
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
return (flags & TypedefDBAdapter.TYPEDEF_FLAG_AUTONAME) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long doGetCategoryID() {
|
||||
return record.getLongValue(TypedefDBAdapter.TYPEDEF_CAT_COL);
|
||||
|
@ -67,6 +135,7 @@ class TypedefDB extends DataTypeDB implements TypeDef {
|
|||
@Override
|
||||
protected void doSetNameRecord(String name) throws IOException {
|
||||
record.setString(TypedefDBAdapter.TYPEDEF_NAME_COL, name);
|
||||
setFlags(getFlags() & ~TypedefDBAdapter.TYPEDEF_FLAG_AUTONAME); // clear auto-name flag if name is set
|
||||
adapter.updateRecord(record, true);
|
||||
}
|
||||
|
||||
|
@ -165,19 +234,13 @@ class TypedefDB extends DataTypeDB implements TypeDef {
|
|||
}
|
||||
|
||||
@Override
|
||||
public DataType clone(DataTypeManager dtm) {
|
||||
TypedefDataType typeDef =
|
||||
new TypedefDataType(getCategoryPath(), getName(), getDataType(), getUniversalID(),
|
||||
getSourceArchive(), getLastChangeTime(), getLastChangeTimeInSourceArchive(), dtm);
|
||||
TypedefDataType.copyTypeDefSettings(this, typeDef, false);
|
||||
return typeDef;
|
||||
public TypeDef clone(DataTypeManager dtm) {
|
||||
return TypedefDataType.clone(this, dtm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType copy(DataTypeManager dtm) {
|
||||
TypedefDataType typeDef = new TypedefDataType(getCategoryPath(), getName(), getDataType(), dtm);
|
||||
TypedefDataType.copyTypeDefSettings(this, typeDef, false);
|
||||
return typeDef;
|
||||
public TypedefDataType copy(DataTypeManager dtm) {
|
||||
return TypedefDataType.copy(this, dtm);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -190,7 +253,12 @@ class TypedefDB extends DataTypeDB implements TypeDef {
|
|||
}
|
||||
TypeDef td = (TypeDef) obj;
|
||||
validate(lock);
|
||||
if (!DataTypeUtilities.equalsIgnoreConflict(getName(), td.getName())) {
|
||||
|
||||
boolean autoNamed = isAutoNamed();
|
||||
if (autoNamed != td.isAutoNamed()) {
|
||||
return false;
|
||||
}
|
||||
if (!autoNamed && !DataTypeUtilities.equalsIgnoreConflict(getName(), td.getName())) {
|
||||
return false;
|
||||
}
|
||||
if (!hasSameTypeDefSettings(td)) {
|
||||
|
@ -199,6 +267,13 @@ class TypedefDB extends DataTypeDB implements TypeDef {
|
|||
return DataTypeUtilities.isSameOrEquivalentDataType(getDataType(), td.getDataType());
|
||||
}
|
||||
|
||||
public void setCategoryPath(CategoryPath path) throws DuplicateNameException {
|
||||
if (isAutoNamed()) {
|
||||
return; // ignore category change if auto-naming enabled
|
||||
}
|
||||
super.setCategoryPath(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doSetCategoryPathRecord(long categoryID) throws IOException {
|
||||
record.setLongValue(TypedefDBAdapter.TYPEDEF_CAT_COL, categoryID);
|
||||
|
@ -251,7 +326,9 @@ class TypedefDB extends DataTypeDB implements TypeDef {
|
|||
|
||||
@Override
|
||||
public void dataTypeNameChanged(DataType dt, String oldName) {
|
||||
// ignore
|
||||
if (getDataType() == dt) {
|
||||
updateAutoName(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -330,6 +407,9 @@ class TypedefDB extends DataTypeDB implements TypeDef {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (isAutoNamed()) {
|
||||
return getName();
|
||||
}
|
||||
return "typedef " + this.getName() + " " + getDataType().getName();
|
||||
}
|
||||
|
||||
|
@ -440,10 +520,92 @@ class TypedefDB extends DataTypeDB implements TypeDef {
|
|||
TypeDef td = (TypeDef) dataType;
|
||||
dataTypeReplaced(getDataType(), td.getDataType());
|
||||
TypedefDataType.copyTypeDefSettings(td, this, true);
|
||||
// NOTE: as with the name, auto-name setting is left unchanged
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updatePath(DataTypeDB dt) {
|
||||
if (isAutoNamed() && dt == getDataType()) {
|
||||
// auto-named typedef follows category of associated datatype
|
||||
CategoryPath oldPath = getCategoryPath();
|
||||
CategoryPath currentPath = dt.getCategoryPath();
|
||||
if (!currentPath.equals(oldPath)) {
|
||||
try {
|
||||
boolean nameChanged = false;
|
||||
String oldName = getName();
|
||||
String newName = generateTypedefName(currentPath);
|
||||
if (!newName.equals(oldName)) {
|
||||
nameChanged = true;
|
||||
record.setString(TypedefDBAdapter.TYPEDEF_NAME_COL, newName);
|
||||
refreshName();
|
||||
}
|
||||
super.setCategoryPath(currentPath);
|
||||
if (nameChanged) {
|
||||
notifyNameChanged(oldName);
|
||||
}
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
// should not happen
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String generateTypedefName(CategoryPath path) {
|
||||
String newName = TypedefDataType.generateTypedefName(this);
|
||||
DataType dt = dataMgr.getDataType(path, newName);
|
||||
if (dt == null || dt == this) {
|
||||
return newName;
|
||||
}
|
||||
|
||||
String baseName = newName + DataType.CONFLICT_SUFFIX;
|
||||
newName = baseName;
|
||||
int count = 0;
|
||||
while (true) {
|
||||
dt = dataMgr.getDataType(path, newName);
|
||||
if (dt == null || dt == this) {
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
newName = baseName + count;
|
||||
}
|
||||
return newName;
|
||||
}
|
||||
|
||||
boolean updateAutoName(boolean notify) {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
|
||||
if (!isAutoNamed()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String oldName = getName();
|
||||
String newName = generateTypedefName(getCategoryPath());
|
||||
if (oldName.equals(newName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
record.setString(TypedefDBAdapter.TYPEDEF_NAME_COL, newName);
|
||||
adapter.updateRecord(record, false);
|
||||
refreshName();
|
||||
|
||||
if (notify) {
|
||||
notifyNameChanged(oldName);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,19 +28,23 @@ import ghidra.util.task.TaskMonitor;
|
|||
abstract class TypedefDBAdapter {
|
||||
|
||||
static final String TYPEDEF_TABLE_NAME = "Typedefs";
|
||||
static final Schema SCHEMA = TypedefDBAdapterV1.V1_SCHEMA;
|
||||
static final Schema SCHEMA = TypedefDBAdapterV2.V2_SCHEMA;
|
||||
|
||||
static final int TYPEDEF_DT_ID_COL = TypedefDBAdapterV1.V1_TYPEDEF_DT_ID_COL;
|
||||
static final int TYPEDEF_NAME_COL = TypedefDBAdapterV1.V1_TYPEDEF_NAME_COL;
|
||||
static final int TYPEDEF_CAT_COL = TypedefDBAdapterV1.V1_TYPEDEF_CAT_COL;
|
||||
static final int TYPEDEF_DT_ID_COL = TypedefDBAdapterV2.V2_TYPEDEF_DT_ID_COL;
|
||||
static final int TYPEDEF_FLAGS_COL = TypedefDBAdapterV2.V2_TYPEDEF_FLAGS_COL;
|
||||
static final int TYPEDEF_NAME_COL = TypedefDBAdapterV2.V2_TYPEDEF_NAME_COL;
|
||||
static final int TYPEDEF_CAT_COL = TypedefDBAdapterV2.V2_TYPEDEF_CAT_COL;
|
||||
static final int TYPEDEF_SOURCE_ARCHIVE_ID_COL =
|
||||
TypedefDBAdapterV1.V1_TYPEDEF_SOURCE_ARCHIVE_ID_COL;
|
||||
TypedefDBAdapterV2.V2_TYPEDEF_SOURCE_ARCHIVE_ID_COL;
|
||||
static final int TYPEDEF_UNIVERSAL_DT_ID_COL =
|
||||
TypedefDBAdapterV1.V1_TYPEDEF_UNIVERSAL_DT_ID_COL;
|
||||
TypedefDBAdapterV2.V2_TYPEDEF_UNIVERSAL_DT_ID_COL;
|
||||
static final int TYPEDEF_SOURCE_SYNC_TIME_COL =
|
||||
TypedefDBAdapterV1.V1_TYPEDEF_SOURCE_SYNC_TIME_COL;
|
||||
TypedefDBAdapterV2.V2_TYPEDEF_SOURCE_SYNC_TIME_COL;
|
||||
static final int TYPEDEF_LAST_CHANGE_TIME_COL =
|
||||
TypedefDBAdapterV1.V1_TYPEDEF_LAST_CHANGE_TIME_COL;
|
||||
TypedefDBAdapterV2.V2_TYPEDEF_LAST_CHANGE_TIME_COL;
|
||||
|
||||
// Typedef flags bits
|
||||
static final int TYPEDEF_FLAG_AUTONAME = 0x1;
|
||||
|
||||
/**
|
||||
* Gets an adapter for working with the Typedef data type database table. The adapter is based
|
||||
|
@ -55,7 +59,7 @@ abstract class TypedefDBAdapter {
|
|||
static TypedefDBAdapter getAdapter(DBHandle handle, int openMode, TaskMonitor monitor)
|
||||
throws VersionException, IOException {
|
||||
try {
|
||||
return new TypedefDBAdapterV1(handle, openMode == DBConstants.CREATE);
|
||||
return new TypedefDBAdapterV2(handle, openMode == DBConstants.CREATE);
|
||||
}
|
||||
catch (VersionException e) {
|
||||
if (!e.isUpgradable() || openMode == DBConstants.UPDATE) {
|
||||
|
@ -76,6 +80,12 @@ abstract class TypedefDBAdapter {
|
|||
* @throws VersionException if a read only adapter can't be obtained for the database handle's version.
|
||||
*/
|
||||
static TypedefDBAdapter findReadOnlyAdapter(DBHandle handle) throws VersionException {
|
||||
try {
|
||||
return new TypedefDBAdapterV1(handle);
|
||||
}
|
||||
catch (VersionException e) {
|
||||
// ignore
|
||||
}
|
||||
return new TypedefDBAdapterV0(handle);
|
||||
}
|
||||
|
||||
|
@ -95,14 +105,14 @@ abstract class TypedefDBAdapter {
|
|||
long id = tmpHandle.startTransaction();
|
||||
TypedefDBAdapter tmpAdapter = null;
|
||||
try {
|
||||
tmpAdapter = new TypedefDBAdapterV1(tmpHandle, true);
|
||||
tmpAdapter = new TypedefDBAdapterV2(tmpHandle, true);
|
||||
RecordIterator it = oldAdapter.getRecords();
|
||||
while (it.hasNext()) {
|
||||
DBRecord rec = it.next();
|
||||
tmpAdapter.updateRecord(rec, false);
|
||||
}
|
||||
oldAdapter.deleteTable(handle);
|
||||
TypedefDBAdapter newAdapter = new TypedefDBAdapterV1(handle, true);
|
||||
TypedefDBAdapter newAdapter = new TypedefDBAdapterV2(handle, true);
|
||||
it = tmpAdapter.getRecords();
|
||||
while (it.hasNext()) {
|
||||
DBRecord rec = it.next();
|
||||
|
@ -120,6 +130,7 @@ abstract class TypedefDBAdapter {
|
|||
* Creates a database record for a type definition data type.
|
||||
* @param dataTypeID the ID of the data type that is referred to by this type definition.
|
||||
* @param name the unique name for this data type
|
||||
* @param flags typedef flags (e.g., auto-name flag bit).
|
||||
* @param categoryID the ID for the category that contains this data type.
|
||||
* @param sourceArchiveID the ID for the source archive where this data type originated.
|
||||
* @param sourceDataTypeID the ID of the associated data type in the source archive.
|
||||
|
@ -127,7 +138,7 @@ abstract class TypedefDBAdapter {
|
|||
* @return the database record for this data type.
|
||||
* @throws IOException if the database can't be accessed.
|
||||
*/
|
||||
abstract DBRecord createRecord(long dataTypeID, String name, long categoryID,
|
||||
abstract DBRecord createRecord(long dataTypeID, String name, short flags, long categoryID,
|
||||
long sourceArchiveID, long sourceDataTypeID, long lastChangeTime) throws IOException;
|
||||
|
||||
/**
|
||||
|
|
|
@ -68,10 +68,9 @@ class TypedefDBAdapterV0 extends TypedefDBAdapter implements RecordTranslator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public DBRecord createRecord(long dataTypeID, String name, long categoryID, long sourceArchiveID,
|
||||
long sourceDataTypeID, long lastChangeTime) throws IOException {
|
||||
throw new UnsupportedOperationException("Not allowed to update prior version #" + VERSION +
|
||||
" of " + TYPEDEF_TABLE_NAME + " table.");
|
||||
public DBRecord createRecord(long dataTypeID, String name, short flags, long categoryID,
|
||||
long sourceArchiveID, long sourceDataTypeID, long lastChangeTime) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -91,7 +90,7 @@ class TypedefDBAdapterV0 extends TypedefDBAdapter implements RecordTranslator {
|
|||
|
||||
@Override
|
||||
public boolean removeRecord(long dataID) throws IOException {
|
||||
return table.deleteRecord(dataID);
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -111,6 +110,7 @@ class TypedefDBAdapterV0 extends TypedefDBAdapter implements RecordTranslator {
|
|||
}
|
||||
DBRecord rec = TypedefDBAdapter.SCHEMA.createRecord(oldRec.getKey());
|
||||
rec.setLongValue(TYPEDEF_DT_ID_COL, oldRec.getLongValue(V0_TYPEDEF_DT_ID_COL));
|
||||
// default TYPEDEF_FLAGS_COL to 0
|
||||
rec.setString(TYPEDEF_NAME_COL, oldRec.getString(V0_TYPEDEF_NAME_COL));
|
||||
rec.setLongValue(TYPEDEF_CAT_COL, oldRec.getLongValue(V0_TYPEDEF_CAT_COL));
|
||||
rec.setLongValue(TYPEDEF_SOURCE_ARCHIVE_ID_COL, DataTypeManager.LOCAL_ARCHIVE_KEY);
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
package ghidra.program.database.data;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
import db.*;
|
||||
import ghidra.util.UniversalID;
|
||||
|
@ -25,7 +24,7 @@ import ghidra.util.exception.VersionException;
|
|||
/**
|
||||
* Version 1 implementation for accessing the Typedef database table.
|
||||
*/
|
||||
class TypedefDBAdapterV1 extends TypedefDBAdapter {
|
||||
class TypedefDBAdapterV1 extends TypedefDBAdapter implements RecordTranslator {
|
||||
static final int VERSION = 1;
|
||||
static final int V1_TYPEDEF_DT_ID_COL = 0;
|
||||
static final int V1_TYPEDEF_NAME_COL = 1;
|
||||
|
@ -34,41 +33,35 @@ class TypedefDBAdapterV1 extends TypedefDBAdapter {
|
|||
static final int V1_TYPEDEF_UNIVERSAL_DT_ID_COL = 4;
|
||||
static final int V1_TYPEDEF_SOURCE_SYNC_TIME_COL = 5;
|
||||
static final int V1_TYPEDEF_LAST_CHANGE_TIME_COL = 6;
|
||||
static final Schema V1_SCHEMA = new Schema(VERSION, "Typedef ID",
|
||||
new Field[] { LongField.INSTANCE, StringField.INSTANCE, LongField.INSTANCE,
|
||||
LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE },
|
||||
new String[] { "Data Type ID", "Name", "Category ID", "Source Archive ID",
|
||||
"Universal Data Type ID", "Source Sync Time", "Last Change Time" });
|
||||
|
||||
// DO NOT REMOVE WHAT'S BELOW - this documents the schema used in version 0.
|
||||
// static final Schema V1_SCHEMA = new Schema(VERSION, "Typedef ID",
|
||||
// new Field[] { LongField.INSTANCE, StringField.INSTANCE, LongField.INSTANCE,
|
||||
// LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE },
|
||||
// new String[] { "Data Type ID", "Name", "Category ID", "Source Archive ID",
|
||||
// "Universal Data Type ID", "Source Sync Time", "Last Change Time" });
|
||||
private Table table;
|
||||
|
||||
/**
|
||||
* Gets a version 1 adapter for the Typedef database table.
|
||||
* @param handle handle to the database containing the table.
|
||||
* @param create true if this constructor should create the table.
|
||||
* @throws VersionException if the the table's version does not match the expected version
|
||||
* for this adapter.
|
||||
*/
|
||||
public TypedefDBAdapterV1(DBHandle handle, boolean create)
|
||||
throws VersionException, IOException {
|
||||
public TypedefDBAdapterV1(DBHandle handle) throws VersionException {
|
||||
|
||||
if (create) {
|
||||
table = handle.createTable(TYPEDEF_TABLE_NAME, V1_SCHEMA,
|
||||
new int[] { V1_TYPEDEF_CAT_COL, V1_TYPEDEF_UNIVERSAL_DT_ID_COL });
|
||||
table = handle.getTable(TYPEDEF_TABLE_NAME);
|
||||
if (table == null) {
|
||||
throw new VersionException("Missing Table: " + TYPEDEF_TABLE_NAME);
|
||||
}
|
||||
else {
|
||||
table = handle.getTable(TYPEDEF_TABLE_NAME);
|
||||
if (table == null) {
|
||||
throw new VersionException("Missing Table: " + TYPEDEF_TABLE_NAME);
|
||||
}
|
||||
int version = table.getSchema().getVersion();
|
||||
if (version != VERSION) {
|
||||
String msg = "Expected version " + VERSION + " for table " + TYPEDEF_TABLE_NAME +
|
||||
" but got " + table.getSchema().getVersion();
|
||||
if (version < VERSION) {
|
||||
throw new VersionException(msg, VersionException.OLDER_VERSION, true);
|
||||
}
|
||||
throw new VersionException(msg, VersionException.NEWER_VERSION, false);
|
||||
int version = table.getSchema().getVersion();
|
||||
if (version != VERSION) {
|
||||
String msg = "Expected version " + VERSION + " for table " + TYPEDEF_TABLE_NAME +
|
||||
" but got " + table.getSchema().getVersion();
|
||||
if (version < VERSION) {
|
||||
throw new VersionException(msg, VersionException.OLDER_VERSION, true);
|
||||
}
|
||||
throw new VersionException(msg, VersionException.NEWER_VERSION, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,49 +71,29 @@ class TypedefDBAdapterV1 extends TypedefDBAdapter {
|
|||
}
|
||||
|
||||
@Override
|
||||
public DBRecord createRecord(long dataTypeID, String name, long categoryID, long sourceArchiveID,
|
||||
long sourceDataTypeID, long lastChangeTime) throws IOException {
|
||||
|
||||
long tableKey = table.getKey();
|
||||
// if (tableKey <= DataManager.VOID_DATATYPE_ID) {
|
||||
// tableKey = DataManager.VOID_DATATYPE_ID +1;
|
||||
// }
|
||||
long key = DataTypeManagerDB.createKey(DataTypeManagerDB.TYPEDEF, tableKey);
|
||||
|
||||
DBRecord record = V1_SCHEMA.createRecord(key);
|
||||
record.setLongValue(V1_TYPEDEF_DT_ID_COL, dataTypeID);
|
||||
record.setString(V1_TYPEDEF_NAME_COL, name);
|
||||
record.setLongValue(V1_TYPEDEF_CAT_COL, categoryID);
|
||||
record.setLongValue(V1_TYPEDEF_SOURCE_ARCHIVE_ID_COL, sourceArchiveID);
|
||||
record.setLongValue(V1_TYPEDEF_UNIVERSAL_DT_ID_COL, sourceDataTypeID);
|
||||
record.setLongValue(V1_TYPEDEF_SOURCE_SYNC_TIME_COL, lastChangeTime);
|
||||
record.setLongValue(V1_TYPEDEF_LAST_CHANGE_TIME_COL, lastChangeTime);
|
||||
table.putRecord(record);
|
||||
return record;
|
||||
public DBRecord createRecord(long dataTypeID, String name, short flags, long categoryID,
|
||||
long sourceArchiveID, long sourceDataTypeID, long lastChangeTime) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DBRecord getRecord(long typedefID) throws IOException {
|
||||
return table.getRecord(typedefID);
|
||||
return translateRecord(table.getRecord(typedefID));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecordIterator getRecords() throws IOException {
|
||||
return table.iterator();
|
||||
RecordIterator getRecords() throws IOException {
|
||||
return new TranslatedRecordIterator(table.iterator(), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
|
||||
if (setLastChangeTime) {
|
||||
record.setLongValue(TypedefDBAdapter.TYPEDEF_LAST_CHANGE_TIME_COL,
|
||||
(new Date()).getTime());
|
||||
}
|
||||
table.putRecord(record);
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeRecord(long dataID) throws IOException {
|
||||
return table.deleteRecord(dataID);
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -137,14 +110,33 @@ class TypedefDBAdapterV1 extends TypedefDBAdapter {
|
|||
DBRecord getRecordWithIDs(UniversalID sourceID, UniversalID datatypeID) throws IOException {
|
||||
Field[] keys =
|
||||
table.findRecords(new LongField(datatypeID.getValue()), V1_TYPEDEF_UNIVERSAL_DT_ID_COL);
|
||||
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
DBRecord record = table.getRecord(keys[i]);
|
||||
if (record.getLongValue(V1_TYPEDEF_SOURCE_ARCHIVE_ID_COL) == sourceID.getValue()) {
|
||||
return record;
|
||||
return translateRecord(record);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DBRecord translateRecord(DBRecord oldRec) {
|
||||
if (oldRec == null) {
|
||||
return null;
|
||||
}
|
||||
DBRecord rec = TypedefDBAdapter.SCHEMA.createRecord(oldRec.getKey());
|
||||
rec.setLongValue(TYPEDEF_DT_ID_COL, oldRec.getLongValue(V1_TYPEDEF_DT_ID_COL));
|
||||
// default TYPEDEF_FLAGS_COL to 0
|
||||
rec.setString(TYPEDEF_NAME_COL, oldRec.getString(V1_TYPEDEF_NAME_COL));
|
||||
rec.setLongValue(TYPEDEF_CAT_COL, oldRec.getLongValue(V1_TYPEDEF_CAT_COL));
|
||||
rec.setLongValue(TYPEDEF_SOURCE_ARCHIVE_ID_COL,
|
||||
oldRec.getLongValue(V1_TYPEDEF_SOURCE_ARCHIVE_ID_COL));
|
||||
rec.setLongValue(TYPEDEF_UNIVERSAL_DT_ID_COL,
|
||||
oldRec.getLongValue(V1_TYPEDEF_UNIVERSAL_DT_ID_COL));
|
||||
rec.setLongValue(TYPEDEF_SOURCE_SYNC_TIME_COL,
|
||||
oldRec.getLongValue(V1_TYPEDEF_SOURCE_SYNC_TIME_COL));
|
||||
rec.setLongValue(TYPEDEF_LAST_CHANGE_TIME_COL,
|
||||
oldRec.getLongValue(V1_TYPEDEF_LAST_CHANGE_TIME_COL));
|
||||
return rec;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.program.database.data;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
import db.*;
|
||||
import ghidra.util.UniversalID;
|
||||
import ghidra.util.exception.VersionException;
|
||||
|
||||
/**
|
||||
* Version 2 implementation for accessing the Typedef database table.
|
||||
*/
|
||||
class TypedefDBAdapterV2 extends TypedefDBAdapter {
|
||||
static final int VERSION = 2;
|
||||
static final int V2_TYPEDEF_DT_ID_COL = 0;
|
||||
static final int V2_TYPEDEF_FLAGS_COL = 1;
|
||||
static final int V2_TYPEDEF_NAME_COL = 2;
|
||||
static final int V2_TYPEDEF_CAT_COL = 3;
|
||||
static final int V2_TYPEDEF_SOURCE_ARCHIVE_ID_COL = 4;
|
||||
static final int V2_TYPEDEF_UNIVERSAL_DT_ID_COL = 5;
|
||||
static final int V2_TYPEDEF_SOURCE_SYNC_TIME_COL = 6;
|
||||
static final int V2_TYPEDEF_LAST_CHANGE_TIME_COL = 7;
|
||||
static final Schema V2_SCHEMA = new Schema(VERSION, "Typedef ID",
|
||||
new Field[] { LongField.INSTANCE, ShortField.INSTANCE, StringField.INSTANCE,
|
||||
LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE,
|
||||
LongField.INSTANCE },
|
||||
new String[] { "Data Type ID", "Flags", "Name", "Category ID", "Source Archive ID",
|
||||
"Universal Data Type ID", "Source Sync Time", "Last Change Time" });
|
||||
private Table table;
|
||||
|
||||
/**
|
||||
* Gets a version 1 adapter for the Typedef database table.
|
||||
* @param handle handle to the database containing the table.
|
||||
* @param create true if this constructor should create the table.
|
||||
* @throws VersionException if the the table's version does not match the expected version
|
||||
* for this adapter.
|
||||
* @throws IOException if IO error occurs
|
||||
*/
|
||||
public TypedefDBAdapterV2(DBHandle handle, boolean create)
|
||||
throws VersionException, IOException {
|
||||
|
||||
if (create) {
|
||||
table = handle.createTable(TYPEDEF_TABLE_NAME, V2_SCHEMA,
|
||||
new int[] { V2_TYPEDEF_CAT_COL, V2_TYPEDEF_UNIVERSAL_DT_ID_COL });
|
||||
}
|
||||
else {
|
||||
table = handle.getTable(TYPEDEF_TABLE_NAME);
|
||||
if (table == null) {
|
||||
throw new VersionException("Missing Table: " + TYPEDEF_TABLE_NAME);
|
||||
}
|
||||
int version = table.getSchema().getVersion();
|
||||
if (version != VERSION) {
|
||||
String msg = "Expected version " + VERSION + " for table " + TYPEDEF_TABLE_NAME +
|
||||
" but got " + table.getSchema().getVersion();
|
||||
if (version < VERSION) {
|
||||
throw new VersionException(msg, VersionException.OLDER_VERSION, true);
|
||||
}
|
||||
throw new VersionException(msg, VersionException.NEWER_VERSION, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void deleteTable(DBHandle handle) throws IOException {
|
||||
handle.deleteTable(TYPEDEF_TABLE_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DBRecord createRecord(long dataTypeID, String name, short flags, long categoryID,
|
||||
long sourceArchiveID, long sourceDataTypeID, long lastChangeTime) throws IOException {
|
||||
|
||||
long tableKey = table.getKey();
|
||||
// if (tableKey <= DataManager.VOID_DATATYPE_ID) {
|
||||
// tableKey = DataManager.VOID_DATATYPE_ID +1;
|
||||
// }
|
||||
long key = DataTypeManagerDB.createKey(DataTypeManagerDB.TYPEDEF, tableKey);
|
||||
|
||||
DBRecord record = V2_SCHEMA.createRecord(key);
|
||||
record.setLongValue(V2_TYPEDEF_DT_ID_COL, dataTypeID);
|
||||
record.setShortValue(V2_TYPEDEF_FLAGS_COL, flags);
|
||||
record.setString(V2_TYPEDEF_NAME_COL, name);
|
||||
record.setLongValue(V2_TYPEDEF_CAT_COL, categoryID);
|
||||
record.setLongValue(V2_TYPEDEF_SOURCE_ARCHIVE_ID_COL, sourceArchiveID);
|
||||
record.setLongValue(V2_TYPEDEF_UNIVERSAL_DT_ID_COL, sourceDataTypeID);
|
||||
record.setLongValue(V2_TYPEDEF_SOURCE_SYNC_TIME_COL, lastChangeTime);
|
||||
record.setLongValue(V2_TYPEDEF_LAST_CHANGE_TIME_COL, lastChangeTime);
|
||||
table.putRecord(record);
|
||||
return record;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DBRecord getRecord(long typedefID) throws IOException {
|
||||
return table.getRecord(typedefID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecordIterator getRecords() throws IOException {
|
||||
return table.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
|
||||
if (setLastChangeTime) {
|
||||
record.setLongValue(TypedefDBAdapter.TYPEDEF_LAST_CHANGE_TIME_COL,
|
||||
(new Date()).getTime());
|
||||
}
|
||||
table.putRecord(record);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeRecord(long dataID) throws IOException {
|
||||
return table.deleteRecord(dataID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Field[] getRecordIdsInCategory(long categoryID) throws IOException {
|
||||
return table.findRecords(new LongField(categoryID), V2_TYPEDEF_CAT_COL);
|
||||
}
|
||||
|
||||
@Override
|
||||
Field[] getRecordIdsForSourceArchive(long archiveID) throws IOException {
|
||||
return table.findRecords(new LongField(archiveID), V2_TYPEDEF_SOURCE_ARCHIVE_ID_COL);
|
||||
}
|
||||
|
||||
@Override
|
||||
DBRecord getRecordWithIDs(UniversalID sourceID, UniversalID datatypeID) throws IOException {
|
||||
Field[] keys =
|
||||
table.findRecords(new LongField(datatypeID.getValue()), V2_TYPEDEF_UNIVERSAL_DT_ID_COL);
|
||||
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
DBRecord record = table.getRecord(keys[i]);
|
||||
if (record.getLongValue(V2_TYPEDEF_SOURCE_ARCHIVE_ID_COL) == sourceID.getValue()) {
|
||||
return record;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -89,7 +89,8 @@ public abstract class AbstractDataType implements DataType {
|
|||
|
||||
@Override
|
||||
public DataTypePath getDataTypePath() {
|
||||
return new DataTypePath(categoryPath, name);
|
||||
// use methods instead of fields since they mey be overriden
|
||||
return new DataTypePath(getCategoryPath(), getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,125 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressOutOfBoundsException;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
import ghidra.program.model.scalar.Scalar;
|
||||
|
||||
abstract class AbstractImageBaseOffsetDataType extends BuiltIn {
|
||||
|
||||
AbstractImageBaseOffsetDataType(CategoryPath path, String name, DataTypeManager dtm) {
|
||||
super(path, name, dtm);
|
||||
}
|
||||
|
||||
abstract DataType getScalarDataType();
|
||||
|
||||
static String generateName(DataType dt) {
|
||||
return "ImageBaseOffset" + dt.getLength() * 8;
|
||||
}
|
||||
|
||||
static String generateMnemonic(DataType dt) {
|
||||
return "ibo" + dt.getLength() * 8;
|
||||
}
|
||||
|
||||
static String generateDescription(DataType dt) {
|
||||
return (dt.getLength() * 8) + "-bit Image Base Offset";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
DataType dt = getScalarDataType();
|
||||
return generateDescription(dt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMnemonic(Settings settings) {
|
||||
DataType dt = getScalarDataType();
|
||||
return generateMnemonic(dt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return getScalarDataType().getLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
|
||||
Address addr = (Address) getValue(buf, settings, length);
|
||||
if (addr == null) { // could not create address, so return "Not a pointer (NaP)"
|
||||
return "NaP";
|
||||
}
|
||||
return addr.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(MemBuffer buf, Settings settings, int length) {
|
||||
DataType dt = getScalarDataType();
|
||||
Address imageBase = buf.getMemory().getProgram().getImageBase();
|
||||
Scalar value = (Scalar) dt.getValue(buf, settings, length);
|
||||
if (value != null && value.getUnsignedValue() != 0) {
|
||||
try {
|
||||
return imageBase.add(value.getUnsignedValue());
|
||||
}
|
||||
catch (AddressOutOfBoundsException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEncodable() {
|
||||
return getScalarDataType().isEncodable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encodeValue(Object value, MemBuffer buf, Settings settings, int length)
|
||||
throws DataTypeEncodeException {
|
||||
if (!(value instanceof Address)) {
|
||||
throw new DataTypeEncodeException("Requires Address", value, this);
|
||||
}
|
||||
Address addressValue = (Address) value;
|
||||
Address imageBase = buf.getMemory().getProgram().getImageBase();
|
||||
long offset;
|
||||
try {
|
||||
offset = addressValue.subtract(imageBase);
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
throw new DataTypeEncodeException(value, this, e);
|
||||
}
|
||||
Scalar scalarOffset = new Scalar(imageBase.getSize(), offset, false);
|
||||
DataType dt = getScalarDataType();
|
||||
return dt.encodeValue(scalarOffset, buf, settings, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encodeRepresentation(String repr, MemBuffer buf, Settings settings, int length)
|
||||
throws DataTypeEncodeException {
|
||||
Address address = buf.getMemory().getProgram().getAddressFactory().getAddress(repr);
|
||||
if (address == null) {
|
||||
throw new DataTypeEncodeException("Cannot parse address", repr, this);
|
||||
}
|
||||
return encodeValue(address, buf, settings, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getValueClass(Settings settings) {
|
||||
return Address.class;
|
||||
}
|
||||
}
|
|
@ -25,14 +25,10 @@ import ghidra.util.UniversalID;
|
|||
import ghidra.util.UniversalIdGenerator;
|
||||
|
||||
/**
|
||||
* <code>AbstractPointerTypedefDataType</code> provides an abstract implementation for
|
||||
* a Pointer-Typedef BuiltIn datatype.
|
||||
* <br>
|
||||
* If a generated name is used the name will be locked-in once this datatype is resolved
|
||||
* and will not automatcally update if any subsequent changes are made to
|
||||
* {@link TypeDefSettingsDefinition} settings or the name of the referenced datatype.
|
||||
* <code>AbstractPointerTypedefDataType</code> provides an abstract {@link BuiltIn} datatype
|
||||
* implementation for a pointer-typedef datatype.
|
||||
*/
|
||||
public abstract class AbstractPointerTypedefDataType extends BuiltIn implements TypeDef {
|
||||
public abstract class AbstractPointerTypedefBuiltIn extends BuiltIn implements TypeDef {
|
||||
|
||||
private String typedefName;
|
||||
private TypedefDataType modelTypedef;
|
||||
|
@ -47,12 +43,13 @@ public abstract class AbstractPointerTypedefDataType extends BuiltIn implements
|
|||
* @param pointerSize pointer size in bytes or -1 for default pointer size
|
||||
* @param dtm data-type manager whose data organization should be used
|
||||
*/
|
||||
public AbstractPointerTypedefDataType(String name, DataType referencedDataType,
|
||||
protected AbstractPointerTypedefBuiltIn(String name, DataType referencedDataType,
|
||||
int pointerSize, DataTypeManager dtm) {
|
||||
super(getCategoryPath(referencedDataType), getTempNameIfNeeded(name), dtm);
|
||||
setTypedefName(name);
|
||||
modelTypedef =
|
||||
new TypedefDataType("TEMP", new PointerDataType(referencedDataType, pointerSize, dtm));
|
||||
setDefaultSettings(modelTypedef.getDefaultSettings());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -63,13 +60,20 @@ public abstract class AbstractPointerTypedefDataType extends BuiltIn implements
|
|||
* @param pointerDataType associated pointer datatype (required)
|
||||
* @param dtm data-type manager whose data organization should be used
|
||||
*/
|
||||
public AbstractPointerTypedefDataType(String name, Pointer pointerDataType,
|
||||
protected AbstractPointerTypedefBuiltIn(String name, Pointer pointerDataType,
|
||||
DataTypeManager dtm) {
|
||||
super(pointerDataType.getCategoryPath(), getTempNameIfNeeded(name), dtm);
|
||||
setTypedefName(name);
|
||||
modelTypedef = new TypedefDataType("TEMP", pointerDataType.clone(dtm));
|
||||
setDefaultSettings(modelTypedef.getDefaultSettings());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableAutoNaming() {
|
||||
typedefName = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoNamed() {
|
||||
return typedefName == null;
|
||||
}
|
||||
|
@ -102,7 +106,7 @@ public abstract class AbstractPointerTypedefDataType extends BuiltIn implements
|
|||
}
|
||||
|
||||
void setTypedefName(String name) {
|
||||
if (name != null) {
|
||||
if (name != null && !DataUtilities.isValidDataTypeName(name)) {
|
||||
throw new IllegalArgumentException("Invalid DataType name: " + name);
|
||||
}
|
||||
this.typedefName = name;
|
||||
|
@ -158,17 +162,7 @@ public abstract class AbstractPointerTypedefDataType extends BuiltIn implements
|
|||
|
||||
@Override
|
||||
public SettingsDefinition[] getBuiltInSettingsDefinitions() {
|
||||
return getTypeDefSettingsDefinitions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDefSettingsDefinition[] getTypeDefSettingsDefinitions() {
|
||||
return modelTypedef.getTypeDefSettingsDefinitions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Settings getDefaultSettings() {
|
||||
return modelTypedef.getDefaultSettings();
|
||||
return modelTypedef.getSettingsDefinitions();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -183,6 +177,11 @@ public abstract class AbstractPointerTypedefDataType extends BuiltIn implements
|
|||
getDataType().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getValueClass(Settings settings) {
|
||||
return modelTypedef.getValueClass(settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(MemBuffer buf, Settings settings, int length) {
|
||||
return modelTypedef.getValue(buf, settings, length);
|
|
@ -128,6 +128,11 @@ public class CharsetSettingsDefinition implements EnumSettingsDefinition {
|
|||
return CHARSET_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStorageKey() {
|
||||
return CHARSET_SETTING_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Character set";
|
||||
|
|
|
@ -114,7 +114,7 @@ public class ComponentOffsetSettingsDefinition
|
|||
public String getAttributeSpecification(Settings settings) {
|
||||
if (hasValue(settings)) {
|
||||
long offset = getValue(settings);
|
||||
return "offset(" + Long.toString(offset) + ")";
|
||||
return "offset(0x" + Long.toHexString(offset) + ")";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -51,6 +51,9 @@ public interface DataType {
|
|||
|
||||
public final static String CONFLICT_SUFFIX = ".conflict";
|
||||
|
||||
public final static String TYPEDEF_ATTRIBUTE_PREFIX = "__((";
|
||||
public final static String TYPEDEF_ATTRIBUTE_SUFFIX = "))";
|
||||
|
||||
static final long NO_SOURCE_SYNC_TIME = 0L;
|
||||
static final long NO_LAST_CHANGE_TIME = 0L;
|
||||
|
||||
|
|
|
@ -246,14 +246,6 @@ public interface DataTypeManager {
|
|||
*/
|
||||
public Category getCategory(CategoryPath path);
|
||||
|
||||
/**
|
||||
* Notification when data type is changed.
|
||||
* @param dataType data type that is changed
|
||||
* @param isAutoChange true if change was an automatic change in response to
|
||||
* another datatype's change (e.g., size, alignment).
|
||||
*/
|
||||
public void dataTypeChanged(DataType dataType, boolean isAutoChange);
|
||||
|
||||
/**
|
||||
* Add a listener that is notified when the dataTypeManger changes.
|
||||
* @param l the listener
|
||||
|
|
|
@ -88,6 +88,11 @@ public class DataTypeMnemonicSettingsDefinition implements EnumSettingsDefinitio
|
|||
return "Mnemonic-style";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStorageKey() {
|
||||
return MNEMONIC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Selects the data-type mnemonic style";
|
||||
|
|
|
@ -108,6 +108,11 @@ public class EndianSettingsDefinition implements EnumSettingsDefinition {
|
|||
return "Endian";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStorageKey() {
|
||||
return ENDIAN_SETTING_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Selects the endianess of the data";
|
||||
|
|
|
@ -15,27 +15,43 @@
|
|||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.util.classfinder.ClassTranslator;
|
||||
|
||||
/**
|
||||
* <code>IBO32DataType</code> provides a Pointer-Typedef BuiltIn for
|
||||
* a 32-bit Image Base Offset Relative Pointer.
|
||||
* a 32-bit Image Base Offset Relative Pointer. This {@link TypeDef} implementation
|
||||
* specifies the {@link PointerType#IMAGE_BASE_RELATIVE} attribute/setting
|
||||
* associated with a 32-bit {@link Pointer}.
|
||||
* <br>
|
||||
* This class replaces the use of the old <code>ImageBaseOffset32DataType</code>
|
||||
* which did not implement the Pointer interface. This is an alternative
|
||||
* {@link BuiltIn} implementation to using the more general {@link PointerTypedef}
|
||||
* datatype with an unspecified referenced datatype. {@link PointerTypedef} should
|
||||
* be used for other cases
|
||||
* (see {@link #createIBO32PointerTypedef(DataType)}).
|
||||
*/
|
||||
public class IBO32DataType extends AbstractPointerTypedefDataType {
|
||||
public class IBO32DataType extends AbstractPointerTypedefBuiltIn {
|
||||
|
||||
static final String NAME = "ibo32";
|
||||
public static final IBO32DataType dataType = new IBO32DataType();
|
||||
|
||||
// TODO: remove old ImageBaseOffset32DataType implementation and uncomment
|
||||
// static {
|
||||
// ClassTranslator.put("ghidra.program.model.data.ImageBaseOffset32",
|
||||
// IBO32DataType.class.getName());
|
||||
// ClassTranslator.put("ghidra.program.model.data.ImageBaseOffset32DataType",
|
||||
// IBO32DataType.class.getName());
|
||||
// }
|
||||
static final String NAME = "ImageBaseOffset32";
|
||||
|
||||
private static TypeDefSettingsDefinition[] IBO_TYPEDEF_SETTINGS_DEFS =
|
||||
{ PointerTypeSettingsDefinition.DEF };
|
||||
|
||||
static {
|
||||
ClassTranslator.put("ghidra.program.model.data.ImageBaseOffset32",
|
||||
IBO32DataType.class.getName());
|
||||
ClassTranslator.put("ghidra.program.model.data.ImageBaseOffset32DataType",
|
||||
IBO32DataType.class.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a 32-bit Image Base Offset relative pointer-typedef.
|
||||
*/
|
||||
public IBO32DataType() {
|
||||
this(DataType.DEFAULT, null);
|
||||
this(null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -43,25 +59,9 @@ public class IBO32DataType extends AbstractPointerTypedefDataType {
|
|||
* @param dtm data-type manager whose data organization should be used
|
||||
*/
|
||||
public IBO32DataType(DataTypeManager dtm) {
|
||||
this(DataType.DEFAULT, dtm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a 32-bit Image Base Offset relative pointer-typedef.
|
||||
* @param referencedDataType data type this pointer-typedef points to
|
||||
*/
|
||||
public IBO32DataType(DataType referencedDataType) {
|
||||
this(referencedDataType, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a 32-bit Image Base Offset relative pointer-typedef.
|
||||
* @param referencedDataType data type this pointer-typedef points to
|
||||
* @param dtm data-type manager whose data organization should be used
|
||||
*/
|
||||
public IBO32DataType(DataType referencedDataType, DataTypeManager dtm) {
|
||||
super(null, referencedDataType, 4, dtm);
|
||||
PointerTypeSettingsDefinition.DEF.setType(getDefaultSettings(), PointerType.IBO);
|
||||
super(NAME, null, 4, dtm);
|
||||
PointerTypeSettingsDefinition.DEF.setType(getDefaultSettings(),
|
||||
PointerType.IMAGE_BASE_RELATIVE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -74,18 +74,30 @@ public class IBO32DataType extends AbstractPointerTypedefDataType {
|
|||
if (dataMgr == dtm) {
|
||||
return this;
|
||||
}
|
||||
IBO32DataType td = new IBO32DataType(getReferencedDataType(), dtm);
|
||||
TypedefDataType.copyTypeDefSettings(this, td, false);
|
||||
return td;
|
||||
return new IBO32DataType(dtm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
DataType dt = getReferencedDataType();
|
||||
if (dt == null || Undefined.isUndefined(dt) || (dt instanceof VoidDataType)) {
|
||||
return NAME; // use simple ibo name
|
||||
}
|
||||
return super.getName(); // use generated named
|
||||
public String getMnemonic(Settings settings) {
|
||||
return "ibo32";
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDefSettingsDefinition[] getBuiltInSettingsDefinitions() {
|
||||
return IBO_TYPEDEF_SETTINGS_DEFS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a IBO32 {@link PointerTypedef} with auto-naming. If needed, a name and category
|
||||
* may be assigned to the returned instance. Unlike using an immutable {@link IBO32DataType} instance
|
||||
* the returned instance is mutable.
|
||||
* @param referencedDataType referenced datatype or null
|
||||
* @return new IBO32 pointer-typedef
|
||||
*/
|
||||
public static PointerTypedef createIBO32PointerTypedef(DataType referencedDataType) {
|
||||
return new PointerTypedef(null, referencedDataType, 4,
|
||||
referencedDataType != null ? referencedDataType.getDataTypeManager() : null,
|
||||
PointerType.IMAGE_BASE_RELATIVE);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,27 +15,43 @@
|
|||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.util.classfinder.ClassTranslator;
|
||||
|
||||
/**
|
||||
* <code>IBO64DataType</code> provides a Pointer-Typedef BuiltIn for
|
||||
* a 64-bit Image Base Offset Relative Pointer.
|
||||
* a 64-bit Image Base Offset Relative Pointer. This {@link TypeDef} implementation
|
||||
* specifies the {@link PointerType#IMAGE_BASE_RELATIVE} attribute/setting
|
||||
* associated with a 64-bit {@link Pointer}.
|
||||
* <br>
|
||||
* This class replaces the use of the old <code>ImageBaseOffset64DataType</code>
|
||||
* which did not implement the Pointer interface. This is an alternative
|
||||
* {@link BuiltIn} implementation to using the more general {@link PointerTypedef}
|
||||
* datatype with an unspecified referenced datatype. {@link PointerTypedef} should
|
||||
* be used for other cases
|
||||
* (see {@link #createIBO64PointerTypedef(DataType)}).
|
||||
*/
|
||||
public class IBO64DataType extends AbstractPointerTypedefDataType {
|
||||
public class IBO64DataType extends AbstractPointerTypedefBuiltIn {
|
||||
|
||||
static final String NAME = "ibo64";
|
||||
public static final IBO64DataType dataType = new IBO64DataType();
|
||||
|
||||
// TODO: remove old ImageBaseOffset64DataType implementation and uncomment
|
||||
// static {
|
||||
// ClassTranslator.put("ghidra.program.model.data.ImageBaseOffset64",
|
||||
// IBO64DataType.class.getName());
|
||||
// ClassTranslator.put("ghidra.program.model.data.ImageBaseOffset64DataType",
|
||||
// IBO64DataType.class.getName());
|
||||
// }
|
||||
static final String NAME = "ImageBaseOffset64";
|
||||
|
||||
private static TypeDefSettingsDefinition[] IBO_TYPEDEF_SETTINGS_DEFS =
|
||||
{ PointerTypeSettingsDefinition.DEF };
|
||||
|
||||
static {
|
||||
ClassTranslator.put("ghidra.program.model.data.ImageBaseOffset64",
|
||||
IBO64DataType.class.getName());
|
||||
ClassTranslator.put("ghidra.program.model.data.ImageBaseOffset64DataType",
|
||||
IBO64DataType.class.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a 64-bit Image Base Offset relative pointer-typedef.
|
||||
*/
|
||||
public IBO64DataType() {
|
||||
this(DataType.DEFAULT, null);
|
||||
this(null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -43,25 +59,8 @@ public class IBO64DataType extends AbstractPointerTypedefDataType {
|
|||
* @param dtm data-type manager whose data organization should be used
|
||||
*/
|
||||
public IBO64DataType(DataTypeManager dtm) {
|
||||
this(DataType.DEFAULT, dtm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a 64-bit Image Base Offset relative pointer-typedef.
|
||||
* @param referencedDataType data type this pointer-typedef points to
|
||||
*/
|
||||
public IBO64DataType(DataType referencedDataType) {
|
||||
this(referencedDataType, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a 64-bit Image Base Offset relative pointer-typedef.
|
||||
* @param referencedDataType data type this pointer-typedef points to
|
||||
* @param dtm data-type manager whose data organization should be used
|
||||
*/
|
||||
public IBO64DataType(DataType referencedDataType, DataTypeManager dtm) {
|
||||
super(null, referencedDataType, 8, dtm);
|
||||
PointerTypeSettingsDefinition.DEF.setType(getDefaultSettings(), PointerType.IBO);
|
||||
super(NAME, null, 8, dtm);
|
||||
PointerTypeSettingsDefinition.DEF.setType(getDefaultSettings(), PointerType.IMAGE_BASE_RELATIVE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -74,18 +73,30 @@ public class IBO64DataType extends AbstractPointerTypedefDataType {
|
|||
if (dataMgr == dtm) {
|
||||
return this;
|
||||
}
|
||||
IBO64DataType td = new IBO64DataType(getReferencedDataType(), dtm);
|
||||
TypedefDataType.copyTypeDefSettings(this, td, false);
|
||||
return td;
|
||||
return new IBO64DataType(dtm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
DataType dt = getReferencedDataType();
|
||||
if (dt == null || Undefined.isUndefined(dt) || (dt instanceof VoidDataType)) {
|
||||
return NAME; // use simple ibo name
|
||||
}
|
||||
return super.getName(); // use generated named
|
||||
public String getMnemonic(Settings settings) {
|
||||
return "ibo64";
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDefSettingsDefinition[] getBuiltInSettingsDefinitions() {
|
||||
return IBO_TYPEDEF_SETTINGS_DEFS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a IBO64 {@link PointerTypedef} with auto-naming. If needed, a name and category
|
||||
* may be assigned to the returned instance. Unlike using an immutable {@link IBO32DataType} instance
|
||||
* the returned instance is mutable.
|
||||
* @param referencedDataType referenced datatype or null
|
||||
* @return new IBO64 pointer-typedef
|
||||
*/
|
||||
public static PointerTypedef createIBO64PointerTypedef(DataType referencedDataType) {
|
||||
return new PointerTypedef(null, referencedDataType, 8,
|
||||
referencedDataType != null ? referencedDataType.getDataTypeManager() : null,
|
||||
PointerType.IMAGE_BASE_RELATIVE);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import ghidra.util.classfinder.*;
|
||||
|
||||
public class ImageBaseOffset32DataType extends AbstractImageBaseOffsetDataType {
|
||||
static {
|
||||
ClassTranslator.put("ghidra.program.model.data.ImageBaseOffset32",
|
||||
ImageBaseOffset32DataType.class.getName());
|
||||
}
|
||||
|
||||
private static DataType datatype = DWordDataType.dataType;
|
||||
|
||||
public ImageBaseOffset32DataType() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public ImageBaseOffset32DataType(DataTypeManager dtm) {
|
||||
super(null, generateName(datatype), dtm);
|
||||
}
|
||||
|
||||
@Override
|
||||
DataType getScalarDataType() {
|
||||
return datatype;
|
||||
}
|
||||
|
||||
public DataType clone(DataTypeManager dtm) {
|
||||
if (dtm == getDataTypeManager()) {
|
||||
return this;
|
||||
}
|
||||
return new ImageBaseOffset32DataType(dtm);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import ghidra.util.classfinder.*;
|
||||
|
||||
public class ImageBaseOffset64DataType extends AbstractImageBaseOffsetDataType {
|
||||
static {
|
||||
ClassTranslator.put("ghidra.program.model.data.ImageBaseOffset64",
|
||||
ImageBaseOffset64DataType.class.getName());
|
||||
}
|
||||
|
||||
private static DataType datatype = QWordDataType.dataType;
|
||||
|
||||
public ImageBaseOffset64DataType() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public ImageBaseOffset64DataType(DataTypeManager dtm) {
|
||||
super(null, generateName(datatype), dtm);
|
||||
}
|
||||
|
||||
@Override
|
||||
DataType getScalarDataType() {
|
||||
return datatype;
|
||||
}
|
||||
|
||||
public DataType clone(DataTypeManager dtm) {
|
||||
if (dtm == getDataTypeManager()) {
|
||||
return this;
|
||||
}
|
||||
return new ImageBaseOffset64DataType(dtm);
|
||||
}
|
||||
|
||||
}
|
|
@ -87,6 +87,11 @@ public class MutabilitySettingsDefinition implements EnumSettingsDefinition {
|
|||
return "Mutability";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStorageKey() {
|
||||
return MUTABILITY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Selects the data mutability";
|
||||
|
|
|
@ -23,8 +23,9 @@ import ghidra.docking.settings.Settings;
|
|||
*/
|
||||
public class PaddingSettingsDefinition implements EnumSettingsDefinition {
|
||||
|
||||
private static final int PADDED_VALUE = 1;
|
||||
private static final int UNPADDED_VALUE = 0;
|
||||
public static final int PADDED_VALUE = 1;
|
||||
public static final int UNPADDED_VALUE = 0;
|
||||
|
||||
private static final String[] choices = { "unpadded", "padded" };
|
||||
private static final String PADDED = "padded";
|
||||
|
||||
|
@ -86,6 +87,11 @@ public class PaddingSettingsDefinition implements EnumSettingsDefinition {
|
|||
return "Padding";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStorageKey() {
|
||||
return PADDED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Selects if the data is padded or not";
|
||||
|
|
|
@ -403,7 +403,7 @@ public class PointerDataType extends BuiltIn implements Pointer {
|
|||
|
||||
try {
|
||||
PointerType choice = PointerTypeSettingsDefinition.DEF.getType(settings);
|
||||
if (choice == PointerType.IBO && mem != null) {
|
||||
if (choice == PointerType.IMAGE_BASE_RELATIVE && mem != null) {
|
||||
// must ignore AddressSpaceSettingsDefinition
|
||||
Address imageBase = mem.getProgram().getImageBase();
|
||||
targetSpace = imageBase.getAddressSpace();
|
||||
|
|
|
@ -33,7 +33,7 @@ public enum PointerType {
|
|||
/**
|
||||
* Pointer offset relative to program image base.
|
||||
*/
|
||||
IBO(1),
|
||||
IMAGE_BASE_RELATIVE(1),
|
||||
/**
|
||||
* Pointer offset relative to pointer storage address.
|
||||
* NOTE: This type has limited usefulness since it can only be applied to
|
||||
|
|
|
@ -31,6 +31,7 @@ public class PointerTypeSettingsDefinition
|
|||
"Specifies the pointer type which affects interpretation of offset";
|
||||
private static final String DISPLAY_NAME = "Pointer Type";
|
||||
|
||||
// Choices correspond to the enumerated PointerType values
|
||||
private static final String[] choices =
|
||||
{ "default", "image-base-relative", "relative", "file-offset" };
|
||||
|
||||
|
|
|
@ -17,7 +17,15 @@ package ghidra.program.model.data;
|
|||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.docking.settings.SettingsDefinition;
|
||||
import ghidra.program.database.data.DataTypeUtilities;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
import ghidra.util.UniversalID;
|
||||
import ghidra.util.UniversalIdGenerator;
|
||||
|
||||
/**
|
||||
* <code>PointerTypedef</code> provides a Pointer-Typedef template datatype
|
||||
|
@ -30,59 +38,151 @@ import ghidra.program.model.address.AddressSpace;
|
|||
* since it does not implement a default constructor so it may not be treated
|
||||
* like other {@link BuiltIn} datatypes which are managed by the
|
||||
* <{@link BuiltInDataTypeManager}.
|
||||
* <br>
|
||||
* NOTE: As a {@link BuiltIn} datatype the use of {@link #setName(String)} and
|
||||
* {@link #setNameAndCategory(CategoryPath, String)} is disabled. The datatype
|
||||
* instance must be instantiated with the correct typedef name.
|
||||
*/
|
||||
public class PointerTypedef extends AbstractPointerTypedefDataType {
|
||||
public class PointerTypedef extends GenericDataType implements TypeDef {
|
||||
|
||||
private boolean isAutoNamed;
|
||||
private TypedefDataType modelTypedef;
|
||||
private UniversalID universalId = UniversalIdGenerator.nextID();
|
||||
|
||||
/**
|
||||
* Constructs a pointer-typedef which dereferences into a specific address space.
|
||||
* @param typeDefName name of this pointer-typedef or null to force name generation.
|
||||
* @param referencedDataType data type this pointer-typedef points to
|
||||
* @param pointerSize pointer size in bytes or -1 for default pointer size based upon datatype manager
|
||||
* @param typeDefName name of this pointer-typedef or null to use auto-named typedef.
|
||||
* @param referencedDataType data type this pointer-typedef points to or null
|
||||
* @param pointerSize pointer size in bytes or -1 for default pointer size based upon specified
|
||||
* address space and datatype manager
|
||||
* @param dtm data-type manager whose data organization should be used (highly recommended, may be null)
|
||||
* @param space address space to be used when dereferencing pointer offset
|
||||
*/
|
||||
public PointerTypedef(String typeDefName, DataType referencedDataType, int pointerSize,
|
||||
DataTypeManager dtm, AddressSpace space) {
|
||||
super(typeDefName, referencedDataType, pointerSize, dtm);
|
||||
Objects.requireNonNull(space, "Address space must be specified");
|
||||
this(typeDefName, referencedDataType, getPreferredPointerSize(pointerSize, dtm, space),
|
||||
dtm);
|
||||
AddressSpaceSettingsDefinition.DEF.setValue(getDefaultSettings(), space.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a pointer-typedef of a specific type
|
||||
* @param typeDefName name of this pointer-typedef or null to force name generation.
|
||||
* @param referencedDataType data type this pointer-typedef points to
|
||||
* @param typeDefName name of this pointer-typedef or null to use auto-named typedef.
|
||||
* @param referencedDataType data type this pointer-typedef points to or null
|
||||
* @param pointerSize pointer size in bytes or -1 for default pointer size based upon datatype manager
|
||||
* @param dtm data-type manager whose data organization should be used (highly recommended, may be null)
|
||||
* @param type pointer type (IBO, RELATIVE, FILE_OFFSET)
|
||||
*/
|
||||
public PointerTypedef(String typeDefName, DataType referencedDataType, int pointerSize,
|
||||
DataTypeManager dtm, PointerType type) {
|
||||
super(typeDefName, referencedDataType, pointerSize, dtm);
|
||||
this(typeDefName, referencedDataType, pointerSize, dtm);
|
||||
Objects.requireNonNull(type, "Pointer type required");
|
||||
PointerTypeSettingsDefinition.DEF.setType(getDefaultSettings(), type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a pointer-typedef without any settings
|
||||
* @param typeDefName name of this pointer-typedef or null to force name generation.
|
||||
* @param referencedDataType data type this pointer-typedef points to
|
||||
* Constructs a offset-pointer-typedef
|
||||
* @param typeDefName name of this pointer-typedef or null to use auto-named typedef.
|
||||
* @param referencedDataType data type this pointer-typedef points to or null
|
||||
* @param pointerSize pointer size in bytes or -1 for default pointer size based upon datatype manager
|
||||
* @param dtm data-type manager whose data organization should be used (highly recommended, may be null)
|
||||
* @param componentOffset signed component offset setting value (see {@link ComponentOffsetSettingsDefinition}
|
||||
*/
|
||||
/* package */ PointerTypedef(String typeDefName, DataType referencedDataType, int pointerSize,
|
||||
DataTypeManager dtm) {
|
||||
super(typeDefName, referencedDataType, pointerSize, dtm);
|
||||
public PointerTypedef(String typeDefName, DataType referencedDataType, int pointerSize,
|
||||
DataTypeManager dtm, long componentOffset) {
|
||||
this(typeDefName, referencedDataType, pointerSize, dtm);
|
||||
ComponentOffsetSettingsDefinition.DEF.setValue(getDefaultSettings(), componentOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a pointer-typedef without any settings
|
||||
* @param typeDefName name of this pointer-typedef or null to force name generation.
|
||||
* @param typeDefName name of this pointer-typedef or null to use auto-named typedef.
|
||||
* @param referencedDataType data type this pointer-typedef points to or null
|
||||
* @param pointerSize pointer size in bytes or -1 for default pointer size based upon datatype manager
|
||||
* @param dtm data-type manager whose data organization should be used (highly recommended, may be null)
|
||||
*/
|
||||
public PointerTypedef(String typeDefName, DataType referencedDataType, int pointerSize,
|
||||
DataTypeManager dtm) {
|
||||
super(getCategoryPath(referencedDataType), getTempNameIfNeeded(typeDefName), dtm);
|
||||
isAutoNamed = StringUtils.isBlank(typeDefName);
|
||||
modelTypedef =
|
||||
new TypedefDataType("TEMP", new PointerDataType(referencedDataType, pointerSize, dtm));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a pointer-typedef without any settings
|
||||
* @param typeDefName name of this pointer-typedef or null to use auto-named typedef.
|
||||
* @param pointerDataType associated pointer datatype
|
||||
* @param dtm data-type manager whose data organization should be used (highly recommended, may be null)
|
||||
*/
|
||||
/* package */ PointerTypedef(String typeDefName, Pointer pointerDataType, DataTypeManager dtm) {
|
||||
super(typeDefName, pointerDataType, dtm);
|
||||
public PointerTypedef(String typeDefName, Pointer pointerDataType, DataTypeManager dtm) {
|
||||
super(pointerDataType.getCategoryPath(), getTempNameIfNeeded(typeDefName), dtm);
|
||||
isAutoNamed = StringUtils.isBlank(typeDefName);
|
||||
modelTypedef = new TypedefDataType("TEMP", pointerDataType.clone(dtm));
|
||||
}
|
||||
|
||||
private static CategoryPath getCategoryPath(DataType referencedDataType) {
|
||||
return referencedDataType != null ? referencedDataType.getCategoryPath()
|
||||
: CategoryPath.ROOT;
|
||||
}
|
||||
|
||||
private static String getTempNameIfNeeded(String baseName) {
|
||||
return StringUtils.isBlank(baseName) ? "TEMP" : baseName;
|
||||
}
|
||||
|
||||
private static int getPreferredPointerSize(int pointerSize, DataTypeManager dtm,
|
||||
AddressSpace space) {
|
||||
Objects.requireNonNull(space, "Address space must be specified");
|
||||
if (pointerSize > 0) {
|
||||
return pointerSize;
|
||||
}
|
||||
pointerSize = space.getSize() / 8;
|
||||
if (dtm.getDataOrganization().getPointerSize() == pointerSize) {
|
||||
pointerSize = -1;
|
||||
}
|
||||
return pointerSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableAutoNaming() {
|
||||
isAutoNamed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoNamed() {
|
||||
return isAutoNamed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the referenced datatype used to construct this datatype
|
||||
* (datatype which pointer references).
|
||||
* @return referenced datatype
|
||||
*/
|
||||
protected DataType getReferencedDataType() {
|
||||
Pointer ptrType = (Pointer) getDataType();
|
||||
return ptrType.getDataType();
|
||||
}
|
||||
|
||||
public UniversalID getUniversalID() {
|
||||
return universalId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEquivalent(DataType obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null || !(obj instanceof TypeDef)) {
|
||||
return false;
|
||||
}
|
||||
TypeDef td = (TypeDef) obj;
|
||||
if (!DataTypeUtilities.equalsIgnoreConflict(getName(), td.getName())) {
|
||||
return false;
|
||||
}
|
||||
if (!hasSameTypeDefSettings(td)) {
|
||||
return false;
|
||||
}
|
||||
return DataTypeUtilities.isSameOrEquivalentDataType(getDataType(), td.getDataType());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -91,12 +191,92 @@ public class PointerTypedef extends AbstractPointerTypedefDataType {
|
|||
}
|
||||
|
||||
@Override
|
||||
public DataType clone(DataTypeManager dtm) {
|
||||
public String getName() {
|
||||
if (isAutoNamed) {
|
||||
// Do not cache name since we do not have listeners to detect
|
||||
// settings change which may impact name generation.
|
||||
return TypedefDataType.generateTypedefName(this);
|
||||
}
|
||||
return super.getName(); // use name provided at instantiation
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasLanguageDependantLength() {
|
||||
return modelTypedef.hasLanguageDependantLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return modelTypedef.getLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType getDataType() {
|
||||
return modelTypedef.getDataType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType getBaseDataType() {
|
||||
return modelTypedef.getBaseDataType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SettingsDefinition[] getSettingsDefinitions() {
|
||||
return modelTypedef.getSettingsDefinitions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDefSettingsDefinition[] getTypeDefSettingsDefinitions() {
|
||||
return modelTypedef.getTypeDefSettingsDefinitions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Settings getDefaultSettings() {
|
||||
return modelTypedef.getDefaultSettings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dependsOn(DataType dt) {
|
||||
DataType myDt = getDataType();
|
||||
return (myDt == dt || myDt.dependsOn(dt));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (isAutoNamed) {
|
||||
return getClass().getSimpleName() + ": " + getName();
|
||||
}
|
||||
return getClass().getSimpleName() + ": typedef " + getName() + " " +
|
||||
getDataType().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getValueClass(Settings settings) {
|
||||
return modelTypedef.getValueClass(settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(MemBuffer buf, Settings settings, int length) {
|
||||
return modelTypedef.getValue(buf, settings, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
|
||||
return modelTypedef.getRepresentation(buf, settings, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PointerTypedef clone(DataTypeManager dtm) {
|
||||
if (dataMgr == dtm) {
|
||||
return this;
|
||||
}
|
||||
return copy(dtm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PointerTypedef copy(DataTypeManager dtm) {
|
||||
Pointer ptrType = (Pointer) getDataType();
|
||||
String n = hasGeneratedNamed() ? null : getName();
|
||||
String n = isAutoNamed ? null : getName();
|
||||
PointerTypedef td = new PointerTypedef(n, ptrType, getDataTypeManager());
|
||||
TypedefDataType.copyTypeDefSettings(this, td, false);
|
||||
return td;
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.util.Objects;
|
|||
import ghidra.program.database.data.PointerTypedefInspector;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.symbol.OffsetReference;
|
||||
import ghidra.util.InvalidNameException;
|
||||
|
||||
/**
|
||||
* <code>PointerTypedefBuilder</code> provides a builder for creating {@link Pointer} - {@link TypeDef}s.
|
||||
|
@ -62,9 +63,10 @@ public class PointerTypedefBuilder {
|
|||
* upon the associated pointer type and the specified settings.
|
||||
* @param name typedef name
|
||||
* @return this builder
|
||||
* @throws InvalidNameException if name contains unsupported characters
|
||||
*/
|
||||
public PointerTypedefBuilder name(String name) {
|
||||
typedef.setTypedefName(name);
|
||||
public PointerTypedefBuilder name(String name) throws InvalidNameException {
|
||||
typedef.setName(name);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,9 @@
|
|||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import ghidra.docking.settings.SettingsDefinition;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Data;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
@ -33,78 +35,102 @@ public interface ProgramBasedDataTypeManager extends DomainFileBasedDataTypeMana
|
|||
Program getProgram();
|
||||
|
||||
/**
|
||||
* Set the long value for instance settings.
|
||||
* Determine if a settings change is permitted for the specified settingsDefinition.
|
||||
* @param data data code unit
|
||||
* @param settingsDefinition settings definition
|
||||
* @return true if change permitted else false
|
||||
*/
|
||||
public boolean isChangeAllowed(Data data, SettingsDefinition settingsDefinition);
|
||||
|
||||
/**
|
||||
* Set the long value for data instance settings.
|
||||
*
|
||||
* @param dataAddr min address of data
|
||||
* @param data data code unit
|
||||
* @param name settings name
|
||||
* @param value value of setting
|
||||
* @return true if the settings actually changed
|
||||
*/
|
||||
public boolean setLongSettingsValue(Address dataAddr, String name, long value);
|
||||
public boolean setLongSettingsValue(Data data, String name, long value);
|
||||
|
||||
/**
|
||||
* Set the string value for instance settings.
|
||||
* Set the string value for data instance settings.
|
||||
*
|
||||
* @param dataAddr min address of data
|
||||
* @param data data code unit
|
||||
* @param name settings name
|
||||
* @param value value of setting
|
||||
* @return true if the settings actually changed
|
||||
*/
|
||||
public boolean setStringSettingsValue(Address dataAddr, String name, String value);
|
||||
public boolean setStringSettingsValue(Data data, String name, String value);
|
||||
|
||||
/**
|
||||
* Set the Object settings.
|
||||
* Set the Object value for data instance settings.
|
||||
*
|
||||
* @param dataAddr min address of data
|
||||
* @param data data code unit
|
||||
* @param name the name of the settings
|
||||
* @param value the value for the settings, must be either a String, byte[]
|
||||
* or Long
|
||||
* @return true if the settings were updated
|
||||
*/
|
||||
public boolean setSettings(Address dataAddr, String name, Object value);
|
||||
public boolean setSettings(Data data, String name, Object value);
|
||||
|
||||
/**
|
||||
* Get the long value for an instance setting.
|
||||
* Get the long value for data instance settings.
|
||||
*
|
||||
* @param dataAddr min address of data
|
||||
* @param data data code unit
|
||||
* @param name settings name
|
||||
* @return null if the named setting was not found
|
||||
*/
|
||||
public Long getLongSettingsValue(Address dataAddr, String name);
|
||||
public Long getLongSettingsValue(Data data, String name);
|
||||
|
||||
/**
|
||||
* Get the String value for an instance setting.
|
||||
* Get the String value for data instance settings.
|
||||
*
|
||||
* @param dataAddr min address of data
|
||||
* @param data data code unit
|
||||
* @param name settings name
|
||||
* @return null if the named setting was not found
|
||||
*/
|
||||
public String getStringSettingsValue(Address dataAddr, String name);
|
||||
public String getStringSettingsValue(Data data, String name);
|
||||
|
||||
/**
|
||||
* Gets the value of a settings as an object (either String, byte[], or Long).
|
||||
* Gets the value for data instance settings in Object form.
|
||||
*
|
||||
* @param dataAddr the address of the data for this settings
|
||||
* @param data data code unit
|
||||
* @param name the name of settings.
|
||||
* @return the settings object
|
||||
*/
|
||||
public Object getSettings(Address dataAddr, String name);
|
||||
public Object getSettings(Data data, String name);
|
||||
|
||||
/**
|
||||
* Clear the setting
|
||||
* Clear the specified setting for the given data
|
||||
*
|
||||
* @param dataAddr min address of data
|
||||
* @param data data code unit
|
||||
* @param name settings name
|
||||
* @return true if the settings were cleared
|
||||
*/
|
||||
public boolean clearSetting(Address dataAddr, String name);
|
||||
public boolean clearSetting(Data data, String name);
|
||||
|
||||
/**
|
||||
* Clear all settings at the given address.
|
||||
* Clear all settings for the given data.
|
||||
*
|
||||
* @param dataAddr the address for this settings.
|
||||
* @param data data code unit
|
||||
*/
|
||||
public void clearAllSettings(Address dataAddr);
|
||||
public void clearAllSettings(Data data);
|
||||
|
||||
/**
|
||||
* Returns all the instance Settings names used for the specified data
|
||||
*
|
||||
* @param data data code unit
|
||||
* @return the names
|
||||
*/
|
||||
public String[] getInstanceSettingsNames(Data data);
|
||||
|
||||
/**
|
||||
* Returns true if no settings are set for the given data
|
||||
*
|
||||
* @param data data code unit
|
||||
* @return true if not settings
|
||||
*/
|
||||
public boolean isEmptySetting(Data data);
|
||||
|
||||
/**
|
||||
* Move the settings in the range to the new start address
|
||||
|
@ -118,22 +144,6 @@ public interface ProgramBasedDataTypeManager extends DomainFileBasedDataTypeMana
|
|||
public void moveAddressRange(Address fromAddr, Address toAddr, long length, TaskMonitor monitor)
|
||||
throws CancelledException;
|
||||
|
||||
/**
|
||||
* Returns all the instance Settings names used at the given address
|
||||
*
|
||||
* @param dataAddr the address
|
||||
* @return the names
|
||||
*/
|
||||
public String[] getInstanceSettingsNames(Address dataAddr);
|
||||
|
||||
/**
|
||||
* Returns true if no settings are set for the given address
|
||||
*
|
||||
* @param dataAddr the address to test
|
||||
* @return true if not settings
|
||||
*/
|
||||
public boolean isEmptySetting(Address dataAddr);
|
||||
|
||||
/**
|
||||
* Removes all settings in the range
|
||||
*
|
||||
|
|
|
@ -82,6 +82,11 @@ public class TerminatedSettingsDefinition implements EnumSettingsDefinition {
|
|||
return "Termination";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStorageKey() {
|
||||
return TERMINATED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Selects if the string is terminated or unterminated";
|
||||
|
|
|
@ -23,15 +23,33 @@ import ghidra.docking.settings.SettingsDefinition;
|
|||
*/
|
||||
public interface TypeDef extends DataType {
|
||||
|
||||
/**
|
||||
* Determine if this datatype use auto-naming (e.g., see {@link PointerTypedef}).
|
||||
* If true, any change to associated {@link TypeDefSettingsDefinition} settings
|
||||
* or naming of the pointer-referenced datatype will cause a automatic renaming
|
||||
* of this datatype.
|
||||
* @return true if auto-named, else false.
|
||||
*/
|
||||
public boolean isAutoNamed();
|
||||
|
||||
/**
|
||||
* Enable auto-naming for this typedef. This will force naming to reflect the name of
|
||||
* associated datatype plus an attribute list which corresponds to any
|
||||
* {@link TypeDefSettingsDefinition} settings which may be set.
|
||||
*/
|
||||
public void enableAutoNaming();
|
||||
|
||||
/**
|
||||
* Returns the dataType that this typedef is based on. This could be
|
||||
* another typedef
|
||||
* @return the datatype which this typedef is based on (may be another {@link TypeDef}).
|
||||
*/
|
||||
public DataType getDataType();
|
||||
|
||||
/**
|
||||
* Returns the non-typedef dataType that this typedef is based on, following
|
||||
* chains of typedefs as necessary.
|
||||
* @return the datatype which this typedef is based on (will not be another {@link TypeDef}).
|
||||
*/
|
||||
public DataType getBaseDataType();
|
||||
|
||||
|
@ -78,4 +96,5 @@ public interface TypeDef extends DataType {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -33,13 +33,6 @@ import ghidra.docking.settings.SettingsDefinition;
|
|||
*/
|
||||
public interface TypeDefSettingsDefinition extends SettingsDefinition {
|
||||
|
||||
/**
|
||||
* Get the storage key which should be used when storing a key/value
|
||||
* map entry which corresponds to this settings definition.
|
||||
* @return settings storage key
|
||||
*/
|
||||
String getStorageKey();
|
||||
|
||||
/**
|
||||
* Get the {@link TypeDef} attribute specification for this setting and its
|
||||
* current value.
|
||||
|
|
|
@ -18,6 +18,7 @@ package ghidra.program.model.data;
|
|||
import ghidra.docking.settings.*;
|
||||
import ghidra.program.database.data.DataTypeUtilities;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
import ghidra.util.InvalidNameException;
|
||||
import ghidra.util.UniversalID;
|
||||
|
||||
/**
|
||||
|
@ -30,6 +31,7 @@ public class TypedefDataType extends GenericDataType implements TypeDef {
|
|||
|
||||
private DataType dataType;
|
||||
private SettingsDefinition[] settingsDef;
|
||||
private boolean isAutoNamed = false;
|
||||
private boolean deleted = false;
|
||||
|
||||
/**
|
||||
|
@ -104,6 +106,20 @@ public class TypedefDataType extends GenericDataType implements TypeDef {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableAutoNaming() {
|
||||
if (isAutoNamed) {
|
||||
return;
|
||||
}
|
||||
isAutoNamed = true;
|
||||
notifyNameChanged(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoNamed() {
|
||||
return isAutoNamed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefaultLabelPrefix() {
|
||||
return getName();
|
||||
|
@ -124,7 +140,10 @@ public class TypedefDataType extends GenericDataType implements TypeDef {
|
|||
}
|
||||
if (obj instanceof TypeDef) {
|
||||
TypeDef td = (TypeDef) obj;
|
||||
if (!DataTypeUtilities.equalsIgnoreConflict(name, td.getName())) {
|
||||
if (isAutoNamed != td.isAutoNamed()) {
|
||||
return false;
|
||||
}
|
||||
if (!isAutoNamed && !DataTypeUtilities.equalsIgnoreConflict(getName(), td.getName())) {
|
||||
return false;
|
||||
}
|
||||
if (!hasSameTypeDefSettings(td)) {
|
||||
|
@ -175,23 +194,66 @@ public class TypedefDataType extends GenericDataType implements TypeDef {
|
|||
return dataType.getValueClass(settings);
|
||||
}
|
||||
|
||||
public static TypeDef clone(TypeDef typedef, DataTypeManager dtm) {
|
||||
if (typedef.getDataTypeManager() == dtm) {
|
||||
return typedef;
|
||||
}
|
||||
TypedefDataType newTypedef =
|
||||
new TypedefDataType(typedef.getCategoryPath(), typedef.getName(), typedef.getDataType(),
|
||||
typedef.getUniversalID(),
|
||||
typedef.getSourceArchive(), typedef.getLastChangeTime(),
|
||||
typedef.getLastChangeTimeInSourceArchive(), dtm);
|
||||
copyTypeDefSettings(typedef, newTypedef, false);
|
||||
newTypedef.isAutoNamed = typedef.isAutoNamed();
|
||||
return newTypedef;
|
||||
}
|
||||
|
||||
public static TypedefDataType copy(TypeDef typedef, DataTypeManager dtm) {
|
||||
TypedefDataType newTypedef = new TypedefDataType(typedef.getCategoryPath(),
|
||||
typedef.getName(), typedef.getDataType(), dtm);
|
||||
copyTypeDefSettings(typedef, newTypedef, false);
|
||||
newTypedef.isAutoNamed = typedef.isAutoNamed();
|
||||
return newTypedef;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedefDataType clone(DataTypeManager dtm) {
|
||||
if (getDataTypeManager() == dtm) {
|
||||
return this;
|
||||
}
|
||||
TypedefDataType typeDef =
|
||||
new TypedefDataType(categoryPath, name, dataType, getUniversalID(),
|
||||
getSourceArchive(), getLastChangeTime(), getLastChangeTimeInSourceArchive(), dtm);
|
||||
copyTypeDefSettings(this, typeDef, false);
|
||||
return typeDef;
|
||||
return (TypedefDataType) clone(this, dtm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedefDataType copy(DataTypeManager dtm) {
|
||||
TypedefDataType typeDef = new TypedefDataType(categoryPath, name, dataType, dtm);
|
||||
copyTypeDefSettings(this, typeDef, false);
|
||||
return typeDef;
|
||||
return copy(this, dtm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
if (isAutoNamed()) {
|
||||
return generateTypedefName(this);
|
||||
}
|
||||
return super.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) throws InvalidNameException {
|
||||
super.setName(name);
|
||||
isAutoNamed = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCategoryPath(CategoryPath path) {
|
||||
if (isAutoNamed()) {
|
||||
return; // ignore category change if auto-naming enabled
|
||||
}
|
||||
super.setCategoryPath(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CategoryPath getCategoryPath() {
|
||||
if (isAutoNamed()) {
|
||||
return getDataType().getCategoryPath();
|
||||
}
|
||||
return super.getCategoryPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -316,6 +378,9 @@ public class TypedefDataType extends GenericDataType implements TypeDef {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (isAutoNamed()) {
|
||||
return getName();
|
||||
}
|
||||
return "typedef " + getName() + " " + dataType.getName();
|
||||
}
|
||||
|
||||
|
@ -351,9 +416,9 @@ public class TypedefDataType extends GenericDataType implements TypeDef {
|
|||
public static String generateTypedefName(TypeDef modelType) {
|
||||
|
||||
// Examples:
|
||||
// string *32 __attribute__((relative))
|
||||
// char *32 __attribute__((image-base-relative))
|
||||
// char *16 __attribute__((space(data)))
|
||||
// string *32 __((relative))
|
||||
// char *32 __((image-base-relative))
|
||||
// char *16 __((space(data)))
|
||||
|
||||
Settings settings = modelType.getDefaultSettings();
|
||||
StringBuilder attributesBuf = new StringBuilder();
|
||||
|
@ -367,9 +432,11 @@ public class TypedefDataType extends GenericDataType implements TypeDef {
|
|||
}
|
||||
}
|
||||
StringBuilder buf = new StringBuilder(modelType.getDataType().getName());
|
||||
buf.append(" __attribute__((");
|
||||
buf.append(' ');
|
||||
buf.append(DataType.TYPEDEF_ATTRIBUTE_PREFIX);
|
||||
buf.append(attributesBuf);
|
||||
buf.append("))");
|
||||
buf.append(DataType.TYPEDEF_ATTRIBUTE_SUFFIX);
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.docking.settings.SettingsDefinition;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.DataTypeDisplayOptions;
|
||||
|
@ -322,6 +323,11 @@ public class DataStub implements Data {
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChangeAllowed(SettingsDefinition settingsDefinition) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getLong(String name) {
|
||||
throw new UnsupportedOperationException();
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue