package rea.extensions.nativeaot; import ghidra.app.util.importer.MessageLog; import ghidra.program.model.address.Address; import ghidra.program.model.listing.Program; import ghidra.util.task.TaskMonitor; import java.util.LinkedHashSet; import nativeaot.rtr.ReadyToRunDirectory; import nativeaot.rtr.ReadyToRunSection; import nativeaot.rtr.SignatureReadyToRunLocator; import nativeaot.rtr.SymbolReadyToRunLocator; /** Validate the producer's NativeAOT row layout before database mutation. */ final class NativeAotDirectory { record Located(Address address, ReadyToRunDirectory directory, String discovery) {} static Located locate(Program program, TaskMonitor monitor, MessageLog log) throws Exception { Address[] symbols = SymbolReadyToRunLocator.instance.locateModules(program, monitor, log); String discovery = symbols.length == 0 ? "signature-heuristic" : "symbol"; Address[] found = symbols.length == 0 ? SignatureReadyToRunLocator.instance.locateModules(program, monitor, log) : symbols; var candidates = new LinkedHashSet
(); for (Address address : found) if (address.getOffset() != 0) candidates.add(address); if (candidates.isEmpty()) return null; if (candidates.size() != 1) throw new UnsupportedOperationException("Ambiguous NativeAOT directory candidates: " + candidates); Address address = candidates.iterator().next(); var memory = program.getMemory(); byte[] header = new byte[16]; if (memory.getBytes(address, header) != header.length) throw new IllegalArgumentException("Incomplete NativeAOT header at " + address); int count = Short.toUnsignedInt(memory.getShort(address.add(12))); if (count < 1 || count > 80 || Byte.toUnsignedInt(header[14]) != 24 || header[15] != 1) throw new UnsupportedOperationException("Unsupported NativeAOT row layout at " + address + ": sections=" + count + ", entry_size=" + Byte.toUnsignedInt(header[14]) + ", entry_type=" + Byte.toUnsignedInt(header[15])); byte[] rows = new byte[count * 24]; if (memory.getBytes(address.add(16), rows) != rows.length) throw new IllegalArgumentException("Incomplete NativeAOT directory rows at " + address); ReadyToRunDirectory directory = ReadyToRunDirectory.readAtAddress(program, address); if (directory.getMajorVersion() != 9 || directory.getMinorVersion() != 1) throw new UnsupportedOperationException("Unsupported NativeAOT RTR format " + directory.getMajorVersion() + "." + directory.getMinorVersion() + " at " + address + "; verified format is 9.1 (.NET 8.0.22 Linux x64 fixture)."); var types = new LinkedHashSet