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.JsonObject;
|
||||||
import com.google.gson.stream.JsonWriter;
|
import com.google.gson.stream.JsonWriter;
|
||||||
|
|
||||||
|
import ghidra.program.database.data.DataTypeUtilities;
|
||||||
import ghidra.program.database.data.ProgramDataTypeManager;
|
import ghidra.program.database.data.ProgramDataTypeManager;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.address.AddressFormatException;
|
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
|
* @param baseWriter the writer to use when writing data types
|
||||||
* @throws IOException if there is an exception writing the output
|
* @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);
|
super(baseWriter);
|
||||||
this.baseWriter = baseWriter;
|
this.baseWriter = baseWriter;
|
||||||
this.dtm = dtm;
|
this.dtm = dtm;
|
||||||
|
@ -117,11 +119,12 @@ public class IsfDataTypeWriter extends AbstractIsfWriter {
|
||||||
STRICT = true;
|
STRICT = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public JsonObject getRootObject(TaskMonitor monitor) throws CancelledException, IOException {
|
public JsonObject getRootObject(TaskMonitor monitor) throws CancelledException, IOException {
|
||||||
genRoot(monitor);
|
genRoot(monitor);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void genRoot(TaskMonitor monitor) throws CancelledException, IOException {
|
protected void genRoot(TaskMonitor monitor) throws CancelledException, IOException {
|
||||||
genMetadata();
|
genMetadata();
|
||||||
|
@ -160,7 +163,8 @@ public class IsfDataTypeWriter extends AbstractIsfWriter {
|
||||||
oskey = metaData.get("Compiler ID");
|
oskey = metaData.get("Compiler ID");
|
||||||
if (metaData.containsKey("PDB Loaded")) {
|
if (metaData.containsKey("PDB Loaded")) {
|
||||||
os = gson.toJsonTree(new IsfWinOS(metaData));
|
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")) {
|
if (metaData.get("Executable Format").contains("ELF")) {
|
||||||
oskey = "linux";
|
oskey = "linux";
|
||||||
os = gson.toJsonTree(new IsfLinuxOS(gson, metaData));
|
os = gson.toJsonTree(new IsfLinuxOS(gson, metaData));
|
||||||
|
@ -201,15 +205,18 @@ public class IsfDataTypeWriter extends AbstractIsfWriter {
|
||||||
Symbol symbol = iterator.next();
|
Symbol symbol = iterator.next();
|
||||||
symbolToJson(imageBase, symbolTable, linkages, map, symbol);
|
symbolToJson(imageBase, symbolTable, linkages, map, symbol);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
for (Address addr : requestedAddresses) {
|
for (Address addr : requestedAddresses) {
|
||||||
Symbol[] symsFromAddr = symbolTable.getSymbols(addr.add(imageBase.getOffset()));
|
Symbol[] symsFromAddr =
|
||||||
|
symbolTable.getSymbols(addr.add(imageBase.getOffset()));
|
||||||
for (Symbol symbol : symsFromAddr) {
|
for (Symbol symbol : symsFromAddr) {
|
||||||
symbolToJson(imageBase, symbolTable, linkages, map, symbol);
|
symbolToJson(imageBase, symbolTable, linkages, map, symbol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
for (String key : requestedSymbols) {
|
for (String key : requestedSymbols) {
|
||||||
SymbolIterator iter = symbolTable.getSymbols(key);
|
SymbolIterator iter = symbolTable.getSymbols(key);
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
|
@ -263,7 +270,7 @@ public class IsfDataTypeWriter extends AbstractIsfWriter {
|
||||||
monitor.setMaximum(keylist.size());
|
monitor.setMaximum(keylist.size());
|
||||||
for (String key : keylist) {
|
for (String key : keylist) {
|
||||||
DataType dataType = map.get(key);
|
DataType dataType = map.get(key);
|
||||||
if (key.contains(".conflict")) {
|
if (DataTypeUtilities.isConflictDataType(dataType)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
obj = getObjectForDataType(dataType, monitor);
|
obj = getObjectForDataType(dataType, monitor);
|
||||||
|
@ -273,28 +280,34 @@ public class IsfDataTypeWriter extends AbstractIsfWriter {
|
||||||
if (dataType instanceof FunctionDefinition) {
|
if (dataType instanceof FunctionDefinition) {
|
||||||
// Would be nice to support this in the future, but Volatility does not
|
// Would be nice to support this in the future, but Volatility does not
|
||||||
add(functions, dataType.getPathName(), obj);
|
add(functions, dataType.getPathName(), obj);
|
||||||
} else if (IsfUtilities.isBaseDataType(dataType)) {
|
}
|
||||||
|
else if (IsfUtilities.isBaseDataType(dataType)) {
|
||||||
add(baseTypes, dataType.getPathName(), obj);
|
add(baseTypes, dataType.getPathName(), obj);
|
||||||
} else if (dataType instanceof TypeDef) {
|
}
|
||||||
|
else if (dataType instanceof TypeDef) {
|
||||||
DataType baseDataType = ((TypeDef) dataType).getBaseDataType();
|
DataType baseDataType = ((TypeDef) dataType).getBaseDataType();
|
||||||
if (IsfUtilities.isBaseDataType(baseDataType)) {
|
if (IsfUtilities.isBaseDataType(baseDataType)) {
|
||||||
add(baseTypes, dataType.getPathName(), obj);
|
add(baseTypes, dataType.getPathName(), obj);
|
||||||
} else if (baseDataType instanceof Enum) {
|
}
|
||||||
|
else if (baseDataType instanceof Enum) {
|
||||||
add(enums, dataType.getPathName(), obj);
|
add(enums, dataType.getPathName(), obj);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
add(userTypes, dataType.getPathName(), obj);
|
add(userTypes, dataType.getPathName(), obj);
|
||||||
}
|
}
|
||||||
} else if (dataType instanceof Enum) {
|
}
|
||||||
|
else if (dataType instanceof Enum) {
|
||||||
add(enums, dataType.getPathName(), obj);
|
add(enums, dataType.getPathName(), obj);
|
||||||
} else if (dataType instanceof Composite) {
|
}
|
||||||
|
else if (dataType instanceof Composite) {
|
||||||
add(userTypes, dataType.getPathName(), obj);
|
add(userTypes, dataType.getPathName(), obj);
|
||||||
}
|
}
|
||||||
monitor.increment();
|
monitor.increment();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void symbolToJson(Address imageBase, SymbolTable symbolTable, Map<String, Symbol> linkages,
|
private void symbolToJson(Address imageBase, SymbolTable symbolTable,
|
||||||
Map<String, JsonObject> map, Symbol symbol) {
|
Map<String, Symbol> linkages, Map<String, JsonObject> map, Symbol symbol) {
|
||||||
String key = symbol.getName();
|
String key = symbol.getName();
|
||||||
Address address = symbol.getAddress();
|
Address address = symbol.getAddress();
|
||||||
JsonObject sym = map.containsKey(key) ? map.get(key) : new JsonObject();
|
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("linkage_name", linkage.getName());
|
||||||
sym.addProperty("address", linkage.getAddress().getOffset());
|
sym.addProperty("address", linkage.getAddress().getOffset());
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
if (address.getAddressSpace().equals(imageBase.getAddressSpace())) {
|
if (address.getAddressSpace().equals(imageBase.getAddressSpace())) {
|
||||||
sym.addProperty("address", address.subtract(imageBase));
|
sym.addProperty("address", address.subtract(imageBase));
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
sym.addProperty("address", address.getOffset());
|
sym.addProperty("address", address.getOffset());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -323,6 +338,7 @@ public class IsfDataTypeWriter extends AbstractIsfWriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void write(JsonObject obj) {
|
public void write(JsonObject obj) {
|
||||||
gson.toJson(obj, writer);
|
gson.toJson(obj, writer);
|
||||||
}
|
}
|
||||||
|
@ -332,7 +348,8 @@ public class IsfDataTypeWriter extends AbstractIsfWriter {
|
||||||
add(baseTypes, "undefined", getTree(newTypedefPointer(null)));
|
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);
|
IsfObject isf = getIsfObject(dt, monitor);
|
||||||
if (isf != null) {
|
if (isf != null) {
|
||||||
JsonObject jobj = (JsonObject) getTree(isf);
|
JsonObject jobj = (JsonObject) getTree(isf);
|
||||||
|
@ -351,7 +368,8 @@ public class IsfDataTypeWriter extends AbstractIsfWriter {
|
||||||
* @param monitor the task monitor
|
* @param monitor the task monitor
|
||||||
* @throws IOException if there is an exception writing the output
|
* @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) {
|
if (dt == null) {
|
||||||
throw new IOException("Null datatype passed to getIsfObject");
|
throw new IOException("Null datatype passed to getIsfObject");
|
||||||
}
|
}
|
||||||
|
@ -377,21 +395,29 @@ public class IsfDataTypeWriter extends AbstractIsfWriter {
|
||||||
if (dt instanceof Dynamic dynamic) {
|
if (dt instanceof Dynamic dynamic) {
|
||||||
DataType rep = dynamic.getReplacementBaseType();
|
DataType rep = dynamic.getReplacementBaseType();
|
||||||
return rep == null ? null : getIsfObject(rep, monitor);
|
return rep == null ? null : getIsfObject(rep, monitor);
|
||||||
} else if (dt instanceof TypeDef typedef) {
|
}
|
||||||
|
else if (dt instanceof TypeDef typedef) {
|
||||||
return getObjectTypeDef(typedef, monitor);
|
return getObjectTypeDef(typedef, monitor);
|
||||||
} else if (dt instanceof Composite composite) {
|
}
|
||||||
|
else if (dt instanceof Composite composite) {
|
||||||
return new IsfComposite(composite, this, monitor);
|
return new IsfComposite(composite, this, monitor);
|
||||||
} else if (dt instanceof Enum enumm) {
|
}
|
||||||
|
else if (dt instanceof Enum enumm) {
|
||||||
return new IsfEnum(enumm);
|
return new IsfEnum(enumm);
|
||||||
} else if (dt instanceof BuiltInDataType builtin) {
|
}
|
||||||
|
else if (dt instanceof BuiltInDataType builtin) {
|
||||||
return new IsfBuiltIn(builtin);
|
return new IsfBuiltIn(builtin);
|
||||||
} else if (dt instanceof BitFieldDataType) {
|
}
|
||||||
|
else if (dt instanceof BitFieldDataType) {
|
||||||
// skip - not hit
|
// skip - not hit
|
||||||
} else if (dt instanceof FunctionDefinition) { /// FAIL
|
}
|
||||||
|
else if (dt instanceof FunctionDefinition) { /// FAIL
|
||||||
// skip - not hit
|
// skip - not hit
|
||||||
} else if (dt.equals(DataType.DEFAULT)) {
|
}
|
||||||
|
else if (dt.equals(DataType.DEFAULT)) {
|
||||||
// skip - not hit
|
// skip - not hit
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
Msg.warn(this, "Unable to write datatype. Type unrecognized: " + dt.getClass());
|
Msg.warn(this, "Unable to write datatype. Type unrecognized: " + dt.getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,8 +443,8 @@ public class IsfDataTypeWriter extends AbstractIsfWriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Msg.warn(this,
|
Msg.warn(this, "WARNING! conflicting data type names: " + dt.getPathName() + " - " +
|
||||||
"WARNING! conflicting data type names: " + dt.getPathName() + " - " + resolvedType.getPathName());
|
resolvedType.getPathName());
|
||||||
return resolved.get(dt);
|
return resolved.get(dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -465,8 +491,9 @@ public class IsfDataTypeWriter extends AbstractIsfWriter {
|
||||||
return newIsfDynamicComponent(dynamic, type, elementCnt);
|
return newIsfDynamicComponent(dynamic, type, elementCnt);
|
||||||
|
|
||||||
}
|
}
|
||||||
Msg.error(this, dynamic.getClass().getSimpleName() + " returned bad replacementBaseType: "
|
Msg.error(this,
|
||||||
+ replacementBaseType.getClass().getSimpleName());
|
dynamic.getClass().getSimpleName() + " returned bad replacementBaseType: " +
|
||||||
|
replacementBaseType.getClass().getSimpleName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -500,7 +527,7 @@ public class IsfDataTypeWriter extends AbstractIsfWriter {
|
||||||
IsfObject baseObject = getObjectDataType(IsfUtilities.getBaseDataType(dataType));
|
IsfObject baseObject = getObjectDataType(IsfUtilities.getBaseDataType(dataType));
|
||||||
return new IsfDataTypeTypeDef(dataType, baseObject);
|
return new IsfDataTypeTypeDef(dataType, baseObject);
|
||||||
}
|
}
|
||||||
if (dataType.getPathName().contains(".conflict")) {
|
if (DataTypeUtilities.isConflictDataType(dataType)) {
|
||||||
if (!deferredKeys.contains(dataType.getPathName())) {
|
if (!deferredKeys.contains(dataType.getPathName())) {
|
||||||
deferredKeys.add(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
|
* @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();
|
DataType dataType = typeDef.getDataType();
|
||||||
String typedefName = typeDef.getPathName();
|
String typedefName = typeDef.getPathName();
|
||||||
|
|
||||||
|
@ -527,7 +555,8 @@ public class IsfDataTypeWriter extends AbstractIsfWriter {
|
||||||
return newTypedefUser(typeDef, isfObject);
|
return newTypedefUser(typeDef, isfObject);
|
||||||
}
|
}
|
||||||
return newTypedefPointer(typeDef);
|
return newTypedefPointer(typeDef);
|
||||||
} catch (Exception e) {
|
}
|
||||||
|
catch (Exception e) {
|
||||||
Msg.error(this, "TypeDef error: " + e);
|
Msg.error(this, "TypeDef error: " + e);
|
||||||
}
|
}
|
||||||
clearResolve(typedefName, baseType);
|
clearResolve(typedefName, baseType);
|
||||||
|
@ -544,7 +573,8 @@ public class IsfDataTypeWriter extends AbstractIsfWriter {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
requestedAddresses.add(address);
|
requestedAddresses.add(address);
|
||||||
} catch (AddressFormatException e) {
|
}
|
||||||
|
catch (AddressFormatException e) {
|
||||||
throw new IOException("Bad address format: " + key);
|
throw new IOException("Bad address format: " + key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Search for the root cause of a datatype conflict based upon a selected datatype.
|
// Search for the root cause of a datatype conflict based upon a selected datatype.
|
||||||
//@category Data Types
|
//@category Data Types
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
@ -55,8 +56,8 @@ public class FindDataTypeConflictCauseScript extends GhidraScript {
|
||||||
}
|
}
|
||||||
|
|
||||||
DataType selectedDt = DataTypeUtilities.getBaseDataType(selectedDatatypes.get(0));
|
DataType selectedDt = DataTypeUtilities.getBaseDataType(selectedDatatypes.get(0));
|
||||||
if (selectedDt instanceof Pointer || selectedDt instanceof Array) {
|
if (selectedDt == null) {
|
||||||
popup("Selected datatype must not be a Pointer or Array");
|
popup("Selected datatype must not be a default Pointer");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -190,11 +190,13 @@ public class DataTypeSyncInfo {
|
||||||
if (sourceDt == null) {
|
if (sourceDt == null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!DataTypeSynchronizer.namesAreEquivalent(sourceDt, refDt)) {
|
if (!DataTypeSynchronizer.isPointerOrArray(refDt)) {
|
||||||
return true;
|
if (!DataTypeSynchronizer.namesAreEquivalent(sourceDt, refDt)) {
|
||||||
}
|
return true;
|
||||||
if (!StringUtils.equals(refDt.getDescription(), sourceDt.getDescription())) {
|
}
|
||||||
return true;
|
if (!StringUtils.equals(refDt.getDescription(), sourceDt.getDescription())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
DataType dt = sourceDt.clone(refDt.getDataTypeManager());
|
DataType dt = sourceDt.clone(refDt.getDataTypeManager());
|
||||||
return !dt.isEquivalent(refDt);
|
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.ToolTipUtils;
|
||||||
import ghidra.app.util.html.HTMLDataTypeRepresentation;
|
import ghidra.app.util.html.HTMLDataTypeRepresentation;
|
||||||
import ghidra.app.util.html.MissingArchiveDataTypeHTMLRepresentation;
|
import ghidra.app.util.html.MissingArchiveDataTypeHTMLRepresentation;
|
||||||
import ghidra.program.database.data.DataTypeManagerDB;
|
import ghidra.program.database.data.*;
|
||||||
import ghidra.program.database.data.ProgramDataTypeManager;
|
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.util.*;
|
import ghidra.util.*;
|
||||||
import ghidra.util.exception.AssertException;
|
import ghidra.util.exception.AssertException;
|
||||||
|
@ -127,11 +126,13 @@ public class DataTypeSynchronizer {
|
||||||
// not handled by resolve.
|
// not handled by resolve.
|
||||||
long lastChangeTime = refDT.getLastChangeTime();
|
long lastChangeTime = refDT.getLastChangeTime();
|
||||||
DataType sourceDT = sourceDTM.resolve(refDT, DataTypeConflictHandler.REPLACE_HANDLER);
|
DataType sourceDT = sourceDTM.resolve(refDT, DataTypeConflictHandler.REPLACE_HANDLER);
|
||||||
if (!namesAreEquivalent(refDT, sourceDT)) {
|
if (!isPointerOrArray(refDT)) {
|
||||||
renameDataType(sourceDTM, sourceDT, refDT);
|
if (!namesAreEquivalent(refDT, sourceDT)) {
|
||||||
}
|
renameDataType(sourceDTM, sourceDT, refDT);
|
||||||
if (!StringUtils.equals(refDT.getDescription(), sourceDT.getDescription())) {
|
}
|
||||||
sourceDT.setDescription(refDT.getDescription());
|
if (!StringUtils.equals(refDT.getDescription(), sourceDT.getDescription())) {
|
||||||
|
sourceDT.setDescription(refDT.getDescription());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sourceDT.setLastChangeTime(lastChangeTime);
|
sourceDT.setLastChangeTime(lastChangeTime);
|
||||||
refDT.setLastChangeTimeInSourceArchive(lastChangeTime);
|
refDT.setLastChangeTimeInSourceArchive(lastChangeTime);
|
||||||
|
@ -140,11 +141,13 @@ public class DataTypeSynchronizer {
|
||||||
public static void updateAssumingTransactionsOpen(DataTypeManager refDTM, DataType sourceDT) {
|
public static void updateAssumingTransactionsOpen(DataTypeManager refDTM, DataType sourceDT) {
|
||||||
long lastChangeTime = sourceDT.getLastChangeTime();
|
long lastChangeTime = sourceDT.getLastChangeTime();
|
||||||
DataType refDT = refDTM.resolve(sourceDT, DataTypeConflictHandler.REPLACE_HANDLER);
|
DataType refDT = refDTM.resolve(sourceDT, DataTypeConflictHandler.REPLACE_HANDLER);
|
||||||
if (!namesAreEquivalent(refDT, sourceDT)) {
|
if (!isPointerOrArray(sourceDT)) {
|
||||||
renameDataType(refDTM, refDT, sourceDT);
|
if (!namesAreEquivalent(refDT, sourceDT)) {
|
||||||
}
|
renameDataType(refDTM, refDT, sourceDT);
|
||||||
if (!StringUtils.equals(sourceDT.getDescription(), refDT.getDescription())) {
|
}
|
||||||
refDT.setDescription(sourceDT.getDescription());
|
if (!StringUtils.equals(sourceDT.getDescription(), refDT.getDescription())) {
|
||||||
|
refDT.setDescription(sourceDT.getDescription());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
refDT.setLastChangeTimeInSourceArchive(lastChangeTime);
|
refDT.setLastChangeTimeInSourceArchive(lastChangeTime);
|
||||||
refDT.setLastChangeTime(lastChangeTime);
|
refDT.setLastChangeTime(lastChangeTime);
|
||||||
|
@ -252,14 +255,10 @@ public class DataTypeSynchronizer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
String name = dtToCopy.getName();
|
String name = dtToCopy.getName();
|
||||||
int index = name.indexOf(DataType.CONFLICT_SUFFIX);
|
|
||||||
if (index > 0) {
|
|
||||||
name = name.substring(0, index);
|
|
||||||
}
|
|
||||||
CategoryPath path = sourceDT.getCategoryPath();
|
CategoryPath path = sourceDT.getCategoryPath();
|
||||||
if (sourceDTM.getDataType(path, name) != null) {
|
if (sourceDTM.getDataType(path, name) != null) {
|
||||||
name = ((DataTypeManagerDB) sourceDTM).getUnusedConflictName(sourceDT.getCategoryPath(),
|
name = ((DataTypeManagerDB) sourceDTM).getUnusedConflictName(sourceDT.getCategoryPath(),
|
||||||
name);
|
dtToCopy);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
sourceDT.setName(name);
|
sourceDT.setName(name);
|
||||||
|
@ -282,27 +281,19 @@ public class DataTypeSynchronizer {
|
||||||
return false;
|
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)) {
|
if (isAutoNamedTypedef(dt1)) {
|
||||||
return isAutoNamedTypedef(dt2);
|
return isAutoNamedTypedef(dt2);
|
||||||
}
|
}
|
||||||
else if (isAutoNamedTypedef(dt2)) {
|
else if (isAutoNamedTypedef(dt2)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
String name1 = dt1.getName();
|
return DataTypeUtilities.getNameWithoutConflict(dt1)
|
||||||
String name2 = dt2.getName();
|
.equals(DataTypeUtilities.getNameWithoutConflict(dt2));
|
||||||
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);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util;
|
package ghidra.app.util;
|
||||||
|
|
||||||
|
import ghidra.program.database.data.DataTypeUtilities;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.listing.Function;
|
import ghidra.program.model.listing.Function;
|
||||||
import ghidra.program.model.listing.FunctionSignature;
|
import ghidra.program.model.listing.FunctionSignature;
|
||||||
|
@ -53,9 +54,9 @@ public class DataTypeNamingUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
sb.append("_");
|
sb.append("_");
|
||||||
sb.append(mangleDTName(returnType.getName()));
|
sb.append(mangleDTName(returnType));
|
||||||
for (ParameterDefinition p : parameters) {
|
for (ParameterDefinition p : parameters) {
|
||||||
sb.append("_").append(mangleDTName(p.getDataType().getName()));
|
sb.append("_").append(mangleDTName(p.getDataType()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (functionDefinition.hasVarArgs()) {
|
if (functionDefinition.hasVarArgs()) {
|
||||||
|
@ -72,8 +73,9 @@ public class DataTypeNamingUtil {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String mangleDTName(String s) {
|
private static String mangleDTName(DataType dt) {
|
||||||
return s.replaceAll(" ", "_").replaceAll("\\*", "ptr");
|
String name = DataTypeUtilities.getNameWithoutConflict(dt);
|
||||||
|
return name.replaceAll(" ", "_").replaceAll("\\*", "ptr");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,14 +25,14 @@ class LibraryExportedSymbol {
|
||||||
private int memsize;
|
private int memsize;
|
||||||
private int ordinal = -1;
|
private int ordinal = -1;
|
||||||
private String symbolName;
|
private String symbolName;
|
||||||
private String fowardLibraryName;
|
private String forwardLibraryName;
|
||||||
private String fowardSymbolName;
|
private String forwardSymbolName;
|
||||||
private int purge;
|
private int purge;
|
||||||
private boolean noReturn;
|
private boolean noReturn;
|
||||||
private String comment;
|
private String comment;
|
||||||
|
|
||||||
LibraryExportedSymbol(String libName, int memsize, int ordinal, String symbolName,
|
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) {
|
String comment) {
|
||||||
this.libName = libName;
|
this.libName = libName;
|
||||||
this.memsize = memsize;
|
this.memsize = memsize;
|
||||||
|
@ -41,8 +41,8 @@ class LibraryExportedSymbol {
|
||||||
this.purge = purge;
|
this.purge = purge;
|
||||||
this.noReturn = noReturn;
|
this.noReturn = noReturn;
|
||||||
this.comment = comment;
|
this.comment = comment;
|
||||||
this.fowardLibraryName = fowardLibraryName;
|
this.forwardLibraryName = forwardLibraryName;
|
||||||
this.fowardSymbolName = fowardSymbolName;
|
this.forwardSymbolName = forwardSymbolName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -125,12 +125,12 @@ class LibraryExportedSymbol {
|
||||||
private synchronized void processForwardedEntry() {
|
private synchronized void processForwardedEntry() {
|
||||||
|
|
||||||
purge = -2;
|
purge = -2;
|
||||||
LibrarySymbolTable lib = LibraryLookupTable.getSymbolTable(fowardLibraryName, memsize);
|
LibrarySymbolTable lib = LibraryLookupTable.getSymbolTable(forwardLibraryName, memsize);
|
||||||
if (lib == null) {
|
if (lib == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LibraryExportedSymbol libSym = lib.getSymbol(fowardSymbolName);
|
LibraryExportedSymbol libSym = lib.getSymbol(forwardSymbolName);
|
||||||
if (libSym == null) {
|
if (libSym == null) {
|
||||||
return;
|
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() {
|
boolean isFowardEntry() {
|
||||||
return fowardLibraryName != null;
|
return forwardLibraryName != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the fowarded library name
|
* @return the forwarded library name
|
||||||
*/
|
*/
|
||||||
String getFowardLibraryName() {
|
String getFowardLibraryName() {
|
||||||
return fowardLibraryName;
|
return forwardLibraryName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the fowarded symbol name
|
* @return the forwarded symbol name
|
||||||
*/
|
*/
|
||||||
String getFowardSymbolName() {
|
String getFowardSymbolName() {
|
||||||
return fowardSymbolName;
|
return forwardSymbolName;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setName(String name) {
|
void setName(String name) {
|
||||||
|
|
|
@ -56,8 +56,8 @@ class LibrarySymbolTable {
|
||||||
private String date;
|
private String date;
|
||||||
private String version;
|
private String version;
|
||||||
private int tempPurge;
|
private int tempPurge;
|
||||||
private String fowardLibrary = null;
|
private String forwardLibrary = null;
|
||||||
private String fowardSymbol = null;
|
private String forwardSymbol = null;
|
||||||
private HashMap<String, LibraryExportedSymbol> symMap = new HashMap<>();
|
private HashMap<String, LibraryExportedSymbol> symMap = new HashMap<>();
|
||||||
private ArrayList<LibraryExportedSymbol> exportList = new ArrayList<>();
|
private ArrayList<LibraryExportedSymbol> exportList = new ArrayList<>();
|
||||||
private HashMap<Integer, LibraryExportedSymbol> ordMap = new HashMap<>();
|
private HashMap<Integer, LibraryExportedSymbol> ordMap = new HashMap<>();
|
||||||
|
@ -140,8 +140,8 @@ class LibrarySymbolTable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fowardLibrary = null;
|
forwardLibrary = null;
|
||||||
fowardSymbol = null;
|
forwardSymbol = null;
|
||||||
tempPurge = -1;
|
tempPurge = -1;
|
||||||
String comment = "";
|
String comment = "";
|
||||||
|
|
||||||
|
@ -160,12 +160,12 @@ class LibrarySymbolTable {
|
||||||
Reference[] refs = library.getReferenceManager().getReferencesFrom(symAddr);
|
Reference[] refs = library.getReferenceManager().getReferencesFrom(symAddr);
|
||||||
if (refs != null && refs.length > 0 && refs[0].isExternalReference()) {
|
if (refs != null && refs.length > 0 && refs[0].isExternalReference()) {
|
||||||
ExternalReference exRef = (ExternalReference) refs[0];
|
ExternalReference exRef = (ExternalReference) refs[0];
|
||||||
fowardLibrary = exRef.getLibraryName();
|
forwardLibrary = exRef.getLibraryName();
|
||||||
fowardSymbol = exRef.getLabel();
|
forwardSymbol = exRef.getLabel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fowardLibrary == null || fowardLibrary.length() <= 0) {
|
if (forwardLibrary == null || forwardLibrary.length() <= 0) {
|
||||||
MemoryBlock block = library.getMemory().getBlock(symAddr);
|
MemoryBlock block = library.getMemory().getBlock(symAddr);
|
||||||
if (block != null && block.isExecute()) {
|
if (block != null && block.isExecute()) {
|
||||||
pseudoDisassemble(library, symAddr);
|
pseudoDisassemble(library, symAddr);
|
||||||
|
@ -179,12 +179,12 @@ class LibrarySymbolTable {
|
||||||
noReturn = true;
|
noReturn = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fowardLibrary != null && fowardLibrary.length() > 0) {
|
if (forwardLibrary != null && forwardLibrary.length() > 0) {
|
||||||
forwards.add(fowardLibrary);
|
forwards.add(forwardLibrary);
|
||||||
}
|
}
|
||||||
|
|
||||||
LibraryExportedSymbol expSym = new LibraryExportedSymbol(tableName, size, ordinal,
|
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
|
// add to export list in order
|
||||||
exportList.add(expSym);
|
exportList.add(expSym);
|
||||||
|
@ -225,8 +225,8 @@ class LibrarySymbolTable {
|
||||||
Scalar scalar = instr.getScalar(0);
|
Scalar scalar = instr.getScalar(0);
|
||||||
if (scalar != null) {
|
if (scalar != null) {
|
||||||
tempPurge = (int) scalar.getSignedValue();
|
tempPurge = (int) scalar.getSignedValue();
|
||||||
fowardLibrary = null;
|
forwardLibrary = null;
|
||||||
fowardSymbol = null;
|
forwardSymbol = null;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -234,15 +234,17 @@ class LibrarySymbolTable {
|
||||||
if (ftype.isJump() && ftype.isComputed()) {
|
if (ftype.isJump() && ftype.isComputed()) {
|
||||||
Reference[] refs = instr.getReferencesFrom();
|
Reference[] refs = instr.getReferencesFrom();
|
||||||
if (refs.length > 0) {
|
if (refs.length > 0) {
|
||||||
Data data = instr.getProgram().getListing().getDefinedDataAt(
|
Data data = instr.getProgram()
|
||||||
refs[0].getToAddress());
|
.getListing()
|
||||||
|
.getDefinedDataAt(refs[0].getToAddress());
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
refs = instr.getProgram().getReferenceManager().getReferencesFrom(
|
refs = instr.getProgram()
|
||||||
data.getMinAddress());
|
.getReferenceManager()
|
||||||
|
.getReferencesFrom(data.getMinAddress());
|
||||||
if (refs != null && refs.length > 0 && refs[0].isExternalReference()) {
|
if (refs != null && refs.length > 0 && refs[0].isExternalReference()) {
|
||||||
ExternalReference exRef = (ExternalReference) refs[0];
|
ExternalReference exRef = (ExternalReference) refs[0];
|
||||||
fowardLibrary = exRef.getLibraryName();
|
forwardLibrary = exRef.getLibraryName();
|
||||||
fowardSymbol = exRef.getLabel();
|
forwardSymbol = exRef.getLabel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -425,26 +427,24 @@ class LibrarySymbolTable {
|
||||||
version = root.getAttributeValue("VERSION");
|
version = root.getAttributeValue("VERSION");
|
||||||
|
|
||||||
List<Element> children = CollectionUtils.asList(root.getChildren(), Element.class);
|
List<Element> children = CollectionUtils.asList(root.getChildren(), Element.class);
|
||||||
Iterator<Element> iter = children.iterator();
|
for (Element export : children) {
|
||||||
while (iter.hasNext()) {
|
|
||||||
Element export = iter.next();
|
|
||||||
int ordinal = Integer.parseInt(export.getAttributeValue("ORDINAL"));
|
int ordinal = Integer.parseInt(export.getAttributeValue("ORDINAL"));
|
||||||
String name = export.getAttributeValue("NAME");
|
String name = export.getAttributeValue("NAME");
|
||||||
int purge = Integer.parseInt(export.getAttributeValue("PURGE"));
|
int purge = Integer.parseInt(export.getAttributeValue("PURGE"));
|
||||||
String comment = export.getAttributeValue("COMMENT");
|
String comment = export.getAttributeValue("COMMENT");
|
||||||
String fowardLibName = export.getAttributeValue("FOWARDLIBRARY");
|
String forwardLibName = export.getAttributeValue("FOWARDLIBRARY");
|
||||||
String fowardSymName = export.getAttributeValue("FOWARDSYMBOL");
|
String forwardSymName = export.getAttributeValue("FOWARDSYMBOL");
|
||||||
|
|
||||||
String noReturnStr = export.getAttributeValue("NO_RETURN");
|
String noReturnStr = export.getAttributeValue("NO_RETURN");
|
||||||
boolean noReturn = noReturnStr != null && "y".equals(noReturnStr);
|
boolean noReturn = noReturnStr != null && "y".equals(noReturnStr);
|
||||||
|
|
||||||
if (fowardLibName != null && fowardLibName.length() > 0 &&
|
if (forwardLibName != null && forwardLibName.length() > 0 &&
|
||||||
!fowardLibName.equals(tableName)) {
|
!forwardLibName.equals(tableName)) {
|
||||||
forwards.add(fowardLibName);
|
forwards.add(forwardLibName);
|
||||||
}
|
}
|
||||||
|
|
||||||
LibraryExportedSymbol sym = new LibraryExportedSymbol(tableName, size, ordinal,
|
LibraryExportedSymbol sym = new LibraryExportedSymbol(tableName, size, ordinal,
|
||||||
name, fowardLibName, fowardSymName, purge, noReturn, comment);
|
name, forwardLibName, forwardSymName, purge, noReturn, comment);
|
||||||
|
|
||||||
exportList.add(sym);
|
exportList.add(sym);
|
||||||
symMap.put(name, sym);
|
symMap.put(name, sym);
|
||||||
|
@ -494,10 +494,7 @@ class LibrarySymbolTable {
|
||||||
root.setAttribute("DATE", TIMESTAMP_FORMAT.format(new Date(lastModifiedSeconds)));
|
root.setAttribute("DATE", TIMESTAMP_FORMAT.format(new Date(lastModifiedSeconds)));
|
||||||
root.setAttribute("VERSION", lversion);
|
root.setAttribute("VERSION", lversion);
|
||||||
|
|
||||||
Iterator<LibraryExportedSymbol> iter = exportList.iterator();
|
for (LibraryExportedSymbol sym : exportList) {
|
||||||
while (iter.hasNext()) {
|
|
||||||
LibraryExportedSymbol sym = iter.next();
|
|
||||||
|
|
||||||
Element export = new Element("EXPORT");
|
Element export = new Element("EXPORT");
|
||||||
|
|
||||||
export.setAttribute("ORDINAL", sym.getOrdinal() + "");
|
export.setAttribute("ORDINAL", sym.getOrdinal() + "");
|
||||||
|
|
|
@ -218,18 +218,6 @@ class CategoryDB extends DatabaseObject implements Category {
|
||||||
return map;
|
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()
|
* @see ghidra.program.model.data.Category#getCategories()
|
||||||
*/
|
*/
|
||||||
|
@ -549,7 +537,7 @@ class CategoryDB extends DatabaseObject implements Category {
|
||||||
}
|
}
|
||||||
else { // both dataTypes remain
|
else { // both dataTypes remain
|
||||||
movedDataType.setNameAndCategory(path,
|
movedDataType.setNameAndCategory(path,
|
||||||
mgr.getUnusedConflictName(path, movedDataType.getName()));
|
mgr.getUnusedConflictName(path, movedDataType));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -621,14 +609,14 @@ class CategoryDB extends DatabaseObject implements Category {
|
||||||
void dataTypeAdded(DataType dataType) {
|
void dataTypeAdded(DataType dataType) {
|
||||||
String dtName = dataType.getName();
|
String dtName = dataType.getName();
|
||||||
dataTypeMap.put(dtName, dataType);
|
dataTypeMap.put(dtName, dataType);
|
||||||
if (isConflictName(dtName)) {
|
if (DataTypeUtilities.isConflictDataType(dataType)) {
|
||||||
conflictMap.addDataType(dataType);
|
conflictMap.addDataType(dataType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void dataTypeRemoved(String dataTypeName) {
|
void dataTypeRemoved(String dataTypeName) {
|
||||||
dataTypeMap.remove(dataTypeName);
|
dataTypeMap.remove(dataTypeName);
|
||||||
if (isConflictName(dataTypeName)) {
|
if (DataTypeUtilities.isConflictDataTypeName(dataTypeName)) {
|
||||||
conflictMap.removeDataTypeName(dataTypeName);
|
conflictMap.removeDataTypeName(dataTypeName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -639,8 +627,9 @@ class CategoryDB extends DatabaseObject implements Category {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<DataType> getDataTypesByBaseName(String dataTypeName) {
|
public List<DataType> getDataTypesByBaseName(String dataTypeName) {
|
||||||
|
|
||||||
List<DataType> list = new ArrayList<>();
|
List<DataType> list = new ArrayList<>();
|
||||||
String baseName = getBaseName(dataTypeName);
|
String baseName = DataTypeUtilities.getNameWithoutConflict(dataTypeName);
|
||||||
|
|
||||||
DataType baseType = dataTypeMap.get(baseName);
|
DataType baseType = dataTypeMap.get(baseName);
|
||||||
if (baseType != null) {
|
if (baseType != null) {
|
||||||
|
@ -681,8 +670,8 @@ class CategoryDB extends DatabaseObject implements Category {
|
||||||
Collection<DataType> values = dataTypeMap.values();
|
Collection<DataType> values = dataTypeMap.values();
|
||||||
for (DataType dataType : values) {
|
for (DataType dataType : values) {
|
||||||
String dataTypeName = dataType.getName();
|
String dataTypeName = dataType.getName();
|
||||||
if (isConflictName(dataTypeName)) {
|
if (DataTypeUtilities.isConflictDataType(dataType)) {
|
||||||
String baseName = getBaseName(dataTypeName);
|
String baseName = DataTypeUtilities.getNameWithoutConflict(dataType);
|
||||||
Map<String, DataType> innerMap =
|
Map<String, DataType> innerMap =
|
||||||
map.computeIfAbsent(baseName, b -> new HashMap<>());
|
map.computeIfAbsent(baseName, b -> new HashMap<>());
|
||||||
innerMap.put(dataTypeName, dataType);
|
innerMap.put(dataTypeName, dataType);
|
||||||
|
@ -705,7 +694,7 @@ class CategoryDB extends DatabaseObject implements Category {
|
||||||
}
|
}
|
||||||
|
|
||||||
String dataTypeName = dataType.getName();
|
String dataTypeName = dataType.getName();
|
||||||
String baseName = getBaseName(dataTypeName);
|
String baseName = DataTypeUtilities.getNameWithoutConflict(dataType);
|
||||||
Map<String, DataType> innerMap = map.computeIfAbsent(baseName, b -> new HashMap<>());
|
Map<String, DataType> innerMap = map.computeIfAbsent(baseName, b -> new HashMap<>());
|
||||||
innerMap.put(dataTypeName, dataType);
|
innerMap.put(dataTypeName, dataType);
|
||||||
}
|
}
|
||||||
|
@ -721,7 +710,7 @@ class CategoryDB extends DatabaseObject implements Category {
|
||||||
if (map == null) {
|
if (map == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String baseName = getBaseName(dataTypeName);
|
String baseName = DataTypeUtilities.getNameWithoutConflict(dataTypeName);
|
||||||
Map<String, DataType> innerMap = map.get(baseName);
|
Map<String, DataType> innerMap = map.get(baseName);
|
||||||
if (innerMap == null) {
|
if (innerMap == null) {
|
||||||
return;
|
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
|
// generate a name that would not cause a duplicate in either the current path
|
||||||
// or
|
// or
|
||||||
// the new path. Use the new name if possible.
|
// 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);
|
doSetName(uniqueName);
|
||||||
|
|
||||||
// set the path - this is guaranteed to work since we make a name that won't
|
// 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
|
@Override
|
||||||
public String getUniqueName(CategoryPath path, String baseName) {
|
public String getUniqueName(CategoryPath path, String baseName) {
|
||||||
int pos = baseName.lastIndexOf('_');
|
int pos = baseName.lastIndexOf('_');
|
||||||
|
@ -1119,7 +1114,8 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
String getUniqueName(CategoryPath path1, CategoryPath path2, String baseName) {
|
String getTemporaryUniqueName(CategoryPath newCategoryPath, CategoryPath currentCategoryPath,
|
||||||
|
String baseName) {
|
||||||
int pos = baseName.lastIndexOf('_');
|
int pos = baseName.lastIndexOf('_');
|
||||||
int oneUpNumber = 0;
|
int oneUpNumber = 0;
|
||||||
String name = baseName;
|
String name = baseName;
|
||||||
|
@ -1134,7 +1130,8 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
||||||
// the number will get updated below
|
// 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;
|
++oneUpNumber;
|
||||||
name = baseName + "_" + 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
|
* 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
|
* @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
|
* @return the unused conflict name or original name for datatypes whose name is automatic
|
||||||
*/
|
*/
|
||||||
public String getUnusedConflictName(DataType dt) {
|
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();
|
String name = dt.getName();
|
||||||
if ((dt instanceof Array) || (dt instanceof Pointer) || (dt instanceof BuiltInDataType)) {
|
if ((dt instanceof Array) || (dt instanceof Pointer) || (dt instanceof BuiltInDataType)) {
|
||||||
// name not used - anything will do
|
// name not used - anything will do
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
return getUnusedConflictName(dt.getCategoryPath(), name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
String baseName = DataTypeUtilities.getNameWithoutConflict(dt);
|
||||||
* This method gets a ".conflict" name that is not currently used by any data
|
String testName = baseName;
|
||||||
* 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;
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
while (getDataType(path, testName) != null) {
|
while (getDataType(path, testName) != null) {
|
||||||
String countSuffix = "";
|
testName = baseName + DataType.CONFLICT_SUFFIX;
|
||||||
if (count != 0) {
|
if (count > 0) {
|
||||||
countSuffix = Integer.toString(count);
|
testName += Integer.toString(count);
|
||||||
}
|
}
|
||||||
testName = baseName + countSuffix;
|
|
||||||
++count;
|
++count;
|
||||||
}
|
}
|
||||||
return testName;
|
return testName;
|
||||||
|
@ -4394,7 +4391,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
||||||
if (dataType instanceof Pointer || dataType instanceof Array) {
|
if (dataType instanceof Pointer || dataType instanceof Array) {
|
||||||
dataType = DataTypeUtilities.getBaseDataType(dataType);
|
dataType = DataTypeUtilities.getBaseDataType(dataType);
|
||||||
}
|
}
|
||||||
if (!contains(dataType)) {
|
if (dataType == null || !contains(dataType)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
List<DataType> relatedByName = findDataTypesSameLocation(dataType);
|
List<DataType> relatedByName = findDataTypesSameLocation(dataType);
|
||||||
|
@ -4508,7 +4505,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
||||||
if (dt instanceof Pointer || dt instanceof Array) {
|
if (dt instanceof Pointer || dt instanceof Array) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
boolean isConflict = dt.getName().contains(DataType.CONFLICT_SUFFIX);
|
boolean isConflict = DataTypeUtilities.isConflictDataType(dt);
|
||||||
String name = DataTypeUtilities.getNameWithoutConflict(dt, false);
|
String name = DataTypeUtilities.getNameWithoutConflict(dt, false);
|
||||||
if (!name.equals(lastBaseName)) {
|
if (!name.equals(lastBaseName)) {
|
||||||
// base name changed
|
// base name changed
|
||||||
|
|
|
@ -62,8 +62,19 @@ public class DataTypeUtilities {
|
||||||
cPrimitiveNameMap.put("long double", LongDoubleDataType.dataType);
|
cPrimitiveNameMap.put("long double", LongDoubleDataType.dataType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Pattern DATATYPE_CONFLICT_PATTERN =
|
// TODO: Should we drop the handling of "_" use in conflict name. It's unclear
|
||||||
Pattern.compile(Pattern.quote(DataType.CONFLICT_SUFFIX) + "_?[0-9]*");
|
// 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) {
|
public static Collection<DataType> getContainedDataTypes(DataType rootDataType) {
|
||||||
HashMap<String, DataType> dataTypeMap = new HashMap<>();
|
HashMap<String, DataType> dataTypeMap = new HashMap<>();
|
||||||
|
@ -296,81 +307,12 @@ public class DataTypeUtilities {
|
||||||
return dataType1.getClass().equals(dataType2.getClass());
|
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
|
* 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.
|
* null will be returned for a default pointer.
|
||||||
*
|
*
|
||||||
* @param dt the data type whose base data type is to be determined.
|
* @param dt the data type whose base data type is to be determined.
|
||||||
* @return the base data type.
|
* @return the base data type (may be null for default pointer).
|
||||||
*/
|
*/
|
||||||
public static DataType getBaseDataType(DataType dt) {
|
public static DataType getBaseDataType(DataType dt) {
|
||||||
DataType baseDataType = dt;
|
DataType baseDataType = dt;
|
||||||
|
@ -840,4 +782,221 @@ public class DataTypeUtilities {
|
||||||
}
|
}
|
||||||
return null;
|
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) {
|
private String generateTypedefName(CategoryPath path) {
|
||||||
String newName = TypedefDataType.generateTypedefName(this);
|
String baseName = TypedefDataType.generateTypedefName(this);
|
||||||
DataType dt = dataMgr.getDataType(path, newName);
|
String testName = baseName;
|
||||||
if (dt == null || dt == this) {
|
|
||||||
return newName;
|
|
||||||
}
|
|
||||||
|
|
||||||
String baseName = newName + DataType.CONFLICT_SUFFIX;
|
|
||||||
newName = baseName;
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
while (true) {
|
while (!isNameUnusedOrMine(path, testName)) {
|
||||||
dt = dataMgr.getDataType(path, newName);
|
testName = baseName + DataType.CONFLICT_SUFFIX;
|
||||||
if (dt == null || dt == this) {
|
if (count > 0) {
|
||||||
break;
|
testName += Integer.toString(count);
|
||||||
}
|
}
|
||||||
count++;
|
++count;
|
||||||
newName = baseName + 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) {
|
boolean updateAutoName(boolean notify) {
|
||||||
|
|
|
@ -563,8 +563,8 @@ public class FunctionManagerDB implements FunctionManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FunctionIterator getFunctions(Address start, boolean foward) {
|
public FunctionIterator getFunctions(Address start, boolean forward) {
|
||||||
return new FunctionIteratorDB(start, foward);
|
return new FunctionIteratorDB(start, forward);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -585,8 +585,8 @@ public class FunctionManagerDB implements FunctionManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FunctionIterator getFunctionsNoStubs(Address start, boolean foward) {
|
public FunctionIterator getFunctionsNoStubs(Address start, boolean forward) {
|
||||||
return new FunctionFilteredIterator(new FunctionIteratorDB(start, foward));
|
return new FunctionFilteredIterator(new FunctionIteratorDB(start, forward));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -54,11 +54,8 @@ public interface Category extends Comparable<Category> {
|
||||||
public abstract DataType[] getDataTypes();
|
public abstract DataType[] getDataTypes();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all data types in this category whose base name matches the base name of the given name.
|
* Get all data types whose name matches the given name once any conflict suffixes have been
|
||||||
* The base name of a name is the first part of the string up to where the first ".conflict"
|
* removed from both the given name and the data types that are being scanned.
|
||||||
* 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.
|
|
||||||
* <br>
|
* <br>
|
||||||
* NOTE: The {@code name} provided must not contain array or pointer decorations.
|
* 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.collections4.CollectionUtils;
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A category path is the full path to a particular data type
|
* 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,
|
* 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
|
* where components are delimited with a forward slash. Any occurance of a forward slash
|
||||||
* slash will be have the forward slash characters escaped.
|
* within individual path components will be escaped (e.g., {@code "\/"}).
|
||||||
* @return the full category path
|
* @return the full category path
|
||||||
*/
|
*/
|
||||||
public String getPath() {
|
public String getPath() {
|
||||||
if (isRoot()) {
|
if (isRoot()) {
|
||||||
return DELIMITER_STRING;
|
return DELIMITER_STRING;
|
||||||
}
|
}
|
||||||
if (parent.isRoot()) {
|
return parent.getPath(name);
|
||||||
return DELIMITER_CHAR + escapeString(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
|
@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 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
|
* this data type (i.e., the specified data type has a component or
|
||||||
* sub-component containing this data type.
|
* sub-component containing this data type).
|
||||||
*
|
*
|
||||||
* @param dataType the data type
|
* @param dataType the data type
|
||||||
* @throws IllegalArgumentException if the data type is an ancestor of this data
|
* @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.Settings;
|
||||||
import ghidra.docking.settings.SettingsDefinition;
|
import ghidra.docking.settings.SettingsDefinition;
|
||||||
|
import ghidra.program.database.data.DataTypeUtilities;
|
||||||
import ghidra.program.model.mem.MemBuffer;
|
import ghidra.program.model.mem.MemBuffer;
|
||||||
import ghidra.program.model.scalar.Scalar;
|
import ghidra.program.model.scalar.Scalar;
|
||||||
import ghidra.util.InvalidNameException;
|
import ghidra.util.InvalidNameException;
|
||||||
|
@ -50,6 +51,12 @@ public interface DataType {
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public static final DataType VOID = VoidDataType.dataType;
|
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 CONFLICT_SUFFIX = ".conflict";
|
||||||
|
|
||||||
public final static String TYPEDEF_ATTRIBUTE_PREFIX = "__((";
|
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
|
* 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 path the path of the name
|
||||||
* @param baseName the base name to be made unique
|
* @param baseName the base name to be made unique
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.program.model.data;
|
package ghidra.program.model.data;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.Comparator;
|
||||||
|
|
||||||
import ghidra.program.database.data.DataTypeUtilities;
|
import ghidra.program.database.data.DataTypeUtilities;
|
||||||
|
|
||||||
|
@ -79,8 +79,8 @@ public class DataTypeNameComparator implements Comparator<String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Same base-name, order by conflict
|
// Same base-name, order by conflict
|
||||||
int conflict1 = getConflictValue(dt1Name);
|
int conflict1 = DataTypeUtilities.getConflictValue(dt1Name);
|
||||||
int conflict2 = getConflictValue(dt2Name);
|
int conflict2 = DataTypeUtilities.getConflictValue(dt2Name);
|
||||||
if (conflict1 != conflict2) {
|
if (conflict1 != conflict2) {
|
||||||
return conflict1 - conflict2;
|
return conflict1 - conflict2;
|
||||||
}
|
}
|
||||||
|
@ -88,15 +88,4 @@ public class DataTypeNameComparator implements Comparator<String> {
|
||||||
return name1.compareTo(name2);
|
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
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* 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.assertEquals;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
|
@ -24,8 +24,9 @@ import org.junit.Test;
|
||||||
|
|
||||||
import generic.test.AbstractGTest;
|
import generic.test.AbstractGTest;
|
||||||
import ghidra.program.database.data.DataTypeUtilities;
|
import ghidra.program.database.data.DataTypeUtilities;
|
||||||
|
import ghidra.program.model.data.*;
|
||||||
|
|
||||||
public class DataTypeUtilitiesTest extends AbstractGTest {
|
public class DataTypeUtilities2Test extends AbstractGTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetContainedDataTypes() {
|
public void testGetContainedDataTypes() {
|
|
@ -13,14 +13,13 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.core.datamgr;
|
package ghidra.program.database.data;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
|
|
||||||
import generic.test.AbstractGenericTest;
|
import generic.test.AbstractGenericTest;
|
||||||
import ghidra.program.database.ProgramBuilder;
|
|
||||||
import ghidra.program.database.ProgramDB;
|
import ghidra.program.database.ProgramDB;
|
||||||
import ghidra.program.database.data.DataTypeUtilities;
|
import ghidra.program.database.data.DataTypeUtilities;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
|
@ -32,8 +31,6 @@ import ghidra.program.model.data.*;
|
||||||
*/
|
*/
|
||||||
public class DataTypeUtilitiesTest extends AbstractGenericTest {
|
public class DataTypeUtilitiesTest extends AbstractGenericTest {
|
||||||
|
|
||||||
private ProgramBuilder builder;
|
|
||||||
private ProgramDB program;
|
|
||||||
private DataTypeManager dataTypeManager;
|
private DataTypeManager dataTypeManager;
|
||||||
private int txID;
|
private int txID;
|
||||||
|
|
||||||
|
@ -43,70 +40,15 @@ public class DataTypeUtilitiesTest extends AbstractGenericTest {
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
builder = new ProgramBuilder("nameTest", ProgramBuilder._TOY, this);
|
dataTypeManager = new StandAloneDataTypeManager("Test");
|
||||||
|
dataTypeManager.startTransaction("Test");
|
||||||
assertNotNull(builder);
|
|
||||||
program = builder.getProgram();
|
|
||||||
assertNotNull(program);
|
|
||||||
dataTypeManager = program.getDataTypeManager();
|
|
||||||
assertNotNull(dataTypeManager);
|
|
||||||
txID = program.startTransaction("NamingUtilities test");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void tearDown() throws Exception {
|
public void tearDown() throws Exception {
|
||||||
if (txID != 0) {
|
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
|
@Test
|
||||||
|
@ -393,16 +335,10 @@ public class DataTypeUtilitiesTest extends AbstractGenericTest {
|
||||||
|
|
||||||
same("/cat1/simpleStruct.conflict1 *32 *64", "/cat1/simpleStruct *32 *64");
|
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", "/cat1/simpleStruct.conflict1");
|
||||||
|
|
||||||
same("/cat1/simpleStruct.conflict_1234.conflict", "/cat1/simpleStruct");
|
|
||||||
|
|
||||||
same("/cat1/simpleStruct.conflict_1234", "/cat1/simpleStruct.conflict3");
|
same("/cat1/simpleStruct.conflict_1234", "/cat1/simpleStruct.conflict3");
|
||||||
|
|
||||||
same("simpleStruct.conflict_1234_abc", "simpleStruct.conflict4_abc");
|
|
||||||
|
|
||||||
same("simpleStruct.conflict12", "simpleStruct.conflict34");
|
same("simpleStruct.conflict12", "simpleStruct.conflict34");
|
||||||
|
|
||||||
same("/cat1/simpleStruct[5]", "/cat1/simpleStruct.conflict1[5]");
|
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[11] *32[2]", "/cat1/simpleStruct.conflict1[11] *8[2]");
|
||||||
|
|
||||||
different("/cat1/simpleStruct[6] *16[9]", "/cat1/simpleStruct.conflict1[6] *64[9]");
|
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) {
|
private void same(String name1, String name2) {
|
|
@ -99,7 +99,7 @@ public class StubFunctionManager implements FunctionManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FunctionIterator getFunctions(Address start, boolean foward) {
|
public FunctionIterator getFunctions(Address start, boolean forward) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ public class StubFunctionManager implements FunctionManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FunctionIterator getFunctionsNoStubs(Address start, boolean foward) {
|
public FunctionIterator getFunctionsNoStubs(Address start, boolean forward) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue