Merge remote-tracking branch 'origin/GP-6456_ghidra_red_ImproveTenetLoader--SQUASHED'

This commit is contained in:
Ryan Kurtz
2026-02-27 12:19:17 -05:00
2 changed files with 156 additions and 35 deletions
@@ -173,7 +173,29 @@ public class TenetLoader implements Loader {
return false; return false;
} }
return true; try {
final byte[] bytes = new byte[1000];
provider.getInputStream(0).read(bytes);
final String[] lines = new String(bytes, StandardCharsets.UTF_8).split("\n");
if (lines.length == 1) {
return false;
}
// Skip last line as it could be a partial one
for (int i = 0; i < (lines.length - 1); i++) {
final String line = lines[i];
if (((i != 0) && SLIDE_PATTERN.matcher(line).find()) ||
(!SLIDE_PATTERN.matcher(line).find() && !REG_PATTERN.matcher(line).find())) {
return false;
}
}
return true;
}
catch (final IOException e) {
return false;
}
} }
/** /**
@@ -209,7 +231,8 @@ public class TenetLoader implements Loader {
final DomainObject domainObject, final boolean loadIntoProgram, final DomainObject domainObject, final boolean loadIntoProgram,
final boolean mirrorFsLayout) { final boolean mirrorFsLayout) {
final List<Option> list = new ArrayList<>(); final List<Option> list = new ArrayList<>();
list.add(new DomainFileOption(DOMAIN_FILE_OPTION_NAME, "", false)); list.add(new DomainFileOption(DOMAIN_FILE_OPTION_NAME,
COMMAND_LINE_ARG_PREFIX + "-associatedProgram", false));
return list; return list;
} }
@@ -258,7 +281,7 @@ public class TenetLoader implements Loader {
final long start = System.currentTimeMillis(); final long start = System.currentTimeMillis();
trace = this.loadTrace(settings.provider(), settings.importName(), program, trace = loadTrace(settings.provider(), settings.importName(), program,
settings.consumer(), settings.log(), settings.monitor()); settings.consumer(), settings.log(), settings.monitor());
final long loadDone = System.currentTimeMillis(); final long loadDone = System.currentTimeMillis();
@@ -347,7 +370,7 @@ public class TenetLoader implements Loader {
snapNumber++; snapNumber++;
this.setupMemoryAndMapping(program, trace, slideValue, snap); setupMemoryAndMapping(program, trace, slideValue, snap);
try { try {
while (line != null) { while (line != null) {
@@ -376,8 +399,8 @@ public class TenetLoader implements Loader {
} }
curIp = Long.parseLong(ipMatcher.group(1), 16); curIp = Long.parseLong(ipMatcher.group(1), 16);
if (!this.parseRegisterOperations(snap, curIp, line, lineNumber, if (!parseRegisterOperations(snap, curIp, line, lineNumber, traceThread,
traceThread, trace, log, monitor)) { trace, log, monitor)) {
errorCount++; errorCount++;
lineNumber++; lineNumber++;
monitor.setProgress(lineNumber); monitor.setProgress(lineNumber);
@@ -391,7 +414,7 @@ public class TenetLoader implements Loader {
} }
continue; continue;
} }
this.parseMemoryOperations(snap, curIp, line, trace, monitor); parseMemoryOperations(snap, curIp, line, trace, monitor);
lineNumber++; lineNumber++;
monitor.setProgress(lineNumber); monitor.setProgress(lineNumber);
@@ -475,8 +498,9 @@ public class TenetLoader implements Loader {
return true; return true;
} }
private void setupMemoryAndMapping(final Program program, final Trace trace, final long slideValue, private void setupMemoryAndMapping(final Program program, final Trace trace,
final long snap) throws DuplicateNameException, TraceOverlappedRegionException { final long slideValue, final long snap)
throws DuplicateNameException, TraceOverlappedRegionException {
final TraceModuleManager modMan = trace.getModuleManager(); final TraceModuleManager modMan = trace.getModuleManager();
final TraceStaticMappingManager mapMan = trace.getStaticMappingManager(); final TraceStaticMappingManager mapMan = trace.getStaticMappingManager();
final URL projectUrl = program.getDomainFile().getLocalProjectURL(""); final URL projectUrl = program.getDomainFile().getLocalProjectURL("");
@@ -522,5 +546,4 @@ public class TenetLoader implements Loader {
} }
return null; return null;
} }
} }
@@ -65,7 +65,7 @@ public class TenetLoaderTest extends AbstractGhidraHeadedDebuggerTest {
private Trace createTraceWithLoader(final String testFile) throws Exception { private Trace createTraceWithLoader(final String testFile) throws Exception {
this.createProgram(); this.createProgram();
this.intoProject(this.program); intoProject(program);
final TenetLoader loader = new TenetLoader(); final TenetLoader loader = new TenetLoader();
final ByteProvider provider = final ByteProvider provider =
@@ -76,11 +76,11 @@ public class TenetLoaderTest extends AbstractGhidraHeadedDebuggerTest {
loader.getDefaultOptions(provider, loadSpec, null, false, false); loader.getDefaultOptions(provider, loadSpec, null, false, false);
final Option programOption = Unique.assertOne( final Option programOption = Unique.assertOne(
options.stream().filter(o -> o.getName().equals(TenetLoader.DOMAIN_FILE_OPTION_NAME))); options.stream().filter(o -> o.getName().equals(TenetLoader.DOMAIN_FILE_OPTION_NAME)));
programOption.setValue(this.program.getDomainFile().getPathname()); programOption.setValue(program.getDomainFile().getPathname());
final MessageLog log = new MessageLog(); final MessageLog log = new MessageLog();
final ImporterSettings settings = new ImporterSettings(provider, "test", final ImporterSettings settings = new ImporterSettings(provider, "test", env.getProject(),
this.env.getProject(), "/", false, loadSpec, options, this, log, this.monitor); "/", false, loadSpec, options, this, log, monitor);
final LoadResults<? extends DomainObject> results = loader.load(settings); final LoadResults<? extends DomainObject> results = loader.load(settings);
if (!(results.getPrimary().domainObject instanceof final Trace trace)) { if (!(results.getPrimary().domainObject instanceof final Trace trace)) {
@@ -99,11 +99,54 @@ public class TenetLoaderTest extends AbstractGhidraHeadedDebuggerTest {
public void testBadRegisterNames() throws Exception { public void testBadRegisterNames() throws Exception {
final String testFile = """ final String testFile = """
pc=0x1,rax=0x1234 pc=0x1,rax=0x1234
pc=0x2,rax=0x1234
pc=0x3,rax=0x1234
pc=0x4,rax=0x1234
pc=0x5,rax=0x1234
pc=0x6,rax=0x1234
pc=0x7,rax=0x1234
pc=0x8,rax=0x1234
pc=0x9,rax=0x1234
pc=0xa,rax=0x1234
"""; """;
final Trace trace = this.createTraceWithLoader(testFile); final Trace trace = createTraceWithLoader(testFile);
assertNotNull(trace); assertNotNull(trace);
} }
/*
* Test the file content check for the loader
*/
@Test
public void testFileContent() throws Exception {
final String junk_line = "asdf\n";
final String slide_line = "slide=0x0\n";
final String reg_line = "pc=0x1,r0=0x1234\n";
this.createProgram();
intoProject(program);
final TenetLoader loader = new TenetLoader();
ByteProvider provider = new ByteArrayProvider("test.tenet", (junk_line).getBytes("utf-8"));
assertEquals(0, loader.findSupportedLoadSpecs(provider).size());
provider = new ByteArrayProvider("test.tenet", (slide_line + junk_line).getBytes("utf-8"));
assertEquals(0, loader.findSupportedLoadSpecs(provider).size());
provider = new ByteArrayProvider("test.tenet", (reg_line + junk_line).getBytes("utf-8"));
assertEquals(0, loader.findSupportedLoadSpecs(provider).size());
provider = new ByteArrayProvider("test.tenet",
(reg_line + slide_line + reg_line.repeat(TenetLoader.ERROR_THRESHOLD))
.getBytes("utf-8"));
assertEquals(0, loader.findSupportedLoadSpecs(provider).size());
provider = new ByteArrayProvider("test.tenet",
(slide_line + reg_line.repeat(TenetLoader.ERROR_THRESHOLD - 2) + junk_line)
.getBytes("utf-8"));
assertEquals(0, loader.findSupportedLoadSpecs(provider).size());
}
/* /*
* Test the filename check for the loader * Test the filename check for the loader
*/ */
@@ -113,10 +156,18 @@ public class TenetLoaderTest extends AbstractGhidraHeadedDebuggerTest {
slide=0x0 slide=0x0
pc=0x1,r0=0x1234 pc=0x1,r0=0x1234
pc=0x2,r1=0x4321 pc=0x2,r1=0x4321
pc=0x3,r1=0x4321
pc=0x4,r1=0x4321
pc=0x5,r1=0x4321
pc=0x6,r1=0x4321
pc=0x7,r1=0x4321
pc=0x8,r1=0x4321
pc=0x9,r1=0x4321
pc=0xa,r1=0x4321
"""; """;
this.createProgram(); this.createProgram();
this.intoProject(this.program); intoProject(program);
final TenetLoader loader = new TenetLoader(); final TenetLoader loader = new TenetLoader();
@@ -139,18 +190,26 @@ public class TenetLoaderTest extends AbstractGhidraHeadedDebuggerTest {
slide=0x0 slide=0x0
pc=0x1,r0=0x1234 pc=0x1,r0=0x1234
pc=0x2,r1=0x4321 pc=0x2,r1=0x4321
pc=0x3,r1=0x4321
pc=0x4,r1=0x4321
pc=0x5,r1=0x4321
pc=0x6,r1=0x4321
pc=0x7,r1=0x4321
pc=0x8,r1=0x4321
pc=0x9,r1=0x4321
pc=0xa,r1=0x4321
"""; """;
addPlugin(this.tool, DebuggerRegistersPlugin.class); addPlugin(tool, DebuggerRegistersPlugin.class);
addPlugin(this.tool, DebuggerModelPlugin.class); addPlugin(tool, DebuggerModelPlugin.class);
addPlugin(this.tool, DebuggerThreadsPlugin.class); addPlugin(tool, DebuggerThreadsPlugin.class);
addPlugin(this.tool, DebuggerListingPlugin.class); addPlugin(tool, DebuggerListingPlugin.class);
addPlugin(this.tool, DebuggerTimePlugin.class); addPlugin(tool, DebuggerTimePlugin.class);
final Trace trace = this.createTraceWithLoader(testFile); final Trace trace = createTraceWithLoader(testFile);
this.traceManager.openTrace(trace); traceManager.openTrace(trace);
this.traceManager.activateTrace(trace); traceManager.activateTrace(trace);
Thread.sleep(1000); Thread.sleep(1000);
} }
@@ -163,7 +222,7 @@ public class TenetLoaderTest extends AbstractGhidraHeadedDebuggerTest {
public void testManyLinesBadRegisterNames() throws Exception { public void testManyLinesBadRegisterNames() throws Exception {
// Should fail after 10 lines with bad registers // Should fail after 10 lines with bad registers
final String badTestFile = "pc=0x1,rax=0x1234\n".repeat(TenetLoader.ERROR_THRESHOLD + 1); final String badTestFile = "pc=0x1,rax=0x1234\n".repeat(TenetLoader.ERROR_THRESHOLD + 1);
assertThrows(LoadException.class, () -> this.createTraceWithLoader(badTestFile)); assertThrows(LoadException.class, () -> createTraceWithLoader(badTestFile));
} }
/* /*
@@ -174,7 +233,7 @@ public class TenetLoaderTest extends AbstractGhidraHeadedDebuggerTest {
public void testManyLinesNoPc() throws Exception { public void testManyLinesNoPc() throws Exception {
// Should fail after {@TenetLoader.ERROR_THRESHOLD} lines with no PC // Should fail after {@TenetLoader.ERROR_THRESHOLD} lines with no PC
final String badTestFile = "r1=0x1234\n".repeat(TenetLoader.ERROR_THRESHOLD + 1); final String badTestFile = "r1=0x1234\n".repeat(TenetLoader.ERROR_THRESHOLD + 1);
assertThrows(LoadException.class, () -> this.createTraceWithLoader(badTestFile)); assertThrows(LoadException.class, () -> createTraceWithLoader(badTestFile));
} }
/* /*
@@ -186,9 +245,16 @@ public class TenetLoaderTest extends AbstractGhidraHeadedDebuggerTest {
pc=0x1,r0=0x1234,mr=0x1000:0000000000001337 pc=0x1,r0=0x1234,mr=0x1000:0000000000001337
pc=0x2,r1=0x4321,mw=0x2000:deadbeefdeadbeef pc=0x2,r1=0x4321,mw=0x2000:deadbeefdeadbeef
pc=0x3,mw=0x1000:87654321,mr=0x2000:c0ffee pc=0x3,mw=0x1000:87654321,mr=0x2000:c0ffee
pc=0x4,r1=0x4321
pc=0x5,r1=0x4321
pc=0x6,r1=0x4321
pc=0x7,r1=0x4321
pc=0x8,r1=0x4321
pc=0x9,r1=0x4321
pc=0xa,r1=0x4321
"""; """;
final Trace trace = this.createTraceWithLoader(testFile); final Trace trace = createTraceWithLoader(testFile);
final AddressSpace addrSpace = final AddressSpace addrSpace =
trace.getBaseLanguage().getAddressFactory().getDefaultAddressSpace(); trace.getBaseLanguage().getAddressFactory().getDefaultAddressSpace();
@@ -219,8 +285,16 @@ public class TenetLoaderTest extends AbstractGhidraHeadedDebuggerTest {
final String testFile = """ final String testFile = """
pc=0x1,r1=0x1234 pc=0x1,r1=0x1234
r2=0x1234 r2=0x1234
pc=0x3,r1=0x4321
pc=0x4,r1=0x4321
pc=0x5,r1=0x4321
pc=0x6,r1=0x4321
pc=0x7,r1=0x4321
pc=0x8,r1=0x4321
pc=0x9,r1=0x4321
pc=0xa,r1=0x4321
"""; """;
final Trace trace = this.createTraceWithLoader(testFile); final Trace trace = createTraceWithLoader(testFile);
assertNotNull(trace); assertNotNull(trace);
} }
@@ -232,13 +306,21 @@ public class TenetLoaderTest extends AbstractGhidraHeadedDebuggerTest {
final String testFile = """ final String testFile = """
pc=0x1,r0=0x1234 pc=0x1,r0=0x1234
pc=0x2,r1=0x4321 pc=0x2,r1=0x4321
pc=0x3,r1=0x4321
pc=0x4,r1=0x4321
pc=0x5,r1=0x4321
pc=0x6,r1=0x4321
pc=0x7,r1=0x4321
pc=0x8,r1=0x4321
pc=0x9,r1=0x4321
pc=0xa,r1=0x4321
"""; """;
final Trace trace = this.createTraceWithLoader(testFile); final Trace trace = createTraceWithLoader(testFile);
final TraceStaticMapping staticMapping = final TraceStaticMapping staticMapping =
Unique.assertOne(trace.getStaticMappingManager().getAllEntries()); Unique.assertOne(trace.getStaticMappingManager().getAllEntries());
assertEquals(this.program.getImageBase().getUnsignedOffset(), assertEquals(program.getImageBase().getUnsignedOffset(),
staticMapping.getMinTraceAddress().getUnsignedOffset()); staticMapping.getMinTraceAddress().getUnsignedOffset());
} }
@@ -251,9 +333,17 @@ public class TenetLoaderTest extends AbstractGhidraHeadedDebuggerTest {
slide=0x0 slide=0x0
pc=0x1,r0=0x1234 pc=0x1,r0=0x1234
pc=0x2,r1=0x4321 pc=0x2,r1=0x4321
pc=0x3,r1=0x4321
pc=0x4,r1=0x4321
pc=0x5,r1=0x4321
pc=0x6,r1=0x4321
pc=0x7,r1=0x4321
pc=0x8,r1=0x4321
pc=0x9,r1=0x4321
pc=0xa,r1=0x4321
"""; """;
final Trace trace = this.createTraceWithLoader(testFile); final Trace trace = createTraceWithLoader(testFile);
final TraceThread thread = Unique.assertOne(trace.getThreadManager().getAllThreads()); final TraceThread thread = Unique.assertOne(trace.getThreadManager().getAllThreads());
final TraceMemorySpace regs = final TraceMemorySpace regs =
@@ -261,12 +351,12 @@ public class TenetLoaderTest extends AbstractGhidraHeadedDebuggerTest {
assertNotNull(regs); assertNotNull(regs);
assertEquals("1", assertEquals("1",
regs.getValue(0, this.program.getLanguage().getProgramCounter()) regs.getValue(0, program.getLanguage().getProgramCounter())
.getUnsignedValue() .getUnsignedValue()
.toString(16)); .toString(16));
assertEquals("2", assertEquals("2",
regs.getValue(1, this.program.getLanguage().getProgramCounter()) regs.getValue(1, program.getLanguage().getProgramCounter())
.getUnsignedValue() .getUnsignedValue()
.toString(16)); .toString(16));
@@ -281,13 +371,21 @@ public class TenetLoaderTest extends AbstractGhidraHeadedDebuggerTest {
slide=0x10000 slide=0x10000
pc=0x1,r0=0x1234 pc=0x1,r0=0x1234
pc=0x2,r1=0x4321 pc=0x2,r1=0x4321
pc=0x3,r1=0x4321
pc=0x4,r1=0x4321
pc=0x5,r1=0x4321
pc=0x6,r1=0x4321
pc=0x7,r1=0x4321
pc=0x8,r1=0x4321
pc=0x9,r1=0x4321
pc=0xa,r1=0x4321
"""; """;
final Trace trace = this.createTraceWithLoader(testFile); final Trace trace = createTraceWithLoader(testFile);
final TraceStaticMapping staticMapping = final TraceStaticMapping staticMapping =
Unique.assertOne(trace.getStaticMappingManager().getAllEntries()); Unique.assertOne(trace.getStaticMappingManager().getAllEntries());
assertEquals(this.program.getImageBase().getUnsignedOffset() + 0x10000, assertEquals(program.getImageBase().getUnsignedOffset() + 0x10000,
staticMapping.getMinTraceAddress().getUnsignedOffset()); staticMapping.getMinTraceAddress().getUnsignedOffset());
} }
} }