diff --git a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfDataTypeWriter.java b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfDataTypeWriter.java index 195b64b519..29e893f8af 100644 --- a/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfDataTypeWriter.java +++ b/Ghidra/Debug/Debugger-isf/src/main/java/ghidra/program/model/data/ISF/IsfDataTypeWriter.java @@ -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 target, Writer baseWriter) throws IOException { + public IsfDataTypeWriter(DataTypeManager dtm, List 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 linkages, - Map map, Symbol symbol) { + private void symbolToJson(Address imageBase, SymbolTable symbolTable, + Map linkages, Map 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); } } diff --git a/Ghidra/Features/Base/ghidra_scripts/FindDataTypeConflictCauseScript.java b/Ghidra/Features/Base/ghidra_scripts/FindDataTypeConflictCauseScript.java index bc461b6f1e..2c89843903 100644 --- a/Ghidra/Features/Base/ghidra_scripts/FindDataTypeConflictCauseScript.java +++ b/Ghidra/Features/Base/ghidra_scripts/FindDataTypeConflictCauseScript.java @@ -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; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeSyncInfo.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeSyncInfo.java index 9045246d16..a26ce6516d 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeSyncInfo.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeSyncInfo.java @@ -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); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeSynchronizer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeSynchronizer.java index 2e73c24d28..d58f90dfc7 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeSynchronizer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypeSynchronizer.java @@ -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)); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/DataTypeNamingUtil.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/DataTypeNamingUtil.java index dc7f9bfa61..f3d52b5cde 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/DataTypeNamingUtil.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/DataTypeNamingUtil.java @@ -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"); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/LibraryExportedSymbol.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/LibraryExportedSymbol.java index b59cd6917f..03fa0b0bde 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/LibraryExportedSymbol.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/LibraryExportedSymbol.java @@ -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) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/LibrarySymbolTable.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/LibrarySymbolTable.java index d973c9f37e..6c1a2c9209 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/LibrarySymbolTable.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/LibrarySymbolTable.java @@ -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 symMap = new HashMap<>(); private ArrayList exportList = new ArrayList<>(); private HashMap 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 children = CollectionUtils.asList(root.getChildren(), Element.class); - Iterator 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 iter = exportList.iterator(); - while (iter.hasNext()) { - LibraryExportedSymbol sym = iter.next(); - + for (LibraryExportedSymbol sym : exportList) { Element export = new Element("EXPORT"); export.setAttribute("ORDINAL", sym.getOrdinal() + ""); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDB.java index 023d56c265..e10c7857b1 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDB.java @@ -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 getDataTypesByBaseName(String dataTypeName) { + List 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 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 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 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 innerMap = map.get(baseName); if (innerMap == null) { return; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeDB.java index c8032ab797..bfb175e18f 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeDB.java @@ -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 diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeManagerDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeManagerDB.java index c2c4dc4ede..213d41f811 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeManagerDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeManagerDB.java @@ -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. + *
+ * 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. + *
+ * 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: , .conflict, .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 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 diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeUtilities.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeUtilities.java index af7354c8a4..ec2754177e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeUtilities.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeUtilities.java @@ -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 getContainedDataTypes(DataType rootDataType) { HashMap 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: - *
    - *
  1. A null value if not a conflict name,
  2. - *
  3. an empty string if conflict name without a number, or
  4. - *
  5. a decimal string value which corresponds to the conflict number in the name.
  6. - *
- */ - 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: + *
    + *
  1. -1: when type does not have a conflict name,
  2. + *
  3. 0: when conflict name does not have a number (i.e., {@code .conflict}), or
  4. + *
  5. a positive value which corresponds to the conflict number in the name + * (e.g., returns 2 for {@code .conflict2}).
  6. + *
+ */ + 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: + *
    + *
  1. -1: when name is not have a conflict name,
  2. + *
  3. 0: when conflict name does not have a number (i.e., {@code .conflict}), or
  4. + *
  5. a positive value which corresponds to the conflict number in the name + * (e.g., returns 2 for {@code .conflict2}).
  6. + *
+ */ + 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)); + } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDB.java index 263ab7a036..de955d5a9f 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDB.java @@ -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) { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionManagerDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionManagerDB.java index 171155b106..63d4e1d0d6 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionManagerDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionManagerDB.java @@ -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 diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Category.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Category.java index 7c41506e7c..a92e09a983 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Category.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Category.java @@ -54,11 +54,8 @@ public interface Category extends Comparable { 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. *
* NOTE: The {@code name} provided must not contain array or pointer decorations. * diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CategoryPath.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CategoryPath.java index 8e1fe70aaa..5da5173c72 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CategoryPath.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CategoryPath.java @@ -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 { /** * 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 diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CompositeDataTypeImpl.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CompositeDataTypeImpl.java index b877120e4c..587be28103 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CompositeDataTypeImpl.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/CompositeDataTypeImpl.java @@ -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 diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataType.java index 016086360d..95a52f7b30 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataType.java @@ -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 = "__(("; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManager.java index 40abb39dd1..2069aeff0c 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManager.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManager.java @@ -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 diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeNameComparator.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeNameComparator.java index 4b3a239dc7..62d55c6491 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeNameComparator.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeNameComparator.java @@ -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 { } // 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 { 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); - } - } diff --git a/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/DataTypeUtilitiesTest.java b/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/database/data/DataTypeUtilities2Test.java similarity index 94% rename from Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/DataTypeUtilitiesTest.java rename to Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/database/data/DataTypeUtilities2Test.java index 1bc7aa8c3d..eae71859bb 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/model/data/DataTypeUtilitiesTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/database/data/DataTypeUtilities2Test.java @@ -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() { diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/DataTypeUtilitiesTest.java b/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/database/data/DataTypeUtilitiesTest.java similarity index 87% rename from Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/DataTypeUtilitiesTest.java rename to Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/database/data/DataTypeUtilitiesTest.java index 90ac08ab20..b3b315c46a 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/DataTypeUtilitiesTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test.slow/java/ghidra/program/database/data/DataTypeUtilitiesTest.java @@ -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) { diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/StubFunctionManager.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/StubFunctionManager.java index d388eff5dd..83e069b13c 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/StubFunctionManager.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/StubFunctionManager.java @@ -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(); }