Merge remote-tracking branch 'origin/GP-809_ghidra1_DemangledThunks--SQUASHED' into patch

This commit is contained in:
ghidra1
2021-04-05 18:25:18 -04:00
2 changed files with 115 additions and 14 deletions
@@ -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;
}
}
@@ -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;