From 03ad6807561aa5263de198cd5fc64b716349dceb Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Tue, 4 May 2021 12:20:41 -0400 Subject: [PATCH] GP-653 ProgramCompilerSpec revisions --- .../core/decompile/SpecExtensionTest.java | 14 +++++--- .../program/database/ProgramCompilerSpec.java | 27 ++++++++++---- .../ghidra/program/database/ProgramDB.java | 35 +++++++++++++------ 3 files changed, 56 insertions(+), 20 deletions(-) diff --git a/Ghidra/Features/Decompiler/src/test.slow/java/ghidra/app/plugin/core/decompile/SpecExtensionTest.java b/Ghidra/Features/Decompiler/src/test.slow/java/ghidra/app/plugin/core/decompile/SpecExtensionTest.java index b12aa27f2f..cce1b19408 100644 --- a/Ghidra/Features/Decompiler/src/test.slow/java/ghidra/app/plugin/core/decompile/SpecExtensionTest.java +++ b/Ghidra/Features/Decompiler/src/test.slow/java/ghidra/app/plugin/core/decompile/SpecExtensionTest.java @@ -53,6 +53,7 @@ public class SpecExtensionTest extends AbstractDecompilerTest { try { SpecExtension specExtension = new SpecExtension(program); specExtension.addReplaceCompilerSpecExtension(myfixup, TaskMonitor.DUMMY); + fail("expected exception"); } catch (SleighException | XmlParseException | SAXException | LockException ex) { errMessage = ex.getMessage(); @@ -80,13 +81,16 @@ public class SpecExtensionTest extends AbstractDecompilerTest { myfixup = " "; errMessage = null; String subError = null; + setErrorsExpected(true); try { specExtension.testExtensionDocument(myfixup); + fail("expected exception"); } catch (Exception e) { errMessage = e.getMessage(); subError = e.getCause().getMessage(); } + setErrorsExpected(true); assertTrue(errMessage.contains("Invalid compiler specification")); assertTrue(subError.contains("must be terminated by the matching")); @@ -95,6 +99,7 @@ public class SpecExtensionTest extends AbstractDecompilerTest { errMessage = null; try { specExtension.testExtensionDocument(myfixup); + fail("expected exception"); } catch (Exception e) { errMessage = e.getMessage(); @@ -111,6 +116,7 @@ public class SpecExtensionTest extends AbstractDecompilerTest { SpecExtension specExtension = new SpecExtension(program); try { specExtension.addReplaceCompilerSpecExtension(myfixup, TaskMonitor.DUMMY); + fail("expected exception"); } catch (SleighException | XmlParseException | SAXException | LockException ex) { errMessage = ex.getMessage(); @@ -139,7 +145,7 @@ public class SpecExtensionTest extends AbstractDecompilerTest { specExtension.addReplaceCompilerSpecExtension(defaultString, TaskMonitor.DUMMY); } catch (LockException | SleighException | SAXException | XmlParseException ex) { - throw new AssertionError("Unexpected exception: " + ex.getMessage()); + fail("Unexpected exception: " + ex.getMessage()); } program.endTransaction(id1, true); PrototypeModel myproto = cspec.getCallingConvention("myproto"); @@ -180,7 +186,7 @@ public class SpecExtensionTest extends AbstractDecompilerTest { specExtension.removeCompilerSpecExtension("prototype_myproto", TaskMonitor.DUMMY); } catch (LockException | CancelledException ex) { - throw new AssertionError("Unexpected exception: " + ex.getMessage()); + fail("Unexpected exception: " + ex.getMessage()); } program.endTransaction(id2, true); myproto = cspec.getCallingConvention("myproto"); @@ -203,7 +209,7 @@ public class SpecExtensionTest extends AbstractDecompilerTest { specExtension.addReplaceCompilerSpecExtension(myfixup, TaskMonitor.DUMMY); } catch (LockException | SleighException | SAXException | XmlParseException ex) { - throw new AssertionError("Unexpected exception: " + ex.getMessage()); + fail("Unexpected exception: " + ex.getMessage()); } program.endTransaction(id1, true); PcodeInjectLibrary library = program.getCompilerSpec().getPcodeInjectLibrary(); @@ -244,7 +250,7 @@ public class SpecExtensionTest extends AbstractDecompilerTest { specExtension.removeCompilerSpecExtension("callfixup_mynewthing", TaskMonitor.DUMMY); } catch (LockException | CancelledException ex) { - throw new AssertionError("Unexpected exception: " + ex.getMessage()); + fail("Unexpected exception: " + ex.getMessage()); } program.endTransaction(id2, true); programPayloads = library.getProgramPayloads(); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramCompilerSpec.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramCompilerSpec.java index ff77329f2a..8e4b0ad2e6 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramCompilerSpec.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramCompilerSpec.java @@ -66,13 +66,9 @@ public class ProgramCompilerSpec extends BasicCompilerSpec { * @param program is the Program * @param langSpec is the CompilerSpec from Language to base this on */ - public ProgramCompilerSpec(Program program, CompilerSpec langSpec) { - super((BasicCompilerSpec) langSpec); + private ProgramCompilerSpec(Program program, BasicCompilerSpec langSpec) { + super(langSpec); this.program = program; - if (langSpec instanceof ProgramCompilerSpec) { - throw new IllegalArgumentException( - "Cannot instantiate ProgramCompilerSpec from another ProgramCompilerSpec"); - } } /** @@ -371,4 +367,23 @@ public class ProgramCompilerSpec extends BasicCompilerSpec { } return true; } + + /** + * Transition specified compiler specification langSpec into a program-specific + * one which supports extensions. If the specified langSpec is not a {@link BasicCompilerSpec} + * instance, the langSpec argument will be returned unmodified. + * @param program program to which langSpec applies + * @param langSpec initial compiler specification which does not support extensions. + * @return compiler specification to be used with program + */ + static CompilerSpec getProgramCompilerSpec(Program program, CompilerSpec langSpec) { + if (langSpec instanceof ProgramCompilerSpec) { + throw new IllegalArgumentException( + "Cannot instantiate ProgramCompilerSpec from another ProgramCompilerSpec"); + } + if (langSpec instanceof BasicCompilerSpec) { + return new ProgramCompilerSpec(program, (BasicCompilerSpec) langSpec); + } + return langSpec; + } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java index 0492f9254b..907c388cfc 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java @@ -190,7 +190,7 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM private ProgramUserDataDB programUserData; private Table table; private Language language; - private ProgramCompilerSpec compilerSpec; + private CompilerSpec compilerSpec; private LanguageID languageID; private CompilerSpecID compilerSpecID; @@ -219,8 +219,13 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM throws IOException { super(new DBHandle(), name, 500, 1000, consumer); + if (!(compilerSpec instanceof BasicCompilerSpec)) { + throw new IllegalArgumentException( + "unsupported compilerSpec: " + compilerSpec.getClass().getName()); + } + this.language = language; - this.compilerSpec = new ProgramCompilerSpec(this, compilerSpec); + this.compilerSpec = ProgramCompilerSpec.getProgramCompilerSpec(this, compilerSpec); languageID = language.getLanguageID(); compilerSpecID = compilerSpec.getCompilerSpecID(); @@ -245,7 +250,7 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM programUserData = new ProgramUserDataDB(this); endTransaction(id, true); clearUndo(false); - this.compilerSpec.registerProgramOptions(); + registerCompilerSpecOptions(); getCodeManager().activateContextLocking(); success = true; } @@ -355,8 +360,8 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM endTransaction(id, true); clearUndo(false); SpecExtension.checkFormatVersion(this); - compilerSpec.installExtensions(); - compilerSpec.registerProgramOptions(); + installExtensions(); + registerCompilerSpecOptions(); getCodeManager().activateContextLocking(); success = true; } @@ -397,7 +402,7 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM } compilerSpecID = compilerSpec.getCompilerSpecID(); } - compilerSpec = new ProgramCompilerSpec(this, langSpec); + compilerSpec = ProgramCompilerSpec.getProgramCompilerSpec(this, langSpec); } /** @@ -1837,7 +1842,7 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM for (int i = 0; i < NUM_MANAGERS; i++) { managers[i].invalidateCache(all); } - compilerSpec.installExtensions(); // Reload any extensions + installExtensions(); // Reload any extensions } catch (IOException e) { dbError(e); @@ -2053,7 +2058,7 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM } if (newCompilerSpecID != null) { - compilerSpec = new ProgramCompilerSpec(this, + compilerSpec = ProgramCompilerSpec.getProgramCompilerSpec(this, language.getCompilerSpecByID(newCompilerSpecID)); } compilerSpecID = compilerSpec.getCompilerSpecID(); @@ -2112,7 +2117,6 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM setChanged(true); clearCache(true); invalidate(); - } catch (Throwable t) { throw new IllegalStateException( @@ -2465,12 +2469,23 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM * See {@link SpecExtension}. */ protected void installExtensions() { + if (!(compilerSpec instanceof ProgramCompilerSpec)) { + return; + } lock.acquire(); try { - compilerSpec.installExtensions(); + ((ProgramCompilerSpec) compilerSpec).installExtensions(); } finally { lock.release(); } } + + private void registerCompilerSpecOptions() { + if (!(compilerSpec instanceof ProgramCompilerSpec)) { + throw new AssertException( + "unsupported compilerSpec: " + compilerSpec.getClass().getName()); + } + ((ProgramCompilerSpec) compilerSpec).registerProgramOptions(); + } }