Fix for NeLoader handling of external functions

This commit is contained in:
caheckman 2019-09-10 11:06:20 -04:00
parent 15c1f43fa5
commit d7888851d3
5 changed files with 71 additions and 54 deletions

View file

@ -228,11 +228,6 @@ public class CreateThunkFunctionCmd extends BackgroundCommand {
thunkFunction = functionMgr.createThunkFunction(name, namespace, entry, body, thunkFunction = functionMgr.createThunkFunction(name, namespace, entry, body,
referencedFunction, source); referencedFunction, source);
} }
catch (DuplicateNameException e) {
Msg.error(this, "Dynamically generated thunk name conlict: " + e.getMessage());
setStatusMsg("Thunk name conflict: " + e.getMessage());
return false;
}
catch (OverlappingFunctionException e) { catch (OverlappingFunctionException e) {
setStatusMsg("Specified body overlaps existing function(s): " + e.getMessage()); setStatusMsg("Specified body overlaps existing function(s): " + e.getMessage());
return false; return false;

View file

@ -30,6 +30,7 @@ import ghidra.app.util.bin.format.ne.Resource;
import ghidra.app.util.importer.MessageLog; import ghidra.app.util.importer.MessageLog;
import ghidra.app.util.importer.MessageLogContinuesFactory; import ghidra.app.util.importer.MessageLogContinuesFactory;
import ghidra.framework.options.Options; import ghidra.framework.options.Options;
import ghidra.program.database.function.OverlappingFunctionException;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.lang.Register; import ghidra.program.model.lang.Register;
@ -401,54 +402,60 @@ public class NeLoader extends AbstractLibrarySupportLoader {
ImportedNameTable imp, Program program, SegmentedAddressSpace space, MessageLog log, ImportedNameTable imp, Program program, SegmentedAddressSpace space, MessageLog log,
TaskMonitor monitor) throws IOException { TaskMonitor monitor) throws IOException {
int pointerSize = space.getAddress(0, 0).getPointerSize(); int thunkBodySize = 4;
PointerDataType ptr = new PointerDataType(); ExternalManager externalManager = program.getExternalManager();
String comment = ""; FunctionManager functionManager = program.getFunctionManager();
String source = ""; Namespace globalNamespace = program.getGlobalNamespace();
Listing listing = program.getListing();
SymbolTable symbolTable = program.getSymbolTable();
LengthStringSet[] names = mrt.getNames(); LengthStringSet[] names = mrt.getNames();
for (LengthStringSet name : names) { String[][] mod2proclist = new String[names.length][];
String[] callnames = getCallNamesForModule(name.getString(), mrt, st, imp); int length = 0;
int length = callnames.length * pointerSize; for (int i = 0; i < names.length; ++i) {
String moduleName = names[i].getString();
String[] callnames = getCallNamesForModule(moduleName, mrt, st, imp);
mod2proclist[i] = callnames;
length += callnames.length * thunkBodySize;
}
if (length == 0) {
return;
}
int segment = space.getNextOpenSegment(program.getMemory().getMaxAddress()); int segment = space.getNextOpenSegment(program.getMemory().getMaxAddress());
Address start = space.getAddress(segment, 0); Address addr = space.getAddress(segment, 0);
if (length > 0) { String comment = "";
String source = "";
// This isn't a real block, just place holder addresses, so don't create an initialized block // This isn't a real block, just place holder addresses, so don't create an initialized block
MemoryBlockUtils.createUninitializedBlock(program, false, name.getString(), start, MemoryBlockUtils.createUninitializedBlock(program, false, MemoryBlock.EXTERNAL_BLOCK_NAME,
length, comment, source, true, false, false, log); addr, length, comment, source, true, false, false, log);
}
Address addr = start;
for (String callname : callnames) {
try {
listing.createData(addr, ptr, pointerSize);
}
catch (CodeUnitInsertionException e) {
log.appendMsg(e.getMessage() + "\n");
continue;
}
catch (DataTypeConflictException e) {
log.appendMsg(e.getMessage() + "\n");
continue;
}
try {
program.getReferenceManager().addExternalReference(addr, name.getString(), for (int i = 0; i < names.length; ++i) {
callname, null, SourceType.IMPORTED, 0, RefType.EXTERNAL_REF); String moduleName = names[i].getString();
symbolTable.createLabel(addr, name.getString() + "_" + callname, String[] callnames = mod2proclist[i];
SourceType.IMPORTED); for (String callname : callnames) {
Function refFunction = null;
try {
ExternalLocation loc;
loc = externalManager.addExtFunction(moduleName, callname, null, SourceType.IMPORTED);
refFunction = loc.getFunction();
} }
catch (DuplicateNameException e) { catch (DuplicateNameException e) {
log.appendMsg(e.getMessage() + "\n"); log.appendMsg(e.getMessage() + '\n');
continue; continue;
} }
catch (InvalidInputException e) { catch (InvalidInputException e) {
log.appendMsg(e.getMessage() + "\n"); log.appendMsg(e.getMessage() + '\n');
continue; continue;
} }
addr = addr.addWrap(pointerSize); AddressSet body = new AddressSet();
body.add(addr, addr.add(thunkBodySize - 1));
try {
functionManager.createThunkFunction(null, globalNamespace, addr, body,
refFunction, SourceType.IMPORTED);
}
catch (OverlappingFunctionException e) {
log.appendMsg(e.getMessage() + '\n');
}
addr = addr.addWrap(thunkBodySize);
} }
} }
} }
@ -555,9 +562,28 @@ public class NeLoader extends AbstractLibrarySupportLoader {
createSymbols(rnt.getNames(), symbolTable); createSymbols(rnt.getNames(), symbolTable);
} }
private SegmentedAddress getImportSymbolByName(SymbolTable symbolTable, String modname,
String procname) {
Namespace libnamespace = symbolTable.getNamespace(modname, null);
List<Symbol> symbols = symbolTable.getSymbols(procname, libnamespace);
if (symbols.isEmpty()) {
return null;
}
Symbol symbol = symbols.get(0);
if (symbol.getSymbolType() == SymbolType.FUNCTION && symbol.isExternal()) {
Function func = (Function) symbol.getObject();
Address[] thunkAddresses = func.getFunctionThunkAddresses();
if (thunkAddresses != null && thunkAddresses.length != 0) {
return (SegmentedAddress) thunkAddresses[0];
}
}
return null;
}
private void processRelocations(SegmentTable st, ImportedNameTable imp, private void processRelocations(SegmentTable st, ImportedNameTable imp,
ModuleReferenceTable mrt, RelocationTable relocTable, Program program, Memory memory, ModuleReferenceTable mrt, RelocationTable relocTable, Program program, Memory memory,
SegmentedAddressSpace space, MessageLog log, TaskMonitor monitor) throws IOException { SegmentedAddressSpace space, MessageLog log, TaskMonitor monitor) throws IOException {
SymbolTable symbolTable = program.getSymbolTable();
Segment[] segments = st.getSegments(); Segment[] segments = st.getSegments();
for (int s = 0; s < segments.length; ++s) { for (int s = 0; s < segments.length; ++s) {
if (monitor.isCancelled()) { if (monitor.isCancelled()) {
@ -586,17 +612,13 @@ public class NeLoader extends AbstractLibrarySupportLoader {
else if (reloc.isImportName()) { else if (reloc.isImportName()) {
String modname = getRelocationModuleName(mrt, reloc); String modname = getRelocationModuleName(mrt, reloc);
String procname = imp.getNameAt(reloc.getTargetOffset()).getString(); String procname = imp.getNameAt(reloc.getTargetOffset()).getString();
Symbol symbol = SymbolUtilities.getLabelOrFunctionSymbol(program, relocAddr = getImportSymbolByName(symbolTable, modname, procname);
modname + "_" + procname, err -> log.error("NE", err));
relocAddr = symbol == null ? null : (SegmentedAddress) symbol.getAddress();
} }
else if (reloc.isImportOrdinal()) { else if (reloc.isImportOrdinal()) {
String modname = getRelocationModuleName(mrt, reloc); String modname = getRelocationModuleName(mrt, reloc);
int ordinal = Conv.shortToInt(reloc.getTargetOffset()); int ordinal = Conv.shortToInt(reloc.getTargetOffset());
Symbol symbol = SymbolUtilities.getLabelOrFunctionSymbol(program, String procname = SymbolUtilities.ORDINAL_PREFIX + ordinal;
modname + "_" + SymbolUtilities.ORDINAL_PREFIX + ordinal, relocAddr = getImportSymbolByName(symbolTable, modname, procname);
err -> log.error("NE", err));
relocAddr = symbol == null ? null : (SegmentedAddress) symbol.getAddress();
} }
else if (reloc.isOpSysFixup()) { else if (reloc.isOpSysFixup()) {
// short fixupType = relocs[r].getTargetSegment(); // short fixupType = relocs[r].getTargetSegment();

View file

@ -326,7 +326,7 @@ public class FunctionManagerDB implements ManagerDB, FunctionManager {
@Override @Override
public Function createThunkFunction(String name, Namespace nameSpace, Address entryPoint, public Function createThunkFunction(String name, Namespace nameSpace, Address entryPoint,
AddressSetView body, Function thunkedFunction, SourceType source) AddressSetView body, Function thunkedFunction, SourceType source)
throws DuplicateNameException, OverlappingFunctionException { throws OverlappingFunctionException {
try { try {
return createFunction(name, nameSpace, entryPoint, body, thunkedFunction, source); return createFunction(name, nameSpace, entryPoint, body, thunkedFunction, source);
} }

View file

@ -107,13 +107,12 @@ public interface FunctionManager {
* @param thunkedFunction referenced function (required is creating a thunk function) * @param thunkedFunction referenced function (required is creating a thunk function)
* @param source the source of this function * @param source the source of this function
* @return new function or null if one or more functions overlap the specified body address set. * @return new function or null if one or more functions overlap the specified body address set.
* @throws DuplicateNameException if a function with the same thunk name already exists
* @throws OverlappingFunctionException if the address set of the body overlaps an existing * @throws OverlappingFunctionException if the address set of the body overlaps an existing
* function * function
*/ */
public Function createThunkFunction(String name, Namespace nameSpace, Address entryPoint, public Function createThunkFunction(String name, Namespace nameSpace, Address entryPoint,
AddressSetView body, Function thunkedFunction, SourceType source) AddressSetView body, Function thunkedFunction, SourceType source)
throws DuplicateNameException, OverlappingFunctionException; throws OverlappingFunctionException;
/** /**
* Returns the total number of functions in the program including external functions. * Returns the total number of functions in the program including external functions.

View file

@ -27,7 +27,8 @@ import ghidra.program.model.lang.PrototypeModel;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.Namespace; import ghidra.program.model.symbol.Namespace;
import ghidra.program.model.symbol.SourceType; import ghidra.program.model.symbol.SourceType;
import ghidra.util.exception.*; import ghidra.util.exception.CancelledException;
import ghidra.util.exception.InvalidInputException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
public class FunctionManagerTestDouble implements FunctionManager { public class FunctionManagerTestDouble implements FunctionManager {
@ -73,7 +74,7 @@ public class FunctionManagerTestDouble implements FunctionManager {
@Override @Override
public Function createThunkFunction(String name, Namespace nameSpace, Address entryPoint, public Function createThunkFunction(String name, Namespace nameSpace, Address entryPoint,
AddressSetView body, Function thunkedFunction, SourceType source) AddressSetView body, Function thunkedFunction, SourceType source)
throws DuplicateNameException, OverlappingFunctionException { throws OverlappingFunctionException {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }