diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerLocationLabel.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerLocationLabel.java index 2ee23c1306..e707f16ee6 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerLocationLabel.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerLocationLabel.java @@ -175,19 +175,24 @@ public class DebuggerLocationLabel extends JLabel { if (address == null) { return "(nowhere)"; } - TraceSection section = getNearestSectionContaining(); - if (section != null) { - return section.getModule().getName() + ":" + section.getName(); + try { + TraceSection section = getNearestSectionContaining(); + if (section != null) { + return section.getModule().getName() + ":" + section.getName(); + } + TraceModule module = getNearestModuleContaining(); + if (module != null) { + return module.getName(); + } + TraceMemoryRegion region = getRegionContaining(); + if (region != null) { + return region.getName(); + } + return "(unknown)"; } - TraceModule module = getNearestModuleContaining(); - if (module != null) { - return module.getName(); + catch (Throwable t) { + return "(error) " + t.getMessage(); } - TraceMemoryRegion region = getRegionContaining(); - if (region != null) { - return region.getName(); - } - return "(unknown)"; } public void updateLabel() { diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/AbstractGhidraHeadedDebuggerGUITest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/AbstractGhidraHeadedDebuggerGUITest.java index 5d58809104..a8906486d3 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/AbstractGhidraHeadedDebuggerGUITest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/AbstractGhidraHeadedDebuggerGUITest.java @@ -495,8 +495,12 @@ public abstract class AbstractGhidraHeadedDebuggerGUITest tool.getProject().getProjectData().getRootFolder().createFile(obj.getName(), obj, monitor); } + protected void createSnaplessTrace(String langID) throws IOException { + tb = new ToyDBTraceBuilder("dynamic-" + name.getMethodName(), langID); + } + protected void createSnaplessTrace() throws IOException { - tb = new ToyDBTraceBuilder("dynamic-" + name.getMethodName(), LANGID_TOYBE64); + createSnaplessTrace(LANGID_TOYBE64); } protected void addSnapshot(String desc) throws IOException { @@ -505,16 +509,28 @@ public abstract class AbstractGhidraHeadedDebuggerGUITest } } - protected void createTrace() throws IOException { - createSnaplessTrace(); + protected void createTrace(String langID) throws IOException { + createSnaplessTrace(langID); addSnapshot("First snap"); } - protected void createAndOpenTrace() throws IOException { - createTrace(); + protected void createTrace() throws IOException { + createTrace(LANGID_TOYBE64); + } + + protected void useTrace(Trace trace) { + tb = new ToyDBTraceBuilder(trace); + } + + protected void createAndOpenTrace(String langID) throws IOException { + createTrace(langID); traceManager.openTrace(tb.trace); } + protected void createAndOpenTrace() throws IOException { + createAndOpenTrace(LANGID_TOYBE64); + } + protected String getProgramName() { return "static-" + getClass().getCanonicalName() + "." + name.getMethodName(); } diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProviderTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProviderTest.java index 04fca7415d..0027466d0d 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProviderTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProviderTest.java @@ -1195,6 +1195,50 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI waitForPass(() -> assertEquals("modExe:.text", listingProvider.locationLabel.getText())); } + @Test + public void testActivateTraceChangeLanguage() throws Exception { + assertEquals(trackPc, listingProvider.actionTrackLocation.getCurrentUserData()); + + createSnaplessTrace("x86:LE:64:default"); + + try (ToyDBTraceBuilder tb2 = + new ToyDBTraceBuilder("dynamic2-" + name.getMethodName(), "dsPIC33F:LE:24:default")) { + + TraceThread thread1; + try (UndoableTransaction tid = tb.startTransaction()) { + tb.trace.getTimeManager().createSnapshot("First"); + tb.trace.getMemoryManager() + .createRegion(".text", 0, tb.range(0x00400000, 0x0040ffff), + TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE); + thread1 = tb.getOrAddThread("Thread1", 0); + tb.exec(0, 0, thread1, java.util.List.of( + "RIP = 0x00400000;")); + } + + TraceThread thread2; + try (UndoableTransaction tid = tb2.startTransaction()) { + tb2.trace.getTimeManager().createSnapshot("First"); + tb2.trace.getMemoryManager() + .createRegion(".text", 0, tb2.range(0x200, 0x3ff), + TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE); + thread2 = tb2.getOrAddThread("Thread2", 0); + tb2.exec(0, 0, thread2, java.util.List.of( + "PC = 0x100;")); + } + + traceManager.openTrace(tb.trace); + traceManager.openTrace(tb2.trace); + + traceManager.activateThread(thread1); + waitForSwing(); + + traceManager.activateThread(thread2); + waitForSwing(); + + assertFalse(listingProvider.locationLabel.getText().startsWith("(error)")); + } + } + @Test public void testActivateThreadTracks() throws Exception { assertEquals(trackPc, listingProvider.actionTrackLocation.getCurrentUserData()); diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/ToyDBTraceBuilder.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/ToyDBTraceBuilder.java index 0079f96350..7ca4ceda1b 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/ToyDBTraceBuilder.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/ToyDBTraceBuilder.java @@ -26,12 +26,14 @@ import java.nio.charset.Charset; import java.nio.charset.CharsetEncoder; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Collection; -import java.util.Objects; +import java.util.*; import com.google.common.collect.Range; import db.DBHandle; +import ghidra.app.plugin.processors.sleigh.SleighLanguage; +import ghidra.pcode.exec.*; +import ghidra.pcode.exec.trace.TraceSleighUtils; import ghidra.program.disassemble.Disassembler; import ghidra.program.model.address.*; import ghidra.program.model.data.DataType; @@ -49,9 +51,9 @@ import ghidra.trace.database.memory.DBTraceMemoryManager; import ghidra.trace.database.symbol.DBTraceReference; import ghidra.trace.database.thread.DBTraceThread; import ghidra.trace.database.thread.DBTraceThreadManager; -import ghidra.trace.model.ImmutableTraceAddressSnapRange; -import ghidra.trace.model.TraceAddressSnapRange; +import ghidra.trace.model.*; import ghidra.trace.model.language.TraceGuestLanguage; +import ghidra.trace.model.thread.TraceThread; import ghidra.util.Msg; import ghidra.util.database.DBOpenMode; import ghidra.util.database.UndoableTransaction; @@ -76,6 +78,19 @@ public class ToyDBTraceBuilder implements AutoCloseable { this.trace = new DBTrace(name, language.getDefaultCompilerSpec(), this); } + public ToyDBTraceBuilder(Trace trace) { + this.language = trace.getBaseLanguage(); + this.trace = (DBTrace) trace; + trace.addConsumer(this); + } + + public void exec(long snap, int frame, TraceThread thread, List sleigh) { + PcodeProgram program = SleighProgramCompiler.compileProgram((SleighLanguage) language, + "builder", sleigh, SleighUseropLibrary.nil()); + TraceSleighUtils.buildByteExecutor(trace, snap, thread, frame) + .execute(program, SleighUseropLibrary.nil()); + } + public Address addr(AddressSpace space, long offset) { return space.getAddress(offset); }