mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-06-02 20:10:50 +08: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:
+10
@@ -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'
|
||||
}
|
||||
|
||||
+16
-7
@@ -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
|
||||
|
||||
+45
-11
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+24
-25
@@ -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);
|
||||
|
||||
|
||||
+30
-3
@@ -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:
|
||||
|
||||
+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
|
||||
}
|
||||
|
||||
+1
-1
@@ -144,7 +144,7 @@ public class DataTypeSyncInfo {
|
||||
}
|
||||
|
||||
public String getRefDtPath() {
|
||||
return refDt.getPathName();
|
||||
return refDt.getCategoryPath().getPath();
|
||||
}
|
||||
|
||||
public long getLastChangeTime(boolean useSource) {
|
||||
|
||||
+25
-3
@@ -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)) {
|
||||
|
||||
+33
-9
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
+3
-14
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
@@ -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
|
||||
|
||||
+2
-2
@@ -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);
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
+2
-1
@@ -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);
|
||||
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
+1
-1
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
-3
@@ -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;
|
||||
}
|
||||
|
||||
+5
@@ -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";
|
||||
|
||||
+5
@@ -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";
|
||||
|
||||
+5
@@ -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";
|
||||
|
||||
+5
@@ -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;
|
||||
|
||||
+5
@@ -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;
|
||||
|
||||
+5
@@ -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;
|
||||
|
||||
+5
@@ -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";
|
||||
|
||||
+207
-1
@@ -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 {
|
||||
|
||||
|
||||
+2
-3
@@ -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,
|
||||
|
||||
+30
-37
@@ -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");
|
||||
|
||||
+14
-4
@@ -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"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+133
-111
@@ -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
|
||||
|
||||
+199
-31
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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() {
|
||||
|
||||
+15
-61
@@ -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);
|
||||
|
||||
+3
-3
@@ -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 {
|
||||
|
||||
+2
-2
@@ -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 {
|
||||
|
||||
+6
-6
@@ -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] */
|
||||
|
||||
+2
-2
@@ -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",
|
||||
|
||||
+2
-2
@@ -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 {
|
||||
|
||||
+2
-2
@@ -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 {
|
||||
|
||||
|
||||
+3
-3
@@ -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 =
|
||||
|
||||
+5
-11
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+7
-8
@@ -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;
|
||||
}
|
||||
|
||||
+5
-6
@@ -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 {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user