mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-25 05:32:14 +00:00
GP-3408: Incorporate function external linkage into Debugger GoTo
This commit is contained in:
parent
2d9a1ac539
commit
727c891113
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user