mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
GP-4340 Improved datatype conflict name handling
This commit is contained in:
parent
7f58541ba0
commit
5dc7347eee
22 changed files with 493 additions and 371 deletions
|
@ -29,6 +29,7 @@ import com.google.gson.JsonElement;
|
|||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
import ghidra.program.database.data.DataTypeUtilities;
|
||||
import ghidra.program.database.data.ProgramDataTypeManager;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressFormatException;
|
||||
|
@ -96,7 +97,8 @@ public class IsfDataTypeWriter extends AbstractIsfWriter {
|
|||
* @param baseWriter the writer to use when writing data types
|
||||
* @throws IOException if there is an exception writing the output
|
||||
*/
|
||||
public IsfDataTypeWriter(DataTypeManager dtm, List<DataType> target, Writer baseWriter) throws IOException {
|
||||
public IsfDataTypeWriter(DataTypeManager dtm, List<DataType> target, Writer baseWriter)
|
||||
throws IOException {
|
||||
super(baseWriter);
|
||||
this.baseWriter = baseWriter;
|
||||
this.dtm = dtm;
|
||||
|
@ -117,11 +119,12 @@ public class IsfDataTypeWriter extends AbstractIsfWriter {
|
|||
STRICT = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonObject getRootObject(TaskMonitor monitor) throws CancelledException, IOException {
|
||||
genRoot(monitor);
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void genRoot(TaskMonitor monitor) throws CancelledException, IOException {
|
||||
genMetadata();
|
||||
|
@ -160,7 +163,8 @@ public class IsfDataTypeWriter extends AbstractIsfWriter {
|
|||
oskey = metaData.get("Compiler ID");
|
||||
if (metaData.containsKey("PDB Loaded")) {
|
||||
os = gson.toJsonTree(new IsfWinOS(metaData));
|
||||
} else if (metaData.containsKey("Executable Format")) {
|
||||
}
|
||||
else if (metaData.containsKey("Executable Format")) {
|
||||
if (metaData.get("Executable Format").contains("ELF")) {
|
||||
oskey = "linux";
|
||||
os = gson.toJsonTree(new IsfLinuxOS(gson, metaData));
|
||||
|
@ -201,15 +205,18 @@ public class IsfDataTypeWriter extends AbstractIsfWriter {
|
|||
Symbol symbol = iterator.next();
|
||||
symbolToJson(imageBase, symbolTable, linkages, map, symbol);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
for (Address addr : requestedAddresses) {
|
||||
Symbol[] symsFromAddr = symbolTable.getSymbols(addr.add(imageBase.getOffset()));
|
||||
Symbol[] symsFromAddr =
|
||||
symbolTable.getSymbols(addr.add(imageBase.getOffset()));
|
||||
for (Symbol symbol : symsFromAddr) {
|
||||
symbolToJson(imageBase, symbolTable, linkages, map, symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
for (String key : requestedSymbols) {
|
||||
SymbolIterator iter = symbolTable.getSymbols(key);
|
||||
while (iter.hasNext()) {
|
||||
|
@ -263,7 +270,7 @@ public class IsfDataTypeWriter extends AbstractIsfWriter {
|
|||
monitor.setMaximum(keylist.size());
|
||||
for (String key : keylist) {
|
||||
DataType dataType = map.get(key);
|
||||
if (key.contains(".conflict")) {
|
||||
if (DataTypeUtilities.isConflictDataType(dataType)) {
|
||||
continue;
|
||||
}
|
||||
obj = getObjectForDataType(dataType, monitor);
|
||||
|
@ -273,28 +280,34 @@ public class IsfDataTypeWriter extends AbstractIsfWriter {
|
|||
if (dataType instanceof FunctionDefinition) {
|
||||
// Would be nice to support this in the future, but Volatility does not
|
||||
add(functions, dataType.getPathName(), obj);
|
||||
} else if (IsfUtilities.isBaseDataType(dataType)) {
|
||||
}
|
||||
else if (IsfUtilities.isBaseDataType(dataType)) {
|
||||
add(baseTypes, dataType.getPathName(), obj);
|
||||
} else if (dataType instanceof TypeDef) {
|
||||
}
|
||||
else if (dataType instanceof TypeDef) {
|
||||
DataType baseDataType = ((TypeDef) dataType).getBaseDataType();
|
||||
if (IsfUtilities.isBaseDataType(baseDataType)) {
|
||||
add(baseTypes, dataType.getPathName(), obj);
|
||||
} else if (baseDataType instanceof Enum) {
|
||||
}
|
||||
else if (baseDataType instanceof Enum) {
|
||||
add(enums, dataType.getPathName(), obj);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
add(userTypes, dataType.getPathName(), obj);
|
||||
}
|
||||
} else if (dataType instanceof Enum) {
|
||||
}
|
||||
else if (dataType instanceof Enum) {
|
||||
add(enums, dataType.getPathName(), obj);
|
||||
} else if (dataType instanceof Composite) {
|
||||
}
|
||||
else if (dataType instanceof Composite) {
|
||||
add(userTypes, dataType.getPathName(), obj);
|
||||
}
|
||||
monitor.increment();
|
||||
}
|
||||
}
|
||||
|
||||
private void symbolToJson(Address imageBase, SymbolTable symbolTable, Map<String, Symbol> linkages,
|
||||
Map<String, JsonObject> map, Symbol symbol) {
|
||||
private void symbolToJson(Address imageBase, SymbolTable symbolTable,
|
||||
Map<String, Symbol> linkages, Map<String, JsonObject> map, Symbol symbol) {
|
||||
String key = symbol.getName();
|
||||
Address address = symbol.getAddress();
|
||||
JsonObject sym = map.containsKey(key) ? map.get(key) : new JsonObject();
|
||||
|
@ -305,10 +318,12 @@ public class IsfDataTypeWriter extends AbstractIsfWriter {
|
|||
sym.addProperty("linkage_name", linkage.getName());
|
||||
sym.addProperty("address", linkage.getAddress().getOffset());
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if (address.getAddressSpace().equals(imageBase.getAddressSpace())) {
|
||||
sym.addProperty("address", address.subtract(imageBase));
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
sym.addProperty("address", address.getOffset());
|
||||
}
|
||||
}
|
||||
|
@ -323,6 +338,7 @@ public class IsfDataTypeWriter extends AbstractIsfWriter {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(JsonObject obj) {
|
||||
gson.toJson(obj, writer);
|
||||
}
|
||||
|
@ -332,7 +348,8 @@ public class IsfDataTypeWriter extends AbstractIsfWriter {
|
|||
add(baseTypes, "undefined", getTree(newTypedefPointer(null)));
|
||||
}
|
||||
|
||||
protected JsonObject getObjectForDataType(DataType dt, TaskMonitor monitor) throws IOException, CancelledException {
|
||||
protected JsonObject getObjectForDataType(DataType dt, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
IsfObject isf = getIsfObject(dt, monitor);
|
||||
if (isf != null) {
|
||||
JsonObject jobj = (JsonObject) getTree(isf);
|
||||
|
@ -351,7 +368,8 @@ public class IsfDataTypeWriter extends AbstractIsfWriter {
|
|||
* @param monitor the task monitor
|
||||
* @throws IOException if there is an exception writing the output
|
||||
*/
|
||||
protected IsfObject getIsfObject(DataType dt, TaskMonitor monitor) throws IOException, CancelledException {
|
||||
protected IsfObject getIsfObject(DataType dt, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
if (dt == null) {
|
||||
throw new IOException("Null datatype passed to getIsfObject");
|
||||
}
|
||||
|
@ -377,21 +395,29 @@ public class IsfDataTypeWriter extends AbstractIsfWriter {
|
|||
if (dt instanceof Dynamic dynamic) {
|
||||
DataType rep = dynamic.getReplacementBaseType();
|
||||
return rep == null ? null : getIsfObject(rep, monitor);
|
||||
} else if (dt instanceof TypeDef typedef) {
|
||||
}
|
||||
else if (dt instanceof TypeDef typedef) {
|
||||
return getObjectTypeDef(typedef, monitor);
|
||||
} else if (dt instanceof Composite composite) {
|
||||
}
|
||||
else if (dt instanceof Composite composite) {
|
||||
return new IsfComposite(composite, this, monitor);
|
||||
} else if (dt instanceof Enum enumm) {
|
||||
}
|
||||
else if (dt instanceof Enum enumm) {
|
||||
return new IsfEnum(enumm);
|
||||
} else if (dt instanceof BuiltInDataType builtin) {
|
||||
}
|
||||
else if (dt instanceof BuiltInDataType builtin) {
|
||||
return new IsfBuiltIn(builtin);
|
||||
} else if (dt instanceof BitFieldDataType) {
|
||||
}
|
||||
else if (dt instanceof BitFieldDataType) {
|
||||
// skip - not hit
|
||||
} else if (dt instanceof FunctionDefinition) { /// FAIL
|
||||
}
|
||||
else if (dt instanceof FunctionDefinition) { /// FAIL
|
||||
// skip - not hit
|
||||
} else if (dt.equals(DataType.DEFAULT)) {
|
||||
}
|
||||
else if (dt.equals(DataType.DEFAULT)) {
|
||||
// skip - not hit
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
Msg.warn(this, "Unable to write datatype. Type unrecognized: " + dt.getClass());
|
||||
}
|
||||
|
||||
|
@ -417,8 +443,8 @@ public class IsfDataTypeWriter extends AbstractIsfWriter {
|
|||
}
|
||||
}
|
||||
}
|
||||
Msg.warn(this,
|
||||
"WARNING! conflicting data type names: " + dt.getPathName() + " - " + resolvedType.getPathName());
|
||||
Msg.warn(this, "WARNING! conflicting data type names: " + dt.getPathName() + " - " +
|
||||
resolvedType.getPathName());
|
||||
return resolved.get(dt);
|
||||
}
|
||||
|
||||
|
@ -465,8 +491,9 @@ public class IsfDataTypeWriter extends AbstractIsfWriter {
|
|||
return newIsfDynamicComponent(dynamic, type, elementCnt);
|
||||
|
||||
}
|
||||
Msg.error(this, dynamic.getClass().getSimpleName() + " returned bad replacementBaseType: "
|
||||
+ replacementBaseType.getClass().getSimpleName());
|
||||
Msg.error(this,
|
||||
dynamic.getClass().getSimpleName() + " returned bad replacementBaseType: " +
|
||||
replacementBaseType.getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -500,7 +527,7 @@ public class IsfDataTypeWriter extends AbstractIsfWriter {
|
|||
IsfObject baseObject = getObjectDataType(IsfUtilities.getBaseDataType(dataType));
|
||||
return new IsfDataTypeTypeDef(dataType, baseObject);
|
||||
}
|
||||
if (dataType.getPathName().contains(".conflict")) {
|
||||
if (DataTypeUtilities.isConflictDataType(dataType)) {
|
||||
if (!deferredKeys.contains(dataType.getPathName())) {
|
||||
deferredKeys.add(dataType.getPathName());
|
||||
}
|
||||
|
@ -513,7 +540,8 @@ public class IsfDataTypeWriter extends AbstractIsfWriter {
|
|||
*
|
||||
* @throws CancelledException if the action is cancelled by the user
|
||||
*/
|
||||
protected IsfObject getObjectTypeDef(TypeDef typeDef, TaskMonitor monitor) throws CancelledException {
|
||||
protected IsfObject getObjectTypeDef(TypeDef typeDef, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
DataType dataType = typeDef.getDataType();
|
||||
String typedefName = typeDef.getPathName();
|
||||
|
||||
|
@ -527,7 +555,8 @@ public class IsfDataTypeWriter extends AbstractIsfWriter {
|
|||
return newTypedefUser(typeDef, isfObject);
|
||||
}
|
||||
return newTypedefPointer(typeDef);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e) {
|
||||
Msg.error(this, "TypeDef error: " + e);
|
||||
}
|
||||
clearResolve(typedefName, baseType);
|
||||
|
@ -544,7 +573,8 @@ public class IsfDataTypeWriter extends AbstractIsfWriter {
|
|||
return;
|
||||
}
|
||||
requestedAddresses.add(address);
|
||||
} catch (AddressFormatException e) {
|
||||
}
|
||||
catch (AddressFormatException e) {
|
||||
throw new IOException("Bad address format: " + key);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// Search for the root cause of a datatype conflict based upon a selected datatype.
|
||||
//@category Data Types
|
||||
import java.util.*;
|
||||
|
@ -55,8 +56,8 @@ public class FindDataTypeConflictCauseScript extends GhidraScript {
|
|||
}
|
||||
|
||||
DataType selectedDt = DataTypeUtilities.getBaseDataType(selectedDatatypes.get(0));
|
||||
if (selectedDt instanceof Pointer || selectedDt instanceof Array) {
|
||||
popup("Selected datatype must not be a Pointer or Array");
|
||||
if (selectedDt == null) {
|
||||
popup("Selected datatype must not be a default Pointer");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -190,11 +190,13 @@ public class DataTypeSyncInfo {
|
|||
if (sourceDt == null) {
|
||||
return true;
|
||||
}
|
||||
if (!DataTypeSynchronizer.namesAreEquivalent(sourceDt, refDt)) {
|
||||
return true;
|
||||
}
|
||||
if (!StringUtils.equals(refDt.getDescription(), sourceDt.getDescription())) {
|
||||
return true;
|
||||
if (!DataTypeSynchronizer.isPointerOrArray(refDt)) {
|
||||
if (!DataTypeSynchronizer.namesAreEquivalent(sourceDt, refDt)) {
|
||||
return true;
|
||||
}
|
||||
if (!StringUtils.equals(refDt.getDescription(), sourceDt.getDescription())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
DataType dt = sourceDt.clone(refDt.getDataTypeManager());
|
||||
return !dt.isEquivalent(refDt);
|
||||
|
|
|
@ -28,8 +28,7 @@ import ghidra.app.plugin.core.datamgr.archive.DataTypeManagerHandler;
|
|||
import ghidra.app.util.ToolTipUtils;
|
||||
import ghidra.app.util.html.HTMLDataTypeRepresentation;
|
||||
import ghidra.app.util.html.MissingArchiveDataTypeHTMLRepresentation;
|
||||
import ghidra.program.database.data.DataTypeManagerDB;
|
||||
import ghidra.program.database.data.ProgramDataTypeManager;
|
||||
import ghidra.program.database.data.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.exception.AssertException;
|
||||
|
@ -127,11 +126,13 @@ public class DataTypeSynchronizer {
|
|||
// not handled by resolve.
|
||||
long lastChangeTime = refDT.getLastChangeTime();
|
||||
DataType sourceDT = sourceDTM.resolve(refDT, DataTypeConflictHandler.REPLACE_HANDLER);
|
||||
if (!namesAreEquivalent(refDT, sourceDT)) {
|
||||
renameDataType(sourceDTM, sourceDT, refDT);
|
||||
}
|
||||
if (!StringUtils.equals(refDT.getDescription(), sourceDT.getDescription())) {
|
||||
sourceDT.setDescription(refDT.getDescription());
|
||||
if (!isPointerOrArray(refDT)) {
|
||||
if (!namesAreEquivalent(refDT, sourceDT)) {
|
||||
renameDataType(sourceDTM, sourceDT, refDT);
|
||||
}
|
||||
if (!StringUtils.equals(refDT.getDescription(), sourceDT.getDescription())) {
|
||||
sourceDT.setDescription(refDT.getDescription());
|
||||
}
|
||||
}
|
||||
sourceDT.setLastChangeTime(lastChangeTime);
|
||||
refDT.setLastChangeTimeInSourceArchive(lastChangeTime);
|
||||
|
@ -140,11 +141,13 @@ public class DataTypeSynchronizer {
|
|||
public static void updateAssumingTransactionsOpen(DataTypeManager refDTM, DataType sourceDT) {
|
||||
long lastChangeTime = sourceDT.getLastChangeTime();
|
||||
DataType refDT = refDTM.resolve(sourceDT, DataTypeConflictHandler.REPLACE_HANDLER);
|
||||
if (!namesAreEquivalent(refDT, sourceDT)) {
|
||||
renameDataType(refDTM, refDT, sourceDT);
|
||||
}
|
||||
if (!StringUtils.equals(sourceDT.getDescription(), refDT.getDescription())) {
|
||||
refDT.setDescription(sourceDT.getDescription());
|
||||
if (!isPointerOrArray(sourceDT)) {
|
||||
if (!namesAreEquivalent(refDT, sourceDT)) {
|
||||
renameDataType(refDTM, refDT, sourceDT);
|
||||
}
|
||||
if (!StringUtils.equals(sourceDT.getDescription(), refDT.getDescription())) {
|
||||
refDT.setDescription(sourceDT.getDescription());
|
||||
}
|
||||
}
|
||||
refDT.setLastChangeTimeInSourceArchive(lastChangeTime);
|
||||
refDT.setLastChangeTime(lastChangeTime);
|
||||
|
@ -252,14 +255,10 @@ public class DataTypeSynchronizer {
|
|||
}
|
||||
}
|
||||
String name = dtToCopy.getName();
|
||||
int index = name.indexOf(DataType.CONFLICT_SUFFIX);
|
||||
if (index > 0) {
|
||||
name = name.substring(0, index);
|
||||
}
|
||||
CategoryPath path = sourceDT.getCategoryPath();
|
||||
if (sourceDTM.getDataType(path, name) != null) {
|
||||
name = ((DataTypeManagerDB) sourceDTM).getUnusedConflictName(sourceDT.getCategoryPath(),
|
||||
name);
|
||||
dtToCopy);
|
||||
}
|
||||
try {
|
||||
sourceDT.setName(name);
|
||||
|
@ -282,27 +281,19 @@ public class DataTypeSynchronizer {
|
|||
return false;
|
||||
}
|
||||
|
||||
public static boolean namesAreEquivalent(DataType dt1, DataType dt2) {
|
||||
static boolean isPointerOrArray(DataType dt) {
|
||||
return (dt instanceof Pointer) || (dt instanceof Array);
|
||||
}
|
||||
|
||||
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)) {
|
||||
return true;
|
||||
}
|
||||
int index = name1.indexOf(DataType.CONFLICT_SUFFIX);
|
||||
if (index > 0) {
|
||||
name1 = name1.substring(0, index);
|
||||
}
|
||||
index = name2.indexOf(DataType.CONFLICT_SUFFIX);
|
||||
if (index > 0) {
|
||||
name2 = name2.substring(0, index);
|
||||
}
|
||||
return name1.equals(name2);
|
||||
return DataTypeUtilities.getNameWithoutConflict(dt1)
|
||||
.equals(DataTypeUtilities.getNameWithoutConflict(dt2));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package ghidra.app.util;
|
||||
|
||||
import ghidra.program.database.data.DataTypeUtilities;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.listing.FunctionSignature;
|
||||
|
@ -53,9 +54,9 @@ public class DataTypeNamingUtil {
|
|||
}
|
||||
|
||||
sb.append("_");
|
||||
sb.append(mangleDTName(returnType.getName()));
|
||||
sb.append(mangleDTName(returnType));
|
||||
for (ParameterDefinition p : parameters) {
|
||||
sb.append("_").append(mangleDTName(p.getDataType().getName()));
|
||||
sb.append("_").append(mangleDTName(p.getDataType()));
|
||||
}
|
||||
|
||||
if (functionDefinition.hasVarArgs()) {
|
||||
|
@ -72,8 +73,9 @@ public class DataTypeNamingUtil {
|
|||
return name;
|
||||
}
|
||||
|
||||
private static String mangleDTName(String s) {
|
||||
return s.replaceAll(" ", "_").replaceAll("\\*", "ptr");
|
||||
private static String mangleDTName(DataType dt) {
|
||||
String name = DataTypeUtilities.getNameWithoutConflict(dt);
|
||||
return name.replaceAll(" ", "_").replaceAll("\\*", "ptr");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -25,14 +25,14 @@ class LibraryExportedSymbol {
|
|||
private int memsize;
|
||||
private int ordinal = -1;
|
||||
private String symbolName;
|
||||
private String fowardLibraryName;
|
||||
private String fowardSymbolName;
|
||||
private String forwardLibraryName;
|
||||
private String forwardSymbolName;
|
||||
private int purge;
|
||||
private boolean noReturn;
|
||||
private String comment;
|
||||
|
||||
LibraryExportedSymbol(String libName, int memsize, int ordinal, String symbolName,
|
||||
String fowardLibraryName, String fowardSymbolName, int purge, boolean noReturn,
|
||||
String forwardLibraryName, String forwardSymbolName, int purge, boolean noReturn,
|
||||
String comment) {
|
||||
this.libName = libName;
|
||||
this.memsize = memsize;
|
||||
|
@ -41,8 +41,8 @@ class LibraryExportedSymbol {
|
|||
this.purge = purge;
|
||||
this.noReturn = noReturn;
|
||||
this.comment = comment;
|
||||
this.fowardLibraryName = fowardLibraryName;
|
||||
this.fowardSymbolName = fowardSymbolName;
|
||||
this.forwardLibraryName = forwardLibraryName;
|
||||
this.forwardSymbolName = forwardSymbolName;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -125,12 +125,12 @@ class LibraryExportedSymbol {
|
|||
private synchronized void processForwardedEntry() {
|
||||
|
||||
purge = -2;
|
||||
LibrarySymbolTable lib = LibraryLookupTable.getSymbolTable(fowardLibraryName, memsize);
|
||||
LibrarySymbolTable lib = LibraryLookupTable.getSymbolTable(forwardLibraryName, memsize);
|
||||
if (lib == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
LibraryExportedSymbol libSym = lib.getSymbol(fowardSymbolName);
|
||||
LibraryExportedSymbol libSym = lib.getSymbol(forwardSymbolName);
|
||||
if (libSym == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -151,24 +151,24 @@ class LibraryExportedSymbol {
|
|||
}
|
||||
|
||||
/**
|
||||
* @return true if this symbol is fowarded to another library
|
||||
* @return true if this symbol is forwarded to another library
|
||||
*/
|
||||
boolean isFowardEntry() {
|
||||
return fowardLibraryName != null;
|
||||
return forwardLibraryName != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the fowarded library name
|
||||
* @return the forwarded library name
|
||||
*/
|
||||
String getFowardLibraryName() {
|
||||
return fowardLibraryName;
|
||||
return forwardLibraryName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the fowarded symbol name
|
||||
* @return the forwarded symbol name
|
||||
*/
|
||||
String getFowardSymbolName() {
|
||||
return fowardSymbolName;
|
||||
return forwardSymbolName;
|
||||
}
|
||||
|
||||
void setName(String name) {
|
||||
|
|
|
@ -56,8 +56,8 @@ class LibrarySymbolTable {
|
|||
private String date;
|
||||
private String version;
|
||||
private int tempPurge;
|
||||
private String fowardLibrary = null;
|
||||
private String fowardSymbol = null;
|
||||
private String forwardLibrary = null;
|
||||
private String forwardSymbol = null;
|
||||
private HashMap<String, LibraryExportedSymbol> symMap = new HashMap<>();
|
||||
private ArrayList<LibraryExportedSymbol> exportList = new ArrayList<>();
|
||||
private HashMap<Integer, LibraryExportedSymbol> ordMap = new HashMap<>();
|
||||
|
@ -140,8 +140,8 @@ class LibrarySymbolTable {
|
|||
}
|
||||
}
|
||||
|
||||
fowardLibrary = null;
|
||||
fowardSymbol = null;
|
||||
forwardLibrary = null;
|
||||
forwardSymbol = null;
|
||||
tempPurge = -1;
|
||||
String comment = "";
|
||||
|
||||
|
@ -160,12 +160,12 @@ class LibrarySymbolTable {
|
|||
Reference[] refs = library.getReferenceManager().getReferencesFrom(symAddr);
|
||||
if (refs != null && refs.length > 0 && refs[0].isExternalReference()) {
|
||||
ExternalReference exRef = (ExternalReference) refs[0];
|
||||
fowardLibrary = exRef.getLibraryName();
|
||||
fowardSymbol = exRef.getLabel();
|
||||
forwardLibrary = exRef.getLibraryName();
|
||||
forwardSymbol = exRef.getLabel();
|
||||
}
|
||||
}
|
||||
|
||||
if (fowardLibrary == null || fowardLibrary.length() <= 0) {
|
||||
if (forwardLibrary == null || forwardLibrary.length() <= 0) {
|
||||
MemoryBlock block = library.getMemory().getBlock(symAddr);
|
||||
if (block != null && block.isExecute()) {
|
||||
pseudoDisassemble(library, symAddr);
|
||||
|
@ -179,12 +179,12 @@ class LibrarySymbolTable {
|
|||
noReturn = true;
|
||||
}
|
||||
|
||||
if (fowardLibrary != null && fowardLibrary.length() > 0) {
|
||||
forwards.add(fowardLibrary);
|
||||
if (forwardLibrary != null && forwardLibrary.length() > 0) {
|
||||
forwards.add(forwardLibrary);
|
||||
}
|
||||
|
||||
LibraryExportedSymbol expSym = new LibraryExportedSymbol(tableName, size, ordinal,
|
||||
realName, fowardLibrary, fowardSymbol, tempPurge, noReturn, comment);
|
||||
realName, forwardLibrary, forwardSymbol, tempPurge, noReturn, comment);
|
||||
|
||||
// add to export list in order
|
||||
exportList.add(expSym);
|
||||
|
@ -225,8 +225,8 @@ class LibrarySymbolTable {
|
|||
Scalar scalar = instr.getScalar(0);
|
||||
if (scalar != null) {
|
||||
tempPurge = (int) scalar.getSignedValue();
|
||||
fowardLibrary = null;
|
||||
fowardSymbol = null;
|
||||
forwardLibrary = null;
|
||||
forwardSymbol = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -234,15 +234,17 @@ class LibrarySymbolTable {
|
|||
if (ftype.isJump() && ftype.isComputed()) {
|
||||
Reference[] refs = instr.getReferencesFrom();
|
||||
if (refs.length > 0) {
|
||||
Data data = instr.getProgram().getListing().getDefinedDataAt(
|
||||
refs[0].getToAddress());
|
||||
Data data = instr.getProgram()
|
||||
.getListing()
|
||||
.getDefinedDataAt(refs[0].getToAddress());
|
||||
if (data != null) {
|
||||
refs = instr.getProgram().getReferenceManager().getReferencesFrom(
|
||||
data.getMinAddress());
|
||||
refs = instr.getProgram()
|
||||
.getReferenceManager()
|
||||
.getReferencesFrom(data.getMinAddress());
|
||||
if (refs != null && refs.length > 0 && refs[0].isExternalReference()) {
|
||||
ExternalReference exRef = (ExternalReference) refs[0];
|
||||
fowardLibrary = exRef.getLibraryName();
|
||||
fowardSymbol = exRef.getLabel();
|
||||
forwardLibrary = exRef.getLibraryName();
|
||||
forwardSymbol = exRef.getLabel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -425,26 +427,24 @@ class LibrarySymbolTable {
|
|||
version = root.getAttributeValue("VERSION");
|
||||
|
||||
List<Element> children = CollectionUtils.asList(root.getChildren(), Element.class);
|
||||
Iterator<Element> iter = children.iterator();
|
||||
while (iter.hasNext()) {
|
||||
Element export = iter.next();
|
||||
for (Element export : children) {
|
||||
int ordinal = Integer.parseInt(export.getAttributeValue("ORDINAL"));
|
||||
String name = export.getAttributeValue("NAME");
|
||||
int purge = Integer.parseInt(export.getAttributeValue("PURGE"));
|
||||
String comment = export.getAttributeValue("COMMENT");
|
||||
String fowardLibName = export.getAttributeValue("FOWARDLIBRARY");
|
||||
String fowardSymName = export.getAttributeValue("FOWARDSYMBOL");
|
||||
String forwardLibName = export.getAttributeValue("FOWARDLIBRARY");
|
||||
String forwardSymName = export.getAttributeValue("FOWARDSYMBOL");
|
||||
|
||||
String noReturnStr = export.getAttributeValue("NO_RETURN");
|
||||
boolean noReturn = noReturnStr != null && "y".equals(noReturnStr);
|
||||
|
||||
if (fowardLibName != null && fowardLibName.length() > 0 &&
|
||||
!fowardLibName.equals(tableName)) {
|
||||
forwards.add(fowardLibName);
|
||||
if (forwardLibName != null && forwardLibName.length() > 0 &&
|
||||
!forwardLibName.equals(tableName)) {
|
||||
forwards.add(forwardLibName);
|
||||
}
|
||||
|
||||
LibraryExportedSymbol sym = new LibraryExportedSymbol(tableName, size, ordinal,
|
||||
name, fowardLibName, fowardSymName, purge, noReturn, comment);
|
||||
name, forwardLibName, forwardSymName, purge, noReturn, comment);
|
||||
|
||||
exportList.add(sym);
|
||||
symMap.put(name, sym);
|
||||
|
@ -494,10 +494,7 @@ class LibrarySymbolTable {
|
|||
root.setAttribute("DATE", TIMESTAMP_FORMAT.format(new Date(lastModifiedSeconds)));
|
||||
root.setAttribute("VERSION", lversion);
|
||||
|
||||
Iterator<LibraryExportedSymbol> iter = exportList.iterator();
|
||||
while (iter.hasNext()) {
|
||||
LibraryExportedSymbol sym = iter.next();
|
||||
|
||||
for (LibraryExportedSymbol sym : exportList) {
|
||||
Element export = new Element("EXPORT");
|
||||
|
||||
export.setAttribute("ORDINAL", sym.getOrdinal() + "");
|
||||
|
|
|
@ -218,18 +218,6 @@ class CategoryDB extends DatabaseObject implements Category {
|
|||
return map;
|
||||
}
|
||||
|
||||
private String getBaseName(String dataTypeName) {
|
||||
int indexOf = dataTypeName.indexOf(DataType.CONFLICT_SUFFIX);
|
||||
if (indexOf <= 0) {
|
||||
return dataTypeName;
|
||||
}
|
||||
return dataTypeName.substring(0, indexOf);
|
||||
}
|
||||
|
||||
private boolean isConflictName(String dataTypeName) {
|
||||
return dataTypeName.contains(DataType.CONFLICT_SUFFIX);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.Category#getCategories()
|
||||
*/
|
||||
|
@ -549,7 +537,7 @@ class CategoryDB extends DatabaseObject implements Category {
|
|||
}
|
||||
else { // both dataTypes remain
|
||||
movedDataType.setNameAndCategory(path,
|
||||
mgr.getUnusedConflictName(path, movedDataType.getName()));
|
||||
mgr.getUnusedConflictName(path, movedDataType));
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -621,14 +609,14 @@ class CategoryDB extends DatabaseObject implements Category {
|
|||
void dataTypeAdded(DataType dataType) {
|
||||
String dtName = dataType.getName();
|
||||
dataTypeMap.put(dtName, dataType);
|
||||
if (isConflictName(dtName)) {
|
||||
if (DataTypeUtilities.isConflictDataType(dataType)) {
|
||||
conflictMap.addDataType(dataType);
|
||||
}
|
||||
}
|
||||
|
||||
void dataTypeRemoved(String dataTypeName) {
|
||||
dataTypeMap.remove(dataTypeName);
|
||||
if (isConflictName(dataTypeName)) {
|
||||
if (DataTypeUtilities.isConflictDataTypeName(dataTypeName)) {
|
||||
conflictMap.removeDataTypeName(dataTypeName);
|
||||
}
|
||||
}
|
||||
|
@ -639,8 +627,9 @@ class CategoryDB extends DatabaseObject implements Category {
|
|||
|
||||
@Override
|
||||
public List<DataType> getDataTypesByBaseName(String dataTypeName) {
|
||||
|
||||
List<DataType> list = new ArrayList<>();
|
||||
String baseName = getBaseName(dataTypeName);
|
||||
String baseName = DataTypeUtilities.getNameWithoutConflict(dataTypeName);
|
||||
|
||||
DataType baseType = dataTypeMap.get(baseName);
|
||||
if (baseType != null) {
|
||||
|
@ -681,8 +670,8 @@ class CategoryDB extends DatabaseObject implements Category {
|
|||
Collection<DataType> values = dataTypeMap.values();
|
||||
for (DataType dataType : values) {
|
||||
String dataTypeName = dataType.getName();
|
||||
if (isConflictName(dataTypeName)) {
|
||||
String baseName = getBaseName(dataTypeName);
|
||||
if (DataTypeUtilities.isConflictDataType(dataType)) {
|
||||
String baseName = DataTypeUtilities.getNameWithoutConflict(dataType);
|
||||
Map<String, DataType> innerMap =
|
||||
map.computeIfAbsent(baseName, b -> new HashMap<>());
|
||||
innerMap.put(dataTypeName, dataType);
|
||||
|
@ -705,7 +694,7 @@ class CategoryDB extends DatabaseObject implements Category {
|
|||
}
|
||||
|
||||
String dataTypeName = dataType.getName();
|
||||
String baseName = getBaseName(dataTypeName);
|
||||
String baseName = DataTypeUtilities.getNameWithoutConflict(dataType);
|
||||
Map<String, DataType> innerMap = map.computeIfAbsent(baseName, b -> new HashMap<>());
|
||||
innerMap.put(dataTypeName, dataType);
|
||||
}
|
||||
|
@ -721,7 +710,7 @@ class CategoryDB extends DatabaseObject implements Category {
|
|||
if (map == null) {
|
||||
return;
|
||||
}
|
||||
String baseName = getBaseName(dataTypeName);
|
||||
String baseName = DataTypeUtilities.getNameWithoutConflict(dataTypeName);
|
||||
Map<String, DataType> innerMap = map.get(baseName);
|
||||
if (innerMap == null) {
|
||||
return;
|
||||
|
|
|
@ -392,7 +392,7 @@ abstract class DataTypeDB extends DatabaseObject implements DataType {
|
|||
// generate a name that would not cause a duplicate in either the current path
|
||||
// or
|
||||
// the new path. Use the new name if possible.
|
||||
String uniqueName = dataMgr.getUniqueName(path, getCategoryPath(), name);
|
||||
String uniqueName = dataMgr.getTemporaryUniqueName(path, getCategoryPath(), name);
|
||||
doSetName(uniqueName);
|
||||
|
||||
// set the path - this is guaranteed to work since we make a name that won't
|
||||
|
|
|
@ -1091,11 +1091,6 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
}
|
||||
}
|
||||
|
||||
ConflictResult resolveConflict(DataTypeConflictHandler handler, DataType addedDataType,
|
||||
DataType existingDataType) {
|
||||
return handler.resolveConflict(addedDataType, existingDataType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUniqueName(CategoryPath path, String baseName) {
|
||||
int pos = baseName.lastIndexOf('_');
|
||||
|
@ -1119,7 +1114,8 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
return name;
|
||||
}
|
||||
|
||||
String getUniqueName(CategoryPath path1, CategoryPath path2, String baseName) {
|
||||
String getTemporaryUniqueName(CategoryPath newCategoryPath, CategoryPath currentCategoryPath,
|
||||
String baseName) {
|
||||
int pos = baseName.lastIndexOf('_');
|
||||
int oneUpNumber = 0;
|
||||
String name = baseName;
|
||||
|
@ -1134,7 +1130,8 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
// the number will get updated below
|
||||
}
|
||||
}
|
||||
while (getDataType(path1, name) != null || getDataType(path2, name) != null) {
|
||||
while (getDataType(newCategoryPath, name) != null ||
|
||||
getDataType(currentCategoryPath, name) != null) {
|
||||
++oneUpNumber;
|
||||
name = baseName + "_" + oneUpNumber;
|
||||
}
|
||||
|
@ -1428,47 +1425,47 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
|
||||
/**
|
||||
* This method gets a ".conflict" name that is not currently used by any data
|
||||
* types in the indicated category of the data type manager.
|
||||
* types in the datatype's category within this data type manager. If the baseName without
|
||||
* conflict suffix is not used that name will be returned.
|
||||
* <br>
|
||||
* NOTE: The original datatype name will be returned unchanged for pointers and arrays since
|
||||
* they cannot be renamed.
|
||||
*
|
||||
* @param dt datatype who name is used to establish non-conflict base name
|
||||
* @return the unused conflict name or original name for datatypes whose name is automatic
|
||||
*/
|
||||
public String getUnusedConflictName(DataType dt) {
|
||||
return getUnusedConflictName(dt.getCategoryPath(), dt);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets a ".conflict" name that is not currently used by any data
|
||||
* types in the indicated category within this data type manager. If the baseName without
|
||||
* conflict suffix is not used that name will be returned.
|
||||
* <br>
|
||||
* NOTE: The original datatype name will be returned unchanged for pointers and arrays since
|
||||
* they cannot be renamed.
|
||||
*
|
||||
* @param path the category path of the category where the new data type live in
|
||||
* the data type manager.
|
||||
* @param dt datatype who name is used to establish non-conflict base name
|
||||
* @return the unused conflict name
|
||||
*/
|
||||
public String getUnusedConflictName(CategoryPath path, DataType dt) {
|
||||
String name = dt.getName();
|
||||
if ((dt instanceof Array) || (dt instanceof Pointer) || (dt instanceof BuiltInDataType)) {
|
||||
// name not used - anything will do
|
||||
return name;
|
||||
}
|
||||
return getUnusedConflictName(dt.getCategoryPath(), name);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets a ".conflict" name that is not currently used by any data
|
||||
* types in the indicated category of the data type manager.
|
||||
*
|
||||
* @param path the category path of the category where the new data type live in
|
||||
* the data type manager.
|
||||
* @param name The name of the data type. This name may or may not contain
|
||||
* ".conflict" as part of it. If the name contains ".conflict", only
|
||||
* the part of the name that comes prior to the ".conflict" will be
|
||||
* used to determine a new unused conflict name.
|
||||
* @return the unused conflict name
|
||||
*/
|
||||
public String getUnusedConflictName(CategoryPath path, String name) {
|
||||
int index = name.indexOf(DataType.CONFLICT_SUFFIX);
|
||||
if (index > 0) {
|
||||
name = name.substring(0, index);
|
||||
}
|
||||
// Name sequence: <baseName>, <baseName>.conflict, <basename>.conflict1, ...
|
||||
|
||||
String baseName = name + DataType.CONFLICT_SUFFIX;
|
||||
String testName = name;
|
||||
String baseName = DataTypeUtilities.getNameWithoutConflict(dt);
|
||||
String testName = baseName;
|
||||
int count = 0;
|
||||
while (getDataType(path, testName) != null) {
|
||||
String countSuffix = "";
|
||||
if (count != 0) {
|
||||
countSuffix = Integer.toString(count);
|
||||
testName = baseName + DataType.CONFLICT_SUFFIX;
|
||||
if (count > 0) {
|
||||
testName += Integer.toString(count);
|
||||
}
|
||||
testName = baseName + countSuffix;
|
||||
++count;
|
||||
}
|
||||
return testName;
|
||||
|
@ -4394,7 +4391,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
if (dataType instanceof Pointer || dataType instanceof Array) {
|
||||
dataType = DataTypeUtilities.getBaseDataType(dataType);
|
||||
}
|
||||
if (!contains(dataType)) {
|
||||
if (dataType == null || !contains(dataType)) {
|
||||
return false;
|
||||
}
|
||||
List<DataType> relatedByName = findDataTypesSameLocation(dataType);
|
||||
|
@ -4508,7 +4505,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
if (dt instanceof Pointer || dt instanceof Array) {
|
||||
continue;
|
||||
}
|
||||
boolean isConflict = dt.getName().contains(DataType.CONFLICT_SUFFIX);
|
||||
boolean isConflict = DataTypeUtilities.isConflictDataType(dt);
|
||||
String name = DataTypeUtilities.getNameWithoutConflict(dt, false);
|
||||
if (!name.equals(lastBaseName)) {
|
||||
// base name changed
|
||||
|
|
|
@ -62,8 +62,19 @@ public class DataTypeUtilities {
|
|||
cPrimitiveNameMap.put("long double", LongDoubleDataType.dataType);
|
||||
}
|
||||
|
||||
private static final Pattern DATATYPE_CONFLICT_PATTERN =
|
||||
Pattern.compile(Pattern.quote(DataType.CONFLICT_SUFFIX) + "_?[0-9]*");
|
||||
// TODO: Should we drop the handling of "_" use in conflict name. It's unclear
|
||||
// when/if this was ever used in the generation of a conflict name.
|
||||
// NOTE: It is assumed that all BuiltInDataType types (other then possibly Pointers)
|
||||
// will not utilize conflict names. This includes pointers and arrays whose base
|
||||
// type is a BuiltInDataType.
|
||||
// NOTE: The BASE_DATATYPE_CONFLICT_PATTERN may never be applied to a pointer
|
||||
// or array name as it will always fail to match. Pointer and array decorations
|
||||
// must be stripped off first.
|
||||
private static final Pattern BASE_DATATYPE_CONFLICT_PATTERN =
|
||||
Pattern.compile(Pattern.quote(DataType.CONFLICT_SUFFIX) + "([_]{0,1}\\d+){0,1}$");
|
||||
|
||||
private static final Pattern DATATYPE_POINTER_ARRAY_PATTERN =
|
||||
Pattern.compile("(( \\*\\d*)|(\\[\\d+\\]))+$");
|
||||
|
||||
public static Collection<DataType> getContainedDataTypes(DataType rootDataType) {
|
||||
HashMap<String, DataType> dataTypeMap = new HashMap<>();
|
||||
|
@ -296,81 +307,12 @@ public class DataTypeUtilities {
|
|||
return dataType1.getClass().equals(dataType2.getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of a data type with all conflict naming patterns removed.
|
||||
*
|
||||
* @param dataType data type
|
||||
* @param includeCategoryPath if true the category path will be included with the
|
||||
* returned name (e.g., /mypath/mydt)
|
||||
* @return name with optional category path included
|
||||
*/
|
||||
public static String getNameWithoutConflict(DataType dataType, boolean includeCategoryPath) {
|
||||
String name = includeCategoryPath ? dataType.getPathName() : dataType.getName();
|
||||
return getNameWithoutConflict(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of a data type with all conflict naming patterns removed.
|
||||
*
|
||||
* @param dataTypeName data type name with optional category path included
|
||||
* @return name with optional category path included
|
||||
*/
|
||||
public static String getNameWithoutConflict(String dataTypeName) {
|
||||
return DATATYPE_CONFLICT_PATTERN.matcher(dataTypeName).replaceAll("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the conflict value string associated with a conflict datatype name.
|
||||
*
|
||||
* @param dataType datatype to be checked
|
||||
* @return conflict value string. Will be null if name is not a conflict name, or
|
||||
* empty string if conflict has no number. Otherwise a decimal value string will be returned.
|
||||
*/
|
||||
public static String getConflictString(DataType dataType) {
|
||||
return getConflictString(dataType.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the conflict value string associated with a conflict datatype name.
|
||||
*
|
||||
* @param dataTypeName datatype name to be checked
|
||||
* @return conflict value string. Will be one of the following:
|
||||
* <ol>
|
||||
* <li>A null value if not a conflict name,</li>
|
||||
* <li>an empty string if conflict name without a number, or</li>
|
||||
* <li>a decimal string value which corresponds to the conflict number in the name.</li>
|
||||
* </ol>
|
||||
*/
|
||||
public static String getConflictString(String dataTypeName) {
|
||||
Matcher matcher = DATATYPE_CONFLICT_PATTERN.matcher(dataTypeName);
|
||||
if (matcher.find()) {
|
||||
MatchResult matchResult = matcher.toMatchResult();
|
||||
return dataTypeName.substring(matchResult.start() + DataType.CONFLICT_SUFFIX.length(),
|
||||
matchResult.end());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two data type name strings to determine if they are equivalent names, ignoring
|
||||
* conflict patterns present.
|
||||
*
|
||||
* @param name1 the first name
|
||||
* @param name2 the second name
|
||||
* @return true if the names are equivalent when conflict suffixes are ignored.
|
||||
*/
|
||||
public static boolean equalsIgnoreConflict(String name1, String name2) {
|
||||
name1 = DATATYPE_CONFLICT_PATTERN.matcher(name1).replaceAll("");
|
||||
name2 = DATATYPE_CONFLICT_PATTERN.matcher(name2).replaceAll("");
|
||||
return name1.equals(name2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base data type for the specified data type stripping away pointers and arrays only. A
|
||||
* null will be returned for a default pointer.
|
||||
*
|
||||
* @param dt the data type whose base data type is to be determined.
|
||||
* @return the base data type.
|
||||
* @param dt the data type whose base data type is to be determined.
|
||||
* @return the base data type (may be null for default pointer).
|
||||
*/
|
||||
public static DataType getBaseDataType(DataType dt) {
|
||||
DataType baseDataType = dt;
|
||||
|
@ -840,4 +782,221 @@ public class DataTypeUtilities {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//
|
||||
// Conflict naming utilities
|
||||
//
|
||||
|
||||
private static boolean canHaveConflictName(DataType dt) {
|
||||
if (dt == null) {
|
||||
return false; // e.g., base type for default pointer
|
||||
}
|
||||
return !(dt instanceof BuiltIn) || (dt instanceof Pointer);
|
||||
}
|
||||
|
||||
private static String getPointerArrayDecorations(String dataTypeName) {
|
||||
// Use of this preliminary check greatly speeds-up the check for cases
|
||||
// not involving a pointer or array
|
||||
if (!dataTypeName.contains("*") && !dataTypeName.contains("[")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Return the trailing pointer and array decorations if they exist
|
||||
Matcher matcher = DATATYPE_POINTER_ARRAY_PATTERN.matcher(dataTypeName);
|
||||
if (matcher.find()) {
|
||||
MatchResult matchResult = matcher.toMatchResult();
|
||||
return dataTypeName.substring(matchResult.start());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of a data type with all conflict naming patterns removed.
|
||||
*
|
||||
* @param dataType data type
|
||||
* @param includeCategoryPath if true, the category path will be included with the
|
||||
* returned name (e.g., /mypath/mydt) and any occurance of a forward slash within individual
|
||||
* path components, including the data type name, will be escaped (e.g., {@code "\/"}).
|
||||
* @return name with optional category path included
|
||||
*/
|
||||
public static String getNameWithoutConflict(DataType dataType, boolean includeCategoryPath) {
|
||||
String name = getNameWithoutConflict(dataType);
|
||||
if (includeCategoryPath) {
|
||||
name = dataType.getCategoryPath().getPath(name);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of a data type with all conflict naming patterns removed.
|
||||
*
|
||||
* @param dataTypeName data type name with optional category path included
|
||||
* @return name with optional category path included
|
||||
*/
|
||||
public static String getNameWithoutConflict(String dataTypeName) {
|
||||
String decorations = getPointerArrayDecorations(dataTypeName);
|
||||
String baseDataTypeName = dataTypeName;
|
||||
if (decorations != null) {
|
||||
baseDataTypeName =
|
||||
dataTypeName.substring(0, dataTypeName.length() - decorations.length());
|
||||
}
|
||||
String name = BASE_DATATYPE_CONFLICT_PATTERN.matcher(baseDataTypeName).replaceAll("");
|
||||
if (decorations != null) {
|
||||
name += decorations;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a datatype's name without conflict suffix.
|
||||
*
|
||||
* @param dt datatype (pointer and array permitted)
|
||||
* @return datatype's name without conflict suffix
|
||||
*/
|
||||
public static String getNameWithoutConflict(DataType dt) {
|
||||
String dtName = dt.getName();
|
||||
if (!canHaveConflictName(dt)) {
|
||||
return dtName; // e.g., many BuiltIn types
|
||||
}
|
||||
DataType baseDataType = getBaseDataType(dt);
|
||||
if (baseDataType == null) {
|
||||
return dtName; // e.g., default pointer
|
||||
}
|
||||
if (baseDataType != dt && !canHaveConflictName(baseDataType)) {
|
||||
return dtName; // e.g., pointer to BuiltIn
|
||||
}
|
||||
|
||||
if (baseDataType == dt) {
|
||||
// Non-pointer/array case
|
||||
return BASE_DATATYPE_CONFLICT_PATTERN.matcher(dtName).replaceAll("");
|
||||
}
|
||||
|
||||
// Isolate pointer/array decorations
|
||||
// NOTE: This is faster than using regex to isolate pointer and array decorations
|
||||
String baseDtName = baseDataType.getName();
|
||||
String decorations = dtName.substring(baseDtName.length());
|
||||
|
||||
// remove conflict suffix
|
||||
return BASE_DATATYPE_CONFLICT_PATTERN.matcher(baseDtName).replaceAll("") + decorations;
|
||||
}
|
||||
|
||||
private static int getBaseConflictValue(String baseDataTypeName) {
|
||||
Matcher matcher = BASE_DATATYPE_CONFLICT_PATTERN.matcher(baseDataTypeName);
|
||||
if (matcher.find()) {
|
||||
MatchResult matchResult = matcher.toMatchResult();
|
||||
int startIx = matchResult.start() + DataType.CONFLICT_SUFFIX.length();
|
||||
if (startIx < baseDataTypeName.length() && baseDataTypeName.charAt(startIx) == '_') {
|
||||
++startIx;
|
||||
}
|
||||
String valueStr = baseDataTypeName.substring(startIx);
|
||||
if (valueStr.length() == 0) {
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
return Integer.parseInt(valueStr);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the conflict value string associated with a conflict datatype name.
|
||||
*
|
||||
* @param dataType datatype to be checked
|
||||
* @return conflict value:
|
||||
* <ol>
|
||||
* <li>-1: when type does not have a conflict name,</li>
|
||||
* <li>0: when conflict name does not have a number (i.e., {@code .conflict}), or</li>
|
||||
* <li>a positive value which corresponds to the conflict number in the name
|
||||
* (e.g., returns 2 for {@code .conflict2}).</li>
|
||||
* </ol>
|
||||
*/
|
||||
public static int getConflictValue(DataType dataType) {
|
||||
if (!canHaveConflictName(dataType)) {
|
||||
return -1; // e.g., many BuiltIn types
|
||||
}
|
||||
DataType baseDataType = getBaseDataType(dataType);
|
||||
if (baseDataType == null) {
|
||||
return -1; // e.g., default pointer
|
||||
}
|
||||
if (baseDataType != dataType && !canHaveConflictName(baseDataType)) {
|
||||
return -1; // e.g., pointer to BuiltIn
|
||||
}
|
||||
return getBaseConflictValue(baseDataType.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the conflict value associated with a conflict datatype name.
|
||||
*
|
||||
* @param dataTypeName datatype name to be checked
|
||||
* @return conflict value:
|
||||
* <ol>
|
||||
* <li>-1: when name is not have a conflict name,</li>
|
||||
* <li>0: when conflict name does not have a number (i.e., {@code .conflict}), or</li>
|
||||
* <li>a positive value which corresponds to the conflict number in the name
|
||||
* (e.g., returns 2 for {@code .conflict2}).</li>
|
||||
* </ol>
|
||||
*/
|
||||
public static int getConflictValue(String dataTypeName) {
|
||||
String decorations = getPointerArrayDecorations(dataTypeName);
|
||||
String baseDataTypeName = dataTypeName;
|
||||
if (decorations != null) {
|
||||
baseDataTypeName =
|
||||
dataTypeName.substring(0, dataTypeName.length() - decorations.length());
|
||||
}
|
||||
return getBaseConflictValue(baseDataTypeName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the specified data type name is a conflict name.
|
||||
*
|
||||
* @param dataTypeName datatype name
|
||||
* @return true if data type name is a conflict name.
|
||||
*/
|
||||
public static boolean isConflictDataTypeName(String dataTypeName) {
|
||||
String decorations = getPointerArrayDecorations(dataTypeName);
|
||||
String baseDataTypeName = dataTypeName;
|
||||
if (decorations != null) {
|
||||
baseDataTypeName =
|
||||
dataTypeName.substring(0, dataTypeName.length() - decorations.length());
|
||||
}
|
||||
Matcher matcher = BASE_DATATYPE_CONFLICT_PATTERN.matcher(baseDataTypeName);
|
||||
return matcher.find();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the specified data type has a conflict name.
|
||||
* @param dt datatype (pointer and array permitted)
|
||||
* @return true if data type has a conflict name.
|
||||
*/
|
||||
public static boolean isConflictDataType(DataType dt) {
|
||||
if (!canHaveConflictName(dt)) {
|
||||
return false; // e.g., many BuiltIn types
|
||||
}
|
||||
DataType baseDataType = getBaseDataType(dt);
|
||||
if (baseDataType == null) {
|
||||
return false; // e.g., default pointer
|
||||
}
|
||||
if (baseDataType != dt && !canHaveConflictName(baseDataType)) {
|
||||
return false; // e.g., pointer to BuiltIn
|
||||
}
|
||||
|
||||
Matcher matcher = BASE_DATATYPE_CONFLICT_PATTERN.matcher(dt.getName());
|
||||
return matcher.find();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two data type name strings to determine if they are equivalent names, ignoring
|
||||
* conflict patterns present.
|
||||
*
|
||||
* @param name1 the first name
|
||||
* @param name2 the second name
|
||||
* @return true if the names are equivalent when conflict suffixes are ignored.
|
||||
*/
|
||||
public static boolean equalsIgnoreConflict(String name1, String name2) {
|
||||
return getNameWithoutConflict(name1).equals(getNameWithoutConflict(name2));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -618,24 +618,22 @@ class TypedefDB extends DataTypeDB implements TypeDef {
|
|||
}
|
||||
|
||||
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;
|
||||
String baseName = TypedefDataType.generateTypedefName(this);
|
||||
String testName = baseName;
|
||||
int count = 0;
|
||||
while (true) {
|
||||
dt = dataMgr.getDataType(path, newName);
|
||||
if (dt == null || dt == this) {
|
||||
break;
|
||||
while (!isNameUnusedOrMine(path, testName)) {
|
||||
testName = baseName + DataType.CONFLICT_SUFFIX;
|
||||
if (count > 0) {
|
||||
testName += Integer.toString(count);
|
||||
}
|
||||
count++;
|
||||
newName = baseName + count;
|
||||
++count;
|
||||
}
|
||||
return newName;
|
||||
return testName;
|
||||
}
|
||||
|
||||
private boolean isNameUnusedOrMine(CategoryPath path, String newName) {
|
||||
DataType dt = dataMgr.getDataType(path, newName);
|
||||
return dt == null || dt == this;
|
||||
}
|
||||
|
||||
boolean updateAutoName(boolean notify) {
|
||||
|
|
|
@ -563,8 +563,8 @@ public class FunctionManagerDB implements FunctionManager {
|
|||
}
|
||||
|
||||
@Override
|
||||
public FunctionIterator getFunctions(Address start, boolean foward) {
|
||||
return new FunctionIteratorDB(start, foward);
|
||||
public FunctionIterator getFunctions(Address start, boolean forward) {
|
||||
return new FunctionIteratorDB(start, forward);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -585,8 +585,8 @@ public class FunctionManagerDB implements FunctionManager {
|
|||
}
|
||||
|
||||
@Override
|
||||
public FunctionIterator getFunctionsNoStubs(Address start, boolean foward) {
|
||||
return new FunctionFilteredIterator(new FunctionIteratorDB(start, foward));
|
||||
public FunctionIterator getFunctionsNoStubs(Address start, boolean forward) {
|
||||
return new FunctionFilteredIterator(new FunctionIteratorDB(start, forward));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -54,11 +54,8 @@ public interface Category extends Comparable<Category> {
|
|||
public abstract DataType[] getDataTypes();
|
||||
|
||||
/**
|
||||
* Get all data types in this category whose base name matches the base name of the given name.
|
||||
* The base name of a name is the first part of the string up to where the first ".conflict"
|
||||
* occurs. In other words, finds all data types whose name matches the given name once
|
||||
* any conflict suffixes have been removed from both the given name and the data types
|
||||
* that are being scanned.
|
||||
* Get all data types whose name matches the given name once any conflict suffixes have been
|
||||
* removed from both the given name and the data types that are being scanned.
|
||||
* <br>
|
||||
* NOTE: The {@code name} provided must not contain array or pointer decorations.
|
||||
*
|
||||
|
|
|
@ -19,6 +19,7 @@ import java.util.*;
|
|||
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* A category path is the full path to a particular data type
|
||||
|
@ -228,18 +229,35 @@ public class CategoryPath implements Comparable<CategoryPath> {
|
|||
|
||||
/**
|
||||
* Return the {@link String} representation of this category path including the category name,
|
||||
* where components are delimited with a forward slash. Any component that contains a forward
|
||||
* slash will be have the forward slash characters escaped.
|
||||
* where components are delimited with a forward slash. Any occurance of a forward slash
|
||||
* within individual path components will be escaped (e.g., {@code "\/"}).
|
||||
* @return the full category path
|
||||
*/
|
||||
public String getPath() {
|
||||
if (isRoot()) {
|
||||
return DELIMITER_STRING;
|
||||
}
|
||||
if (parent.isRoot()) {
|
||||
return DELIMITER_CHAR + escapeString(name);
|
||||
return parent.getPath(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link String} representation of the specified {@code childName} within this
|
||||
* category path where all path components are delimited with a forward slash. Any occurance
|
||||
* of a forward slash within individual path components, including the {@code childName}, will
|
||||
* be escaped (e.g., {@code "\/"}).
|
||||
* @param childName child name
|
||||
* @return full path for a child within this category
|
||||
*/
|
||||
public String getPath(String childName) {
|
||||
if (StringUtils.isBlank(childName)) {
|
||||
throw new IllegalArgumentException("blank child name");
|
||||
}
|
||||
return parent.getPath() + DELIMITER_CHAR + escapeString(name);
|
||||
String path = getPath();
|
||||
if (!isRoot()) {
|
||||
path += DELIMITER_STRING;
|
||||
}
|
||||
path += escapeString(childName);
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -177,8 +177,8 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C
|
|||
|
||||
/**
|
||||
* This method throws an exception if the indicated data type is an ancestor of
|
||||
* this data type. In other words, the specified data type has a component or
|
||||
* sub-component containing this data type.
|
||||
* this data type (i.e., the specified data type has a component or
|
||||
* sub-component containing this data type).
|
||||
*
|
||||
* @param dataType the data type
|
||||
* @throws IllegalArgumentException if the data type is an ancestor of this data
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.util.Collection;
|
|||
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.docking.settings.SettingsDefinition;
|
||||
import ghidra.program.database.data.DataTypeUtilities;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
import ghidra.program.model.scalar.Scalar;
|
||||
import ghidra.util.InvalidNameException;
|
||||
|
@ -50,6 +51,12 @@ public interface DataType {
|
|||
@Deprecated
|
||||
public static final DataType VOID = VoidDataType.dataType;
|
||||
|
||||
/**
|
||||
* Datatype name conflict suffix.
|
||||
*
|
||||
* See {@link DataTypeUtilities} for various methods related to conflict name handling.
|
||||
* Direct use of this string in application/user-level code is discouraged.
|
||||
*/
|
||||
public final static String CONFLICT_SUFFIX = ".conflict";
|
||||
|
||||
public final static String TYPEDEF_ATTRIBUTE_PREFIX = "__((";
|
||||
|
|
|
@ -88,7 +88,9 @@ public interface DataTypeManager {
|
|||
|
||||
/**
|
||||
* Returns a unique name not currently used by any other dataType or category
|
||||
* with the same baseName
|
||||
* with the same baseName. This does not produce a conflict name and is intended
|
||||
* to be used when generating an artifical datatype name only (e.g., {@code temp_1},
|
||||
* {@code temp_2}; for {@code baseName="temp"}.
|
||||
*
|
||||
* @param path the path of the name
|
||||
* @param baseName the base name to be made unique
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Comparator;
|
||||
|
||||
import ghidra.program.database.data.DataTypeUtilities;
|
||||
|
||||
|
@ -79,8 +79,8 @@ public class DataTypeNameComparator implements Comparator<String> {
|
|||
}
|
||||
|
||||
// Same base-name, order by conflict
|
||||
int conflict1 = getConflictValue(dt1Name);
|
||||
int conflict2 = getConflictValue(dt2Name);
|
||||
int conflict1 = DataTypeUtilities.getConflictValue(dt1Name);
|
||||
int conflict2 = DataTypeUtilities.getConflictValue(dt2Name);
|
||||
if (conflict1 != conflict2) {
|
||||
return conflict1 - conflict2;
|
||||
}
|
||||
|
@ -88,15 +88,4 @@ public class DataTypeNameComparator implements Comparator<String> {
|
|||
return name1.compareTo(name2);
|
||||
}
|
||||
|
||||
private int getConflictValue(String dtName) {
|
||||
String conflict = DataTypeUtilities.getConflictString(dtName);
|
||||
if (conflict == null) {
|
||||
return -1;
|
||||
}
|
||||
if (conflict.length() == 0) {
|
||||
return 0;
|
||||
}
|
||||
return Integer.parseInt(conflict);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.data;
|
||||
package ghidra.program.database.data;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
@ -24,8 +24,9 @@ import org.junit.Test;
|
|||
|
||||
import generic.test.AbstractGTest;
|
||||
import ghidra.program.database.data.DataTypeUtilities;
|
||||
import ghidra.program.model.data.*;
|
||||
|
||||
public class DataTypeUtilitiesTest extends AbstractGTest {
|
||||
public class DataTypeUtilities2Test extends AbstractGTest {
|
||||
|
||||
@Test
|
||||
public void testGetContainedDataTypes() {
|
|
@ -13,14 +13,13 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.plugin.core.datamgr;
|
||||
package ghidra.program.database.data;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.*;
|
||||
|
||||
import generic.test.AbstractGenericTest;
|
||||
import ghidra.program.database.ProgramBuilder;
|
||||
import ghidra.program.database.ProgramDB;
|
||||
import ghidra.program.database.data.DataTypeUtilities;
|
||||
import ghidra.program.model.data.*;
|
||||
|
@ -32,8 +31,6 @@ import ghidra.program.model.data.*;
|
|||
*/
|
||||
public class DataTypeUtilitiesTest extends AbstractGenericTest {
|
||||
|
||||
private ProgramBuilder builder;
|
||||
private ProgramDB program;
|
||||
private DataTypeManager dataTypeManager;
|
||||
private int txID;
|
||||
|
||||
|
@ -43,70 +40,15 @@ public class DataTypeUtilitiesTest extends AbstractGenericTest {
|
|||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
builder = new ProgramBuilder("nameTest", ProgramBuilder._TOY, this);
|
||||
|
||||
assertNotNull(builder);
|
||||
program = builder.getProgram();
|
||||
assertNotNull(program);
|
||||
dataTypeManager = program.getDataTypeManager();
|
||||
assertNotNull(dataTypeManager);
|
||||
txID = program.startTransaction("NamingUtilities test");
|
||||
dataTypeManager = new StandAloneDataTypeManager("Test");
|
||||
dataTypeManager.startTransaction("Test");
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
if (txID != 0) {
|
||||
program.endTransaction(txID, false);
|
||||
dataTypeManager.endTransaction(txID, true);
|
||||
}
|
||||
if (builder != null) {
|
||||
builder.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsSameKindDataType() {
|
||||
|
||||
assertTrue(
|
||||
DataTypeUtilities.isSameKindDataType(IntegerDataType.dataType, ShortDataType.dataType));
|
||||
assertFalse(
|
||||
DataTypeUtilities.isSameKindDataType(FloatDataType.dataType, ShortDataType.dataType));
|
||||
|
||||
assertTrue(
|
||||
DataTypeUtilities.isSameKindDataType(new PointerDataType(IntegerDataType.dataType),
|
||||
new PointerDataType(ShortDataType.dataType)));
|
||||
assertFalse(
|
||||
DataTypeUtilities.isSameKindDataType(new PointerDataType(FloatDataType.dataType),
|
||||
new PointerDataType(ShortDataType.dataType)));
|
||||
|
||||
assertTrue(
|
||||
DataTypeUtilities.isSameKindDataType(new StructureDataType("X", 10),
|
||||
new StructureDataType("Y", 5)));
|
||||
assertTrue(
|
||||
DataTypeUtilities.isSameKindDataType(new UnionDataType("X"), new UnionDataType("Y")));
|
||||
assertFalse(
|
||||
DataTypeUtilities.isSameKindDataType(new StructureDataType("X", 10),
|
||||
new UnionDataType("Y")));
|
||||
|
||||
assertTrue(
|
||||
DataTypeUtilities.isSameKindDataType(
|
||||
new PointerDataType(new StructureDataType("X", 10)),
|
||||
new PointerDataType(new StructureDataType("Y", 5))));
|
||||
assertTrue(
|
||||
DataTypeUtilities.isSameKindDataType(new PointerDataType(new UnionDataType("X")),
|
||||
new PointerDataType(new UnionDataType("Y"))));
|
||||
assertFalse(
|
||||
DataTypeUtilities.isSameKindDataType(
|
||||
new PointerDataType(new StructureDataType("X", 10)),
|
||||
new PointerDataType(new UnionDataType("Y"))));
|
||||
|
||||
assertTrue(
|
||||
DataTypeUtilities.isSameKindDataType(
|
||||
new TypedefDataType("Foo", new PointerDataType(new StructureDataType("X", 10))),
|
||||
new PointerDataType(new StructureDataType("Y", 5))));
|
||||
assertFalse(
|
||||
DataTypeUtilities.isSameKindDataType(
|
||||
new TypedefDataType("Foo", new PointerDataType(new StructureDataType("X", 10))),
|
||||
new PointerDataType(new UnionDataType("Y"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -393,16 +335,10 @@ public class DataTypeUtilitiesTest extends AbstractGenericTest {
|
|||
|
||||
same("/cat1/simpleStruct.conflict1 *32 *64", "/cat1/simpleStruct *32 *64");
|
||||
|
||||
same("/cat1/simpleStruct.conflict_1234 *64", "/cat1.conflict5/simpleStruct *64");
|
||||
|
||||
same("/cat1/simpleStruct", "/cat1/simpleStruct.conflict1");
|
||||
|
||||
same("/cat1/simpleStruct.conflict_1234.conflict", "/cat1/simpleStruct");
|
||||
|
||||
same("/cat1/simpleStruct.conflict_1234", "/cat1/simpleStruct.conflict3");
|
||||
|
||||
same("simpleStruct.conflict_1234_abc", "simpleStruct.conflict4_abc");
|
||||
|
||||
same("simpleStruct.conflict12", "simpleStruct.conflict34");
|
||||
|
||||
same("/cat1/simpleStruct[5]", "/cat1/simpleStruct.conflict1[5]");
|
||||
|
@ -525,6 +461,12 @@ public class DataTypeUtilitiesTest extends AbstractGenericTest {
|
|||
different("/cat1/simpleStruct[11] *32[2]", "/cat1/simpleStruct.conflict1[11] *8[2]");
|
||||
|
||||
different("/cat1/simpleStruct[6] *16[9]", "/cat1/simpleStruct.conflict1[6] *64[9]");
|
||||
|
||||
different("/cat1/simpleStruct.conflict_1234 *64", "/cat1.conflict5/simpleStruct *64");
|
||||
|
||||
different("/cat1/simpleStruct.conflict_1234.conflict", "/cat1/simpleStruct");
|
||||
|
||||
different("simpleStruct.conflict_1234_abc", "simpleStruct.conflict4_abc");
|
||||
}
|
||||
|
||||
private void same(String name1, String name2) {
|
|
@ -99,7 +99,7 @@ public class StubFunctionManager implements FunctionManager {
|
|||
}
|
||||
|
||||
@Override
|
||||
public FunctionIterator getFunctions(Address start, boolean foward) {
|
||||
public FunctionIterator getFunctions(Address start, boolean forward) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
@ -114,7 +114,7 @@ public class StubFunctionManager implements FunctionManager {
|
|||
}
|
||||
|
||||
@Override
|
||||
public FunctionIterator getFunctionsNoStubs(Address start, boolean foward) {
|
||||
public FunctionIterator getFunctionsNoStubs(Address start, boolean forward) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue