From 60ab148afae256c399dc479d0e8beebcdf14069e Mon Sep 17 00:00:00 2001 From: Adolanium <94890352+Adolanium@users.noreply.github.com> Date: Sun, 25 Oct 2026 07:45:11 +0200 Subject: [PATCH] fix(ghidra): accept stock language IDs with LEBE endianness or a slash (#7070) REA_GHIDRA_LANGUAGE_ID only allowed LE or BE as the endian field and no '/' in the processor, so it rejected four language IDs that ship with Ghidra: ARM:LEBE:32:v7LEInstruction and v8LEInstruction (ARM BE8) and M16C/60:LE:16:default and M16C/80:LE:16:default. The syntax check now allows LEBE and a slash between processor name parts; the installed .ldefs catalog check is unchanged. --- src/config/ghidraLanguageOverride.ts | 4 +++- src/ghidra/GhidraLanguageOverride.test.ts | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/config/ghidraLanguageOverride.ts b/src/config/ghidraLanguageOverride.ts index 6e1b3d1f7b..70a5ad50eb 100644 --- a/src/config/ghidraLanguageOverride.ts +++ b/src/config/ghidraLanguageOverride.ts @@ -13,10 +13,12 @@ export interface GhidraLanguageOverride { // Ghidra language IDs are four colon-separated fields; variants may contain // spaces ("x86:LE:16:Real Mode") but never leading or trailing whitespace. +// Stock .ldefs also use "/" in processors ("M16C/60") and LEBE for ARM BE8 +// (big-endian data, little-endian instructions). export const ghidraLanguageIdSchema = z .string() .regex( - /^[A-Za-z0-9_.+-]+:(?:LE|BE):[1-9]\d*:[A-Za-z0-9_.+-](?:[A-Za-z0-9_.+ -]*[A-Za-z0-9_.+-])?$/u, + /^[A-Za-z0-9_.+-]+(?:\/[A-Za-z0-9_.+-]+)*:(?:LE|BE|LEBE):[1-9]\d*:[A-Za-z0-9_.+-](?:[A-Za-z0-9_.+ -]*[A-Za-z0-9_.+-])?$/u, "must be a Ghidra language ID such as x86:LE:32:default", ); diff --git a/src/ghidra/GhidraLanguageOverride.test.ts b/src/ghidra/GhidraLanguageOverride.test.ts index b00a07d9be..76919a39c2 100644 --- a/src/ghidra/GhidraLanguageOverride.test.ts +++ b/src/ghidra/GhidraLanguageOverride.test.ts @@ -156,6 +156,25 @@ describe("Ghidra language override configuration", () => { }); }); + it.each([ + "ARM:LEBE:32:v8LEInstruction", + "ARM:LEBE:32:v7LEInstruction", + "M16C/60:LE:16:default", + "M16C/80:LE:16:default", + ])("accepts the stock Ghidra language ID %s", (languageId) => { + const parsed = parseConfig({ REA_GHIDRA_LANGUAGE_ID: languageId }); + if (!parsed.ok) throw parsed.error; + expect(parsed.value.ghidraLanguageOverride).toEqual({ languageId }); + }); + + it.each(["ARM:BELE:32:v8", "/x86:LE:32:default", "x86:LE:32:default "])( + "still refuses the malformed language ID %j", + (languageId) => { + const parsed = parseConfig({ REA_GHIDRA_LANGUAGE_ID: languageId }); + expect(parsed.ok).toBe(false); + }, + ); + it("requires a language for a compiler spec, as analyzeHeadless does", () => { const parsed = parseConfig({ REA_GHIDRA_COMPILER_SPEC_ID: "borlandcpp" }); if (parsed.ok) throw new Error("Expected a configuration error");