diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AbstractDemanglerAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AbstractDemanglerAnalyzer.java index 7763217f21..966e4fa931 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AbstractDemanglerAnalyzer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AbstractDemanglerAnalyzer.java @@ -18,8 +18,7 @@ package ghidra.app.plugin.core.analysis; import ghidra.app.services.*; import ghidra.app.util.demangler.*; import ghidra.app.util.importer.MessageLog; -import ghidra.program.model.address.Address; -import ghidra.program.model.address.AddressSetView; +import ghidra.program.model.address.*; import ghidra.program.model.listing.*; import ghidra.program.model.symbol.*; import ghidra.util.exception.CancelledException; @@ -41,6 +40,9 @@ import ghidra.util.task.TaskMonitor; */ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer { + private static final AddressSetView EXTERNAL_SET = new AddressSet( + AddressSpace.EXTERNAL_SPACE.getMinAddress(), AddressSpace.EXTERNAL_SPACE.getMaxAddress()); + public AbstractDemanglerAnalyzer(String name, String description) { super(name, description, AnalyzerType.BYTE_ANALYZER); setPriority(AnalysisPriority.DATA_TYPE_PROPOGATION.before().before().before()); @@ -59,6 +61,8 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer { try { monitor.setIndeterminate(true); + // NOTE: demangling of Externals may lose mangled name if original + // imported name has already been assigned to the External symbol (e.g., ordinal based name) return doAdded(program, set, monitor, log); } finally { @@ -75,18 +79,42 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer { log.appendMsg(getName(), "Invalid demangler options--cannot demangle"); return false; } + + // Demangle external symbols after memory symbols. + // This is done to compensate for cases where the mangled name on externals may be lost + // after demangling when an alternate Ordinal symbol exists. The external mangled + // name is helpful in preserving thunk relationships when a mangled symbols have been + // placed on a thunk. It is assumed that analyzer is presented with entire + // EXTERNAL space in set (all or none). + boolean demangleExternals = set.contains(EXTERNAL_SET.getMinAddress()); + if (demangleExternals) { + set = set.subtract(EXTERNAL_SET); + } - int count = 0; + String baseMonitorMessage = monitor.getMessage(); + int memorySymbolCount = + demangleSymbols(program, set, 0, baseMonitorMessage, options, log, monitor); + if (demangleExternals) { + // process external symbols last + demangleSymbols(program, EXTERNAL_SET, memorySymbolCount, baseMonitorMessage, options, + log, monitor); + } - String defaultMessage = monitor.getMessage(); + return true; + } + private int demangleSymbols(Program program, AddressSetView set, int initialCount, + String baseMonitorMessage, DemanglerOptions options, MessageLog log, + TaskMonitor monitor) throws CancelledException { + + int count = initialCount; SymbolTable symbolTable = program.getSymbolTable(); SymbolIterator it = symbolTable.getPrimarySymbolIterator(set, true); while (it.hasNext()) { monitor.checkCanceled(); if (++count % 100 == 0) { - monitor.setMessage(defaultMessage + " - " + count + " symbols"); + monitor.setMessage(baseMonitorMessage + " - " + count + " symbols"); } Symbol symbol = it.next(); @@ -101,8 +129,7 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer { apply(program, address, demangled, options, log, monitor); } } - - return true; + return count; } /** @@ -152,10 +179,13 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer { return true; } - // Someone has already added arguments or return to the function signature + // Someone has already added arguments or return to the function signature. + // Treatment of thunks must be handled later since thunk relationship may + // need to be broken if (symbol.getSymbolType() == SymbolType.FUNCTION) { Function function = (Function) symbol.getObject(); - if (function.getSignatureSource().isHigherPriorityThan(SourceType.ANALYSIS)) { + if (!function.isThunk() && + function.getSignatureSource().isHigherPriorityThan(SourceType.ANALYSIS)) { return true; } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledFunction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledFunction.java index cc0e591505..60a759ac82 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledFunction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledFunction.java @@ -349,14 +349,26 @@ public class DemangledFunction extends DemangledObject { Function function = createFunction(program, address, options.doDisassembly(), monitor); if (function == null) { - // no function whose signature we need to update - // NOTE: this does not make much sense - // renameExistingSymbol(program, address, symbolTable); - // maybeCreateUndefined(program, address); + // No function whose signature we need to update return false; } - //if existing function signature is user defined - add demangled label only + if (function.isThunk()) { + // If thunked function has same mangled name we can discard our + // symbol if no other symbols at this address (i.e., rely entirely on + // thunked function). + // NOTE: mangled name on external may be lost once it is demangled. + if (shouldThunkBePreserved(function)) { + // Preserve thunk and remove mangled symbol. Allow to proceed normally by returning true. + function.getSymbol().setName(null, SourceType.DEFAULT); + return true; + } + + // Break thunk relationship and continue applying demangle function below + function.setThunkedFunction(null); + } + + // If existing function signature is user defined - add demangled label only boolean makePrimary = (function.getSignatureSource() != SourceType.USER_DEFINED); Symbol demangledSymbol = @@ -395,6 +407,65 @@ public class DemangledFunction extends DemangledObject { return true; } + /** + * Determine if existing thunk relationship should be preserved and mangled symbol + * discarded. This is the case when the thunk function mangled name matches + * the thunked function since we want to avoid duplicate symbol names. + * @param thunkFunction thunk function with a mangled symbol which is currently + * being demangled. + * @return true if thunk should be preserved and mangled symbol discarded, otherwise + * false if thunk relationship should be eliminated and demangled function information + * should be applied as normal. + */ + private boolean shouldThunkBePreserved(Function thunkFunction) { + Program program = thunkFunction.getProgram(); + SymbolTable symbolTable = program.getSymbolTable(); + if (thunkFunction.getSymbol().isExternalEntryPoint()) { + return false; // entry point should retain its own symbol + } + Symbol[] symbols = symbolTable.getSymbols(thunkFunction.getEntryPoint()); + if (symbols.length > 1) { + return false; // too many symbols present to preserve thunk + } + // NOTE: order of demangling unknown - thunked function may, or may not, have + // already been demangled + Function thunkedFunction = thunkFunction.getThunkedFunction(true); + if (mangled.equals(thunkedFunction.getName())) { + // thunked function has matching mangled name + return true; + } + if (thunkedFunction.isExternal()) { + if (thunkedFunction.getParentNamespace() instanceof Library) { + // Thunked function does not have mangled name, if it did it would have + // matched name check above or now reside in a different namespace + return false; + } + // assume external contained with specific namespace + ExternalLocation externalLocation = + program.getExternalManager().getExternalLocation(thunkedFunction.getSymbol()); + String originalImportedName = externalLocation.getOriginalImportedName(); + if (originalImportedName == null) { + // assume external manually manipulated without use of mangled name + return false; + } + if (mangled.equals(externalLocation.getOriginalImportedName())) { + // matching mangled name also resides at thunked function location + return true; + } + + // TODO: carefully compare signature in absense of matching mangled name + return false; + } + + if (symbolTable.getSymbol(mangled, thunkedFunction.getEntryPoint(), + program.getGlobalNamespace()) != null) { + // matching mangled name also resides at thunked function location + return true; + } + + return false; + } + private boolean hasVarArgs() { if (parameters.isEmpty()) { return false;