diff --git a/bridge/ghidra/ReaGhidraBridge.java b/bridge/ghidra/ReaGhidraBridge.java index df639a6732..25256fcc90 100644 --- a/bridge/ghidra/ReaGhidraBridge.java +++ b/bridge/ghidra/ReaGhidraBridge.java @@ -1340,7 +1340,8 @@ public final class ReaGhidraBridge extends HeadlessScript { ReferenceIterator incomingIterator = currentProgram.getReferenceManager().getReferencesTo(address); while (incomingIterator.hasNext()) { monitor.checkCancelled(); - addReference(incoming, incomingIterator.next()); + Reference reference = incomingIterator.next(); + if (!reference.isEntryPointReference()) addReference(incoming, reference); } List orderedIncoming = new ArrayList<>(incoming.values()); orderedIncoming.sort(REFERENCE_ORDER); diff --git a/src/ghidra/GhidraAnalysisProfile.ts b/src/ghidra/GhidraAnalysisProfile.ts index 1ba15ff846..01e87ac6b3 100644 --- a/src/ghidra/GhidraAnalysisProfile.ts +++ b/src/ghidra/GhidraAnalysisProfile.ts @@ -14,6 +14,7 @@ import type { AnalysisError } from "../domain/analysisErrorBase.js"; import { err, ok, type Result } from "../domain/result.js"; import type { GhidraInstallationInspection } from "./GhidraInstallation.js"; import { + isLegacyMipsAdmission, ghidraMipsProfileParameters, ghidraMipsLanguageOverride, } from "./GhidraMipsProfile.js"; @@ -164,9 +165,12 @@ export const resolveGhidraAnalysisProfile = async ( const dosCom = target.format === "dos-com"; const dos = dosMz || dosCom; const pinnedLanguage = ghidraPinnedLanguage(target); + const callerMaySelectLegacyMipsLanguage = + target.architecture === "mips" && isLegacyMipsAdmission(target); if ( pinnedLanguage !== undefined && target.architecture !== "powerpc" && + !callerMaySelectLegacyMipsLanguage && languageOverride !== undefined && (languageOverride.languageId !== pinnedLanguage.languageId || (languageOverride.compilerSpecId !== undefined && diff --git a/src/ghidra/GhidraLanguageOverride.test.ts b/src/ghidra/GhidraLanguageOverride.test.ts index 86909112e2..6a07445d2c 100644 --- a/src/ghidra/GhidraLanguageOverride.test.ts +++ b/src/ghidra/GhidraLanguageOverride.test.ts @@ -39,6 +39,16 @@ const X86_LDEFS = ` `; +const MIPS_LDEFS = ` + + + MIPS 32-bit little endian + + + +`; + const pe: BinaryTarget = { path: "/fixture.exe", sha256: "a".repeat(64), @@ -50,6 +60,23 @@ const pe: BinaryTarget = { managed: false, }; +const legacyMips: BinaryTarget = { + path: "/fixture-mips.elf", + sha256: "b".repeat(64), + kind: "executable", + format: "elf", + architecture: "mips", + availableArchitectures: ["mips"], + mips: { + elfClass: 32, + byteOrder: "little", + type: 2, + flags: 0x50000001, + abiFlags: null, + gnuAttributes: null, + }, +}; + let installDir = ""; beforeAll(async () => { installDir = await mkdtemp(join(tmpdir(), "rea-ghidra-languages-")); @@ -276,6 +303,30 @@ describe("Ghidra language override profile", () => { }); }); + it("accepts the caller-selected language on the legacy MIPS lane", async () => { + const mipsLanguages = join( + installDir, + "Ghidra/Processors/MIPS/data/languages", + ); + await mkdir(mipsLanguages, { recursive: true }); + const definition = join(mipsLanguages, "mips.ldefs"); + await writeFile(definition, MIPS_LDEFS); + try { + const resolved = await provider({ + REA_GHIDRA_LANGUAGE_ID: "MIPS:LE:32:default", + REA_GHIDRA_COMPILER_SPEC_ID: "default", + }).resolveAnalysisProfile(legacyMips); + if (!resolved.ok) throw resolved.error; + expect(resolved.value.profile?.parameters).toMatchObject({ + language_id: "MIPS:LE:32:default", + compiler_spec_id: "default", + language_selection: "configured-v1", + }); + } finally { + await rm(mipsLanguages, { recursive: true, force: true }); + } + }); + it("records the language default when no compiler spec is configured", async () => { const resolved = await provider({ REA_GHIDRA_LANGUAGE_ID: "x86:LE:32:default",