From cd9a57d859f64866f1ef357f14ef2d4bfa5ea51c Mon Sep 17 00:00:00 2001 From: ghidranoob Date: Tue, 17 Jun 2025 12:11:06 -0400 Subject: [PATCH 1/2] Show spec files in Help About Program --- .../app/plugin/core/help/AboutProgramPlugin.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/help/AboutProgramPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/help/AboutProgramPlugin.java index 1ae42ec8a0..dc0d62fa44 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/help/AboutProgramPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/help/AboutProgramPlugin.java @@ -34,6 +34,7 @@ import ghidra.framework.main.datatable.ProjectDataContext; import ghidra.framework.model.DomainFile; import ghidra.framework.plugintool.*; import ghidra.framework.plugintool.util.PluginStatus; +import ghidra.program.model.lang.*; import ghidra.program.model.listing.Program; import ghidra.util.HelpLocation; @@ -106,7 +107,18 @@ public class AboutProgramPlugin extends Plugin implements ApplicationLevelPlugin @Override public void actionPerformed(ProgramActionContext context) { Program program = context.getProgram(); - showAbout(program.getDomainFile(), program.getMetadata()); + + Map metadata = program.getMetadata(); + String cspec = program.getCompilerSpec().getCompilerSpecDescription().getSource(); + metadata.put("Compiler Spec", cspec); + + Language language = program.getLanguage(); + LanguageDescription languageDescription = language.getLanguageDescription(); + if (languageDescription instanceof SleighLanguageDescription sleighDescription) { + metadata.put("Sleigh Spec", sleighDescription.getSlaFile().toString() + "spec"); + metadata.put("Processor Spec", sleighDescription.getSpecFile().toString()); + } + showAbout(program.getDomainFile(), metadata); } @Override From 2a14a5f20100b14002eaa49f16d13b03c0571638 Mon Sep 17 00:00:00 2001 From: Dan <46821332+nsadeveloper789@users.noreply.github.com> Date: Mon, 25 Aug 2025 20:00:18 +0000 Subject: [PATCH 2/2] GP-5716: Port for FrontEnd. Changes per reivew. --- .../plugin/core/help/AboutProgramPlugin.java | 127 +++++++++++++++--- 1 file changed, 111 insertions(+), 16 deletions(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/help/AboutProgramPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/help/AboutProgramPlugin.java index dc0d62fa44..005178f7a1 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/help/AboutProgramPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/help/AboutProgramPlugin.java @@ -15,7 +15,9 @@ */ package ghidra.app.plugin.core.help; -import java.util.Map; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import docking.ActionContext; import docking.action.DockingAction; @@ -34,13 +36,15 @@ import ghidra.framework.main.datatable.ProjectDataContext; import ghidra.framework.model.DomainFile; import ghidra.framework.plugintool.*; import ghidra.framework.plugintool.util.PluginStatus; +import ghidra.program.database.ProgramDB; import ghidra.program.model.lang.*; import ghidra.program.model.listing.Program; +import ghidra.program.util.DefaultLanguageService; import ghidra.util.HelpLocation; /** - * Display a pop-up dialog containing information about the Domain Object - * that is currently open in the tool. + * Display a pop-up dialog containing information about the Domain Object that is currently open in + * the tool. */ //@formatter:off @PluginInfo( @@ -73,6 +77,106 @@ public class AboutProgramPlugin extends Plugin implements ApplicationLevelPlugin super.dispose(); } + record LcspAndVersion(Language language, CompilerSpec compilerSpec, Integer languageVersion, + Integer languageMinorVersion) { + public static final Pattern LANG_PAT = + Pattern.compile("(?\\S+) \\((?\\d+)\\.(?\\d+)\\)"); + + static Language tryLang(String languageID) { + LanguageService langServ = DefaultLanguageService.getLanguageService(); + try { + return langServ.getLanguage(new LanguageID(languageID)); + } + catch (LanguageNotFoundException e) { + return null; + } + } + + static Integer tryInt(String i) { + try { + return Integer.parseInt(i); + } + catch (NumberFormatException e) { + return null; + } + } + + static CompilerSpec tryCompiler(Language language, String compilerSpecID) { + try { + return language.getCompilerSpecByID(new CompilerSpecID(compilerSpecID)); + } + catch (CompilerSpecNotFoundException e) { + return null; + } + } + + /** + * @see ProgramDB#getMetadata() + * @param metadata the metadata + * @return the parsed language, compiler spec, and language version + */ + public static LcspAndVersion fromMetadata(Map metadata) { + String languageInfo = metadata.get("Language ID"); + if (languageInfo == null) { + return null; + } + Matcher matcher = LANG_PAT.matcher(languageInfo); + Language language; + Integer languageVersion; + Integer languageMinorVersion; + if (matcher.matches()) { + language = tryLang(matcher.group("id")); + languageVersion = tryInt(matcher.group("major")); + languageMinorVersion = tryInt(matcher.group("minor")); + } + else { + language = tryLang(languageInfo); + languageVersion = null; + languageMinorVersion = null; + } + if (language == null) { + return null; + } + + String compilerInfo = metadata.get("Compiler ID"); + if (compilerInfo == null) { + return new LcspAndVersion(language, null, languageVersion, languageMinorVersion); + } + CompilerSpec compilerSpec = tryCompiler(language, compilerInfo); + return new LcspAndVersion(language, compilerSpec, languageVersion, + languageMinorVersion); + } + + public boolean isMismatch() { + return !Objects.equals(language.getVersion(), languageVersion) || + !Objects.equals(language.getMinorVersion(), languageMinorVersion); + } + + public String getVersionDisplay() { + if (language == null) { + return ""; + } + return " (%d.%d)".formatted(language.getVersion(), language.getMinorVersion()); + } + } + + private void addLanguageFileInfo(Map metadata) { + LcspAndVersion lav = LcspAndVersion.fromMetadata(metadata); + if (lav == null || lav.language == null) { + return; + } + if (lav.language.getLanguageDescription() instanceof SleighLanguageDescription lDesc) { + metadata.put("Language Spec", + lDesc.getDefsFile() + (lav.isMismatch() ? lav.getVersionDisplay() : "")); + metadata.put("Processor Spec", lDesc.getSpecFile().getAbsolutePath()); + metadata.put("Sleigh Spec", lDesc.getSlaFile().getAbsolutePath() + "spec"); + } + if (lav.compilerSpec != null) { + metadata.put("Compiler Spec", + lav.compilerSpec.getCompilerSpecDescription().getSource()); + } + } + private void setupActions() { if (tool instanceof FrontEndTool) { aboutAction = new FrontendProjectTreeAction(ACTION_NAME, PLUGIN_NAME) { @@ -80,8 +184,8 @@ public class AboutProgramPlugin extends Plugin implements ApplicationLevelPlugin @Override protected void actionPerformed(ProjectDataContext context) { DomainFile domainFile = context.getSelectedFiles().get(0); - Map metadata = domainFile.getMetadata(); - + Map metadata = new LinkedHashMap<>(domainFile.getMetadata()); + addLanguageFileInfo(metadata); showAbout(domainFile, metadata); } @@ -107,17 +211,8 @@ public class AboutProgramPlugin extends Plugin implements ApplicationLevelPlugin @Override public void actionPerformed(ProgramActionContext context) { Program program = context.getProgram(); - - Map metadata = program.getMetadata(); - String cspec = program.getCompilerSpec().getCompilerSpecDescription().getSource(); - metadata.put("Compiler Spec", cspec); - - Language language = program.getLanguage(); - LanguageDescription languageDescription = language.getLanguageDescription(); - if (languageDescription instanceof SleighLanguageDescription sleighDescription) { - metadata.put("Sleigh Spec", sleighDescription.getSlaFile().toString() + "spec"); - metadata.put("Processor Spec", sleighDescription.getSpecFile().toString()); - } + Map metadata = new LinkedHashMap<>(program.getMetadata()); + addLanguageFileInfo(metadata); showAbout(program.getDomainFile(), metadata); }