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:
ghidra1 2022-02-15 10:16:08 -05:00
parent ec5b6aada7
commit 8f0589a6d8
103 changed files with 2226 additions and 1156 deletions

View file

@ -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()) {

View file

@ -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'
}

View file

@ -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

View file

@ -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);
}
}
}

View file

@ -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);

View file

@ -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:

View file

@ -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
}

View file

@ -144,7 +144,7 @@ public class DataTypeSyncInfo {
}
public String getRefDtPath() {
return refDt.getPathName();
return refDt.getCategoryPath().getPath();
}
public long getLastChangeTime(boolean useSource) {

View file

@ -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)) {

View file

@ -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();
}
}

View file

@ -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();
}
}

View file

@ -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);

View file

@ -118,7 +118,6 @@ class DbViewerComponent extends JPanel {
if (dbh == null) {
return;
}
Msg.info(this, "Updating dbViewer...");
synchronized (dbh) {
updateTableChoices((TableItem) combo.getSelectedItem());
updateTable();

View file

@ -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

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);
}
}

View file

@ -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;
}

View file

@ -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";

View file

@ -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";

View file

@ -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";

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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";

View file

@ -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 {

View file

@ -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,

View file

@ -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");

View file

@ -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());
}
}

View file

@ -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"));
}
}

View file

@ -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

View file

@ -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();
}
}

View file

@ -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
}
}
}

View file

@ -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() {

View file

@ -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();

View file

@ -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);

View file

@ -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 {

View file

@ -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 {

View file

@ -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] */

View file

@ -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",

View file

@ -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 {

View file

@ -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 {

View file

@ -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 =

View file

@ -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);
}
/**

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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);
}
/**

View file

@ -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 {

View file

@ -92,6 +92,11 @@ public class FloatingPointPrecisionSettingsDefinition implements EnumSettingsDef
return PRECISION_DIGITS;
}
@Override
public String getStorageKey() {
return PRECISION_DIGITS;
}
@Override
public String getDescription() {
return "Selects the number of digits of precision to display";

View file

@ -114,6 +114,11 @@ public class FormatSettingsDefinition implements EnumSettingsDefinition {
return "Format";
}
@Override
public String getStorageKey() {
return FORMAT;
}
@Override
public String getDescription() {
return "Selects the display format";

View file

@ -113,6 +113,11 @@ public class IntegerSignednessFormattingModeSettingsDefinition implements EnumSe
return "Signedness Mode";
}
@Override
public String getStorageKey() {
return SIGN_FORMAT;
}
@Override
public String getDescription() {
return "Selects the display mode for signed values";

View file

@ -80,7 +80,7 @@ public class JavaEnumSettingsDefinition<T extends Enum<T>> implements EnumSettin
* @return Enum&lt;T&gt; value, or the specified defaultValueOveride if not present.
*/
public T getEnumValue(Settings settings, T defaultValueOverride) {
Long lvalue = settings.getLong(getSettingName());
Long lvalue = settings.getLong(settingName);
if (lvalue == null) {
return defaultValueOverride;
}
@ -126,38 +126,34 @@ public class JavaEnumSettingsDefinition<T extends Enum<T>> implements EnumSettin
return -1;
}
/**
* The name of this setting as it is stored in a {@link Settings} object.
*
* @return String name.
*/
public String getSettingName() {
return settingName;
}
@Override
public boolean hasValue(Settings setting) {
return setting.getValue(getSettingName()) != null;
return setting.getValue(settingName) != null;
}
@Override
public String getName() {
public final String getName() {
return name;
}
@Override
public String getDescription() {
public final String getStorageKey() {
return settingName;
}
@Override
public final String getDescription() {
return description;
}
@Override
public void clear(Settings settings) {
settings.clearSetting(getSettingName());
settings.clearSetting(settingName);
}
@Override
public void copySetting(Settings srcSettings, Settings destSettings) {
Long l = srcSettings.getLong(getSettingName());
Long l = srcSettings.getLong(settingName);
if (l == null) {
clear(destSettings);
}
@ -168,7 +164,7 @@ public class JavaEnumSettingsDefinition<T extends Enum<T>> implements EnumSettin
@Override
public int getChoice(Settings settings) {
Long lvalue = settings.getLong(getSettingName());
Long lvalue = settings.getLong(settingName);
int value = (lvalue != null) ? (int) (long) lvalue : defaultValue.ordinal();
return Math.min(Math.max(value, 0), values.length - 1);
@ -181,7 +177,7 @@ public class JavaEnumSettingsDefinition<T extends Enum<T>> implements EnumSettin
@Override
public void setChoice(Settings settings, int value) {
settings.setLong(getSettingName(), value);
settings.setLong(settingName, value);
}
@Override

View file

@ -22,6 +22,14 @@ package ghidra.docking.settings;
*/
public interface Settings {
/**
* Determine if a settings change corresponding to the specified
* settingsDefinition is permitted.
* @param settingsDefinition settings definition
* @return true if change permitted else false
*/
boolean isChangeAllowed(SettingsDefinition settingsDefinition);
/**
* Gets the Long value associated with the given name
* @param name the key used to retrieve a value

View file

@ -16,6 +16,7 @@
package ghidra.docking.settings;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.function.Predicate;
/**
@ -26,8 +27,7 @@ public interface SettingsDefinition {
/**
* Create a new list of {@link SettingsDefinition}s by concat'ing a base list with
* a var-arg'ish additional list of setting defs.
*
* a var-arg'ish additional list of setting defs. Any additional duplicates are discarded.
* @param settings List of settings defs.
* @param additional More settings defs to add
* @return new array with all the settings defs joined together.
@ -40,11 +40,14 @@ public interface SettingsDefinition {
if (settings == null) {
return additional;
}
SettingsDefinition[] result = new SettingsDefinition[settings.length + additional.length];
System.arraycopy(settings, 0, result, 0, settings.length);
System.arraycopy(additional, 0, result, settings.length, additional.length);
return result;
ArrayList<SettingsDefinition> list = new ArrayList<>();
list.addAll(Arrays.asList(settings));
for (SettingsDefinition def : additional) {
if (!list.contains(def)) {
list.add(def);
}
}
return list.toArray(new SettingsDefinition[list.size()]);
}
/**
@ -81,11 +84,17 @@ public interface SettingsDefinition {
public String getValueString(Settings settings);
/**
* Returns the name of this SettingsDefinition
* Returns the display name of this SettingsDefinition
* @return display name for setting
*/
public String getName();
/**
* Get the {@link Settings} key which is used when storing a key/value entry.
* @return settings storage key
*/
String getStorageKey();
/**
* Returns a description of this settings definition
* @return setting description

View file

@ -65,31 +65,19 @@ public class SettingsImpl implements Settings, Serializable {
}
/**
* Check for immutable settings and log error of modification not permitted
* @param type setting type or null
* @param name setting name or null
* @return true if change permitted
* Construct a new SettingsImpl object. If settings object is specified this
* settings will copy all name/value pairs and underlying defaults.
* @param settings the settings object to copy
*/
private boolean checkSetting(String type, String name) {
if (immutable) {
String typeStr = "";
if (type != null) {
typeStr = type + " ";
public SettingsImpl(Settings settings) {
this();
if (settings != null) {
String[] names = settings.getNames();
for (int i = 0; i < names.length; i++) {
map.put(names[i], settings.getValue(names[i]));
}
String nameStr = ": " + name;
if (name == null) {
nameStr = "s";
}
Msg.warn(SettingsImpl.class,
"Ignored invalid attempt to modify immutable " + typeStr + "component setting" +
nameStr);
return false;
defaultSettings = settings.getDefaultSettings();
}
if (allowedSettingPredicate != null && !allowedSettingPredicate.apply(name)) {
Msg.warn(this, "Ignored disallowed setting '" + name + "'");
return false;
}
return true;
}
/**
@ -113,20 +101,45 @@ public class SettingsImpl implements Settings, Serializable {
this.changeSourceObj = changeSourceObj;
}
/**
* Construct a new SettingsImpl object. If settings object is specified this
* settings will copy all name/value pairs and underlying defaults.
* @param settings the settings object to copy
*/
public SettingsImpl(Settings settings) {
this();
if (settings != null) {
String[] names = settings.getNames();
for (int i = 0; i < names.length; i++) {
map.put(names[i], settings.getValue(names[i]));
}
defaultSettings = settings.getDefaultSettings();
@Override
public boolean isChangeAllowed(SettingsDefinition settingsDefinition) {
if (immutable) {
return false;
}
if (allowedSettingPredicate != null &&
!allowedSettingPredicate.apply(settingsDefinition.getStorageKey())) {
return false;
}
return true;
}
/**
* Check for immutable settings and log error of modification not permitted
* @param type setting type or null
* @param name setting name or null
* @return true if change permitted
*/
private boolean checkSetting(String type, String name) {
if (immutable) {
String typeStr = "";
if (type != null) {
typeStr = type + " ";
}
String nameStr = ": " + name;
if (name == null) {
nameStr = "s";
}
Msg.warn(SettingsImpl.class,
"Ignored invalid attempt to modify immutable " + typeStr + "component setting" +
nameStr);
return false;
}
if (name != null && allowedSettingPredicate != null &&
!allowedSettingPredicate.apply(name)) {
Msg.warn(this, "Ignored disallowed setting '" + name + "'");
return false;
}
return true;
}
@Override

View file

@ -82,9 +82,10 @@ public class PackedDBHandle extends DBHandle {
}
@Override
protected synchronized void saveAs(BufferFile outFile, Long newDatabaseId, TaskMonitor monitor)
protected synchronized void saveAs(BufferFile outFile, Long newDatabaseId,
boolean associateWithNewFile, TaskMonitor monitor)
throws IOException, CancelledException {
super.saveAs(outFile, newDatabaseId, monitor);
super.saveAs(outFile, newDatabaseId, associateWithNewFile, monitor);
if (pdb != null) {
pdb.dispose();
pdb = null;

View file

@ -179,7 +179,7 @@ public class PackedDatabase extends Database {
LocalManagedBufferFile bfile = new LocalManagedBufferFile(dbHandle.getBufferSize(),
bfMgr, FolderItem.DEFAULT_CHECKOUT_ID);
dbHandle.saveAs(bfile, newDatabaseId, monitor);
dbHandle.saveAs(bfile, newDatabaseId, true, monitor);
packDatabase(monitor);
addInstance(this);
success = true;

View file

@ -18,6 +18,7 @@ package ghidra.app.util;
import java.util.*;
import ghidra.docking.settings.Settings;
import ghidra.docking.settings.SettingsDefinition;
import ghidra.program.database.ProgramDB;
import ghidra.program.database.data.ProgramDataTypeManager;
import ghidra.program.model.address.Address;
@ -228,7 +229,12 @@ public class PseudoData extends PseudoCodeUnit implements Data {
@Override
public Long getLong(String name) {
return null;
return getDefaultSettings().getLong(name);
}
@Override
public boolean isChangeAllowed(SettingsDefinition settingsDefinition) {
return false;
}
@Override
@ -238,15 +244,12 @@ public class PseudoData extends PseudoCodeUnit implements Data {
@Override
public String getString(String name) {
return null;
return getDefaultSettings().getString(name);
}
@Override
public Object getValue(String name) {
if (baseDataType != null) {
return baseDataType.getValue(this, this, length);
}
return null;
return getDefaultSettings().getValue(name);
}
@Override
@ -369,41 +372,6 @@ public class PseudoData extends PseudoCodeUnit implements Data {
return null;
}
// /**
// * @see ghidra.program.model.listing.Data#getComponents()
// */
// public Data[] getComponents() {
// if (length < dataType.getLength()) {
// return null;
// }
// Data[] retData = EMPTY_COMPONENTS;
// if (baseDataType instanceof Composite) {
// Composite composite = (Composite)baseDataType;
// int n = composite.getNumComponents();
// retData = new Data[n];
// for(int i=0;i<n;i++) {
// retData[i] = getComponent(i);
// }
// }
// else if (baseDataType instanceof Array) {
// Array array = (Array)baseDataType;
// int n = array.getNumElements();
// retData = new Data[n];
// for(int i=0;i<n;i++) {
// retData[i] = getComponent(i);
// }
// }
// else if (baseDataType instanceof DynamicDataType) {
// DynamicDataType ddt = (DynamicDataType)baseDataType;
// int n = ddt.getNumComponents(this);
// retData = new Data[n];
// for(int i=0;i<n;i++) {
// retData[i] = getComponent(i);
// }
// }
// return retData;
// }
@Override
public DataType getDataType() {
return dataType;
@ -542,7 +510,7 @@ public class PseudoData extends PseudoCodeUnit implements Data {
if (dataMgr == null) {
return true;
}
return dataMgr.isEmptySetting(address);
return dataMgr.isEmptySetting(this);
}
@Override

View file

@ -38,7 +38,6 @@ class PseudoDataComponent extends PseudoData {
private int indexInParent;
private int offset;
private int[] path;
private Settings defaultSettings;
PseudoDataComponent(Program program, Address address, PseudoData parent,
DataTypeComponent component, MemBuffer memBuffer)
@ -170,60 +169,6 @@ class PseudoDataComponent extends PseudoData {
return super.equals(obj);
}
@Override
public Long getLong(String name) {
if (dataMgr == null) {
return null;
}
Long value = dataMgr.getLongSettingsValue(address, name);
if (value != null) {
return value;
}
if (component == null) {
return null;
}
if (defaultSettings == null) {
defaultSettings = component.getDefaultSettings();
}
return defaultSettings.getLong(name);
}
@Override
public String getString(String name) {
if (dataMgr == null) {
return null;
}
String value = dataMgr.getStringSettingsValue(address, name);
if (value != null) {
return value;
}
if (component == null) {
return null;
}
if (defaultSettings == null) {
defaultSettings = component.getDefaultSettings();
}
return defaultSettings.getString(name);
}
@Override
public Object getValue(String name) {
if (dataMgr == null) {
return null;
}
Object value = dataMgr.getSettings(address, name);
if (value != null) {
return value;
}
if (component == null) {
return null;
}
if (defaultSettings == null) {
defaultSettings = component.getDefaultSettings();
}
return defaultSettings.getValue(name);
}
@Override
public synchronized String getComment(int commentType) {
String cmt = super.getComment(commentType);
@ -238,7 +183,7 @@ class PseudoDataComponent extends PseudoData {
if (component != null) {
return component.getDefaultSettings();
}
return dataType.getDefaultSettings();
return super.getDefaultSettings();
}
}

View file

@ -283,12 +283,4 @@ class DataComponent extends DataDB {
return super.getDefaultSettings();
}
@Override
protected Address getDataSettingsAddress() {
if (parent.getBaseDataType() instanceof Array) {
return parent.getDataSettingsAddress();
}
return address;
}
}

View file

@ -373,17 +373,22 @@ class DataDB extends CodeUnitDB implements Data {
return hasMutability(MutabilitySettingsDefinition.VOLATILE);
}
@Override
public boolean isChangeAllowed(SettingsDefinition settingsDefinition) {
refreshIfNeeded();
return dataMgr.isChangeAllowed(this, settingsDefinition);
}
@Override
public void clearSetting(String name) {
refreshIfNeeded();
Address cuAddr = getDataSettingsAddress();
dataMgr.clearSetting(cuAddr, name);
dataMgr.clearSetting(this, name);
}
@Override
public Long getLong(String name) {
refreshIfNeeded();
Long value = dataMgr.getLongSettingsValue(getDataSettingsAddress(), name);
Long value = dataMgr.getLongSettingsValue(this, name);
if (value == null) {
value = getDefaultSettings().getLong(name);
}
@ -393,13 +398,13 @@ class DataDB extends CodeUnitDB implements Data {
@Override
public String[] getNames() {
refreshIfNeeded();
return dataMgr.getInstanceSettingsNames(getDataSettingsAddress());
return dataMgr.getInstanceSettingsNames(this);
}
@Override
public String getString(String name) {
refreshIfNeeded();
String value = dataMgr.getStringSettingsValue(getDataSettingsAddress(), name);
String value = dataMgr.getStringSettingsValue(this, name);
if (value == null) {
value = getDefaultSettings().getString(name);
}
@ -409,7 +414,7 @@ class DataDB extends CodeUnitDB implements Data {
@Override
public Object getValue(String name) {
refreshIfNeeded();
Object value = dataMgr.getSettings(getDataSettingsAddress(), name);
Object value = dataMgr.getSettings(this, name);
if (value == null) {
value = getDefaultSettings().getValue(name);
}
@ -419,22 +424,19 @@ class DataDB extends CodeUnitDB implements Data {
@Override
public void setLong(String name, long value) {
refreshIfNeeded();
Address cuAddr = getDataSettingsAddress();
dataMgr.setLongSettingsValue(cuAddr, name, value);
dataMgr.setLongSettingsValue(this, name, value);
}
@Override
public void setString(String name, String value) {
refreshIfNeeded();
Address cuAddr = getDataSettingsAddress();
dataMgr.setStringSettingsValue(cuAddr, name, value);
dataMgr.setStringSettingsValue(this, name, value);
}
@Override
public void setValue(String name, Object value) {
refreshIfNeeded();
Address cuAddr = getDataSettingsAddress();
dataMgr.setSettings(cuAddr, name, value);
dataMgr.setSettings(this, name, value);
}
@Override
@ -758,14 +760,13 @@ class DataDB extends CodeUnitDB implements Data {
@Override
public void clearAllSettings() {
refreshIfNeeded();
Address cuAddr = getDataSettingsAddress();
dataMgr.clearAllSettings(cuAddr);
dataMgr.clearAllSettings(this);
}
@Override
public boolean isEmpty() {
refreshIfNeeded();
return dataMgr.isEmptySetting(getDataSettingsAddress());
return dataMgr.isEmptySetting(this);
}
@Override
@ -789,7 +790,4 @@ class DataDB extends CodeUnitDB implements Data {
return dataType.getDefaultSettings();
}
protected Address getDataSettingsAddress() {
return address;
}
}

View file

@ -18,8 +18,7 @@ package ghidra.program.database.data;
import java.io.IOException;
import db.DBRecord;
import ghidra.docking.settings.Settings;
import ghidra.docking.settings.SettingsImpl;
import ghidra.docking.settings.*;
import ghidra.program.model.data.*;
import ghidra.util.SystemUtilities;
import ghidra.util.exception.DuplicateNameException;
@ -433,6 +432,19 @@ class DataTypeComponentDB implements InternalDataTypeComponent {
dataMgr.dataTypeChanged(getParent(), false);
}
@Override
public boolean isChangeAllowed(SettingsDefinition settingsDefinition) {
if (settingsDefinition instanceof TypeDefSettingsDefinition) {
return false;
}
for (SettingsDefinition def : getDataType().getSettingsDefinitions()) {
if (def.equals(settingsDefinition)) {
return true;
}
}
return false;
}
@Override
public Long getLong(String name) {
SettingDB settingDB = dataMgr.getSetting(record.getKey(), name);

View file

@ -26,6 +26,8 @@ import db.*;
import db.util.ErrorHandler;
import generic.jar.ResourceFile;
import ghidra.app.plugin.core.datamgr.archive.BuiltInSourceArchive;
import ghidra.docking.settings.Settings;
import ghidra.docking.settings.SettingsDefinition;
import ghidra.framework.store.db.PackedDBHandle;
import ghidra.framework.store.db.PackedDatabase;
import ghidra.graph.*;
@ -63,8 +65,9 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
*
* Due to the frequent use of read-only mode for certain archives, read-only
* mode must always be allowed when opening older versions.
* - version 1 - legacy prior to overall DTM versioning (not stored)
* 12-Jan-2022 - version 2 - introduced DataTypeManager data map table and overall DTM version
* - version 1 - Legacy prior to overall DTM versioning (not stored)
* 12-Jan-2022 - version 2 - Introduced DataTypeManager data map table and overall DTM version.
* Also added typedef flags and auto-naming support.
*/
static final int DB_VERSION = 2;
@ -869,7 +872,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
return name;
}
public String getUniqueName(CategoryPath path1, CategoryPath path2, String baseName) {
String getUniqueName(CategoryPath path1, CategoryPath path2, String baseName) {
int pos = baseName.lastIndexOf('_');
int oneUpNumber = 0;
String name = baseName;
@ -893,6 +896,9 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
@Override
public Category getCategory(CategoryPath path) {
if (path == null) {
return null;
}
if (path.equals(CategoryPath.ROOT)) {
return root;
}
@ -2166,7 +2172,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
@Override
public DataType getDataType(CategoryPath path, String name) {
if (path.equals(DataType.DEFAULT.getCategoryPath()) &&
if (CategoryPath.ROOT.equals(path) &&
name.equals(DataType.DEFAULT.getName())) {
return DataType.DEFAULT;
}
@ -2279,16 +2285,13 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
private DataType getBuiltInDataType(long dataTypeID, DBRecord record) {
lock.acquire();
try {
Long key = dataTypeID;
DataType dt = builtInMap.get(key);
DataType dt = builtInMap.get(dataTypeID);
if (dt != null) {
return dt;
}
if (record == null) {
record = builtinAdapter.getRecord(dataTypeID);
if (record == null) {
return null;
}
@ -2301,7 +2304,6 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
String name = record.getString(BuiltinDBAdapter.BUILT_IN_NAME_COL);
try { // TODO: !! Can we look for alternate constructor which takes DTM argument
Class<?> c;
try {
c = Class.forName(classPath);
}
@ -2322,18 +2324,41 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
BuiltInDataType bdt = (BuiltInDataType) c.getDeclaredConstructor().newInstance();
bdt.setName(name);
bdt.setCategoryPath(catPath);
bdt = (BuiltInDataType) bdt.clone(this);
if (allowsDefaultBuiltInSettings() && bdt.getSettingsDefinitions().length != 0) {
bdt.setDefaultSettings(new DataTypeSettingsDB(this, bdt, dataTypeID));
final BuiltInDataType builtInDt = (BuiltInDataType) bdt.clone(this);
// check for prior instantiation with different id
Long id = builtIn2IdMap.get(builtInDt);
if (id != null) {
DataType datatype = builtInMap.get(id);
if (datatype != null) {
builtInMap.put(dataTypeID, datatype);
return datatype;
}
}
dt = bdt;
if (allowsDefaultBuiltInSettings() &&
builtInDt.getSettingsDefinitions().length != 0) {
DataTypeSettingsDB settings =
new DataTypeSettingsDB(this, builtInDt, dataTypeID);
if (builtInDt instanceof TypeDef) {
// Copy default immutable builtin typedef settings
Settings typedefSettings = builtInDt.getDefaultSettings();
for (String n : typedefSettings.getNames()) {
settings.setValue(n, typedefSettings.getValue(n));
}
}
settings.setAllowedSettingPredicate(n -> isBuiltInSettingAllowed(builtInDt, n));
builtInDt.setDefaultSettings(settings);
}
dt = builtInDt;
}
catch (Exception e) {
Msg.error(this, e);
dt = new MissingBuiltInDataType(catPath, name, classPath, this);
}
builtInMap.put(key, dt);
builtIn2IdMap.put(dt, key);
builtInMap.put(dataTypeID, dt);
builtIn2IdMap.put(dt, dataTypeID);
return dt;
}
catch (IOException e) {
@ -2345,6 +2370,18 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
return null;
}
private boolean isBuiltInSettingAllowed(BuiltInDataType bdt, String settingName) {
SettingsDefinition def = null;
for (SettingsDefinition sd : bdt.getSettingsDefinitions()) {
if (sd.getStorageKey().equals(settingName)) {
def = sd;
break;
}
}
// restrict to non-TypeDefSettingsDefinitions which are defined for the datatype
return def != null && !(def instanceof TypeDefSettingsDefinition);
}
private Enum getEnumDataType(long dataTypeID, DBRecord record) {
lock.acquire();
try {
@ -2526,6 +2563,10 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
int len = ptr.hasLanguageDependantLength() ? -1 : ptr.getLength();
newDataType = createPointer(ptr.getDataType(), cat, (byte) len, handler);
}
else if (dt instanceof BuiltInDataType) {
BuiltInDataType builtInDataType = (BuiltInDataType) dt;
newDataType = createBuiltIn(builtInDataType, cat);
}
else if (dt instanceof StructureInternal) {
StructureInternal structure = (StructureInternal) dt;
newDataType = createStructure(structure, name, cat, sourceArchiveIdValue,
@ -2550,10 +2591,6 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
newDataType = createFunctionDefinition(funDef, name, cat, sourceArchiveIdValue,
id.getValue());
}
else if (dt instanceof BuiltInDataType) {
BuiltInDataType builtInDataType = (BuiltInDataType) dt;
newDataType = createBuiltIn(builtInDataType, cat);
}
else if (dt instanceof MissingBuiltInDataType) {
MissingBuiltInDataType missingBuiltInDataType = (MissingBuiltInDataType) dt;
newDataType = createMissingBuiltIn(missingBuiltInDataType, cat);
@ -2621,7 +2658,13 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
throw new IllegalArgumentException("Data type must have a valid name");
}
DataType dataType = resolve(typedef.getDataType(), getDependencyConflictHandler());
DBRecord record = typedefAdapter.createRecord(getID(dataType), name, cat.getID(),
boolean isAutoNamed = typedef.isAutoNamed();
short flags = 0;
if (isAutoNamed) {
flags = (short) TypedefDBAdapter.TYPEDEF_FLAG_AUTONAME;
cat = getCategory(dataType.getCategoryPath()); // force category
}
DBRecord record = typedefAdapter.createRecord(getID(dataType), name, flags, cat.getID(),
sourceArchiveIdValue, universalIdValue, typedef.getLastChangeTime());
TypedefDB typedefDB = new TypedefDB(this, dtCache, typedefAdapter, record);
@ -2631,6 +2674,8 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
TypedefDataType.copyTypeDefSettings(typedef, typedefDB, false);
settings.setLock(wasLocked);
typedefDB.updateAutoName(false);
dataType.addParent(typedefDB);
return typedefDB;
}
@ -3047,8 +3092,9 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
* @param oldCatId the old category's record id
*/
void dataTypeCategoryPathChanged(DataTypeDB dt, CategoryPath oldPath, long oldCatId) {
if (!(dt instanceof Array) && !(dt instanceof Pointer)) {
try {
try {
if (!(dt instanceof Array) && !(dt instanceof Pointer)) {
for (Field arrayId : arrayAdapter.getRecordIdsInCategory(oldCatId)) {
long id = arrayId.getLongValue();
DBRecord rec = arrayAdapter.getRecord(id);
@ -3062,10 +3108,18 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
ptr.updatePath(dt);
}
}
catch (IOException e) {
dbError(e);
// only affects those with auto-naming which must follow category change
for (Field ptrId : typedefAdapter.getRecordIdsInCategory(oldCatId)) {
long id = ptrId.getLongValue();
DBRecord rec = typedefAdapter.getRecord(id);
TypedefDB td = (TypedefDB) getDataType(id, rec);
td.updatePath(dt);
}
}
catch (IOException e) {
dbError(e);
}
dataTypeMoved(dt, new DataTypePath(oldPath, dt.getName()), dt.getDataTypePath());
}
@ -3341,7 +3395,12 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
return creatingDataType != 0;
}
@Override
/**
* Notification when data type is changed.
* @param dt data type that is changed
* @param isAutoChange true if change was an automatic change in response to
* another datatype's change (e.g., size, alignment).
*/
public void dataTypeChanged(DataType dt, boolean isAutoChange) {
if (dt instanceof Enum) {
enumValueMap = null;
@ -3353,6 +3412,22 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
defaultListener.dataTypeChanged(this, dt.getDataTypePath());
}
/**
* Notification when data type settings have changed.
* @param dt data type that is changed
*/
public void dataTypeSettingsChanged(DataType dt) {
if (dt instanceof TypedefDB) {
TypedefDB td = (TypedefDB) dt;
td.updateAutoName(true);
if (creatingDataType == 0) {
td.setLastChangeTime(System.currentTimeMillis());
setDirtyFlag(dt);
}
}
defaultListener.dataTypeChanged(this, dt.getDataTypePath());
}
protected void dataTypeAdded(DataType newDt, DataType originalDataType) {
CategoryDB category = (CategoryDB) getCategory(newDt.getCategoryPath());
category.dataTypeAdded(newDt);

View file

@ -17,8 +17,7 @@ package ghidra.program.database.data;
import com.google.common.base.Predicate;
import ghidra.docking.settings.Settings;
import ghidra.docking.settings.SettingsImpl;
import ghidra.docking.settings.*;
import ghidra.program.model.data.*;
import ghidra.util.Msg;
@ -78,6 +77,18 @@ class DataTypeSettingsDB implements Settings {
return wasLocked;
}
@Override
public boolean isChangeAllowed(SettingsDefinition settingsDefinition) {
if (locked) {
return false;
}
if (allowedSettingPredicate != null &&
!allowedSettingPredicate.apply(settingsDefinition.getStorageKey())) {
return false;
}
return true;
}
/**
* Set predicate for settings modification
* @param allowedSettingPredicate callback for checking an allowed setting modification
@ -107,7 +118,8 @@ class DataTypeSettingsDB implements Settings {
nameStr);
return false;
}
if (allowedSettingPredicate != null && !allowedSettingPredicate.apply(name)) {
if (name != null && allowedSettingPredicate != null &&
!allowedSettingPredicate.apply(name)) {
Msg.warn(this, "Ignored disallowed setting '" + name + "'");
return false;
}
@ -118,7 +130,7 @@ class DataTypeSettingsDB implements Settings {
// NOTE: Merge currently only supports TypeDefDB default settings changes which correspond
// to TypeDefSettingsDefinition established by the base datatype
// and does not consider DataTypeComponent default settings changes or other setting types.
dataMgr.dataTypeChanged(dataType, false);
dataMgr.dataTypeSettingsChanged(dataType);
}
@Override

View file

@ -52,8 +52,8 @@ public class PointerTypedefInspector {
* its default settings.
* @param pointerTypeDef Pointer TypeDef
* @param addrFactory target address factory
* @return referenced address space or null if not applicable
* or the space setting is not defined within the addrFactory.
* @return referenced address space or null if not specified or address space
* lookup fails.
*/
public static AddressSpace getPointerAddressSpace(TypeDef pointerTypeDef,
AddressFactory addrFactory) {

View file

@ -20,11 +20,14 @@ import java.util.List;
import db.*;
import db.util.ErrorHandler;
import ghidra.docking.settings.SettingsDefinition;
import ghidra.program.database.map.AddressMap;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.KeyRange;
import ghidra.program.model.data.ProgramBasedDataTypeManager;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.Data;
import ghidra.util.Lock;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.VersionException;
import ghidra.util.task.TaskMonitor;
@ -91,22 +94,36 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
abstract protected void dataSettingChanged(Address address);
@Override
public boolean setLongSettingsValue(Address dataAddr, String name, long value) {
return updateInstanceSettings(dataAddr, name, null, value);
public boolean isChangeAllowed(Data data,
SettingsDefinition settingsDefinition) {
if (settingsDefinition instanceof TypeDefSettingsDefinition) {
return false;
}
for (SettingsDefinition def : data.getDataType().getSettingsDefinitions()) {
if (def.equals(settingsDefinition)) {
return true;
}
}
return false;
}
@Override
public boolean setStringSettingsValue(Address dataAddr, String name, String value) {
return updateInstanceSettings(dataAddr, name, value, -1);
public boolean setLongSettingsValue(Data data, String name, long value) {
return updateInstanceSettings(data, name, null, value);
}
@Override
public boolean setSettings(Address dataAddr, String name, Object value) {
public boolean setStringSettingsValue(Data data, String name, String value) {
return updateInstanceSettings(data, name, value, -1);
}
@Override
public boolean setSettings(Data data, String name, Object value) {
if (value instanceof String) {
return updateInstanceSettings(dataAddr, name, (String) value, -1);
return updateInstanceSettings(data, name, (String) value, -1);
}
else if (isAllowedNumberType(value)) {
return updateInstanceSettings(dataAddr, name, null, ((Number) value).longValue());
return updateInstanceSettings(data, name, null, ((Number) value).longValue());
}
throw new IllegalArgumentException(
"Unsupportd Settings Value: " + (value == null ? "null" : value.getClass().getName()));
@ -129,8 +146,8 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
}
@Override
public Long getLongSettingsValue(Address dataAddr, String name) {
SettingDB settings = getSettingDB(dataAddr, name);
public Long getLongSettingsValue(Data data, String name) {
SettingDB settings = getSettingDB(data, name);
if (settings != null) {
return settings.getLongValue();
}
@ -138,8 +155,8 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
}
@Override
public String getStringSettingsValue(Address dataAddr, String name) {
SettingDB settings = getSettingDB(dataAddr, name);
public String getStringSettingsValue(Data data, String name) {
SettingDB settings = getSettingDB(data, name);
if (settings != null) {
return settings.getStringValue();
}
@ -147,21 +164,22 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
}
@Override
public Object getSettings(Address dataAddr, String name) {
Object obj = getStringSettingsValue(dataAddr, name);
public Object getSettings(Data data, String name) {
Object obj = getStringSettingsValue(data, name);
if (obj != null) {
return obj;
}
return getLongSettingsValue(dataAddr, name);
return getLongSettingsValue(data, name);
}
@Override
public boolean clearSetting(Address dataAddr, String name) {
public boolean clearSetting(Data data, String name) {
if (instanceSettingsAdapter == null) {
throw new UnsupportedOperationException();
}
lock.acquire();
try {
Address dataAddr = getDataSettingsAddress(data);
instanceSettingsCache.remove(dataAddr, name);
long addr = addrMap.getKey(dataAddr, false);
if (instanceSettingsAdapter.removeSettingsRecord(addr, name)) {
@ -180,7 +198,7 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
}
@Override
public void clearAllSettings(Address dataAddr) {
public void clearAllSettings(Data data) {
if (instanceSettingsAdapter == null) {
throw new UnsupportedOperationException();
}
@ -188,6 +206,7 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
try {
instanceSettingsCache.clear();
boolean changed = false;
Address dataAddr = getDataSettingsAddress(data);
Field[] keys = instanceSettingsAdapter.getSettingsKeys(addrMap.getKey(dataAddr, false));
for (Field key : keys) {
instanceSettingsAdapter.removeSettingsRecord(key.getLongValue());
@ -267,12 +286,13 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
}
@Override
public String[] getInstanceSettingsNames(Address dataAddr) {
public String[] getInstanceSettingsNames(Data data) {
if (instanceSettingsAdapter == null) {
throw new UnsupportedOperationException();
}
lock.acquire();
try {
Address dataAddr = getDataSettingsAddress(data);
return instanceSettingsAdapter.getSettingsNames(addrMap.getKey(dataAddr, false));
}
catch (IOException e) {
@ -285,11 +305,12 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
}
@Override
public boolean isEmptySetting(Address dataAddr) {
public boolean isEmptySetting(Data data) {
if (instanceSettingsAdapter == null) {
throw new UnsupportedOperationException();
}
try {
Address dataAddr = getDataSettingsAddress(data);
return instanceSettingsAdapter
.getSettingsKeys(addrMap.getKey(dataAddr, false)).length == 0;
}
@ -299,7 +320,7 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
return true;
}
private boolean updateInstanceSettings(Address dataAddr, String name, String strValue,
private boolean updateInstanceSettings(Data data, String name, String strValue,
long longValue) {
boolean wasChanged = false;
@ -309,6 +330,10 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
if (instanceSettingsAdapter == null) {
throw new UnsupportedOperationException();
}
if (!checkSetting(data, name)) {
return false;
}
Address dataAddr = getDataSettingsAddress(data);
long addrKey = addrMap.getKey(dataAddr, true);
DBRecord rec =
instanceSettingsAdapter.updateSettingsRecord(addrKey, name, strValue, longValue);
@ -330,12 +355,31 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
return wasChanged;
}
private SettingDB getSettingDB(Address dataAddr, String name) {
private boolean checkSetting(Data data, String name) {
SettingsDefinition settingsDefinition = null;
for (SettingsDefinition def : data.getDataType().getSettingsDefinitions()) {
if (def.getStorageKey().equals(name)) {
settingsDefinition = def;
break;
}
}
if (settingsDefinition == null) {
Msg.warn(this, "Ignored unrecognized setting '" + name + "'");
return false;
}
if (settingsDefinition instanceof TypeDefSettingsDefinition) {
Msg.warn(this, "Ignored disallowed instance setting '" + name + "'");
}
return true;
}
private SettingDB getSettingDB(Data data, String name) {
lock.acquire();
try {
if (instanceSettingsAdapter == null) {
throw new UnsupportedOperationException();
}
Address dataAddr = getDataSettingsAddress(data);
SettingDB settings = instanceSettingsCache.get(dataAddr, name);
if (settings != null) {
return settings;
@ -380,4 +424,15 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
lock.release();
}
}
private static Address getDataSettingsAddress(Data data) {
Data parent = data.getParent();
if (parent != null) {
DataType dataType = parent.getDataType();
if (dataType instanceof Array) {
return getDataSettingsAddress(parent);
}
}
return data.getAddress();
}
}

View file

@ -55,8 +55,8 @@ class SettingsDBAdapterV1 extends SettingsDBAdapter {
private Table settingsTable;
private Table settingsNameTable;
private HashMap<Short, String> nameIndexMap = new HashMap<>();
private HashMap<String, Short> nameStringMap = new HashMap<>();
private HashMap<Short, String> nameIndexMap;
private HashMap<String, Short> nameStringMap;
SettingsDBAdapterV1(String tableName, DBHandle handle, boolean create)
throws VersionException, IOException {

View file

@ -24,6 +24,7 @@ import ghidra.program.database.DBObjectCache;
import ghidra.program.model.data.*;
import ghidra.program.model.mem.MemBuffer;
import ghidra.util.UniversalID;
import ghidra.util.exception.DuplicateNameException;
/**
* Database implementation for a Typedef data type.
@ -49,6 +50,73 @@ class TypedefDB extends DataTypeDB implements TypeDef {
this.defaultSettings = null; // ensure lazy initialization
}
private void setFlags(int flags) {
record.setShortValue(TypedefDBAdapter.TYPEDEF_FLAGS_COL, (short) flags);
}
private int getFlags() {
return record.getShortValue(TypedefDBAdapter.TYPEDEF_FLAGS_COL);
}
@Override
public void enableAutoNaming() {
if (isAutoNamed()) {
return;
}
lock.acquire();
try {
checkDeleted();
String oldName = getName();
setFlags(getFlags() | TypedefDBAdapter.TYPEDEF_FLAG_AUTONAME);
adapter.updateRecord(record, true);
// auto-named typedef follows category of associated datatype
CategoryPath oldPath = getCategoryPath();
CategoryPath currentPath = getDataType().getCategoryPath();
String newName = generateTypedefName(currentPath);
record.setString(TypedefDBAdapter.TYPEDEF_NAME_COL, newName);
adapter.updateRecord(record, true);
refreshName();
if (!currentPath.equals(oldPath)) {
// update category for typedef
try {
super.setCategoryPath(currentPath);
}
catch (DuplicateNameException e) {
// should not happen
}
}
notifyNameChanged(oldName);
}
catch (IOException e) {
dataMgr.dbError(e);
}
finally {
lock.release();
}
}
@Override
public boolean isAutoNamed() {
int flags = getFlags();
if (isInvalid()) {
lock.acquire();
try {
checkIsValid();
flags = getFlags();
}
finally {
lock.release();
}
}
return (flags & TypedefDBAdapter.TYPEDEF_FLAG_AUTONAME) != 0;
}
@Override
protected long doGetCategoryID() {
return record.getLongValue(TypedefDBAdapter.TYPEDEF_CAT_COL);
@ -67,6 +135,7 @@ class TypedefDB extends DataTypeDB implements TypeDef {
@Override
protected void doSetNameRecord(String name) throws IOException {
record.setString(TypedefDBAdapter.TYPEDEF_NAME_COL, name);
setFlags(getFlags() & ~TypedefDBAdapter.TYPEDEF_FLAG_AUTONAME); // clear auto-name flag if name is set
adapter.updateRecord(record, true);
}
@ -165,19 +234,13 @@ class TypedefDB extends DataTypeDB implements TypeDef {
}
@Override
public DataType clone(DataTypeManager dtm) {
TypedefDataType typeDef =
new TypedefDataType(getCategoryPath(), getName(), getDataType(), getUniversalID(),
getSourceArchive(), getLastChangeTime(), getLastChangeTimeInSourceArchive(), dtm);
TypedefDataType.copyTypeDefSettings(this, typeDef, false);
return typeDef;
public TypeDef clone(DataTypeManager dtm) {
return TypedefDataType.clone(this, dtm);
}
@Override
public DataType copy(DataTypeManager dtm) {
TypedefDataType typeDef = new TypedefDataType(getCategoryPath(), getName(), getDataType(), dtm);
TypedefDataType.copyTypeDefSettings(this, typeDef, false);
return typeDef;
public TypedefDataType copy(DataTypeManager dtm) {
return TypedefDataType.copy(this, dtm);
}
@Override
@ -190,7 +253,12 @@ class TypedefDB extends DataTypeDB implements TypeDef {
}
TypeDef td = (TypeDef) obj;
validate(lock);
if (!DataTypeUtilities.equalsIgnoreConflict(getName(), td.getName())) {
boolean autoNamed = isAutoNamed();
if (autoNamed != td.isAutoNamed()) {
return false;
}
if (!autoNamed && !DataTypeUtilities.equalsIgnoreConflict(getName(), td.getName())) {
return false;
}
if (!hasSameTypeDefSettings(td)) {
@ -199,6 +267,13 @@ class TypedefDB extends DataTypeDB implements TypeDef {
return DataTypeUtilities.isSameOrEquivalentDataType(getDataType(), td.getDataType());
}
public void setCategoryPath(CategoryPath path) throws DuplicateNameException {
if (isAutoNamed()) {
return; // ignore category change if auto-naming enabled
}
super.setCategoryPath(path);
}
@Override
protected void doSetCategoryPathRecord(long categoryID) throws IOException {
record.setLongValue(TypedefDBAdapter.TYPEDEF_CAT_COL, categoryID);
@ -251,7 +326,9 @@ class TypedefDB extends DataTypeDB implements TypeDef {
@Override
public void dataTypeNameChanged(DataType dt, String oldName) {
// ignore
if (getDataType() == dt) {
updateAutoName(true);
}
}
@Override
@ -330,6 +407,9 @@ class TypedefDB extends DataTypeDB implements TypeDef {
@Override
public String toString() {
if (isAutoNamed()) {
return getName();
}
return "typedef " + this.getName() + " " + getDataType().getName();
}
@ -440,10 +520,92 @@ class TypedefDB extends DataTypeDB implements TypeDef {
TypeDef td = (TypeDef) dataType;
dataTypeReplaced(getDataType(), td.getDataType());
TypedefDataType.copyTypeDefSettings(td, this, true);
// NOTE: as with the name, auto-name setting is left unchanged
}
finally {
lock.release();
}
}
@Override
protected void updatePath(DataTypeDB dt) {
if (isAutoNamed() && dt == getDataType()) {
// auto-named typedef follows category of associated datatype
CategoryPath oldPath = getCategoryPath();
CategoryPath currentPath = dt.getCategoryPath();
if (!currentPath.equals(oldPath)) {
try {
boolean nameChanged = false;
String oldName = getName();
String newName = generateTypedefName(currentPath);
if (!newName.equals(oldName)) {
nameChanged = true;
record.setString(TypedefDBAdapter.TYPEDEF_NAME_COL, newName);
refreshName();
}
super.setCategoryPath(currentPath);
if (nameChanged) {
notifyNameChanged(oldName);
}
}
catch (DuplicateNameException e) {
// should not happen
}
}
}
}
private String generateTypedefName(CategoryPath path) {
String newName = TypedefDataType.generateTypedefName(this);
DataType dt = dataMgr.getDataType(path, newName);
if (dt == null || dt == this) {
return newName;
}
String baseName = newName + DataType.CONFLICT_SUFFIX;
newName = baseName;
int count = 0;
while (true) {
dt = dataMgr.getDataType(path, newName);
if (dt == null || dt == this) {
break;
}
count++;
newName = baseName + count;
}
return newName;
}
boolean updateAutoName(boolean notify) {
lock.acquire();
try {
checkIsValid();
if (!isAutoNamed()) {
return false;
}
String oldName = getName();
String newName = generateTypedefName(getCategoryPath());
if (oldName.equals(newName)) {
return false;
}
record.setString(TypedefDBAdapter.TYPEDEF_NAME_COL, newName);
adapter.updateRecord(record, false);
refreshName();
if (notify) {
notifyNameChanged(oldName);
}
}
catch (IOException e) {
dataMgr.dbError(e);
}
finally {
lock.release();
}
return true;
}
}

View file

@ -28,19 +28,23 @@ import ghidra.util.task.TaskMonitor;
abstract class TypedefDBAdapter {
static final String TYPEDEF_TABLE_NAME = "Typedefs";
static final Schema SCHEMA = TypedefDBAdapterV1.V1_SCHEMA;
static final Schema SCHEMA = TypedefDBAdapterV2.V2_SCHEMA;
static final int TYPEDEF_DT_ID_COL = TypedefDBAdapterV1.V1_TYPEDEF_DT_ID_COL;
static final int TYPEDEF_NAME_COL = TypedefDBAdapterV1.V1_TYPEDEF_NAME_COL;
static final int TYPEDEF_CAT_COL = TypedefDBAdapterV1.V1_TYPEDEF_CAT_COL;
static final int TYPEDEF_DT_ID_COL = TypedefDBAdapterV2.V2_TYPEDEF_DT_ID_COL;
static final int TYPEDEF_FLAGS_COL = TypedefDBAdapterV2.V2_TYPEDEF_FLAGS_COL;
static final int TYPEDEF_NAME_COL = TypedefDBAdapterV2.V2_TYPEDEF_NAME_COL;
static final int TYPEDEF_CAT_COL = TypedefDBAdapterV2.V2_TYPEDEF_CAT_COL;
static final int TYPEDEF_SOURCE_ARCHIVE_ID_COL =
TypedefDBAdapterV1.V1_TYPEDEF_SOURCE_ARCHIVE_ID_COL;
TypedefDBAdapterV2.V2_TYPEDEF_SOURCE_ARCHIVE_ID_COL;
static final int TYPEDEF_UNIVERSAL_DT_ID_COL =
TypedefDBAdapterV1.V1_TYPEDEF_UNIVERSAL_DT_ID_COL;
TypedefDBAdapterV2.V2_TYPEDEF_UNIVERSAL_DT_ID_COL;
static final int TYPEDEF_SOURCE_SYNC_TIME_COL =
TypedefDBAdapterV1.V1_TYPEDEF_SOURCE_SYNC_TIME_COL;
TypedefDBAdapterV2.V2_TYPEDEF_SOURCE_SYNC_TIME_COL;
static final int TYPEDEF_LAST_CHANGE_TIME_COL =
TypedefDBAdapterV1.V1_TYPEDEF_LAST_CHANGE_TIME_COL;
TypedefDBAdapterV2.V2_TYPEDEF_LAST_CHANGE_TIME_COL;
// Typedef flags bits
static final int TYPEDEF_FLAG_AUTONAME = 0x1;
/**
* Gets an adapter for working with the Typedef data type database table. The adapter is based
@ -55,7 +59,7 @@ abstract class TypedefDBAdapter {
static TypedefDBAdapter getAdapter(DBHandle handle, int openMode, TaskMonitor monitor)
throws VersionException, IOException {
try {
return new TypedefDBAdapterV1(handle, openMode == DBConstants.CREATE);
return new TypedefDBAdapterV2(handle, openMode == DBConstants.CREATE);
}
catch (VersionException e) {
if (!e.isUpgradable() || openMode == DBConstants.UPDATE) {
@ -76,6 +80,12 @@ abstract class TypedefDBAdapter {
* @throws VersionException if a read only adapter can't be obtained for the database handle's version.
*/
static TypedefDBAdapter findReadOnlyAdapter(DBHandle handle) throws VersionException {
try {
return new TypedefDBAdapterV1(handle);
}
catch (VersionException e) {
// ignore
}
return new TypedefDBAdapterV0(handle);
}
@ -95,14 +105,14 @@ abstract class TypedefDBAdapter {
long id = tmpHandle.startTransaction();
TypedefDBAdapter tmpAdapter = null;
try {
tmpAdapter = new TypedefDBAdapterV1(tmpHandle, true);
tmpAdapter = new TypedefDBAdapterV2(tmpHandle, true);
RecordIterator it = oldAdapter.getRecords();
while (it.hasNext()) {
DBRecord rec = it.next();
tmpAdapter.updateRecord(rec, false);
}
oldAdapter.deleteTable(handle);
TypedefDBAdapter newAdapter = new TypedefDBAdapterV1(handle, true);
TypedefDBAdapter newAdapter = new TypedefDBAdapterV2(handle, true);
it = tmpAdapter.getRecords();
while (it.hasNext()) {
DBRecord rec = it.next();
@ -120,6 +130,7 @@ abstract class TypedefDBAdapter {
* Creates a database record for a type definition data type.
* @param dataTypeID the ID of the data type that is referred to by this type definition.
* @param name the unique name for this data type
* @param flags typedef flags (e.g., auto-name flag bit).
* @param categoryID the ID for the category that contains this data type.
* @param sourceArchiveID the ID for the source archive where this data type originated.
* @param sourceDataTypeID the ID of the associated data type in the source archive.
@ -127,7 +138,7 @@ abstract class TypedefDBAdapter {
* @return the database record for this data type.
* @throws IOException if the database can't be accessed.
*/
abstract DBRecord createRecord(long dataTypeID, String name, long categoryID,
abstract DBRecord createRecord(long dataTypeID, String name, short flags, long categoryID,
long sourceArchiveID, long sourceDataTypeID, long lastChangeTime) throws IOException;
/**

View file

@ -68,10 +68,9 @@ class TypedefDBAdapterV0 extends TypedefDBAdapter implements RecordTranslator {
}
@Override
public DBRecord createRecord(long dataTypeID, String name, long categoryID, long sourceArchiveID,
long sourceDataTypeID, long lastChangeTime) throws IOException {
throw new UnsupportedOperationException("Not allowed to update prior version #" + VERSION +
" of " + TYPEDEF_TABLE_NAME + " table.");
public DBRecord createRecord(long dataTypeID, String name, short flags, long categoryID,
long sourceArchiveID, long sourceDataTypeID, long lastChangeTime) throws IOException {
throw new UnsupportedOperationException();
}
@Override
@ -91,7 +90,7 @@ class TypedefDBAdapterV0 extends TypedefDBAdapter implements RecordTranslator {
@Override
public boolean removeRecord(long dataID) throws IOException {
return table.deleteRecord(dataID);
throw new UnsupportedOperationException();
}
@Override
@ -111,6 +110,7 @@ class TypedefDBAdapterV0 extends TypedefDBAdapter implements RecordTranslator {
}
DBRecord rec = TypedefDBAdapter.SCHEMA.createRecord(oldRec.getKey());
rec.setLongValue(TYPEDEF_DT_ID_COL, oldRec.getLongValue(V0_TYPEDEF_DT_ID_COL));
// default TYPEDEF_FLAGS_COL to 0
rec.setString(TYPEDEF_NAME_COL, oldRec.getString(V0_TYPEDEF_NAME_COL));
rec.setLongValue(TYPEDEF_CAT_COL, oldRec.getLongValue(V0_TYPEDEF_CAT_COL));
rec.setLongValue(TYPEDEF_SOURCE_ARCHIVE_ID_COL, DataTypeManager.LOCAL_ARCHIVE_KEY);

View file

@ -16,7 +16,6 @@
package ghidra.program.database.data;
import java.io.IOException;
import java.util.Date;
import db.*;
import ghidra.util.UniversalID;
@ -25,7 +24,7 @@ import ghidra.util.exception.VersionException;
/**
* Version 1 implementation for accessing the Typedef database table.
*/
class TypedefDBAdapterV1 extends TypedefDBAdapter {
class TypedefDBAdapterV1 extends TypedefDBAdapter implements RecordTranslator {
static final int VERSION = 1;
static final int V1_TYPEDEF_DT_ID_COL = 0;
static final int V1_TYPEDEF_NAME_COL = 1;
@ -34,41 +33,35 @@ class TypedefDBAdapterV1 extends TypedefDBAdapter {
static final int V1_TYPEDEF_UNIVERSAL_DT_ID_COL = 4;
static final int V1_TYPEDEF_SOURCE_SYNC_TIME_COL = 5;
static final int V1_TYPEDEF_LAST_CHANGE_TIME_COL = 6;
static final Schema V1_SCHEMA = new Schema(VERSION, "Typedef ID",
new Field[] { LongField.INSTANCE, StringField.INSTANCE, LongField.INSTANCE,
LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE },
new String[] { "Data Type ID", "Name", "Category ID", "Source Archive ID",
"Universal Data Type ID", "Source Sync Time", "Last Change Time" });
// DO NOT REMOVE WHAT'S BELOW - this documents the schema used in version 0.
// static final Schema V1_SCHEMA = new Schema(VERSION, "Typedef ID",
// new Field[] { LongField.INSTANCE, StringField.INSTANCE, LongField.INSTANCE,
// LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE },
// new String[] { "Data Type ID", "Name", "Category ID", "Source Archive ID",
// "Universal Data Type ID", "Source Sync Time", "Last Change Time" });
private Table table;
/**
* Gets a version 1 adapter for the Typedef database table.
* @param handle handle to the database containing the table.
* @param create true if this constructor should create the table.
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
*/
public TypedefDBAdapterV1(DBHandle handle, boolean create)
throws VersionException, IOException {
public TypedefDBAdapterV1(DBHandle handle) throws VersionException {
if (create) {
table = handle.createTable(TYPEDEF_TABLE_NAME, V1_SCHEMA,
new int[] { V1_TYPEDEF_CAT_COL, V1_TYPEDEF_UNIVERSAL_DT_ID_COL });
table = handle.getTable(TYPEDEF_TABLE_NAME);
if (table == null) {
throw new VersionException("Missing Table: " + TYPEDEF_TABLE_NAME);
}
else {
table = handle.getTable(TYPEDEF_TABLE_NAME);
if (table == null) {
throw new VersionException("Missing Table: " + TYPEDEF_TABLE_NAME);
}
int version = table.getSchema().getVersion();
if (version != VERSION) {
String msg = "Expected version " + VERSION + " for table " + TYPEDEF_TABLE_NAME +
" but got " + table.getSchema().getVersion();
if (version < VERSION) {
throw new VersionException(msg, VersionException.OLDER_VERSION, true);
}
throw new VersionException(msg, VersionException.NEWER_VERSION, false);
int version = table.getSchema().getVersion();
if (version != VERSION) {
String msg = "Expected version " + VERSION + " for table " + TYPEDEF_TABLE_NAME +
" but got " + table.getSchema().getVersion();
if (version < VERSION) {
throw new VersionException(msg, VersionException.OLDER_VERSION, true);
}
throw new VersionException(msg, VersionException.NEWER_VERSION, false);
}
}
@ -78,49 +71,29 @@ class TypedefDBAdapterV1 extends TypedefDBAdapter {
}
@Override
public DBRecord createRecord(long dataTypeID, String name, long categoryID, long sourceArchiveID,
long sourceDataTypeID, long lastChangeTime) throws IOException {
long tableKey = table.getKey();
// if (tableKey <= DataManager.VOID_DATATYPE_ID) {
// tableKey = DataManager.VOID_DATATYPE_ID +1;
// }
long key = DataTypeManagerDB.createKey(DataTypeManagerDB.TYPEDEF, tableKey);
DBRecord record = V1_SCHEMA.createRecord(key);
record.setLongValue(V1_TYPEDEF_DT_ID_COL, dataTypeID);
record.setString(V1_TYPEDEF_NAME_COL, name);
record.setLongValue(V1_TYPEDEF_CAT_COL, categoryID);
record.setLongValue(V1_TYPEDEF_SOURCE_ARCHIVE_ID_COL, sourceArchiveID);
record.setLongValue(V1_TYPEDEF_UNIVERSAL_DT_ID_COL, sourceDataTypeID);
record.setLongValue(V1_TYPEDEF_SOURCE_SYNC_TIME_COL, lastChangeTime);
record.setLongValue(V1_TYPEDEF_LAST_CHANGE_TIME_COL, lastChangeTime);
table.putRecord(record);
return record;
public DBRecord createRecord(long dataTypeID, String name, short flags, long categoryID,
long sourceArchiveID, long sourceDataTypeID, long lastChangeTime) throws IOException {
throw new UnsupportedOperationException();
}
@Override
public DBRecord getRecord(long typedefID) throws IOException {
return table.getRecord(typedefID);
return translateRecord(table.getRecord(typedefID));
}
@Override
public RecordIterator getRecords() throws IOException {
return table.iterator();
RecordIterator getRecords() throws IOException {
return new TranslatedRecordIterator(table.iterator(), this);
}
@Override
public void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
if (setLastChangeTime) {
record.setLongValue(TypedefDBAdapter.TYPEDEF_LAST_CHANGE_TIME_COL,
(new Date()).getTime());
}
table.putRecord(record);
throw new UnsupportedOperationException();
}
@Override
public boolean removeRecord(long dataID) throws IOException {
return table.deleteRecord(dataID);
throw new UnsupportedOperationException();
}
@Override
@ -137,14 +110,33 @@ class TypedefDBAdapterV1 extends TypedefDBAdapter {
DBRecord getRecordWithIDs(UniversalID sourceID, UniversalID datatypeID) throws IOException {
Field[] keys =
table.findRecords(new LongField(datatypeID.getValue()), V1_TYPEDEF_UNIVERSAL_DT_ID_COL);
for (int i = 0; i < keys.length; i++) {
DBRecord record = table.getRecord(keys[i]);
if (record.getLongValue(V1_TYPEDEF_SOURCE_ARCHIVE_ID_COL) == sourceID.getValue()) {
return record;
return translateRecord(record);
}
}
return null;
}
@Override
public DBRecord translateRecord(DBRecord oldRec) {
if (oldRec == null) {
return null;
}
DBRecord rec = TypedefDBAdapter.SCHEMA.createRecord(oldRec.getKey());
rec.setLongValue(TYPEDEF_DT_ID_COL, oldRec.getLongValue(V1_TYPEDEF_DT_ID_COL));
// default TYPEDEF_FLAGS_COL to 0
rec.setString(TYPEDEF_NAME_COL, oldRec.getString(V1_TYPEDEF_NAME_COL));
rec.setLongValue(TYPEDEF_CAT_COL, oldRec.getLongValue(V1_TYPEDEF_CAT_COL));
rec.setLongValue(TYPEDEF_SOURCE_ARCHIVE_ID_COL,
oldRec.getLongValue(V1_TYPEDEF_SOURCE_ARCHIVE_ID_COL));
rec.setLongValue(TYPEDEF_UNIVERSAL_DT_ID_COL,
oldRec.getLongValue(V1_TYPEDEF_UNIVERSAL_DT_ID_COL));
rec.setLongValue(TYPEDEF_SOURCE_SYNC_TIME_COL,
oldRec.getLongValue(V1_TYPEDEF_SOURCE_SYNC_TIME_COL));
rec.setLongValue(TYPEDEF_LAST_CHANGE_TIME_COL,
oldRec.getLongValue(V1_TYPEDEF_LAST_CHANGE_TIME_COL));
return rec;
}
}

View file

@ -0,0 +1,154 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.database.data;
import java.io.IOException;
import java.util.Date;
import db.*;
import ghidra.util.UniversalID;
import ghidra.util.exception.VersionException;
/**
* Version 2 implementation for accessing the Typedef database table.
*/
class TypedefDBAdapterV2 extends TypedefDBAdapter {
static final int VERSION = 2;
static final int V2_TYPEDEF_DT_ID_COL = 0;
static final int V2_TYPEDEF_FLAGS_COL = 1;
static final int V2_TYPEDEF_NAME_COL = 2;
static final int V2_TYPEDEF_CAT_COL = 3;
static final int V2_TYPEDEF_SOURCE_ARCHIVE_ID_COL = 4;
static final int V2_TYPEDEF_UNIVERSAL_DT_ID_COL = 5;
static final int V2_TYPEDEF_SOURCE_SYNC_TIME_COL = 6;
static final int V2_TYPEDEF_LAST_CHANGE_TIME_COL = 7;
static final Schema V2_SCHEMA = new Schema(VERSION, "Typedef ID",
new Field[] { LongField.INSTANCE, ShortField.INSTANCE, StringField.INSTANCE,
LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE,
LongField.INSTANCE },
new String[] { "Data Type ID", "Flags", "Name", "Category ID", "Source Archive ID",
"Universal Data Type ID", "Source Sync Time", "Last Change Time" });
private Table table;
/**
* Gets a version 1 adapter for the Typedef database table.
* @param handle handle to the database containing the table.
* @param create true if this constructor should create the table.
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
* @throws IOException if IO error occurs
*/
public TypedefDBAdapterV2(DBHandle handle, boolean create)
throws VersionException, IOException {
if (create) {
table = handle.createTable(TYPEDEF_TABLE_NAME, V2_SCHEMA,
new int[] { V2_TYPEDEF_CAT_COL, V2_TYPEDEF_UNIVERSAL_DT_ID_COL });
}
else {
table = handle.getTable(TYPEDEF_TABLE_NAME);
if (table == null) {
throw new VersionException("Missing Table: " + TYPEDEF_TABLE_NAME);
}
int version = table.getSchema().getVersion();
if (version != VERSION) {
String msg = "Expected version " + VERSION + " for table " + TYPEDEF_TABLE_NAME +
" but got " + table.getSchema().getVersion();
if (version < VERSION) {
throw new VersionException(msg, VersionException.OLDER_VERSION, true);
}
throw new VersionException(msg, VersionException.NEWER_VERSION, false);
}
}
}
@Override
void deleteTable(DBHandle handle) throws IOException {
handle.deleteTable(TYPEDEF_TABLE_NAME);
}
@Override
public DBRecord createRecord(long dataTypeID, String name, short flags, long categoryID,
long sourceArchiveID, long sourceDataTypeID, long lastChangeTime) throws IOException {
long tableKey = table.getKey();
// if (tableKey <= DataManager.VOID_DATATYPE_ID) {
// tableKey = DataManager.VOID_DATATYPE_ID +1;
// }
long key = DataTypeManagerDB.createKey(DataTypeManagerDB.TYPEDEF, tableKey);
DBRecord record = V2_SCHEMA.createRecord(key);
record.setLongValue(V2_TYPEDEF_DT_ID_COL, dataTypeID);
record.setShortValue(V2_TYPEDEF_FLAGS_COL, flags);
record.setString(V2_TYPEDEF_NAME_COL, name);
record.setLongValue(V2_TYPEDEF_CAT_COL, categoryID);
record.setLongValue(V2_TYPEDEF_SOURCE_ARCHIVE_ID_COL, sourceArchiveID);
record.setLongValue(V2_TYPEDEF_UNIVERSAL_DT_ID_COL, sourceDataTypeID);
record.setLongValue(V2_TYPEDEF_SOURCE_SYNC_TIME_COL, lastChangeTime);
record.setLongValue(V2_TYPEDEF_LAST_CHANGE_TIME_COL, lastChangeTime);
table.putRecord(record);
return record;
}
@Override
public DBRecord getRecord(long typedefID) throws IOException {
return table.getRecord(typedefID);
}
@Override
public RecordIterator getRecords() throws IOException {
return table.iterator();
}
@Override
public void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
if (setLastChangeTime) {
record.setLongValue(TypedefDBAdapter.TYPEDEF_LAST_CHANGE_TIME_COL,
(new Date()).getTime());
}
table.putRecord(record);
}
@Override
public boolean removeRecord(long dataID) throws IOException {
return table.deleteRecord(dataID);
}
@Override
public Field[] getRecordIdsInCategory(long categoryID) throws IOException {
return table.findRecords(new LongField(categoryID), V2_TYPEDEF_CAT_COL);
}
@Override
Field[] getRecordIdsForSourceArchive(long archiveID) throws IOException {
return table.findRecords(new LongField(archiveID), V2_TYPEDEF_SOURCE_ARCHIVE_ID_COL);
}
@Override
DBRecord getRecordWithIDs(UniversalID sourceID, UniversalID datatypeID) throws IOException {
Field[] keys =
table.findRecords(new LongField(datatypeID.getValue()), V2_TYPEDEF_UNIVERSAL_DT_ID_COL);
for (int i = 0; i < keys.length; i++) {
DBRecord record = table.getRecord(keys[i]);
if (record.getLongValue(V2_TYPEDEF_SOURCE_ARCHIVE_ID_COL) == sourceID.getValue()) {
return record;
}
}
return null;
}
}

View file

@ -89,7 +89,8 @@ public abstract class AbstractDataType implements DataType {
@Override
public DataTypePath getDataTypePath() {
return new DataTypePath(categoryPath, name);
// use methods instead of fields since they mey be overriden
return new DataTypePath(getCategoryPath(), getName());
}
@Override

View file

@ -1,125 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.model.data;
import ghidra.docking.settings.Settings;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressOutOfBoundsException;
import ghidra.program.model.mem.MemBuffer;
import ghidra.program.model.scalar.Scalar;
abstract class AbstractImageBaseOffsetDataType extends BuiltIn {
AbstractImageBaseOffsetDataType(CategoryPath path, String name, DataTypeManager dtm) {
super(path, name, dtm);
}
abstract DataType getScalarDataType();
static String generateName(DataType dt) {
return "ImageBaseOffset" + dt.getLength() * 8;
}
static String generateMnemonic(DataType dt) {
return "ibo" + dt.getLength() * 8;
}
static String generateDescription(DataType dt) {
return (dt.getLength() * 8) + "-bit Image Base Offset";
}
@Override
public String getDescription() {
DataType dt = getScalarDataType();
return generateDescription(dt);
}
@Override
public String getMnemonic(Settings settings) {
DataType dt = getScalarDataType();
return generateMnemonic(dt);
}
@Override
public int getLength() {
return getScalarDataType().getLength();
}
@Override
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
Address addr = (Address) getValue(buf, settings, length);
if (addr == null) { // could not create address, so return "Not a pointer (NaP)"
return "NaP";
}
return addr.toString();
}
@Override
public Object getValue(MemBuffer buf, Settings settings, int length) {
DataType dt = getScalarDataType();
Address imageBase = buf.getMemory().getProgram().getImageBase();
Scalar value = (Scalar) dt.getValue(buf, settings, length);
if (value != null && value.getUnsignedValue() != 0) {
try {
return imageBase.add(value.getUnsignedValue());
}
catch (AddressOutOfBoundsException e) {
// ignore
}
}
return null;
}
@Override
public boolean isEncodable() {
return getScalarDataType().isEncodable();
}
@Override
public byte[] encodeValue(Object value, MemBuffer buf, Settings settings, int length)
throws DataTypeEncodeException {
if (!(value instanceof Address)) {
throw new DataTypeEncodeException("Requires Address", value, this);
}
Address addressValue = (Address) value;
Address imageBase = buf.getMemory().getProgram().getImageBase();
long offset;
try {
offset = addressValue.subtract(imageBase);
}
catch (IllegalArgumentException e) {
throw new DataTypeEncodeException(value, this, e);
}
Scalar scalarOffset = new Scalar(imageBase.getSize(), offset, false);
DataType dt = getScalarDataType();
return dt.encodeValue(scalarOffset, buf, settings, length);
}
@Override
public byte[] encodeRepresentation(String repr, MemBuffer buf, Settings settings, int length)
throws DataTypeEncodeException {
Address address = buf.getMemory().getProgram().getAddressFactory().getAddress(repr);
if (address == null) {
throw new DataTypeEncodeException("Cannot parse address", repr, this);
}
return encodeValue(address, buf, settings, length);
}
@Override
public Class<?> getValueClass(Settings settings) {
return Address.class;
}
}

View file

@ -25,14 +25,10 @@ import ghidra.util.UniversalID;
import ghidra.util.UniversalIdGenerator;
/**
* <code>AbstractPointerTypedefDataType</code> provides an abstract implementation for
* a Pointer-Typedef BuiltIn datatype.
* <br>
* If a generated name is used the name will be locked-in once this datatype is resolved
* and will not automatcally update if any subsequent changes are made to
* {@link TypeDefSettingsDefinition} settings or the name of the referenced datatype.
* <code>AbstractPointerTypedefDataType</code> provides an abstract {@link BuiltIn} datatype
* implementation for a pointer-typedef datatype.
*/
public abstract class AbstractPointerTypedefDataType extends BuiltIn implements TypeDef {
public abstract class AbstractPointerTypedefBuiltIn extends BuiltIn implements TypeDef {
private String typedefName;
private TypedefDataType modelTypedef;
@ -47,12 +43,13 @@ public abstract class AbstractPointerTypedefDataType extends BuiltIn implements
* @param pointerSize pointer size in bytes or -1 for default pointer size
* @param dtm data-type manager whose data organization should be used
*/
public AbstractPointerTypedefDataType(String name, DataType referencedDataType,
protected AbstractPointerTypedefBuiltIn(String name, DataType referencedDataType,
int pointerSize, DataTypeManager dtm) {
super(getCategoryPath(referencedDataType), getTempNameIfNeeded(name), dtm);
setTypedefName(name);
modelTypedef =
new TypedefDataType("TEMP", new PointerDataType(referencedDataType, pointerSize, dtm));
setDefaultSettings(modelTypedef.getDefaultSettings());
}
/**
@ -63,13 +60,20 @@ public abstract class AbstractPointerTypedefDataType extends BuiltIn implements
* @param pointerDataType associated pointer datatype (required)
* @param dtm data-type manager whose data organization should be used
*/
public AbstractPointerTypedefDataType(String name, Pointer pointerDataType,
protected AbstractPointerTypedefBuiltIn(String name, Pointer pointerDataType,
DataTypeManager dtm) {
super(pointerDataType.getCategoryPath(), getTempNameIfNeeded(name), dtm);
setTypedefName(name);
modelTypedef = new TypedefDataType("TEMP", pointerDataType.clone(dtm));
setDefaultSettings(modelTypedef.getDefaultSettings());
}
@Override
public void enableAutoNaming() {
typedefName = null;
}
@Override
public boolean isAutoNamed() {
return typedefName == null;
}
@ -102,7 +106,7 @@ public abstract class AbstractPointerTypedefDataType extends BuiltIn implements
}
void setTypedefName(String name) {
if (name != null) {
if (name != null && !DataUtilities.isValidDataTypeName(name)) {
throw new IllegalArgumentException("Invalid DataType name: " + name);
}
this.typedefName = name;
@ -158,17 +162,7 @@ public abstract class AbstractPointerTypedefDataType extends BuiltIn implements
@Override
public SettingsDefinition[] getBuiltInSettingsDefinitions() {
return getTypeDefSettingsDefinitions();
}
@Override
public TypeDefSettingsDefinition[] getTypeDefSettingsDefinitions() {
return modelTypedef.getTypeDefSettingsDefinitions();
}
@Override
public Settings getDefaultSettings() {
return modelTypedef.getDefaultSettings();
return modelTypedef.getSettingsDefinitions();
}
@Override
@ -183,6 +177,11 @@ public abstract class AbstractPointerTypedefDataType extends BuiltIn implements
getDataType().getName();
}
@Override
public Class<?> getValueClass(Settings settings) {
return modelTypedef.getValueClass(settings);
}
@Override
public Object getValue(MemBuffer buf, Settings settings, int length) {
return modelTypedef.getValue(buf, settings, length);

View file

@ -128,6 +128,11 @@ public class CharsetSettingsDefinition implements EnumSettingsDefinition {
return CHARSET_NAME;
}
@Override
public String getStorageKey() {
return CHARSET_SETTING_NAME;
}
@Override
public String getDescription() {
return "Character set";

View file

@ -114,7 +114,7 @@ public class ComponentOffsetSettingsDefinition
public String getAttributeSpecification(Settings settings) {
if (hasValue(settings)) {
long offset = getValue(settings);
return "offset(" + Long.toString(offset) + ")";
return "offset(0x" + Long.toHexString(offset) + ")";
}
return null;
}

View file

@ -51,6 +51,9 @@ public interface DataType {
public final static String CONFLICT_SUFFIX = ".conflict";
public final static String TYPEDEF_ATTRIBUTE_PREFIX = "__((";
public final static String TYPEDEF_ATTRIBUTE_SUFFIX = "))";
static final long NO_SOURCE_SYNC_TIME = 0L;
static final long NO_LAST_CHANGE_TIME = 0L;

View file

@ -246,14 +246,6 @@ public interface DataTypeManager {
*/
public Category getCategory(CategoryPath path);
/**
* Notification when data type is changed.
* @param dataType data type that is changed
* @param isAutoChange true if change was an automatic change in response to
* another datatype's change (e.g., size, alignment).
*/
public void dataTypeChanged(DataType dataType, boolean isAutoChange);
/**
* Add a listener that is notified when the dataTypeManger changes.
* @param l the listener

View file

@ -88,6 +88,11 @@ public class DataTypeMnemonicSettingsDefinition implements EnumSettingsDefinitio
return "Mnemonic-style";
}
@Override
public String getStorageKey() {
return MNEMONIC;
}
@Override
public String getDescription() {
return "Selects the data-type mnemonic style";

View file

@ -108,6 +108,11 @@ public class EndianSettingsDefinition implements EnumSettingsDefinition {
return "Endian";
}
@Override
public String getStorageKey() {
return ENDIAN_SETTING_NAME;
}
@Override
public String getDescription() {
return "Selects the endianess of the data";

View file

@ -15,27 +15,43 @@
*/
package ghidra.program.model.data;
import ghidra.docking.settings.Settings;
import ghidra.util.classfinder.ClassTranslator;
/**
* <code>IBO32DataType</code> provides a Pointer-Typedef BuiltIn for
* a 32-bit Image Base Offset Relative Pointer.
* a 32-bit Image Base Offset Relative Pointer. This {@link TypeDef} implementation
* specifies the {@link PointerType#IMAGE_BASE_RELATIVE} attribute/setting
* associated with a 32-bit {@link Pointer}.
* <br>
* This class replaces the use of the old <code>ImageBaseOffset32DataType</code>
* which did not implement the Pointer interface. This is an alternative
* {@link BuiltIn} implementation to using the more general {@link PointerTypedef}
* datatype with an unspecified referenced datatype. {@link PointerTypedef} should
* be used for other cases
* (see {@link #createIBO32PointerTypedef(DataType)}).
*/
public class IBO32DataType extends AbstractPointerTypedefDataType {
public class IBO32DataType extends AbstractPointerTypedefBuiltIn {
static final String NAME = "ibo32";
public static final IBO32DataType dataType = new IBO32DataType();
// TODO: remove old ImageBaseOffset32DataType implementation and uncomment
// static {
// ClassTranslator.put("ghidra.program.model.data.ImageBaseOffset32",
// IBO32DataType.class.getName());
// ClassTranslator.put("ghidra.program.model.data.ImageBaseOffset32DataType",
// IBO32DataType.class.getName());
// }
static final String NAME = "ImageBaseOffset32";
private static TypeDefSettingsDefinition[] IBO_TYPEDEF_SETTINGS_DEFS =
{ PointerTypeSettingsDefinition.DEF };
static {
ClassTranslator.put("ghidra.program.model.data.ImageBaseOffset32",
IBO32DataType.class.getName());
ClassTranslator.put("ghidra.program.model.data.ImageBaseOffset32DataType",
IBO32DataType.class.getName());
}
/**
* Constructs a 32-bit Image Base Offset relative pointer-typedef.
*/
public IBO32DataType() {
this(DataType.DEFAULT, null);
this(null);
}
/**
@ -43,25 +59,9 @@ public class IBO32DataType extends AbstractPointerTypedefDataType {
* @param dtm data-type manager whose data organization should be used
*/
public IBO32DataType(DataTypeManager dtm) {
this(DataType.DEFAULT, dtm);
}
/**
* Constructs a 32-bit Image Base Offset relative pointer-typedef.
* @param referencedDataType data type this pointer-typedef points to
*/
public IBO32DataType(DataType referencedDataType) {
this(referencedDataType, null);
}
/**
* Constructs a 32-bit Image Base Offset relative pointer-typedef.
* @param referencedDataType data type this pointer-typedef points to
* @param dtm data-type manager whose data organization should be used
*/
public IBO32DataType(DataType referencedDataType, DataTypeManager dtm) {
super(null, referencedDataType, 4, dtm);
PointerTypeSettingsDefinition.DEF.setType(getDefaultSettings(), PointerType.IBO);
super(NAME, null, 4, dtm);
PointerTypeSettingsDefinition.DEF.setType(getDefaultSettings(),
PointerType.IMAGE_BASE_RELATIVE);
}
@Override
@ -74,18 +74,30 @@ public class IBO32DataType extends AbstractPointerTypedefDataType {
if (dataMgr == dtm) {
return this;
}
IBO32DataType td = new IBO32DataType(getReferencedDataType(), dtm);
TypedefDataType.copyTypeDefSettings(this, td, false);
return td;
return new IBO32DataType(dtm);
}
@Override
public String getName() {
DataType dt = getReferencedDataType();
if (dt == null || Undefined.isUndefined(dt) || (dt instanceof VoidDataType)) {
return NAME; // use simple ibo name
}
return super.getName(); // use generated named
public String getMnemonic(Settings settings) {
return "ibo32";
}
@Override
public TypeDefSettingsDefinition[] getBuiltInSettingsDefinitions() {
return IBO_TYPEDEF_SETTINGS_DEFS;
}
/**
* Create a IBO32 {@link PointerTypedef} with auto-naming. If needed, a name and category
* may be assigned to the returned instance. Unlike using an immutable {@link IBO32DataType} instance
* the returned instance is mutable.
* @param referencedDataType referenced datatype or null
* @return new IBO32 pointer-typedef
*/
public static PointerTypedef createIBO32PointerTypedef(DataType referencedDataType) {
return new PointerTypedef(null, referencedDataType, 4,
referencedDataType != null ? referencedDataType.getDataTypeManager() : null,
PointerType.IMAGE_BASE_RELATIVE);
}
}

View file

@ -15,27 +15,43 @@
*/
package ghidra.program.model.data;
import ghidra.docking.settings.Settings;
import ghidra.util.classfinder.ClassTranslator;
/**
* <code>IBO64DataType</code> provides a Pointer-Typedef BuiltIn for
* a 64-bit Image Base Offset Relative Pointer.
* a 64-bit Image Base Offset Relative Pointer. This {@link TypeDef} implementation
* specifies the {@link PointerType#IMAGE_BASE_RELATIVE} attribute/setting
* associated with a 64-bit {@link Pointer}.
* <br>
* This class replaces the use of the old <code>ImageBaseOffset64DataType</code>
* which did not implement the Pointer interface. This is an alternative
* {@link BuiltIn} implementation to using the more general {@link PointerTypedef}
* datatype with an unspecified referenced datatype. {@link PointerTypedef} should
* be used for other cases
* (see {@link #createIBO64PointerTypedef(DataType)}).
*/
public class IBO64DataType extends AbstractPointerTypedefDataType {
public class IBO64DataType extends AbstractPointerTypedefBuiltIn {
static final String NAME = "ibo64";
public static final IBO64DataType dataType = new IBO64DataType();
// TODO: remove old ImageBaseOffset64DataType implementation and uncomment
// static {
// ClassTranslator.put("ghidra.program.model.data.ImageBaseOffset64",
// IBO64DataType.class.getName());
// ClassTranslator.put("ghidra.program.model.data.ImageBaseOffset64DataType",
// IBO64DataType.class.getName());
// }
static final String NAME = "ImageBaseOffset64";
private static TypeDefSettingsDefinition[] IBO_TYPEDEF_SETTINGS_DEFS =
{ PointerTypeSettingsDefinition.DEF };
static {
ClassTranslator.put("ghidra.program.model.data.ImageBaseOffset64",
IBO64DataType.class.getName());
ClassTranslator.put("ghidra.program.model.data.ImageBaseOffset64DataType",
IBO64DataType.class.getName());
}
/**
* Constructs a 64-bit Image Base Offset relative pointer-typedef.
*/
public IBO64DataType() {
this(DataType.DEFAULT, null);
this(null);
}
/**
@ -43,25 +59,8 @@ public class IBO64DataType extends AbstractPointerTypedefDataType {
* @param dtm data-type manager whose data organization should be used
*/
public IBO64DataType(DataTypeManager dtm) {
this(DataType.DEFAULT, dtm);
}
/**
* Constructs a 64-bit Image Base Offset relative pointer-typedef.
* @param referencedDataType data type this pointer-typedef points to
*/
public IBO64DataType(DataType referencedDataType) {
this(referencedDataType, null);
}
/**
* Constructs a 64-bit Image Base Offset relative pointer-typedef.
* @param referencedDataType data type this pointer-typedef points to
* @param dtm data-type manager whose data organization should be used
*/
public IBO64DataType(DataType referencedDataType, DataTypeManager dtm) {
super(null, referencedDataType, 8, dtm);
PointerTypeSettingsDefinition.DEF.setType(getDefaultSettings(), PointerType.IBO);
super(NAME, null, 8, dtm);
PointerTypeSettingsDefinition.DEF.setType(getDefaultSettings(), PointerType.IMAGE_BASE_RELATIVE);
}
@Override
@ -74,18 +73,30 @@ public class IBO64DataType extends AbstractPointerTypedefDataType {
if (dataMgr == dtm) {
return this;
}
IBO64DataType td = new IBO64DataType(getReferencedDataType(), dtm);
TypedefDataType.copyTypeDefSettings(this, td, false);
return td;
return new IBO64DataType(dtm);
}
@Override
public String getName() {
DataType dt = getReferencedDataType();
if (dt == null || Undefined.isUndefined(dt) || (dt instanceof VoidDataType)) {
return NAME; // use simple ibo name
}
return super.getName(); // use generated named
public String getMnemonic(Settings settings) {
return "ibo64";
}
@Override
public TypeDefSettingsDefinition[] getBuiltInSettingsDefinitions() {
return IBO_TYPEDEF_SETTINGS_DEFS;
}
/**
* Create a IBO64 {@link PointerTypedef} with auto-naming. If needed, a name and category
* may be assigned to the returned instance. Unlike using an immutable {@link IBO32DataType} instance
* the returned instance is mutable.
* @param referencedDataType referenced datatype or null
* @return new IBO64 pointer-typedef
*/
public static PointerTypedef createIBO64PointerTypedef(DataType referencedDataType) {
return new PointerTypedef(null, referencedDataType, 8,
referencedDataType != null ? referencedDataType.getDataTypeManager() : null,
PointerType.IMAGE_BASE_RELATIVE);
}
}

View file

@ -1,48 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.model.data;
import ghidra.util.classfinder.*;
public class ImageBaseOffset32DataType extends AbstractImageBaseOffsetDataType {
static {
ClassTranslator.put("ghidra.program.model.data.ImageBaseOffset32",
ImageBaseOffset32DataType.class.getName());
}
private static DataType datatype = DWordDataType.dataType;
public ImageBaseOffset32DataType() {
this(null);
}
public ImageBaseOffset32DataType(DataTypeManager dtm) {
super(null, generateName(datatype), dtm);
}
@Override
DataType getScalarDataType() {
return datatype;
}
public DataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}
return new ImageBaseOffset32DataType(dtm);
}
}

View file

@ -1,48 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.model.data;
import ghidra.util.classfinder.*;
public class ImageBaseOffset64DataType extends AbstractImageBaseOffsetDataType {
static {
ClassTranslator.put("ghidra.program.model.data.ImageBaseOffset64",
ImageBaseOffset64DataType.class.getName());
}
private static DataType datatype = QWordDataType.dataType;
public ImageBaseOffset64DataType() {
this(null);
}
public ImageBaseOffset64DataType(DataTypeManager dtm) {
super(null, generateName(datatype), dtm);
}
@Override
DataType getScalarDataType() {
return datatype;
}
public DataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}
return new ImageBaseOffset64DataType(dtm);
}
}

View file

@ -87,6 +87,11 @@ public class MutabilitySettingsDefinition implements EnumSettingsDefinition {
return "Mutability";
}
@Override
public String getStorageKey() {
return MUTABILITY;
}
@Override
public String getDescription() {
return "Selects the data mutability";

View file

@ -23,8 +23,9 @@ import ghidra.docking.settings.Settings;
*/
public class PaddingSettingsDefinition implements EnumSettingsDefinition {
private static final int PADDED_VALUE = 1;
private static final int UNPADDED_VALUE = 0;
public static final int PADDED_VALUE = 1;
public static final int UNPADDED_VALUE = 0;
private static final String[] choices = { "unpadded", "padded" };
private static final String PADDED = "padded";
@ -86,6 +87,11 @@ public class PaddingSettingsDefinition implements EnumSettingsDefinition {
return "Padding";
}
@Override
public String getStorageKey() {
return PADDED;
}
@Override
public String getDescription() {
return "Selects if the data is padded or not";

View file

@ -403,7 +403,7 @@ public class PointerDataType extends BuiltIn implements Pointer {
try {
PointerType choice = PointerTypeSettingsDefinition.DEF.getType(settings);
if (choice == PointerType.IBO && mem != null) {
if (choice == PointerType.IMAGE_BASE_RELATIVE && mem != null) {
// must ignore AddressSpaceSettingsDefinition
Address imageBase = mem.getProgram().getImageBase();
targetSpace = imageBase.getAddressSpace();

View file

@ -33,7 +33,7 @@ public enum PointerType {
/**
* Pointer offset relative to program image base.
*/
IBO(1),
IMAGE_BASE_RELATIVE(1),
/**
* Pointer offset relative to pointer storage address.
* NOTE: This type has limited usefulness since it can only be applied to

View file

@ -31,6 +31,7 @@ public class PointerTypeSettingsDefinition
"Specifies the pointer type which affects interpretation of offset";
private static final String DISPLAY_NAME = "Pointer Type";
// Choices correspond to the enumerated PointerType values
private static final String[] choices =
{ "default", "image-base-relative", "relative", "file-offset" };

View file

@ -17,7 +17,15 @@ package ghidra.program.model.data;
import java.util.Objects;
import org.apache.commons.lang3.StringUtils;
import ghidra.docking.settings.Settings;
import ghidra.docking.settings.SettingsDefinition;
import ghidra.program.database.data.DataTypeUtilities;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.mem.MemBuffer;
import ghidra.util.UniversalID;
import ghidra.util.UniversalIdGenerator;
/**
* <code>PointerTypedef</code> provides a Pointer-Typedef template datatype
@ -30,59 +38,151 @@ import ghidra.program.model.address.AddressSpace;
* since it does not implement a default constructor so it may not be treated
* like other {@link BuiltIn} datatypes which are managed by the
* <{@link BuiltInDataTypeManager}.
* <br>
* NOTE: As a {@link BuiltIn} datatype the use of {@link #setName(String)} and
* {@link #setNameAndCategory(CategoryPath, String)} is disabled. The datatype
* instance must be instantiated with the correct typedef name.
*/
public class PointerTypedef extends AbstractPointerTypedefDataType {
public class PointerTypedef extends GenericDataType implements TypeDef {
private boolean isAutoNamed;
private TypedefDataType modelTypedef;
private UniversalID universalId = UniversalIdGenerator.nextID();
/**
* Constructs a pointer-typedef which dereferences into a specific address space.
* @param typeDefName name of this pointer-typedef or null to force name generation.
* @param referencedDataType data type this pointer-typedef points to
* @param pointerSize pointer size in bytes or -1 for default pointer size based upon datatype manager
* @param typeDefName name of this pointer-typedef or null to use auto-named typedef.
* @param referencedDataType data type this pointer-typedef points to or null
* @param pointerSize pointer size in bytes or -1 for default pointer size based upon specified
* address space and datatype manager
* @param dtm data-type manager whose data organization should be used (highly recommended, may be null)
* @param space address space to be used when dereferencing pointer offset
*/
public PointerTypedef(String typeDefName, DataType referencedDataType, int pointerSize,
DataTypeManager dtm, AddressSpace space) {
super(typeDefName, referencedDataType, pointerSize, dtm);
Objects.requireNonNull(space, "Address space must be specified");
this(typeDefName, referencedDataType, getPreferredPointerSize(pointerSize, dtm, space),
dtm);
AddressSpaceSettingsDefinition.DEF.setValue(getDefaultSettings(), space.getName());
}
/**
* Constructs a pointer-typedef of a specific type
* @param typeDefName name of this pointer-typedef or null to force name generation.
* @param referencedDataType data type this pointer-typedef points to
* @param typeDefName name of this pointer-typedef or null to use auto-named typedef.
* @param referencedDataType data type this pointer-typedef points to or null
* @param pointerSize pointer size in bytes or -1 for default pointer size based upon datatype manager
* @param dtm data-type manager whose data organization should be used (highly recommended, may be null)
* @param type pointer type (IBO, RELATIVE, FILE_OFFSET)
*/
public PointerTypedef(String typeDefName, DataType referencedDataType, int pointerSize,
DataTypeManager dtm, PointerType type) {
super(typeDefName, referencedDataType, pointerSize, dtm);
this(typeDefName, referencedDataType, pointerSize, dtm);
Objects.requireNonNull(type, "Pointer type required");
PointerTypeSettingsDefinition.DEF.setType(getDefaultSettings(), type);
}
/**
* Constructs a pointer-typedef without any settings
* @param typeDefName name of this pointer-typedef or null to force name generation.
* @param referencedDataType data type this pointer-typedef points to
* Constructs a offset-pointer-typedef
* @param typeDefName name of this pointer-typedef or null to use auto-named typedef.
* @param referencedDataType data type this pointer-typedef points to or null
* @param pointerSize pointer size in bytes or -1 for default pointer size based upon datatype manager
* @param dtm data-type manager whose data organization should be used (highly recommended, may be null)
* @param componentOffset signed component offset setting value (see {@link ComponentOffsetSettingsDefinition}
*/
/* package */ PointerTypedef(String typeDefName, DataType referencedDataType, int pointerSize,
DataTypeManager dtm) {
super(typeDefName, referencedDataType, pointerSize, dtm);
public PointerTypedef(String typeDefName, DataType referencedDataType, int pointerSize,
DataTypeManager dtm, long componentOffset) {
this(typeDefName, referencedDataType, pointerSize, dtm);
ComponentOffsetSettingsDefinition.DEF.setValue(getDefaultSettings(), componentOffset);
}
/**
* Constructs a pointer-typedef without any settings
* @param typeDefName name of this pointer-typedef or null to force name generation.
* @param typeDefName name of this pointer-typedef or null to use auto-named typedef.
* @param referencedDataType data type this pointer-typedef points to or null
* @param pointerSize pointer size in bytes or -1 for default pointer size based upon datatype manager
* @param dtm data-type manager whose data organization should be used (highly recommended, may be null)
*/
public PointerTypedef(String typeDefName, DataType referencedDataType, int pointerSize,
DataTypeManager dtm) {
super(getCategoryPath(referencedDataType), getTempNameIfNeeded(typeDefName), dtm);
isAutoNamed = StringUtils.isBlank(typeDefName);
modelTypedef =
new TypedefDataType("TEMP", new PointerDataType(referencedDataType, pointerSize, dtm));
}
/**
* Constructs a pointer-typedef without any settings
* @param typeDefName name of this pointer-typedef or null to use auto-named typedef.
* @param pointerDataType associated pointer datatype
* @param dtm data-type manager whose data organization should be used (highly recommended, may be null)
*/
/* package */ PointerTypedef(String typeDefName, Pointer pointerDataType, DataTypeManager dtm) {
super(typeDefName, pointerDataType, dtm);
public PointerTypedef(String typeDefName, Pointer pointerDataType, DataTypeManager dtm) {
super(pointerDataType.getCategoryPath(), getTempNameIfNeeded(typeDefName), dtm);
isAutoNamed = StringUtils.isBlank(typeDefName);
modelTypedef = new TypedefDataType("TEMP", pointerDataType.clone(dtm));
}
private static CategoryPath getCategoryPath(DataType referencedDataType) {
return referencedDataType != null ? referencedDataType.getCategoryPath()
: CategoryPath.ROOT;
}
private static String getTempNameIfNeeded(String baseName) {
return StringUtils.isBlank(baseName) ? "TEMP" : baseName;
}
private static int getPreferredPointerSize(int pointerSize, DataTypeManager dtm,
AddressSpace space) {
Objects.requireNonNull(space, "Address space must be specified");
if (pointerSize > 0) {
return pointerSize;
}
pointerSize = space.getSize() / 8;
if (dtm.getDataOrganization().getPointerSize() == pointerSize) {
pointerSize = -1;
}
return pointerSize;
}
@Override
public void enableAutoNaming() {
isAutoNamed = true;
}
@Override
public boolean isAutoNamed() {
return isAutoNamed;
}
/**
* Get the referenced datatype used to construct this datatype
* (datatype which pointer references).
* @return referenced datatype
*/
protected DataType getReferencedDataType() {
Pointer ptrType = (Pointer) getDataType();
return ptrType.getDataType();
}
public UniversalID getUniversalID() {
return universalId;
}
@Override
public boolean isEquivalent(DataType obj) {
if (obj == this) {
return true;
}
if (obj == null || !(obj instanceof TypeDef)) {
return false;
}
TypeDef td = (TypeDef) obj;
if (!DataTypeUtilities.equalsIgnoreConflict(getName(), td.getName())) {
return false;
}
if (!hasSameTypeDefSettings(td)) {
return false;
}
return DataTypeUtilities.isSameOrEquivalentDataType(getDataType(), td.getDataType());
}
@Override
@ -91,12 +191,92 @@ public class PointerTypedef extends AbstractPointerTypedefDataType {
}
@Override
public DataType clone(DataTypeManager dtm) {
public String getName() {
if (isAutoNamed) {
// Do not cache name since we do not have listeners to detect
// settings change which may impact name generation.
return TypedefDataType.generateTypedefName(this);
}
return super.getName(); // use name provided at instantiation
}
@Override
public boolean hasLanguageDependantLength() {
return modelTypedef.hasLanguageDependantLength();
}
@Override
public int getLength() {
return modelTypedef.getLength();
}
@Override
public DataType getDataType() {
return modelTypedef.getDataType();
}
@Override
public DataType getBaseDataType() {
return modelTypedef.getBaseDataType();
}
@Override
public SettingsDefinition[] getSettingsDefinitions() {
return modelTypedef.getSettingsDefinitions();
}
@Override
public TypeDefSettingsDefinition[] getTypeDefSettingsDefinitions() {
return modelTypedef.getTypeDefSettingsDefinitions();
}
@Override
public Settings getDefaultSettings() {
return modelTypedef.getDefaultSettings();
}
@Override
public boolean dependsOn(DataType dt) {
DataType myDt = getDataType();
return (myDt == dt || myDt.dependsOn(dt));
}
@Override
public String toString() {
if (isAutoNamed) {
return getClass().getSimpleName() + ": " + getName();
}
return getClass().getSimpleName() + ": typedef " + getName() + " " +
getDataType().getName();
}
@Override
public Class<?> getValueClass(Settings settings) {
return modelTypedef.getValueClass(settings);
}
@Override
public Object getValue(MemBuffer buf, Settings settings, int length) {
return modelTypedef.getValue(buf, settings, length);
}
@Override
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
return modelTypedef.getRepresentation(buf, settings, length);
}
@Override
public PointerTypedef clone(DataTypeManager dtm) {
if (dataMgr == dtm) {
return this;
}
return copy(dtm);
}
@Override
public PointerTypedef copy(DataTypeManager dtm) {
Pointer ptrType = (Pointer) getDataType();
String n = hasGeneratedNamed() ? null : getName();
String n = isAutoNamed ? null : getName();
PointerTypedef td = new PointerTypedef(n, ptrType, getDataTypeManager());
TypedefDataType.copyTypeDefSettings(this, td, false);
return td;

View file

@ -20,6 +20,7 @@ import java.util.Objects;
import ghidra.program.database.data.PointerTypedefInspector;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.symbol.OffsetReference;
import ghidra.util.InvalidNameException;
/**
* <code>PointerTypedefBuilder</code> provides a builder for creating {@link Pointer} - {@link TypeDef}s.
@ -62,9 +63,10 @@ public class PointerTypedefBuilder {
* upon the associated pointer type and the specified settings.
* @param name typedef name
* @return this builder
* @throws InvalidNameException if name contains unsupported characters
*/
public PointerTypedefBuilder name(String name) {
typedef.setTypedefName(name);
public PointerTypedefBuilder name(String name) throws InvalidNameException {
typedef.setName(name);
return this;
}

View file

@ -15,7 +15,9 @@
*/
package ghidra.program.model.data;
import ghidra.docking.settings.SettingsDefinition;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Data;
import ghidra.program.model.listing.Program;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
@ -33,78 +35,102 @@ public interface ProgramBasedDataTypeManager extends DomainFileBasedDataTypeMana
Program getProgram();
/**
* Set the long value for instance settings.
* Determine if a settings change is permitted for the specified settingsDefinition.
* @param data data code unit
* @param settingsDefinition settings definition
* @return true if change permitted else false
*/
public boolean isChangeAllowed(Data data, SettingsDefinition settingsDefinition);
/**
* Set the long value for data instance settings.
*
* @param dataAddr min address of data
* @param data data code unit
* @param name settings name
* @param value value of setting
* @return true if the settings actually changed
*/
public boolean setLongSettingsValue(Address dataAddr, String name, long value);
public boolean setLongSettingsValue(Data data, String name, long value);
/**
* Set the string value for instance settings.
* Set the string value for data instance settings.
*
* @param dataAddr min address of data
* @param data data code unit
* @param name settings name
* @param value value of setting
* @return true if the settings actually changed
*/
public boolean setStringSettingsValue(Address dataAddr, String name, String value);
public boolean setStringSettingsValue(Data data, String name, String value);
/**
* Set the Object settings.
* Set the Object value for data instance settings.
*
* @param dataAddr min address of data
* @param data data code unit
* @param name the name of the settings
* @param value the value for the settings, must be either a String, byte[]
* or Long
* @return true if the settings were updated
*/
public boolean setSettings(Address dataAddr, String name, Object value);
public boolean setSettings(Data data, String name, Object value);
/**
* Get the long value for an instance setting.
* Get the long value for data instance settings.
*
* @param dataAddr min address of data
* @param data data code unit
* @param name settings name
* @return null if the named setting was not found
*/
public Long getLongSettingsValue(Address dataAddr, String name);
public Long getLongSettingsValue(Data data, String name);
/**
* Get the String value for an instance setting.
* Get the String value for data instance settings.
*
* @param dataAddr min address of data
* @param data data code unit
* @param name settings name
* @return null if the named setting was not found
*/
public String getStringSettingsValue(Address dataAddr, String name);
public String getStringSettingsValue(Data data, String name);
/**
* Gets the value of a settings as an object (either String, byte[], or Long).
* Gets the value for data instance settings in Object form.
*
* @param dataAddr the address of the data for this settings
* @param data data code unit
* @param name the name of settings.
* @return the settings object
*/
public Object getSettings(Address dataAddr, String name);
public Object getSettings(Data data, String name);
/**
* Clear the setting
* Clear the specified setting for the given data
*
* @param dataAddr min address of data
* @param data data code unit
* @param name settings name
* @return true if the settings were cleared
*/
public boolean clearSetting(Address dataAddr, String name);
public boolean clearSetting(Data data, String name);
/**
* Clear all settings at the given address.
* Clear all settings for the given data.
*
* @param dataAddr the address for this settings.
* @param data data code unit
*/
public void clearAllSettings(Address dataAddr);
public void clearAllSettings(Data data);
/**
* Returns all the instance Settings names used for the specified data
*
* @param data data code unit
* @return the names
*/
public String[] getInstanceSettingsNames(Data data);
/**
* Returns true if no settings are set for the given data
*
* @param data data code unit
* @return true if not settings
*/
public boolean isEmptySetting(Data data);
/**
* Move the settings in the range to the new start address
@ -118,22 +144,6 @@ public interface ProgramBasedDataTypeManager extends DomainFileBasedDataTypeMana
public void moveAddressRange(Address fromAddr, Address toAddr, long length, TaskMonitor monitor)
throws CancelledException;
/**
* Returns all the instance Settings names used at the given address
*
* @param dataAddr the address
* @return the names
*/
public String[] getInstanceSettingsNames(Address dataAddr);
/**
* Returns true if no settings are set for the given address
*
* @param dataAddr the address to test
* @return true if not settings
*/
public boolean isEmptySetting(Address dataAddr);
/**
* Removes all settings in the range
*

View file

@ -82,6 +82,11 @@ public class TerminatedSettingsDefinition implements EnumSettingsDefinition {
return "Termination";
}
@Override
public String getStorageKey() {
return TERMINATED;
}
@Override
public String getDescription() {
return "Selects if the string is terminated or unterminated";

View file

@ -23,15 +23,33 @@ import ghidra.docking.settings.SettingsDefinition;
*/
public interface TypeDef extends DataType {
/**
* Determine if this datatype use auto-naming (e.g., see {@link PointerTypedef}).
* If true, any change to associated {@link TypeDefSettingsDefinition} settings
* or naming of the pointer-referenced datatype will cause a automatic renaming
* of this datatype.
* @return true if auto-named, else false.
*/
public boolean isAutoNamed();
/**
* Enable auto-naming for this typedef. This will force naming to reflect the name of
* associated datatype plus an attribute list which corresponds to any
* {@link TypeDefSettingsDefinition} settings which may be set.
*/
public void enableAutoNaming();
/**
* Returns the dataType that this typedef is based on. This could be
* another typedef
* @return the datatype which this typedef is based on (may be another {@link TypeDef}).
*/
public DataType getDataType();
/**
* Returns the non-typedef dataType that this typedef is based on, following
* chains of typedefs as necessary.
* @return the datatype which this typedef is based on (will not be another {@link TypeDef}).
*/
public DataType getBaseDataType();
@ -78,4 +96,5 @@ public interface TypeDef extends DataType {
}
return true;
}
}

View file

@ -33,13 +33,6 @@ import ghidra.docking.settings.SettingsDefinition;
*/
public interface TypeDefSettingsDefinition extends SettingsDefinition {
/**
* Get the storage key which should be used when storing a key/value
* map entry which corresponds to this settings definition.
* @return settings storage key
*/
String getStorageKey();
/**
* Get the {@link TypeDef} attribute specification for this setting and its
* current value.

View file

@ -18,6 +18,7 @@ package ghidra.program.model.data;
import ghidra.docking.settings.*;
import ghidra.program.database.data.DataTypeUtilities;
import ghidra.program.model.mem.MemBuffer;
import ghidra.util.InvalidNameException;
import ghidra.util.UniversalID;
/**
@ -30,6 +31,7 @@ public class TypedefDataType extends GenericDataType implements TypeDef {
private DataType dataType;
private SettingsDefinition[] settingsDef;
private boolean isAutoNamed = false;
private boolean deleted = false;
/**
@ -104,6 +106,20 @@ public class TypedefDataType extends GenericDataType implements TypeDef {
}
}
@Override
public void enableAutoNaming() {
if (isAutoNamed) {
return;
}
isAutoNamed = true;
notifyNameChanged(name);
}
@Override
public boolean isAutoNamed() {
return isAutoNamed;
}
@Override
public String getDefaultLabelPrefix() {
return getName();
@ -124,7 +140,10 @@ public class TypedefDataType extends GenericDataType implements TypeDef {
}
if (obj instanceof TypeDef) {
TypeDef td = (TypeDef) obj;
if (!DataTypeUtilities.equalsIgnoreConflict(name, td.getName())) {
if (isAutoNamed != td.isAutoNamed()) {
return false;
}
if (!isAutoNamed && !DataTypeUtilities.equalsIgnoreConflict(getName(), td.getName())) {
return false;
}
if (!hasSameTypeDefSettings(td)) {
@ -175,23 +194,66 @@ public class TypedefDataType extends GenericDataType implements TypeDef {
return dataType.getValueClass(settings);
}
public static TypeDef clone(TypeDef typedef, DataTypeManager dtm) {
if (typedef.getDataTypeManager() == dtm) {
return typedef;
}
TypedefDataType newTypedef =
new TypedefDataType(typedef.getCategoryPath(), typedef.getName(), typedef.getDataType(),
typedef.getUniversalID(),
typedef.getSourceArchive(), typedef.getLastChangeTime(),
typedef.getLastChangeTimeInSourceArchive(), dtm);
copyTypeDefSettings(typedef, newTypedef, false);
newTypedef.isAutoNamed = typedef.isAutoNamed();
return newTypedef;
}
public static TypedefDataType copy(TypeDef typedef, DataTypeManager dtm) {
TypedefDataType newTypedef = new TypedefDataType(typedef.getCategoryPath(),
typedef.getName(), typedef.getDataType(), dtm);
copyTypeDefSettings(typedef, newTypedef, false);
newTypedef.isAutoNamed = typedef.isAutoNamed();
return newTypedef;
}
@Override
public TypedefDataType clone(DataTypeManager dtm) {
if (getDataTypeManager() == dtm) {
return this;
}
TypedefDataType typeDef =
new TypedefDataType(categoryPath, name, dataType, getUniversalID(),
getSourceArchive(), getLastChangeTime(), getLastChangeTimeInSourceArchive(), dtm);
copyTypeDefSettings(this, typeDef, false);
return typeDef;
return (TypedefDataType) clone(this, dtm);
}
@Override
public TypedefDataType copy(DataTypeManager dtm) {
TypedefDataType typeDef = new TypedefDataType(categoryPath, name, dataType, dtm);
copyTypeDefSettings(this, typeDef, false);
return typeDef;
return copy(this, dtm);
}
@Override
public String getName() {
if (isAutoNamed()) {
return generateTypedefName(this);
}
return super.getName();
}
@Override
public void setName(String name) throws InvalidNameException {
super.setName(name);
isAutoNamed = false;
}
@Override
public void setCategoryPath(CategoryPath path) {
if (isAutoNamed()) {
return; // ignore category change if auto-naming enabled
}
super.setCategoryPath(path);
}
@Override
public CategoryPath getCategoryPath() {
if (isAutoNamed()) {
return getDataType().getCategoryPath();
}
return super.getCategoryPath();
}
@Override
@ -316,6 +378,9 @@ public class TypedefDataType extends GenericDataType implements TypeDef {
@Override
public String toString() {
if (isAutoNamed()) {
return getName();
}
return "typedef " + getName() + " " + dataType.getName();
}
@ -351,9 +416,9 @@ public class TypedefDataType extends GenericDataType implements TypeDef {
public static String generateTypedefName(TypeDef modelType) {
// Examples:
// string *32 __attribute__((relative))
// char *32 __attribute__((image-base-relative))
// char *16 __attribute__((space(data)))
// string *32 __((relative))
// char *32 __((image-base-relative))
// char *16 __((space(data)))
Settings settings = modelType.getDefaultSettings();
StringBuilder attributesBuf = new StringBuilder();
@ -367,9 +432,11 @@ public class TypedefDataType extends GenericDataType implements TypeDef {
}
}
StringBuilder buf = new StringBuilder(modelType.getDataType().getName());
buf.append(" __attribute__((");
buf.append(' ');
buf.append(DataType.TYPEDEF_ATTRIBUTE_PREFIX);
buf.append(attributesBuf);
buf.append("))");
buf.append(DataType.TYPEDEF_ATTRIBUTE_SUFFIX);
return buf.toString();
}
}

View file

@ -20,6 +20,7 @@ import java.util.Iterator;
import java.util.List;
import ghidra.docking.settings.Settings;
import ghidra.docking.settings.SettingsDefinition;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.DataTypeDisplayOptions;
@ -322,6 +323,11 @@ public class DataStub implements Data {
throw new UnsupportedOperationException();
}
@Override
public boolean isChangeAllowed(SettingsDefinition settingsDefinition) {
throw new UnsupportedOperationException();
}
@Override
public Long getLong(String name) {
throw new UnsupportedOperationException();

Some files were not shown because too many files have changed in this diff Show more