GP-3408: Incorporate function external linkage into Debugger GoTo

This commit is contained in:
Dan 2024-02-13 14:44:00 -05:00
parent 2d9a1ac539
commit 727c891113
3 changed files with 98 additions and 15 deletions

View File

@ -24,7 +24,8 @@ import ghidra.debug.api.platform.DebuggerPlatformMapper;
import ghidra.debug.api.platform.DisassemblyResult;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.*;
import ghidra.program.model.lang.*;
import ghidra.program.model.lang.Endian;
import ghidra.program.model.lang.Language;
import ghidra.trace.model.Trace;
import ghidra.trace.model.guest.TracePlatform;
import ghidra.trace.model.target.TraceObject;
@ -85,9 +86,10 @@ public abstract class AbstractDebuggerPlatformMapper implements DebuggerPlatform
if (!result) {
return DisassemblyResult.failed(dis.getStatusMsg());
}
AddressSetView actualSet = dis.getDisassembledAddressSet();
for (DisassemblyInject i : injects) {
i.post(tool, trace, snap, dis.getDisassembledAddressSet());
i.post(tool, trace, snap, actualSet);
}
return DisassemblyResult.success(!dis.getDisassembledAddressSet().isEmpty());
return DisassemblyResult.success(actualSet != null && !actualSet.isEmpty());
}
}

View File

@ -19,6 +19,7 @@ import java.math.BigInteger;
import java.util.*;
import java.util.Map.Entry;
import ghidra.app.nav.NavigationUtils;
import ghidra.app.plugin.core.debug.service.emulation.*;
import ghidra.app.plugin.core.debug.service.emulation.data.DefaultPcodeDebuggerAccess;
import ghidra.app.plugin.processors.sleigh.SleighException;
@ -38,6 +39,7 @@ import ghidra.pcodeCPort.slghsymbol.SleighSymbol;
import ghidra.pcodeCPort.slghsymbol.VarnodeSymbol;
import ghidra.program.model.address.*;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.MemBuffer;
import ghidra.program.model.symbol.Symbol;
@ -102,7 +104,7 @@ public enum DebuggerPcodeUtils {
* TODO: This may break things that check for the absence of a symbol
*
* I don't think it'll affect expressions, but it could later affect user Sleigh
* libraries than an expression might like to use. The better approach would be to
* libraries that an expression might like to use. The better approach would be to
* incorporate a better error message into the Sleigh compiler, but it won't always
* know the use case for a clear message.
*/
@ -111,6 +113,42 @@ public enum DebuggerPcodeUtils {
return symbol;
}
protected SleighSymbol tryMap(String nm, Trace trace, long snap, Program program,
Symbol symbol, Address addr, List<SleighSymbol> externals) {
TraceLocation tloc =
mappings.getOpenMappedLocation(trace, new ProgramLocation(program, addr), snap);
if (tloc == null) {
return null;
}
SleighSymbol mapped = createSleighConstant(program.getName(), nm, tloc.getAddress());
if (!symbol.isExternal()) {
return mapped;
}
// Most externals will not map, but if one does, use it as a fallback
externals.add(mapped);
return null;
}
protected SleighSymbol tryExternalLinkage(String nm, Trace trace, long snap,
Program program, Symbol symbol, List<SleighSymbol> externals) {
if (!(symbol.getObject() instanceof Function func)) {
return null;
}
// This covers refs and thunks
Address[] extAddresses =
NavigationUtils.getExternalLinkageAddresses(program, symbol.getAddress());
if (extAddresses == null) {
return null;
}
for (Address addr : extAddresses) {
SleighSymbol mapped = tryMap(nm, trace, snap, program, symbol, addr, externals);
if (mapped != null) {
return mapped;
}
}
return null;
}
protected SleighSymbol findUserSymbol(String nm) {
Trace trace = coordinates.getTrace();
long snap = coordinates.getSnap();
@ -121,23 +159,28 @@ public enum DebuggerPcodeUtils {
}
return createSleighConstant(trace.getName(), nm, symbol.getAddress());
}
List<SleighSymbol> externals = new ArrayList<>();
for (Program program : mappings.getOpenMappedProgramsAtSnap(trace, snap)) {
for (Symbol symbol : program.getSymbolTable().getSymbols(nm)) {
if (symbol.isDynamic() || symbol.isExternal()) {
continue;
}
if (symbol.getSymbolType() != SymbolType.FUNCTION &&
symbol.getSymbolType() != SymbolType.LABEL) {
continue;
}
TraceLocation tloc = mappings.getOpenMappedLocation(trace,
new ProgramLocation(program, symbol.getAddress()), snap);
if (tloc == null) {
return null;
SleighSymbol mapped =
tryMap(nm, trace, snap, program, symbol, symbol.getAddress(), externals);
if (mapped != null) {
return mapped;
}
mapped = tryExternalLinkage(nm, trace, snap, program, symbol, externals);
if (mapped != null) {
return mapped;
}
return createSleighConstant(program.getName(), nm, tloc.getAddress());
}
}
// TODO: Some way to prioritize among these?
for (SleighSymbol ext : externals) {
return ext;
}
return null;
}
}

View File

@ -58,9 +58,12 @@ import ghidra.debug.api.tracemgr.DebuggerCoordinates;
import ghidra.framework.model.*;
import ghidra.plugin.importer.ImporterPlugin;
import ghidra.program.model.address.*;
import ghidra.program.model.data.PointerDataType;
import ghidra.program.model.lang.Register;
import ghidra.program.model.lang.RegisterValue;
import ghidra.program.model.listing.Instruction;
import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.RefType;
import ghidra.program.model.symbol.SourceType;
import ghidra.program.util.*;
import ghidra.trace.database.ToyDBTraceBuilder;
import ghidra.trace.database.memory.DBTraceMemoryManager;
@ -877,6 +880,39 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerTes
() -> assertEquals(tb.addr(0x00404321), listingProvider.getLocation().getAddress()));
}
@Test
public void testActionGoToExternalLinkage() throws Exception {
createMappedTraceAndProgram();
AddressSpace ss = program.getAddressFactory().getDefaultAddressSpace();
try (Transaction tx = program.openTransaction("Add EXTERNAL and ref")) {
Function func = program.getExternalManager()
.addExtLocation("lib", "testExtFunc", null, SourceType.IMPORTED)
.createFunction();
// This is the same construct as imported from a PE's IAT
Address dataAddr = ss.getAddress(0x00600123);
Data data = program.getListing().createData(dataAddr, PointerDataType.dataType);
data.addMnemonicReference(func.getEntryPoint(), RefType.EXTERNAL_REF,
SourceType.IMPORTED);
}
waitForProgram(program);
traceManager.activateTrace(tb.trace);
waitForSwing();
assertTrue(listingProvider.actionGoTo.isEnabled());
performAction(listingProvider.actionGoTo, false);
DebuggerGoToDialog dialog1 = waitForDialogComponent(DebuggerGoToDialog.class);
runSwing(() -> {
dialog1.setOffset("testExtFunc");
dialog1.okCallback();
});
waitForPass(
() -> assertEquals(tb.addr(0x00400123), listingProvider.getLocation().getAddress()));
}
@Test
public void testActionTrackLocation() throws Exception {
assertTrue(listingProvider.actionTrackLocation.isEnabled());
@ -1457,7 +1493,8 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerTes
traceManager.activate(DebuggerCoordinates.NOWHERE.thread(thread).snap(0));
waitForSwing();
assertEquals(tb.addr(0x00401234), listingProvider.getLocation().getAddress());
waitForPass(
() -> assertEquals(tb.addr(0x00401234), listingProvider.getLocation().getAddress()));
try (Transaction tx = tb.startTransaction()) {
TraceMemorySpace regs = mm.getMemoryRegisterSpace(thread, true);
@ -1465,7 +1502,8 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerTes
}
waitForDomainObject(tb.trace);
assertEquals(tb.addr(0x00404321), listingProvider.getLocation().getAddress());
waitForPass(
() -> assertEquals(tb.addr(0x00404321), listingProvider.getLocation().getAddress()));
}
@Test