From 1779fdd94dffd589a602874ccb1b857e7f0a7ae1 Mon Sep 17 00:00:00 2001 From: emteere <47253321+emteere@users.noreply.github.com> Date: Tue, 11 Jun 2019 17:18:52 -0400 Subject: [PATCH] GT-113_emteere Adding initial SleighEditor to public version. --- .gitignore | 6 + .../SleighEditor/certification.manifest | 42 + .../build.properties | 2 + .../ghidra.xtext.sleigh.feature/category.xml | 7 + .../ghidra.xtext.sleigh.feature/feature.xml | 56 + .../META-INF/MANIFEST.MF | 15 + .../ghidra.xtext.sleigh.ide/build.properties | 6 + .../xtext/sleigh/ide/SleighIdeModule.xtend | 23 + .../xtext/sleigh/ide/SleighIdeSetup.xtend | 32 + .../META-INF/MANIFEST.MF | 15 + .../build.properties | 6 + .../sleigh/tests/CrossReferenceTest.xtend | 171 +++ .../xtext/sleigh/tests/SleighMacroTest.xtend | 89 ++ .../sleigh/tests/SleighParsingTest.xtend | 194 +++ .../xtext/sleigh/tests/SleighScopeTest.xtend | 301 ++++ .../META-INF/MANIFEST.MF | 18 + .../build.properties | 6 + .../META-INF/MANIFEST.MF | 26 + .../ghidra.xtext.sleigh.ui/build.properties | 7 + .../ghidra.xtext.sleigh.ui/plugin.xml | 513 +++++++ .../xtext/sleigh/ui/ConsoleLineTracker.java | 43 + .../ui/SleighEObjectHoverProvider.xtend | 202 +++ .../ui/SleighHighlightingCalculator.java | 238 ++++ .../ui/SleighHighlightingConfiguration.java | 61 + .../sleigh/ui/SleighTextEditComposer.xtend | 11 + .../xtext/sleigh/ui/SleighUiModule.xtend | 53 + .../SleighProposalProvider.xtend | 24 + .../SleighDescriptionLabelProvider.xtend | 83 ++ .../ui/labeling/SleighLabelProvider.xtend | 248 ++++ .../outline/SleighOutlineTreeProvider.xtend | 82 ++ .../ui/quickfix/SleighQuickfixProvider.xtend | 323 +++++ ...gh (sleigh) Language Infrastructure.launch | 18 + .../.launch/Launch Runtime Eclipse.launch | 34 + .../ghidra.xtext.sleigh/META-INF/MANIFEST.MF | 31 + .../ghidra.xtext.sleigh/build.properties | 20 + .../ghidra.xtext.sleigh/plugin.xml | 10 + .../ghidra/xtext/sleigh/GenerateSleigh.mwe2 | 58 + .../src/ghidra/xtext/sleigh/Sleigh.xtext | 1142 +++++++++++++++ .../xtext/sleigh/SleighRuntimeModule.xtend | 23 + .../xtext/sleigh/SleighStandaloneSetup.xtend | 27 + .../sleigh/converter/IntValueConverter.java | 67 + .../converter/SleighValueConverter.java | 55 + .../sleigh/formatting2/SleighFormatter.xtend | 1234 +++++++++++++++++ .../sleigh/generator/SleighGenerator.xtend | 32 + .../sleigh/scoping/SleighScopeProvider.xtend | 237 ++++ .../sleigh/validation/SleighValidator.xtend | 169 +++ 46 files changed, 6060 insertions(+) create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/certification.manifest create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.feature/build.properties create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.feature/category.xml create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.feature/feature.xml create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ide/META-INF/MANIFEST.MF create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ide/build.properties create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ide/src/ghidra/xtext/sleigh/ide/SleighIdeModule.xtend create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ide/src/ghidra/xtext/sleigh/ide/SleighIdeSetup.xtend create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/META-INF/MANIFEST.MF create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/build.properties create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/CrossReferenceTest.xtend create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/SleighMacroTest.xtend create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/SleighParsingTest.xtend create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/SleighScopeTest.xtend create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui.tests/META-INF/MANIFEST.MF create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui.tests/build.properties create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/META-INF/MANIFEST.MF create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/build.properties create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/plugin.xml create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/ConsoleLineTracker.java create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighEObjectHoverProvider.xtend create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighHighlightingCalculator.java create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighHighlightingConfiguration.java create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighTextEditComposer.xtend create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighUiModule.xtend create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/contentassist/SleighProposalProvider.xtend create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/labeling/SleighDescriptionLabelProvider.xtend create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/labeling/SleighLabelProvider.xtend create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/outline/SleighOutlineTreeProvider.xtend create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/quickfix/SleighQuickfixProvider.xtend create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/.launch/Generate Sleigh (sleigh) Language Infrastructure.launch create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/.launch/Launch Runtime Eclipse.launch create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/META-INF/MANIFEST.MF create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/build.properties create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/plugin.xml create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/GenerateSleigh.mwe2 create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/Sleigh.xtext create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/SleighRuntimeModule.xtend create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/SleighStandaloneSetup.xtend create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/converter/IntValueConverter.java create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/converter/SleighValueConverter.java create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/formatting2/SleighFormatter.xtend create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/generator/SleighGenerator.xtend create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/scoping/SleighScopeProvider.xtend create mode 100644 GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/validation/SleighValidator.xtend diff --git a/.gitignore b/.gitignore index 90f4b9de6c..9075ef5713 100644 --- a/.gitignore +++ b/.gitignore @@ -62,3 +62,9 @@ Release .project .classpath .settings/ + +# Ignore XTEXT generated dirs/files +*/*/*/*/xtend-gen +*/*/*/*/src-gen +*/*/*/*/model/generated +*/*/*/*/test-bin diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/certification.manifest b/GhidraBuild/EclipsePlugins/SleighEditor/certification.manifest new file mode 100644 index 0000000000..76d9ac723b --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/certification.manifest @@ -0,0 +1,42 @@ +##VERSION: 2.0 +##MODULE IP: BSD +##MODULE IP: Eclipse Public License 1.0 +ghidra.xtext.sleigh.feature/build.properties||GHIDRA||||END| +ghidra.xtext.sleigh.feature/category.xml||GHIDRA||||END| +ghidra.xtext.sleigh.feature/feature.xml||GHIDRA||||END| +ghidra.xtext.sleigh.ide/META-INF/MANIFEST.MF||GHIDRA||||END| +ghidra.xtext.sleigh.ide/build.properties||GHIDRA||||END| +ghidra.xtext.sleigh.ide/src/ghidra/xtext/sleigh/ide/SleighIdeModule.xtend||GHIDRA||||END| +ghidra.xtext.sleigh.ide/src/ghidra/xtext/sleigh/ide/SleighIdeSetup.xtend||GHIDRA||||END| +ghidra.xtext.sleigh.tests/META-INF/MANIFEST.MF||GHIDRA||||END| +ghidra.xtext.sleigh.tests/build.properties||GHIDRA||||END| +ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/CrossReferenceTest.xtend||GHIDRA||||END| +ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/SleighMacroTest.xtend||GHIDRA||||END| +ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/SleighParsingTest.xtend||GHIDRA||||END| +ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/SleighScopeTest.xtend||GHIDRA||||END| +ghidra.xtext.sleigh.ui.tests/META-INF/MANIFEST.MF||GHIDRA||||END| +ghidra.xtext.sleigh.ui.tests/build.properties||GHIDRA||||END| +ghidra.xtext.sleigh.ui/META-INF/MANIFEST.MF||GHIDRA||||END| +ghidra.xtext.sleigh.ui/build.properties||GHIDRA||||END| +ghidra.xtext.sleigh.ui/plugin.xml||GHIDRA||||END| +ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighEObjectHoverProvider.xtend||GHIDRA||||END| +ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighTextEditComposer.xtend||GHIDRA||||END| +ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighUiModule.xtend||GHIDRA||||END| +ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/contentassist/SleighProposalProvider.xtend||GHIDRA||||END| +ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/labeling/SleighDescriptionLabelProvider.xtend||GHIDRA||||END| +ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/labeling/SleighLabelProvider.xtend||GHIDRA||||END| +ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/outline/SleighOutlineTreeProvider.xtend||GHIDRA||||END| +ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/quickfix/SleighQuickfixProvider.xtend||GHIDRA||||END| +ghidra.xtext.sleigh/.launch/Generate Sleigh (sleigh) Language Infrastructure.launch||GHIDRA||||END| +ghidra.xtext.sleigh/.launch/Launch Runtime Eclipse.launch||GHIDRA||||END| +ghidra.xtext.sleigh/META-INF/MANIFEST.MF||GHIDRA||||END| +ghidra.xtext.sleigh/build.properties||GHIDRA||||END| +ghidra.xtext.sleigh/plugin.xml||GHIDRA||||END| +ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/GenerateSleigh.mwe2||GHIDRA||||END| +ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/Sleigh.xtext||GHIDRA||||END| +ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/SleighRuntimeModule.xtend||GHIDRA||||END| +ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/SleighStandaloneSetup.xtend||GHIDRA||||END| +ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/formatting2/SleighFormatter.xtend||GHIDRA||||END| +ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/generator/SleighGenerator.xtend||GHIDRA||||END| +ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/scoping/SleighScopeProvider.xtend||GHIDRA||||END| +ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/validation/SleighValidator.xtend||GHIDRA||||END| diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.feature/build.properties b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.feature/build.properties new file mode 100644 index 0000000000..29e05b8a3e --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.feature/build.properties @@ -0,0 +1,2 @@ +bin.includes = feature.xml,\ + category.xml diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.feature/category.xml b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.feature/category.xml new file mode 100644 index 0000000000..50b3e3542c --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.feature/category.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.feature/feature.xml b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.feature/feature.xml new file mode 100644 index 0000000000..07ab50de59 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.feature/feature.xml @@ -0,0 +1,56 @@ + + + + + /* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + + + + + + + + + + + + + + + + + diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ide/META-INF/MANIFEST.MF b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ide/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..0cf44b6aa1 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ide/META-INF/MANIFEST.MF @@ -0,0 +1,15 @@ +Manifest-Version: 1.0 +Automatic-Module-Name: ghidra.xtext.sleigh.ide +Bundle-ManifestVersion: 2 +Bundle-Name: ghidra.xtext.sleigh.ide +Bundle-Vendor: My Company +Bundle-Version: 1.0.0.qualifier +Bundle-SymbolicName: ghidra.xtext.sleigh.ide; singleton:=true +Bundle-ActivationPolicy: lazy +Require-Bundle: ghidra.xtext.sleigh, + org.eclipse.xtext.ide, + org.eclipse.xtext.xbase.ide, + org.antlr.runtime;bundle-version="[3.2.0,3.2.1)" +Bundle-RequiredExecutionEnvironment: JavaSE-11 +Export-Package: ghidra.xtext.sleigh.ide.contentassist.antlr, + ghidra.xtext.sleigh.ide.contentassist.antlr.internal diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ide/build.properties b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ide/build.properties new file mode 100644 index 0000000000..5c6bbf99f0 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ide/build.properties @@ -0,0 +1,6 @@ +source.. = src/,\ + src-gen/,\ + xtend-gen/ +bin.includes = .,\ + META-INF/ +bin.excludes = **/*.xtend diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ide/src/ghidra/xtext/sleigh/ide/SleighIdeModule.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ide/src/ghidra/xtext/sleigh/ide/SleighIdeModule.xtend new file mode 100644 index 0000000000..aa58a23aa3 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ide/src/ghidra/xtext/sleigh/ide/SleighIdeModule.xtend @@ -0,0 +1,23 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.ide + + +/** + * Use this class to register ide components. + */ +class SleighIdeModule extends AbstractSleighIdeModule { +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ide/src/ghidra/xtext/sleigh/ide/SleighIdeSetup.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ide/src/ghidra/xtext/sleigh/ide/SleighIdeSetup.xtend new file mode 100644 index 0000000000..c2bd22e665 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ide/src/ghidra/xtext/sleigh/ide/SleighIdeSetup.xtend @@ -0,0 +1,32 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.ide + +import com.google.inject.Guice +import ghidra.xtext.sleigh.SleighRuntimeModule +import ghidra.xtext.sleigh.SleighStandaloneSetup +import org.eclipse.xtext.util.Modules2 + +/** + * Initialization support for running Xtext languages as language servers. + */ +class SleighIdeSetup extends SleighStandaloneSetup { + + override createInjector() { + Guice.createInjector(Modules2.mixin(new SleighRuntimeModule, new SleighIdeModule)) + } + +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/META-INF/MANIFEST.MF b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..c7f00b95cc --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/META-INF/MANIFEST.MF @@ -0,0 +1,15 @@ +Manifest-Version: 1.0 +Automatic-Module-Name: ghidra.xtext.sleigh.tests +Bundle-ManifestVersion: 2 +Bundle-Name: ghidra.xtext.sleigh.tests +Bundle-Vendor: My Company +Bundle-Version: 1.0.0.qualifier +Bundle-SymbolicName: ghidra.xtext.sleigh.tests; singleton:=true +Bundle-ActivationPolicy: lazy +Require-Bundle: ghidra.xtext.sleigh, + org.junit.jupiter.api;bundle-version="[5.0.0,6.0.0)", + org.eclipse.xtext.testing, + org.eclipse.xtext.xbase.testing, + org.eclipse.xtext.xbase.lib;bundle-version="2.14.0" +Bundle-RequiredExecutionEnvironment: JavaSE-11 +Export-Package: ghidra.xtext.sleigh.tests;x-internal=true diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/build.properties b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/build.properties new file mode 100644 index 0000000000..5c6bbf99f0 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/build.properties @@ -0,0 +1,6 @@ +source.. = src/,\ + src-gen/,\ + xtend-gen/ +bin.includes = .,\ + META-INF/ +bin.excludes = **/*.xtend diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/CrossReferenceTest.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/CrossReferenceTest.xtend new file mode 100644 index 0000000000..c581c497cc --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/CrossReferenceTest.xtend @@ -0,0 +1,171 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.tests + +import com.google.inject.Inject +import org.eclipse.xtext.diagnostics.Diagnostic +import org.eclipse.xtext.testing.InjectWith +import org.eclipse.xtext.testing.extensions.InjectionExtension +import org.eclipse.xtext.testing.util.ParseHelper +import org.eclipse.xtext.testing.validation.ValidationTestHelper +import ghidra.xtext.sleigh.sleigh.Model +import ghidra.xtext.sleigh.sleigh.SleighPackage +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.^extension.ExtendWith + +@ExtendWith(InjectionExtension) +@InjectWith(SleighInjectorProvider) +class CrossReferenceTest { + + @Inject extension ParseHelper + @Inject extension ValidationTestHelper + + @Test def void testReferences() { + // Macro should have access to registers (globals) + var model = ''' + define space register size=2 type=register_space wordsize=1 default; + define register offset=0 size=1 [ Z C N V ]; + + define token instr(16) + op = (0,15) + reg = (0,1) + cc = (2,3) + ; + + attach variables [ reg ] [ Z C N V ]; + + :mov reg,N is op=0 & N & reg { + + tmp:1 = N; + if (tmp == 0) goto ; + reg = tmp; + } + + :mov reg,N is op=0 & N & reg { + tmp = N; # tmp should not resolve + } + '''.parse + // model.assertNoErrors + // temp should not resolve + model.assertError( + SleighPackage::eINSTANCE.getassignSym(), + Diagnostic.LINKING_DIAGNOSTIC, + 353, + 3, + "tmp" + ) + } + + @Test def void testCrossbuildReferences() { + // Macro should have access to registers (globals) + var model = ''' + define space register size=2 type=register_space wordsize=1 default; + define register offset=0 size=1 [ Z C N V pc ]; + + define token instr(16) + op = (0,15) + reg = (0,1) + cc = (2,3) + ; + + attach variables [ reg ] [ Z C N V ]; + + CrossbuildAddr0: loc is epsilon [ loc = inst_start; ] { export *:4 loc; } + + Parallel32: "" is op=0x0 & CrossbuildAddr0 { + crossbuild CrossbuildAddr0,COMMIT; + crossbuild CrossbuildAddr0,LOOP; + } + + :^instruction is cc=0x1 & instruction { + build instruction; + <> + pc = 0; + goto [pc]; + } + + :L is op=0x999 { + build Parallel32; + <> + pc = 0; + } + '''.parse + model.assertNoErrors + } + + + @Test def void testSubPieceReferences() { + var model = ''' + define space register size=2 type=register_space wordsize=1 default; + define register offset=0 size=1 [ Z C N V ]; + define register offset=0 size=4 [ BR ]; + + define token instr(16) + op = (0,15) + reg = (0,1) + cc = (2,3) + ; + + attach variables [ reg ] [ Z C N V ]; + + macro macro_a(arg1,arg2) { + local foo = 1; + foo = (~foo & foo | foo) << foo; + Z = 1; + arg1 = 3; + arg2 = foo; + } + + :mov reg,N,op is op=0 & N & reg & op & op=1 { + tmp:1 = 1; + tmp2:1 = reg(4); + macro_a(reg,tmp); + tmp2:2 = BR:2; + tmp2:2 = BR(2); + tmp2:2 = reg:2; + } + '''.parse + model.assertNoErrors + } + + @Test def void testglobalsetReferences() { + var model = ''' + define space register size=2 type=register_space wordsize=1 default; + define register offset=0 size=1 [ Z C N V contextreg ]; + define register offset=0 size=4 [ BR ]; + + define context contextreg + TMode = (0,0) + ; + + define token instr(16) + op = (0,15) + reg = (0,1) + cc = (2,3) + ; + + attach variables [ reg ] [ Z C N V ]; + + GS: reloff is op=100 + [ reloff = inst_start + 8; TMode=1; globalset(reloff,TMode); globalset(inst_next,TMode); ] + { + export *:4 reloff; + } + + '''.parse + model.assertNoErrors + } +} \ No newline at end of file diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/SleighMacroTest.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/SleighMacroTest.xtend new file mode 100644 index 0000000000..8e988d1298 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/SleighMacroTest.xtend @@ -0,0 +1,89 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.tests + +import com.google.inject.Inject +import org.eclipse.xtext.diagnostics.Diagnostic +import org.eclipse.xtext.testing.InjectWith +import org.eclipse.xtext.testing.extensions.InjectionExtension +import org.eclipse.xtext.testing.util.ParseHelper +import org.eclipse.xtext.testing.validation.ValidationTestHelper +import ghidra.xtext.sleigh.sleigh.Model +import ghidra.xtext.sleigh.sleigh.SleighPackage +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.^extension.ExtendWith + +@ExtendWith(InjectionExtension) +@InjectWith(SleighInjectorProvider) +class SleighMacroTest { + + @Inject extension ParseHelper + @Inject extension ValidationTestHelper + + @Test def void testMacros() { + var model = ''' + macro xyz(tom,dick,harry) { + tom = dick; + harry = tom; + tom = 1; + } + + macro ijk(do,wop) { + do = 1; + wop = 1; + } + '''.parse + model.assertNoErrors + } + + @Test def void testMacroReferences() { + // Macro should have access to registers (globals) + var model = ''' + define space register size=2 type=register_space wordsize=1 default; + define register offset=0 size=1 [ Z ]; + + macro a() { + Z = 1; + } + '''.parse + model.assertNoErrors + } + + @Test def void testCrossedMacroRefs() { + // Macro should not have cross parameter reference + var model = ''' + macro xyz(tom,dick,harry) { + tom = dick; + harry = do; + } + + macro ijk(do,wop) { + do = 1; + tom = wop; + } + '''.parse + model.assertError( + SleighPackage::eINSTANCE.getassignSym(), + Diagnostic.LINKING_DIAGNOSTIC, + "Couldn't resolve reference to lhsvarnode 'tom'." + ) + model.assertError( + SleighPackage::eINSTANCE.getexprSym(), + Diagnostic.LINKING_DIAGNOSTIC, + "Couldn't resolve reference to EObject 'do'." + ) + } +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/SleighParsingTest.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/SleighParsingTest.xtend new file mode 100644 index 0000000000..21c62985f6 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/SleighParsingTest.xtend @@ -0,0 +1,194 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.tests + +import com.google.inject.Inject +import org.eclipse.xtext.testing.InjectWith +import org.eclipse.xtext.testing.extensions.InjectionExtension +import org.eclipse.xtext.testing.util.ParseHelper +import org.eclipse.xtext.testing.validation.ValidationTestHelper +import ghidra.xtext.sleigh.sleigh.Model +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.^extension.ExtendWith + +@ExtendWith(InjectionExtension) +@InjectWith(SleighInjectorProvider) +class SleighParsingTest { + + @Inject + ParseHelper parseHelper + + @Inject extension ValidationTestHelper + + @Test def void testEndian() { + var model = parseHelper.parse(''' + define endian= big; + ''') + model.assertNoErrors + + model = parseHelper.parse(''' + define endian= little; + ''') + model.assertNoErrors + + + model = parseHelper.parse(''' + define endian= little; + ''') + + } + + @Test def void macroUse() { + var model = parseHelper.parse(''' + define space register size=2 type=register_space wordsize=1 default; + define register offset=0 size=1 [ Z C N V + @if ENDIAN == "little" + EF + @else + BF + @endif + ]; + + define register offset=100 size=1 [ contReg + @if defined(ENDIAN) + ifReg + @endif + ]; + + define token instr(16) + op = (0,15) + @if ENDIAN == "big" + reg = (0,1) + @endif + cc = (2,3) + @else + ; + + define context contReg + contFlag = (0,0) + ; + + attach variables [ reg ] [ Z C N V + @if ENDIAN == "little" + EF + @else + BF + @endif + ]; + + macro a(arg1,arg2) { + local foo = 1; + @if defined(ENDIAN) + foo = (~foo & foo | foo) << foo; + @endif + Z = 1; + arg1 = 3; + arg2 = foo; + } + + CC: "ne" is cc=0x1 { local tmp = !Z; C = 1; tmp = C; export tmp; } + CC: "lt" is cc=0x2 { local tmp = N != V; export tmp; } + CC: "lt" is cc=0x2 { local tmp:1 = N != V; export tmp; } + CC: "lt" is cc=0x2 { tmp:1 = N != V; export tmp; } + CC: "lt" is cc=0x2 { tmp:1 = N != V; export tmp; tmp = 1; } + + :mov reg,N,op is op=0 & CC & N & reg & op & op=1 + { tmp:1 = CC; + @if defined(ENDIAN) + reg = tmp; + @endif + } + + Dest: loc is op=0 [ loc = inst_next; ] { export loc; } + :jmp Dest is Dest { call Dest; } + + :set reg is contFlag=0 & op=0 [ contFlag = 1; ] {} + ''') + model.assertNoErrors + } + + @Test def void testWith() { + var model = parseHelper.parse(''' + define space register size=2 type=register_space wordsize=1 default; + define register offset=0 size=1 [ Z C N V + @if ENDIAN == "little" + EF + @else + BF + @endif + ]; + + define register offset=100 size=1 [ contReg + @if defined(ENDIAN) + ifReg + @endif + ]; + + define token instr(16) + op = (0,15) + @if ENDIAN == "big" + reg = (0,1) + @endif + cc = (2,3) + @else + ; + + define context contReg + contFlag = (0,0) + ; + + attach variables [ reg ] [ Z C N V + @if ENDIAN == "little" + EF + @else + BF + @endif + ]; + + macro a(arg1,arg2) { + local foo = 1; + @if defined(ENDIAN) + foo = (~foo & foo | foo) << foo; + @endif + Z = 1; + arg1 = 3; + arg2 = foo; + } + + with CC : cc=0x1 { + CC: "ne" is cc=0x1 { local tmp = !Z; C = 1; tmp = C; export tmp; } + CC: "lt" is cc=0x2 { local tmp = N != V; export tmp; } + CC: "lt" is cc=0x2 { local tmp:1 = N != V; export tmp; } + CC: "lt" is cc=0x2 { tmp:1 = N != V; export tmp; } + CC: "lt" is cc=0x2 { tmp:1 = N != V; export tmp; tmp = 1; } + } + + :mov reg,N,op is op=0 & CC & N & reg & op & op=1 + { tmp:1 = CC; + @if defined(ENDIAN) + reg = tmp; + @endif + } + + Dest: loc is op=0 [ loc = inst_next; ] { export loc; } + :jmp Dest is Dest { call Dest; } + + :set reg is contFlag=0 & op=0 [ contFlag = 1; ] {} + ''') + model.assertNoErrors + } +} + diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/SleighScopeTest.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/SleighScopeTest.xtend new file mode 100644 index 0000000000..ab66999b90 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.tests/src/ghidra/xtext/sleigh/tests/SleighScopeTest.xtend @@ -0,0 +1,301 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.tests + +import com.google.inject.Inject +import com.google.inject.Provider +import org.eclipse.emf.ecore.util.EcoreUtil +import org.eclipse.xtext.diagnostics.Diagnostic +import org.eclipse.xtext.resource.XtextResourceSet +import org.eclipse.xtext.testing.InjectWith +import org.eclipse.xtext.testing.extensions.InjectionExtension +import org.eclipse.xtext.testing.util.ParseHelper +import org.eclipse.xtext.testing.validation.ValidationTestHelper +import ghidra.xtext.sleigh.sleigh.Model +import ghidra.xtext.sleigh.sleigh.SleighPackage +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.^extension.ExtendWith + +@ExtendWith(InjectionExtension) +@InjectWith(SleighInjectorProvider) +class SleighScopeTest { + + @Inject extension ParseHelper parser + @Inject extension ValidationTestHelper validationTester + + @Inject + private Provider resourceSetProvider; + +// Sample to use for testing +// var model = ''' +// define space register size=2 type=register_space wordsize=1 default; +// define register offset=0 size=1 [ Z C N V ]; +// +// define token instr(16) +// op = (0,15) +// reg = (0,1) +// cc = (2,3) +// ; +// +// attach variables [ reg ] [ Z C N V ]; +// +// macro a() { +// Z = 1; +// } +// +// CC: "ne" is cc=0x1 { local tmp = !Z; C = 1; tmp = C; export tmp; } +// CC: "lt" is cc=0x2 { local tmp = N != V; export tmp; } +// CC: "lt" is cc=0x2 { local tmp:1 = N != V; export tmp; } +// CC: "lt" is cc=0x2 { tmp:1 = N != V; export tmp; } +// CC: "lt" is cc=0x2 { tmp:1 = N != V; export tmp; tmp = 1; } +// +// :mov reg,N is op=0 & CC & N & reg { tmp:1 = CC; reg = tmp; } +// '''.parse + + @Test def void testReferences() { + // tmp should not resolve + var model = ''' + define space register size=2 type=register_space wordsize=1 default; + define register offset=0 size=1 [ Z C N V ]; + + define token instr(16) + op = (0,15) + reg = (0,1) + cc = (2,3) + ; + + attach variables [ reg ] [ Z C N V ]; + + :mov reg,N is op=0 & C & N & reg { tmp:1 = 1; } + + :mov reg,N is op=0 & C & N & reg { tmp = C; } + '''.parse + + assertError(model, + SleighPackage::eINSTANCE.getassignSym(), + Diagnostic.LINKING_DIAGNOSTIC, 311, 3, + "Couldn't resolve reference to lhsvarnode 'tmp'." + ) + + // tmp should not resolve + model = ''' + define space register size=2 type=register_space wordsize=1 default; + define register offset=0 size=1 [ Z C N V ]; + + define token instr(16) + op = (0,15) + reg = (0,1) + cc = (2,3) + ; + + attach variables [ reg ] [ Z C N V ]; + + :mov reg,N is op=0 & C & N & reg { tmp:1 = 1; } + + :mov reg,N is op=0 & C & N & reg { reg = tmp; } + '''.parse + + assertError(model, + SleighPackage::eINSTANCE.getexprSym(), + Diagnostic.LINKING_DIAGNOSTIC, 314, 3, + "Couldn't resolve reference to EObject 'tmp'." + ) + } + + @Test def void testMacroReferences() { + var model = ''' + define space register size=2 type=register_space wordsize=1 default; + define register offset=0 size=1 [ Z C N V ]; + + define token instr(16) + op = (0,15) + reg = (0,1) + cc = (2,3) + ; + + attach variables [ reg ] [ Z C N V ]; + + macro macro_a(arg1,arg2) { + local foo = 1; + foo = (~foo & foo | foo) << foo; + Z = 1; + arg1 = 3; + arg2 = foo; + } + + :mov reg,N,op is op=0 & N & reg & op & op=1 { + tmp:1 = 1; + tmp2:1 = reg(4); + macro_a(reg,tmp); + } + '''.parse + model.assertNoErrors + } + + + @Test def void testBadAliasReferences() { + var model = ''' + define space register size=2 type=register_space wordsize=1 default; + + define token instr(16) + op = (0,15) + reg = (0,1) + cc = (2,3) + ; + + :mov AliasRef is op=0 & AliasRef [ AliasRef = inst_next; ] { tmp:1 = AliasRef; } #AliasRef in constraint + '''.parse + + assertError(model, + SleighPackage::eINSTANCE.getconstraint(), + Diagnostic.LINKING_DIAGNOSTIC, 164,8, + "Couldn't resolve reference to EObject 'AliasRef'." + ) + + model = ''' + define space register size=2 type=register_space wordsize=1 default; + + define token instr(16) + op = (0,15) + reg = (0,1) + cc = (2,3) + ; + + AliasRef: "empty" is op=0 {} + + :mov AliasRef is op=0 [ AliasRef = inst_next; ] { tmp:1 = AliasRef; } #AliasRef in constraint + '''.parse + + var references = EcoreUtil.UsageCrossReferencer.find(model.elements) + + references.forEach[p1, p2 | + System.out.println(p1 + " -> " + p2) + ] + } + + @Test def void testAliasRefOverrid() { + + var XtextResourceSet resourceSet = resourceSetProvider.get(); + + parser.parse("REGGsrc: reg is reg { export reg; } ", resourceSet) + + var model = parser.parse(''' + define space register size=2 type=register_space wordsize=1 default; + define register offset=0 size=1 [ Z C N V ]; + define register offset=100 size=1 [ contReg ]; + + define token instr(16) + op = (0,15) + reg = (0,1) + cc = (2,3) + ; + + define context contReg + contFlag = (0,0) + ; + + attach variables [ reg ] [ Z C N V ]; + + macro a(arg1,arg2) { + local foo = 1; + foo = (~foo & foo | foo) << foo; + Z = 1; + arg1 = 3; + arg2 = foo; + } + + CC: "ne" is cc=0x1 { local tmp = !Z; C = 1; tmp = C; export tmp; } + CC: "lt" is cc=0x2 { local tmp = N != V; export tmp; } + CC: "lt" is cc=0x2 { local tmp:1 = N != V; export tmp; } + CC: "lt" is cc=0x2 { tmp:1 = N != V; export tmp; } + CC: "lt" is cc=0x2 { tmp:1 = N != V; export tmp; tmp = 1; } + + :mov reg,N,op is op=0 & CC & N & reg & op & op=1 { tmp:1 = CC; reg = tmp; } + + :mov REGGsrc,N,op is op=0 & CC & N & reg & REGGsrc & op & op=1 { REGGsrc = op; } + + Dest: loc is op=0 [ loc = inst_next; ] { export loc; } + :jmp Dest is Dest { call Dest; } + + :set reg is contFlag=0 & op=0 [ contFlag = 1; ] {} + ''', resourceSet) + model.assertNoErrors; + + var references = EcoreUtil.UsageCrossReferencer.find(model.elements) + + references.forEach[p1, p2 | + System.out.println(p1 + " -> " + p2) + ] + + +// +// model.eAllContents.filter[elem | +// elem instanceof SUBTABLESYM +// ].forEach[ +// elem | var list = elem.eCrossReferences; System.out.println(list) +// ] +// +// // now need to verify xref of reg,N,op are not aliases in the match or pcode +// var refs = model.eCrossReferences; +// refs.forEach[ +// element | println(element); +// ] +// + // need to verify that an alias in the context var stays as an alias var + // unless it is also a global symbol + } + + @Test def void testContextAliasRef() { + + var XtextResourceSet resourceSet = resourceSetProvider.get(); + + parser.parse("REGGsrc: reg is reg { export reg; } ", resourceSet) + + var model = parser.parse(''' + define space register size=2 type=register_space wordsize=1 default; + define register offset=0 size=1 [ Z C N V ]; + define register offset=100 size=1 [ contReg ]; + + define token instr(16) + op = (0,15) + reg = (0,1) + cc = (2,3) + ; + + define context contReg + contFlag = (0,0) + cont2 = (1,1) + ; + + attach variables [ reg ] [ Z C N V ]; + + + #:mov reg,N,op,vis is op=0 & N & reg & op & op=1 [ vis = op << 20; ] { tmp:1 = vis reg = tmp; } + + #:mov reg,N,op,vis is op=0 & N & reg & op & op=1 [ vis = op << 20; contFlag=op; cont2=contFlag; ] { tmp:1 = vis; reg = tmp; } + + :mov reg,vis is op=0 & reg [ vis = 20; contFlag=vis; ] { tmp:1 = vis; reg = tmp; } + + ''', resourceSet) + model.assertNoErrors; + + var references = EcoreUtil.UsageCrossReferencer.find(model.elements) + + references.forEach[p1, p2 | + System.out.println(p1 + " -> " + p2) + ] + } +} \ No newline at end of file diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui.tests/META-INF/MANIFEST.MF b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui.tests/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..f700b7eb73 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui.tests/META-INF/MANIFEST.MF @@ -0,0 +1,18 @@ +Manifest-Version: 1.0 +Automatic-Module-Name: ghidra.xtext.sleigh.ui.tests +Bundle-ManifestVersion: 2 +Bundle-Name: ghidra.xtext.sleigh.ui.tests +Bundle-Vendor: My Company +Bundle-Version: 1.0.0.qualifier +Bundle-SymbolicName: ghidra.xtext.sleigh.ui.tests; singleton:=true +Bundle-ActivationPolicy: lazy +Require-Bundle: ghidra.xtext.sleigh.ui, + org.junit.jupiter.api;bundle-version="[5.0.0,6.0.0)", + org.eclipse.xtext.testing, + org.eclipse.xtext.xbase.testing, + org.eclipse.xtext.junit4, + org.eclipse.xtext.xbase.junit, + org.eclipse.core.runtime, + org.eclipse.ui.workbench;resolution:=optional +Bundle-RequiredExecutionEnvironment: JavaSE-11 +Export-Package: ghidra.xtext.sleigh.ui.tests;x-internal=true diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui.tests/build.properties b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui.tests/build.properties new file mode 100644 index 0000000000..5c6bbf99f0 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui.tests/build.properties @@ -0,0 +1,6 @@ +source.. = src/,\ + src-gen/,\ + xtend-gen/ +bin.includes = .,\ + META-INF/ +bin.excludes = **/*.xtend diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/META-INF/MANIFEST.MF b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..1fa442904a --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/META-INF/MANIFEST.MF @@ -0,0 +1,26 @@ +Manifest-Version: 1.0 +Automatic-Module-Name: ghidra.xtext.sleigh.ui +Bundle-ManifestVersion: 2 +Bundle-Name: ghidra.xtext.sleigh.ui +Bundle-Vendor: My Company +Bundle-Version: 1.0.0.qualifier +Bundle-SymbolicName: ghidra.xtext.sleigh.ui; singleton:=true +Bundle-ActivationPolicy: lazy +Require-Bundle: ghidra.xtext.sleigh, + ghidra.xtext.sleigh.ide, + org.eclipse.xtext.ui, + org.eclipse.xtext.ui.shared, + org.eclipse.xtext.ui.codetemplates.ui, + org.eclipse.ui.editors;bundle-version="3.5.0", + org.eclipse.ui.ide;bundle-version="3.5.0", + org.eclipse.ui, + org.eclipse.compare, + org.eclipse.xtext.builder, + org.eclipse.xtext.xbase.lib;bundle-version="2.14.0", + org.eclipse.xtend.lib;bundle-version="2.14.0";resolution:=optional +Import-Package: org.apache.log4j +Bundle-RequiredExecutionEnvironment: JavaSE-11 +Export-Package: ghidra.xtext.sleigh.ui.internal, + ghidra.xtext.sleigh.ui.contentassist, + ghidra.xtext.sleigh.ui.quickfix +Bundle-Activator: ghidra.xtext.sleigh.ui.internal.SleighActivator diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/build.properties b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/build.properties new file mode 100644 index 0000000000..323f56c513 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/build.properties @@ -0,0 +1,7 @@ +source.. = src/,\ + src-gen/,\ + xtend-gen/ +bin.includes = .,\ + META-INF/,\ + plugin.xml +bin.excludes = **/*.xtend diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/plugin.xml b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/plugin.xml new file mode 100644 index 0000000000..7ab07ef916 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/plugin.xml @@ -0,0 +1,513 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/ConsoleLineTracker.java b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/ConsoleLineTracker.java new file mode 100644 index 0000000000..1a1a035b80 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/ConsoleLineTracker.java @@ -0,0 +1,43 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.ui; + +import org.eclipse.debug.core.model.IProcess; +import org.eclipse.debug.ui.console.IConsole; +import org.eclipse.debug.ui.console.IConsoleLineTracker; +import org.eclipse.jface.text.IRegion; + +public class ConsoleLineTracker implements IConsoleLineTracker { + + @Override + public void init(IConsole console) { + IProcess process = console.getProcess(); + + System.out.println(process.getLabel()); + } + + @Override + public void lineAppended(IRegion line) { + System.out.println(line.toString()); + } + + @Override + public void dispose() { + // TODO Auto-generated method stub + + } + +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighEObjectHoverProvider.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighEObjectHoverProvider.xtend new file mode 100644 index 0000000000..bee9abe17f --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighEObjectHoverProvider.xtend @@ -0,0 +1,202 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.ui + +import ghidra.xtext.sleigh.sleigh.DefineSym +import ghidra.xtext.sleigh.sleigh.SUBTABLESYM +import ghidra.xtext.sleigh.sleigh.aliasSym +import ghidra.xtext.sleigh.sleigh.integerValue +import ghidra.xtext.sleigh.sleigh.macroDefine +import ghidra.xtext.sleigh.sleigh.printpiece +import ghidra.xtext.sleigh.sleigh.subconstructor +import java.math.BigInteger +import org.eclipse.emf.common.util.EList +import org.eclipse.emf.ecore.EObject +import org.eclipse.xtext.conversion.ValueConverterException +import org.eclipse.xtext.nodemodel.util.NodeModelUtils +import org.eclipse.xtext.ui.editor.hover.html.DefaultEObjectHoverProvider +import org.eclipse.xtext.util.Strings + +class SleighEObjectHoverProvider extends DefaultEObjectHoverProvider { + + EObject model + + override boolean hasHover(EObject o) { + if (o instanceof integerValue) { return true; } + return super.hasHover(o) + } + + override String getFirstLine(EObject o) { + var label = getLabel(o); + var str = o.eClass().getName(); + if (label == null) { + str += ""; + } else { + str = " " + label + ""; + } + return str; + } + + override String getLabel(EObject element) { + switch element { + DefineSym: + return " " + element.name + "" + default: + return super.getLabel(element) + } + } + + override String getDocumentation(EObject element) { + switch element { + DefineSym: + return getDefineSymText(element) + SUBTABLESYM: + return getSubTableText(element) + aliasSym: + return getSubTableText(element) + integerValue: + return getIntegerFormats(element) + default: + return super.getDocumentation(element) + } + } + + def getIntegerFormats(integerValue value) { + var retStr = ""; + var valueOf = getIntValue(value) + + retStr = retStr + "

" + "0b" + valueOf.toString(2) + "

\n" + retStr = retStr + "

" + "0x" + valueOf.toString(16) + "

\n" + retStr = retStr + "

" + " " + valueOf.toString(10) + "

\n" + + if (retStr.length == 0) { + return value.value; + } + return retStr; + } + + def getIntValue(integerValue value) { + var parseString = value.value; + var string = value.value + if (Strings.isEmpty(parseString)) + throw new NumberFormatException("Couldn't convert empty string to an int value."); + try { + var radix = 10; + if (parseString.startsWith("0x") || parseString.startsWith("0X")) { + parseString = string.substring(2); + radix=16; + } + if (parseString.startsWith("0b") || parseString.startsWith("0B")) { + parseString = string.substring(2); + radix=2; + } + return new BigInteger(parseString,radix); + } catch (NumberFormatException e) { + throw new NumberFormatException("Couldn't convert '" + string + "' to a BigInteger value."); + } + } + + def getDefineSymText(DefineSym element) { + var retStr = ""; + model = element.eResource.contents.get(0); + var macDefs = model.eAllContents.filter(typeof(macroDefine)); + var len = ""; + while (macDefs.hasNext) { + var next = macDefs.next; + if (next.defineType.equals("@define")) { + if (next.definename.name == element.name) { + retStr = retStr + "

" + next.value + "

\n" + } + } + } + if (retStr.length == 0) { + return element.name; + } + return retStr; + } + + def getSubTableText(SUBTABLESYM element) { + var retStr = ""; + model = element.eResource.contents.get(0); + var subs = model.eAllContents.filter(typeof(subconstructor)); + var len = ""; + while (subs.hasNext) { + var next = subs.next; + if (next.tableName.name == element.name) { + retStr = retStr + "

" + formatString(next.print.printpieces) + + " is " + formatConstraintString(next.match.constraints) + "

\n" + } + } + if (retStr.length == 0) { + return element.name; + } + return retStr; + } + + def getSubTableText(aliasSym element) { + var retStr = ""; + model = element.eResource.contents.get(0); + var subs = model.eAllContents.filter(typeof(subconstructor)); + while (subs.hasNext) { + var next = subs.next; + if (next.tableName.name == element.sym) { + retStr = retStr + "

" + formatString(next.print.printpieces) + + " is " + formatConstraintString(next.match.constraints) + "

\n" + } + } + if (retStr.length != 0) { + return retStr; + } + var macDefs = model.eAllContents.filter(typeof(macroDefine)); + while (macDefs.hasNext) { + var next = macDefs.next; + if (next.defineType.equals("@define")) { + if (next.definename.name == element.sym) { + retStr = retStr + "

" + next.value + "

\n" + } + } + } + if (retStr.length == 0) { + return element.sym; + } + return retStr; + } + + def String formatString(EList list) { + var str = ""; + var iter = list.iterator; + while (iter.hasNext) { + var piece = iter.next; + if (piece.str == null) { + if (piece.sym != null) { + str += piece.sym.sym; + } else { + str = '{empty}' + } + } else { + str += piece.str; + } + } + str += "" + str + } + + def String formatConstraintString(EObject o) { + var node = NodeModelUtils.getNode(o); + return node.text + } + +} \ No newline at end of file diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighHighlightingCalculator.java b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighHighlightingCalculator.java new file mode 100644 index 0000000000..368f30290f --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighHighlightingCalculator.java @@ -0,0 +1,238 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.ui; + +import static org.eclipse.xtext.ui.editor.syntaxcoloring.DefaultHighlightingConfiguration.COMMENT_ID; +import static org.eclipse.xtext.ui.editor.syntaxcoloring.DefaultHighlightingConfiguration.KEYWORD_ID; +import static ghidra.xtext.sleigh.ui.SleighHighlightingConfiguration.CONTEXTFIELD; +import static ghidra.xtext.sleigh.ui.SleighHighlightingConfiguration.LOCAL; +import static ghidra.xtext.sleigh.ui.SleighHighlightingConfiguration.PRINTPIECE; +import static ghidra.xtext.sleigh.ui.SleighHighlightingConfiguration.SUBTABLE; +import static ghidra.xtext.sleigh.ui.SleighHighlightingConfiguration.TOKENFIELD; +import static ghidra.xtext.sleigh.ui.SleighHighlightingConfiguration.VARIABLE; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.xtext.CrossReference; +import org.eclipse.xtext.impl.TerminalRuleImpl; +import org.eclipse.xtext.nodemodel.BidiIterator; +import org.eclipse.xtext.nodemodel.BidiTreeIterator; +import org.eclipse.xtext.nodemodel.INode; +import org.eclipse.xtext.nodemodel.impl.HiddenLeafNode; +import org.eclipse.xtext.nodemodel.impl.LeafNode; +import org.eclipse.xtext.resource.XtextResource; +import org.eclipse.xtext.util.CancelIndicator; +import org.eclipse.xtext.ide.editor.syntaxcoloring.DefaultSemanticHighlightingCalculator; +import org.eclipse.xtext.ide.editor.syntaxcoloring.IHighlightedPositionAcceptor; + +import ghidra.xtext.sleigh.sleigh.CONTEXTSYM; +import ghidra.xtext.sleigh.sleigh.LOCALSYM; +import ghidra.xtext.sleigh.sleigh.SUBTABLESYM; +import ghidra.xtext.sleigh.sleigh.TOKENSYM; +import ghidra.xtext.sleigh.sleigh.VARSYM; +import ghidra.xtext.sleigh.sleigh.aliasSym; +import ghidra.xtext.sleigh.sleigh.anysymbol; +import ghidra.xtext.sleigh.sleigh.assignSym; +import ghidra.xtext.sleigh.sleigh.constraint; +import ghidra.xtext.sleigh.sleigh.exprSym; +import ghidra.xtext.sleigh.sleigh.fielddef; +import ghidra.xtext.sleigh.sleigh.isKeyword; +import ghidra.xtext.sleigh.sleigh.pexprSym; +import ghidra.xtext.sleigh.sleigh.printpiece; +import ghidra.xtext.sleigh.sleigh.valuepart; +import ghidra.xtext.sleigh.sleigh.varpart; + +public class SleighHighlightingCalculator extends DefaultSemanticHighlightingCalculator { + + @Override + public void provideHighlightingFor(XtextResource resource, IHighlightedPositionAcceptor acceptor, + CancelIndicator cancelIndicator) { + + if (resource == null || resource.getParseResult() == null) + return; + + super.provideHighlightingFor(resource, acceptor, cancelIndicator); + + INode root = resource.getParseResult().getRootNode(); + BidiTreeIterator it = root.getAsTreeIterable().iterator(); + while (it.hasNext()) { + INode node = it.next(); + EObject grammarElement = node.getGrammarElement(); + EObject semanticElement = node.getSemanticElement(); + printNodeInfo(node, grammarElement, semanticElement); + +// if (node instanceof CompositeNodeWithSemanticElement +// && semanticElement instanceof contextfielddef) { +// setStyles(acceptor, it, CONTEXTFIELD, "GROUP", CONTEXTFIELD); +// setStyles(acceptor, node.getAsTreeIterable().reverse() +// .iterator(), null, CONTEXTFIELD); +// } else + if (semanticElement instanceof VARSYM) { + setNodeStyle(acceptor, node, VARIABLE); +// } else if (grammarElement instanceof Keyword) { +// setStyles(acceptor, it, KEYWORD_ID); + } else if (semanticElement instanceof CONTEXTSYM) { + setNodeStyle(acceptor, node, CONTEXTFIELD); + } else if (semanticElement instanceof LOCALSYM) { + setNodeStyle(acceptor, node, LOCAL); + } else if (semanticElement instanceof TOKENSYM) { + setNodeStyle(acceptor, node, TOKENFIELD); + } else if (semanticElement instanceof fielddef) { + setNodeStyle(acceptor, node, TOKENFIELD); + } else if (semanticElement instanceof anysymbol) { + setStyle(acceptor, node, semanticElement); + } else if (grammarElement instanceof CrossReference) { + CrossReference defn = (CrossReference) grammarElement; + EObject semElem = semanticElement; + if (semElem instanceof varpart || semElem instanceof valuepart) { + setNodeStyle(acceptor, node, VARIABLE); + } else if (semElem instanceof LOCALSYM) { + setNodeStyle(acceptor, node, LOCAL); + } else if (semElem instanceof exprSym) { + exprSym sym = (exprSym) semElem; + EObject vnode = sym.getVnode(); + if (vnode != null) { + setStyle(acceptor, node, vnode); + } else { + // System.out.println(" exprSym--" + semElem); + } + } else if (semElem instanceof assignSym) { + // TODO: Causing a lazy linking error sometimes + // Possibly something wrong with the grammer for [lhsvarnode] + // ERROR org.eclipse.xtext.linking.lazy.LazyLinkingResource - An element of type ghidra.xtext.sleigh.sleigh.impl.aliasSymImpl is not assignable to the reference assignSym.symref + assignSym sym = (assignSym) semElem; + EObject vnode = sym.getSymref(); + if (vnode != null) { + setStyle(acceptor, node, vnode); + } else { + // System.out.println(" exprSym--" + semElem); + } + } + else if (semElem instanceof constraint) { + constraint sym = (constraint) semElem; + EObject vnode = sym.getSym(); + if (vnode != null) { + setStyle(acceptor, node, vnode); + } else { + // System.out.println(" exprSym--" + semElem); + } + } + else if (semElem instanceof pexprSym) { + pexprSym sym = (pexprSym) semElem; + EObject vnode = sym.getSym(); + if (vnode != null) { + setStyle(acceptor, node, vnode); + } else { + // System.out.println(" exprSym--" + semElem); + } + } + else if (semElem instanceof aliasSym) { + System.out.println(" semElem="+semElem); + } + else { + // System.out.println(" semElem="+semElem); + } + } else if (semanticElement instanceof isKeyword) { + setStyles(acceptor, it, KEYWORD_ID); + } else if (semanticElement instanceof aliasSym && semanticElement.eContainer() instanceof printpiece) { + setStyles(acceptor, it, PRINTPIECE); + } else if (semanticElement instanceof printpiece) { + setStyles(acceptor, it, PRINTPIECE); + } else if (node instanceof HiddenLeafNode + && grammarElement instanceof TerminalRuleImpl) { + processHiddenNode(acceptor, (HiddenLeafNode) node); + } + + + } + } + + private void setStyle(IHighlightedPositionAcceptor acceptor, INode n, EObject vnode) { + if (vnode instanceof LOCALSYM) { + setNodeStyle(acceptor, n, LOCAL); + } else if (vnode instanceof VARSYM) { + setNodeStyle(acceptor, n, VARIABLE); + } else if (vnode instanceof SUBTABLESYM) { + setNodeStyle(acceptor, n, SUBTABLE); + } else if (vnode instanceof fielddef) { + setNodeStyle(acceptor, n, TOKENFIELD); + } else { + // System.out.println(" symtype = " + vnode); + } + } + + private void setNodeStyle(IHighlightedPositionAcceptor acceptor, INode n, String styleName) { + acceptor.addPosition(n.getOffset(), n.getLength(), styleName); + } + + private void printNodeInfo(INode node, EObject grammarElement, + EObject semanticElement) { + String grammar = ""; + String semantic = ""; + + if (grammarElement != null) { + grammar = grammarElement.getClass().getSimpleName(); + } + if (semanticElement != null) { + semantic = semanticElement.getClass().getSimpleName(); + } + if (grammarElement instanceof TerminalRuleImpl) return; + if (! (node instanceof LeafNode)) return; +// System.err.println( "Node: " + node.getClass().getSimpleName() + +// "\t\t\t\t" + grammar + " =\t\t\t\t" + semantic + "\"" + node.getText() + "\""); + } + + void setStyles(IHighlightedPositionAcceptor acceptor, + BidiIterator it, String... styles) { + for (String s : styles) { + if (!it.hasNext()) + return; + INode n = skipWhiteSpace(acceptor, it); + if (n != null && s != null) + acceptor.addPosition(n.getOffset(), n.getLength(), s); + } + } + + INode skipWhiteSpace(IHighlightedPositionAcceptor acceptor, + BidiIterator it) { + INode n = null; + while (it.hasNext() + && (n = it.next()).getClass() == HiddenLeafNode.class) + processHiddenNode(acceptor, (HiddenLeafNode) n); + return n; + } + + INode skipWhiteSpaceBackwards(IHighlightedPositionAcceptor acceptor, + BidiIterator it) { + INode n = null; + while (it.hasPrevious() + && (n = it.previous()).getClass() == HiddenLeafNode.class) + processHiddenNode(acceptor, (HiddenLeafNode) n); + return n; + } + + void processHiddenNode(IHighlightedPositionAcceptor acceptor, + HiddenLeafNode node) { + if (node.getGrammarElement() instanceof TerminalRuleImpl) { + TerminalRuleImpl ge = (TerminalRuleImpl) node.getGrammarElement(); + String name = ge.getName(); + if (name.equalsIgnoreCase("PDL_COMMENT") || name.equalsIgnoreCase("ML_COMMENT") || name.equalsIgnoreCase("SL_COMMENT")) { + acceptor.addPosition(node.getOffset(), node.getLength(), COMMENT_ID); + } + } + + } + +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighHighlightingConfiguration.java b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighHighlightingConfiguration.java new file mode 100644 index 0000000000..eb1d54dac4 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighHighlightingConfiguration.java @@ -0,0 +1,61 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.ui; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.xtext.ui.editor.syntaxcoloring.DefaultHighlightingConfiguration; +import org.eclipse.xtext.ui.editor.syntaxcoloring.IHighlightingConfigurationAcceptor; +import org.eclipse.xtext.ui.editor.utils.TextStyle; + +public class SleighHighlightingConfiguration extends DefaultHighlightingConfiguration { + // provide an id string for the highlighting calculator + public static final String CONTEXTFIELD = "Context Field"; + public static final String TOKENFIELD = "Token Field"; + public static final String SYMBOL = "Symbol"; + public static final String VARIABLE = "Variable"; + public static final String ATTACHEDSYM = "Attached Symbol"; + public static final String PRINTPIECE = "Print Piece"; + public static final String LOCAL = "Local Symbol"; + public static final String SUBTABLE = "SubTable"; + + public void configure(IHighlightingConfigurationAcceptor acceptor) { + super.configure(acceptor); + addType(acceptor, CONTEXTFIELD, 50, 50, 0, SWT.ITALIC); + addType(acceptor, TOKENFIELD, 50, 50, 0, SWT.NORMAL); + addType(acceptor, SYMBOL, 50, 50, 50, TextStyle.DEFAULT_FONT_STYLE); + addType(acceptor, VARIABLE, 106, 62, 63, SWT.BOLD); + addType(acceptor, ATTACHEDSYM, 50, 50, 50, SWT.BOLD); + addType(acceptor, PRINTPIECE, 0,0,255, SWT.BOLD); + addType(acceptor, LOCAL, 40,40,40, SWT.ITALIC); + addType(acceptor, SUBTABLE, 192, 82, 5, SWT.NORMAL); + } + + public void addType(IHighlightingConfigurationAcceptor acceptor, String s, + int r, int g, int b, int style) { + addType(acceptor, s, new RGB(r,g,b), style); + } + + public void addType(IHighlightingConfigurationAcceptor acceptor, String s, + RGB rgb, int style) { + TextStyle textStyle = new TextStyle(); + textStyle.setBackgroundColor(new RGB(255, 255, 255)); + textStyle.setColor(rgb); + textStyle.setStyle(style); + acceptor.acceptDefaultHighlighting(s, s, textStyle); + } + +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighTextEditComposer.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighTextEditComposer.xtend new file mode 100644 index 0000000000..d3deb8a5b0 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighTextEditComposer.xtend @@ -0,0 +1,11 @@ +package ghidra.xtext.sleigh.ui + +import org.eclipse.xtext.resource.SaveOptions +import org.eclipse.xtext.ui.editor.model.edit.DefaultTextEditComposer + +class SleighTextEditComposer extends DefaultTextEditComposer { + + override SaveOptions getSaveOptions() { + return SaveOptions.newBuilder().format().getOptions(); + } +} \ No newline at end of file diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighUiModule.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighUiModule.xtend new file mode 100644 index 0000000000..d7c14006c7 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/SleighUiModule.xtend @@ -0,0 +1,53 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.ui + +import com.google.inject.Binder +import ghidra.xtext.sleigh.ui.labeling.SleighLabelProvider +import org.eclipse.jface.viewers.ILabelProvider +import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor +import org.eclipse.xtext.ide.editor.syntaxcoloring.ISemanticHighlightingCalculator +import org.eclipse.xtext.ui.editor.contentassist.ContentProposalLabelProvider +import org.eclipse.xtext.ui.editor.hover.IEObjectHoverProvider +import org.eclipse.xtext.ui.editor.model.edit.ITextEditComposer +import org.eclipse.xtext.ui.editor.syntaxcoloring.IHighlightingConfiguration + +/** + * Use this class to register components to be used within the Eclipse IDE. + */ +@FinalFieldsConstructor +class SleighUiModule extends AbstractSleighUiModule { + + override void configureContentProposalLabelProvider(Binder binder) { + binder.bind(ILabelProvider).annotatedWith(ContentProposalLabelProvider).to(SleighLabelProvider); + } + + def Class bindIHighlightingConfiguration() { + return SleighHighlightingConfiguration + } + + def Class bindISemanticHighlightingCalculator() { + return SleighHighlightingCalculator + } + + def Class bindIEObjectHoverProvider() { + return SleighEObjectHoverProvider + } + + def Class bindITextEditComposer() { + return SleighTextEditComposer + } +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/contentassist/SleighProposalProvider.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/contentassist/SleighProposalProvider.xtend new file mode 100644 index 0000000000..1850198edf --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/contentassist/SleighProposalProvider.xtend @@ -0,0 +1,24 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.ui.contentassist + + +/** + * See https://www.eclipse.org/Xtext/documentation/304_ide_concepts.html#content-assist + * on how to customize the content assistant. + */ +class SleighProposalProvider extends AbstractSleighProposalProvider { +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/labeling/SleighDescriptionLabelProvider.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/labeling/SleighDescriptionLabelProvider.xtend new file mode 100644 index 0000000000..6e4b038557 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/labeling/SleighDescriptionLabelProvider.xtend @@ -0,0 +1,83 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.ui.labeling + +import com.google.inject.Inject +import org.eclipse.emf.ecore.EObject +import org.eclipse.emf.ecore.resource.ResourceSet +import org.eclipse.xtext.nodemodel.util.NodeModelUtils +import org.eclipse.xtext.resource.IEObjectDescription +import org.eclipse.xtext.resource.IReferenceDescription +import org.eclipse.xtext.ui.label.DefaultDescriptionLabelProvider +import ghidra.xtext.sleigh.sleigh.exportStmt +import ghidra.xtext.sleigh.sleigh.pequation +import ghidra.xtext.sleigh.sleigh.statement + +/** + * Provides labels for IEObjectDescriptions and IResourceDescriptions. + * + * See https://www.eclipse.org/Xtext/documentation/304_ide_concepts.html#label-provider + */ + +/** + * Provides labels for a IEObjectDescriptions and IResourceDescriptions. + * + * see http://www.eclipse.org/Xtext/documentation.html#labelProvider + */ +class SleighDescriptionLabelProvider extends DefaultDescriptionLabelProvider { + + @Inject ResourceSet rdp + + // Labels and icons can be computed like this: + override String getText(Object element) { + var ele = element; + + if (element instanceof IReferenceDescription) { + var o = rdp.getEObject(element.sourceEObjectUri,true); + if (o != null){ + return containerLine(o); + } + return element.EReference.name + } + return super.getText(ele); + } + + def String containerLine(EObject o) { + var c = o; + var text = NodeModelUtils.getNode(o).text + while (c.eContainer != null) { + if (c instanceof pequation) { + return NodeModelUtils.getNode(c).text + } + if (c instanceof statement || + c instanceof exportStmt + ) { + text = NodeModelUtils.getNode(c).text + text = text.trim() + return text + } + c = c.eContainer + } + return text + } + override text(IEObjectDescription ele) { + return super.text(ele); + } + + override image(IEObjectDescription ele) { + ele.EClass.name + '.gif' + } +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/labeling/SleighLabelProvider.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/labeling/SleighLabelProvider.xtend new file mode 100644 index 0000000000..50db77194d --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/labeling/SleighLabelProvider.xtend @@ -0,0 +1,248 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.ui.labeling + +import com.google.inject.Inject +import java.util.Iterator +import org.eclipse.emf.common.util.EList +import org.eclipse.emf.ecore.EObject +import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider +import org.eclipse.jface.viewers.StyledString +import org.eclipse.xtext.naming.IQualifiedNameProvider +import org.eclipse.xtext.naming.QualifiedName +import org.eclipse.xtext.ui.label.DefaultEObjectLabelProvider +import ghidra.xtext.sleigh.sleigh.DefineSym +import ghidra.xtext.sleigh.sleigh.SUBTABLESYM +import ghidra.xtext.sleigh.sleigh.VARSYM +import ghidra.xtext.sleigh.sleigh.baseconstructor +import ghidra.xtext.sleigh.sleigh.constraint +import ghidra.xtext.sleigh.sleigh.constructprint +import ghidra.xtext.sleigh.sleigh.contextfielddef +import ghidra.xtext.sleigh.sleigh.fielddef +import ghidra.xtext.sleigh.sleigh.integerValue +import ghidra.xtext.sleigh.sleigh.macroDefine +import ghidra.xtext.sleigh.sleigh.printpiece +import ghidra.xtext.sleigh.sleigh.subconstructor +import ghidra.xtext.sleigh.sleigh.varattach +import ghidra.xtext.sleigh.sleigh.varnodedef + +import static extension org.eclipse.emf.ecore.util.EcoreUtil.* +import static extension org.eclipse.xtext.EcoreUtil2.* + +/** + * Provides labels for EObjects. + * + * See https://www.eclipse.org/Xtext/documentation/304_ide_concepts.html#label-provider + */ +class SleighLabelProvider extends DefaultEObjectLabelProvider { + @Inject + new(AdapterFactoryLabelProvider delegate) { + super(delegate); + } + + @Inject + private IQualifiedNameProvider nameProvider; + + QualifiedName qn + + EObject model + + Iterator varatt + + def String text(EObject eObject) { + qn = nameProvider.getFullyQualifiedName(eObject); + if(qn == null) { + return getObjectText(eObject); + } + + return qn.toString(); + } + + def String getObjectText(EObject element) { + switch element { + macroDefine: + element.defineType // + element.definename.name + " = " + element.value + VARSYM: + element.name + " : " + getSizeStr((element.eContainer.eContainer as varnodedef).size) + SUBTABLESYM: + element.name + contextfielddef: + element.name + fielddef: + element.name + subconstructor: + doGetText(element.tableName) + ':' + baseconstructor: + ':' + doGetText(element.print) + constructprint: + formatString(element.printpieces) + constraint: + element.eClass.baseName + default: { + //System.out.println(element.class.simpleName) + element.class.simpleName + } + } + } + + String possible; + + def getfielddefText(fielddef element) { + // find all var attaches and display possible names + var len = getVarAttachesForElement(element) + return convertToStyledString('field ' + element.name).append( + " " + len + " " + ' (' + element.start.value + ',' + element.end.value + ')' + + (if(element.isSigned()) ' signed' else ''), StyledString::QUALIFIER_STYLER).append("\n\n" + possible); + } + + def getcontextfielddefText(contextfielddef element) { + // find all var attaches and display possible names + var len = getVarAttachesForElement(element) + // is in a context, put out the name + return convertToStyledString('context ' + element.name).append( + " " + len + " " + ' (' + element.start.value + ',' + element.end.value + ')' + + (if(element.isSigned()) ' signed' else ''), StyledString::QUALIFIER_STYLER).append("\n\n" + possible); + } + + protected def String getVarAttachesForElement(EObject element) { + model = element.eResource.contents.get(0); + varatt = model.eAllContents.filter(typeof(varattach)); + possible = ""; + var len = ""; + while (varatt.hasNext) { + var next = varatt.next; + var vlist = next.valuelist.valuelist.listIterator; + while (vlist.hasNext) { + var v = vlist.next; + if (v.sym.equals(element)) { + var viter = next.vlist.varDefList.iterator; + possible = "attached to: " + while (viter.hasNext) { + var varname = viter.next; + var vref = varname.varpart; + if (vref != null) { + var vdef = vref.getContainerOfType(typeof(varnodedef)); + if (vdef != null) { + var size = vdef.size.value; + len = size; // works even if is a $Define + } + possible = possible + vref.name + " "; + } + } + } + } + } + len + } + + def getDefineSymText(DefineSym element) { + // find all var attaches and display possible names + var retStr = ""; + model = element.eResource.contents.get(0); + var macDefs = model.eAllContents.filter(typeof(macroDefine)); + possible = ""; + var len = ""; + while (macDefs.hasNext) { + var next = macDefs.next; + if (next.defineType.equals("@define")) { + if (next.definename.name == element.name) { + retStr = retStr + next.value + "\r\n" + } + } + } + if (retStr.length == 0) { + return super.doGetText(element); + } + return retStr; + } + + override protected doGetText(Object element) { + if(element == null) return null; + // System.out.println("Label:" + element.class.baseName + " : " + element); + switch element { + macroDefine: + element.defineType // + element.definename.name + " = " + element.value + VARSYM: + element.name + " : " + getSizeStr((element.getContainerOfType(typeof(varnodedef))).size) + SUBTABLESYM: + element.name + contextfielddef: + getcontextfielddefText(element) + fielddef: + getfielddefText(element) + subconstructor: + doGetText(element.tableName) + ':' + baseconstructor: + ':' + doGetText(element.print) + constructprint: + formatString(element.printpieces) + constraint: + doGetText(element.sym) + DefineSym: + getDefineSymText(element) + default: + super.doGetText(element) + } + } + + def getSizeStr(integerValue size) { + if (size.value != null) { + return size.value + } + if (size.sym != null) { + return size.sym.getText + } + return "?" + } + + def getBaseName(Object element) { + element.class.name.substring(element.class.name.lastIndexOf('.') + 1) + } + + def String formatString(EList list) { + var str = ""; + var iter = list.iterator; + while (iter.hasNext) { + var piece = iter.next; + if (piece.str == null) { + if (piece.sym != null) { + str += piece.sym.sym; + } else { + str = '{empty}' + } + } else { + str += piece.str; + } + } + str + } + + override protected doGetImage(Object element) { + // icons are stored in the 'icons' folder of this project. + // when adding such a folder, don't forget to add it to the 'bin.includes' section in the build.properties + switch element { +// fielddef: +// 'F-blue.png' +// contextfielddef: +// 'C-blue.png' +// VARSYM: +// 'F-blue.png' + default: + super.doGetImage(element) + } + } +} + diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/outline/SleighOutlineTreeProvider.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/outline/SleighOutlineTreeProvider.xtend new file mode 100644 index 0000000000..dcb991bea8 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/outline/SleighOutlineTreeProvider.xtend @@ -0,0 +1,82 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.ui.outline + +import java.util.ArrayList +import org.eclipse.emf.ecore.EObject +import org.eclipse.xtext.ui.editor.model.IXtextDocument +import org.eclipse.xtext.ui.editor.outline.IOutlineNode +import org.eclipse.xtext.ui.editor.outline.impl.DefaultOutlineTreeProvider +import org.eclipse.xtext.util.concurrent.IUnitOfWork + +/** + * Customization of the default outline structure. + * + * See https://www.eclipse.org/Xtext/documentation/310_eclipse_support.html#outline + */ +class SleighOutlineTreeProvider extends DefaultOutlineTreeProvider { + + // This controls the size of the outline + // Displaying the outline can be expensive + // TODO: figure out performance issue, possibly carefully + // building the outline based on Sleigh ideas not pure grammer + + override createRoot(IXtextDocument document) { + if (document.numberOfLines < 100) { + super.createRoot(document); + } else { + new IOutlineNode() { + + override getChildren() { + new ArrayList(); + } + + override getFullTextRegion() { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + override getImage() { + return null + } + + override getParent() { + return null + } + + override getSignificantTextRegion() { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + override getText() { + return "suppressed outline" + } + + override hasChildren() { + return false + } + + override getAdapter(Class adapter) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + override readOnly(IUnitOfWork work) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + } + } + } +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/quickfix/SleighQuickfixProvider.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/quickfix/SleighQuickfixProvider.xtend new file mode 100644 index 0000000000..3fb7075042 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh.ui/src/ghidra/xtext/sleigh/ui/quickfix/SleighQuickfixProvider.xtend @@ -0,0 +1,323 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.ui.quickfix + +import org.eclipse.emf.ecore.EObject +import org.eclipse.emf.ecore.util.EcoreUtil +import org.eclipse.xtext.EcoreUtil2 +import org.eclipse.xtext.diagnostics.Diagnostic +import org.eclipse.xtext.resource.XtextResource +import org.eclipse.xtext.ui.editor.quickfix.DefaultQuickfixProvider +import org.eclipse.xtext.ui.editor.quickfix.Fix +import org.eclipse.xtext.ui.editor.quickfix.IssueResolutionAcceptor +import org.eclipse.xtext.util.concurrent.IUnitOfWork +import org.eclipse.xtext.validation.Issue +import ghidra.xtext.sleigh.sleigh.Expression +import ghidra.xtext.sleigh.sleigh.LOCALSYM +import ghidra.xtext.sleigh.sleigh.Model +import ghidra.xtext.sleigh.sleigh.SleighFactory +import ghidra.xtext.sleigh.sleigh.VARSYM +import ghidra.xtext.sleigh.sleigh.constraint +import ghidra.xtext.sleigh.sleigh.constructor +import ghidra.xtext.sleigh.sleigh.exprSym +import ghidra.xtext.sleigh.sleigh.fielddef +import ghidra.xtext.sleigh.sleigh.integerValue +import ghidra.xtext.sleigh.sleigh.lhsvarnode +import ghidra.xtext.sleigh.sleigh.localDefine +import ghidra.xtext.sleigh.sleigh.macroOrPcode +import ghidra.xtext.sleigh.sleigh.statement +import ghidra.xtext.sleigh.sleigh.tokendef +import ghidra.xtext.sleigh.sleigh.varattach +import ghidra.xtext.sleigh.sleigh.varnodedef +import ghidra.xtext.sleigh.sleigh.vnoderef + +import static extension org.eclipse.emf.ecore.util.EcoreUtil.* +import static extension org.eclipse.xtext.EcoreUtil2.* + +/** + * Custom quickfixes. + * + * See https://www.eclipse.org/Xtext/documentation/310_eclipse_support.html#quick-fixes + */ +class SleighQuickfixProvider extends DefaultQuickfixProvider { + + @Fix(Diagnostic::LINKING_DIAGNOSTIC) + def void createMissingVariable(Issue issue, IssueResolutionAcceptor acceptor) { + var message = issue.message; + var to = getToName(message); + var linkName = getLinkName(message); + var sname = macroOrPcode.simpleName.toString(); + switch (to) { + case macroOrPcode.simpleName: + missingPseudoOp(issue, acceptor, to, linkName) + case lhsvarnode.simpleName: + createLocalVarnode(issue, acceptor, to, linkName) + case EObject.simpleName: + missingEObjectLink(issue, acceptor, to, linkName) + } + } + + def missingPseudoOp(Issue issue, IssueResolutionAcceptor acceptor, String to, String linkName) { + acceptor.accept( + issue, + "Create pcodeop '" + linkName + "'", + "Create pcodeop '" + linkName + "'", + "", + [ element, context | + val currentEntity = EcoreUtil2.getContainerOfType(element,constructor) + val model = currentEntity.eContainer as Model + val newdef = SleighFactory::eINSTANCE.createpcodeopdef() => [ + ops.add(SleighFactory::eINSTANCE.createUSEROPSYM() => [ + name = context.xtextDocument.get(issue.offset, issue.length) + ]) + ]; + model.elements.add(model.elements.indexOf(currentEntity), newdef) + ] + ); + } + + def missingEObjectLink(Issue issue, IssueResolutionAcceptor acceptor, String to, String linkName) { + val modificationContext = getModificationContextFactory().createModificationContext(issue); + val xtextDocument = modificationContext.getXtextDocument(); + xtextDocument.readOnly( + new IUnitOfWork.Void() { + + override process(XtextResource state) throws Exception { + var cause = state.getResourceSet().getEObject(issue.getUriToProblem(), false); + if (cause instanceof constraint) { + missingConstraint(issue, acceptor, to, linkName, cause) + missingSubConstructor(issue, acceptor, to, linkName, cause) + } +// switch cause { +// case constraint: +// +// default: { +// var x = cause +// } +// } + } + } + ) + } + + def missingConstraint(Issue issue, IssueResolutionAcceptor acceptor, String to, String linkName, EObject cause) { + acceptor.accept( + issue, + "Create fieldef '" + linkName + "'", + "Create fieldef '" + linkName + "'", + "", + [ element, context | + var root = EcoreUtil2.getRootContainer(cause) as Model; + // find fielddef + var tokendefs = root.getAllContentsOfType(typeof(tokendef)) + if(tokendefs.size <= 0) return; + var tokendef = tokendefs.get(0); + + // if found, put at end + val newfielddef = SleighFactory::eINSTANCE.createfielddef() => [ + name = linkName + // TODO: try to figure out start/end + // TODO: ask start / end + start = SleighFactory.eINSTANCE.createintegerValue() => [ + value = '0'; + ] + end = SleighFactory.eINSTANCE.createintegerValue() => [ + value = '0'; + ] + ]; + // add + tokendef.fields.tokens.add(newfielddef) + ] + ); + } + + def missingSubConstructor(Issue issue, IssueResolutionAcceptor acceptor, String to, String linkName, EObject cause) { + acceptor.accept( + issue, + "Create SubConstruct '" + linkName + "'", + "Create SubConstruct '" + linkName + "'", + "", + [ element, context | + var model = cause.rootContainer as Model; + + var container = EcoreUtil2.getContainerOfType(cause, constructor) + + // create subconstructor template + val sub = SleighFactory::eINSTANCE.createsubconstructor() => [ + tableName = SleighFactory.eINSTANCE.createSUBTABLESYM() => [ + name = linkName; + ] + print = SleighFactory.eINSTANCE.createconstructprint() => [ + var pp = SleighFactory.eINSTANCE.createprintpiece() => [ + str = "" + ] + printpieces.add(pp) + is = SleighFactory.eINSTANCE.createisKeyword() => [] + ] + match = SleighFactory.eINSTANCE.createpequation() => [ + constraints = SleighFactory.eINSTANCE.createconstraint() => [ + isepsilon = true + ] + ] + body = SleighFactory.eINSTANCE.creatertlbody() => [ + unimpl = true + ] + ]; + // add before this instance + model.elements.add(model.elements.indexOf(container), sub) + ] + ); + } + + def createLocalVarnode(Issue issue, IssueResolutionAcceptor acceptor, String to, String linkName) { + acceptor.accept( + issue, + "Create local '" + linkName + "'", + "Create local '" + linkName + "'", + "", + [ element, context | + // find size of first element if it can + val s = findElementSize(element); + if (s == null) { + val newdef = SleighFactory::eINSTANCE.createassignSym() => [ + local = SleighFactory::eINSTANCE.createlocalDefine() => [ + sym = SleighFactory.eINSTANCE.createLOCALSYM() => [ + name = linkName; + ] + ] + ]; + element.replace(newdef); + } else { + val newdef = SleighFactory::eINSTANCE.createassignSym() => [ + local = SleighFactory::eINSTANCE.createlocalDefine() => [ + sym = SleighFactory.eINSTANCE.createLOCALSYM() => [ + name = linkName; + ] + size = SleighFactory.eINSTANCE.createintegerValue() => [ + value = s.value; + sym = s.sym; + ] + ] + ]; + element.replace(newdef); + } + ] + ); + } + + def integerValue findElementSize(EObject element) { + val currentEntity = EcoreUtil2.getContainerOfType(element, statement) + val rhs = currentEntity.rhs; + val s = findSize(rhs); + return s; + } + + var integerValue len; + + def integerValue findSize(Expression rhs) { + len = null; + if (rhs instanceof exprSym) { + return getExprSymLength(rhs); + } + var vlist = rhs.getAllContentsOfType(typeof(exprSym)); + vlist.forEach [ it | + getExprSymLength(it) + ] + return len; + } + + def getExprSymLength(exprSym sym) { + var node = sym.vnode; + switch node { + VARSYM: { + var def = node.getContainerOfType(typeof(varnodedef)); + if (def != null && def.size != null) { + if (len == null) { + len = def.size; + } + } else if (len != def.size) { + len = null; + } + } + fielddef: { + len = findVarAttachLen(node); + } + LOCALSYM: { + var ldef = node.getContainerOfType(typeof(localDefine)); + if (ldef != null && ldef.size != null) { + if (len == null) { + len = ldef.size; + } + } else if (len != ldef.size) { + len = null; + } + } + } + } + + def integerValue findVarAttachLen(fielddef fdef) { + // find all var attaches and display possible names + var model = fdef.eResource.contents.get(0); + var varatt = model.eAllContents.filter(typeof(varattach)); + while (varatt.hasNext) { + var next = varatt.next; + var vlist = next.valuelist.valuelist.listIterator; + while (vlist.hasNext) { + var v = vlist.next; + if (v.sym.equals(fdef)) { + var viter = next.vlist.varDefList.iterator; + while (viter.hasNext) { + var varname = viter.next; + var vref = varname.varpart; + if (vref != null) { + var vdef = vref.getContainerOfType(typeof(varnodedef)); + if (vdef != null) { + var size = vdef.size; + return size; + } + } + } + } + } + + } + return null; + } + + def findVnodeSize(vnoderef ref) { + System.out.println(' printit ' + ref.ID); + } + + def String getLinkName(String str) { + var end = str.lastIndexOf('\'') + var start = str.lastIndexOf('\'', end - 1) + return str.substring(start + 1, end) + } + + def String getToName(String str) { + val refString = "reference to "; + + var index = str.indexOf(refString); + if (index == -1) { + return null; + } + var start = index + refString.length; + var refStr = str.substring(start); + refStr = refStr.substring(0, refStr.indexOf(' ')); + return refStr; + } + +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/.launch/Generate Sleigh (sleigh) Language Infrastructure.launch b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/.launch/Generate Sleigh (sleigh) Language Infrastructure.launch new file mode 100644 index 0000000000..0eef2d27b4 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/.launch/Generate Sleigh (sleigh) Language Infrastructure.launch @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/.launch/Launch Runtime Eclipse.launch b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/.launch/Launch Runtime Eclipse.launch new file mode 100644 index 0000000000..e03e3b4d49 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/.launch/Launch Runtime Eclipse.launch @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/META-INF/MANIFEST.MF b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..9128be7ba4 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/META-INF/MANIFEST.MF @@ -0,0 +1,31 @@ +Manifest-Version: 1.0 +Automatic-Module-Name: ghidra.xtext.sleigh +Bundle-ManifestVersion: 2 +Bundle-Name: ghidra.xtext.sleigh +Bundle-Vendor: My Company +Bundle-Version: 1.0.0.qualifier +Bundle-SymbolicName: ghidra.xtext.sleigh; singleton:=true +Bundle-ActivationPolicy: lazy +Require-Bundle: org.eclipse.xtext, + org.eclipse.xtext.xbase, + org.eclipse.equinox.common;bundle-version="3.5.0", + org.eclipse.emf.ecore, + org.eclipse.xtext.xbase.lib;bundle-version="2.14.0", + org.eclipse.xtext.util, + org.eclipse.emf.common, + org.eclipse.xtend.lib;bundle-version="2.14.0", + org.antlr.runtime;bundle-version="[3.2.0,3.2.1)" +Bundle-RequiredExecutionEnvironment: JavaSE-11 +Export-Package: ghidra.xtext.sleigh.formatting2, + ghidra.xtext.sleigh, + ghidra.xtext.sleigh.sleigh.impl, + ghidra.xtext.sleigh.validation, + ghidra.xtext.sleigh.scoping, + ghidra.xtext.sleigh.sleigh, + ghidra.xtext.sleigh.serializer, + ghidra.xtext.sleigh.parser.antlr.internal, + ghidra.xtext.sleigh.services, + ghidra.xtext.sleigh.sleigh.util, + ghidra.xtext.sleigh.generator, + ghidra.xtext.sleigh.parser.antlr +Import-Package: org.apache.log4j diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/build.properties b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/build.properties new file mode 100644 index 0000000000..18d540bf6c --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/build.properties @@ -0,0 +1,20 @@ +source.. = src/,\ + src-gen/,\ + xtend-gen/ +bin.includes = model/generated/,\ + .,\ + META-INF/,\ + plugin.xml +bin.excludes = **/*.mwe2,\ + **/*.xtend +additional.bundles = org.eclipse.xtext.xbase,\ + org.eclipse.xtext.common.types,\ + org.eclipse.xtext.xtext.generator,\ + org.eclipse.emf.codegen.ecore,\ + org.eclipse.emf.mwe.utils,\ + org.eclipse.emf.mwe2.launch,\ + org.eclipse.emf.mwe2.lib,\ + org.objectweb.asm,\ + org.apache.commons.logging,\ + org.apache.log4j,\ + com.ibm.icu diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/plugin.xml b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/plugin.xml new file mode 100644 index 0000000000..26c699fb0e --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/plugin.xml @@ -0,0 +1,10 @@ + + + + + + + diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/GenerateSleigh.mwe2 b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/GenerateSleigh.mwe2 new file mode 100644 index 0000000000..b23e05b85b --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/GenerateSleigh.mwe2 @@ -0,0 +1,58 @@ +module ghidra.xtext.sleigh.GenerateSleigh + +import org.eclipse.xtext.xtext.generator.* +import org.eclipse.xtext.xtext.generator.model.project.* + +var rootPath = ".." + +Workflow { + + component = XtextGenerator { + configuration = { + project = StandardProjectConfig { + baseName = "ghidra.xtext.sleigh" + rootPath = rootPath + runtimeTest = { + enabled = true + } + eclipsePlugin = { + enabled = true + } + eclipsePluginTest = { + enabled = true + } + createEclipseMetaData = true + } + code = { + encoding = "UTF-8" + lineDelimiter = "\n" + fileHeader = "/*\n * generated by Xtext \${version}\n */" + } + } + language = StandardLanguage { + name = "ghidra.xtext.sleigh.Sleigh" + fileExtensions = "slaspec,sinc" + + serializer = { + generateStub = false + } + validator = { + // composedCheck = "org.eclipse.xtext.validation.NamesAreUniqueValidator" + // Generates checks for @Deprecated grammar annotations, an IssueProvider and a corresponding PropertyPage + generateDeprecationValidation = true + } + fragment = ui.labeling.LabelProviderFragment2 {} + + fragment = formatting.Formatter2Fragment2 {} + + fragment = ui.quickfix.QuickfixProviderFragment2 {} + + // enable rename refactoring + fragment = ui.refactoring.RefactorElementNameFragment2 {} + + junitSupport = { + junitVersion = "5" + } + } + } +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/Sleigh.xtext b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/Sleigh.xtext new file mode 100644 index 0000000000..d5d22878df --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/Sleigh.xtext @@ -0,0 +1,1142 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +grammar ghidra.xtext.sleigh.Sleigh hidden(WS, ML_COMMENT, SL_COMMENT) + +generate sleigh "http://www.xtext.ghidra/sleigh/Sleigh" + +import "http://www.eclipse.org/emf/2002/Ecore" as ecore + +Model: + elements+=spec*; + +Import: + '@include' importURI = STRING; + +macroDefine : + defineType='@define' definename=DefineSym value=DefineValue + | + defineType='@if' tests=DefineTest + | + defineType='@ifdef' sym=DefineSym + | + defineType='@ifndef' sym=DefineSym + | + defineType='@elif' ( (isdefined+=IsDefined (OP_BOOL_OR isdefined+=IsDefined )*) | (symref=DefineSym OP_EQUAL value=STRING)) + | + defineType='@else' + | + defineType='@endif' +; + +IsDefined: + 'defined' '(' DefineSym')' +; + +DefineTest: + ( '(' test=DefineTest ')' + | symref=DefineSym OP_EQUAL value=(STRING|intvalue|ID) + | isdefined=IsDefined ) ( (OP_BOOL_AND andtest=DefineTest) | (OP_BOOL_OR ortest=DefineTest) )? +; + + +DefineValue: +// STRING | ( sym=[constraintsym] | OP_AND | OP_OR | ';' | '...' | '(' | ')' | '=' | '<' | '>' | OP_LESSEQUAL| OP_GREATEQUAL )+ + STRING | intvalue // | ( OP_AND | OP_OR | ';' | '...' | '(' | ')' | '=' | '<' | '>' /* | OP_LESSEQUAL | OP_GREATEQUAL */ )+ +; + +spec: + iswith?='with' withTableName+=(SUBTABLESYM)* ':' withmatch+=pequation '{' elements+=spec+ '}' + | Import + | macroDefine + | endiandef + | aligndef + | definition + | constructorlike +; + +endiandef : + 'define' 'endian' '=' (is_big?='big' | is_little?='little' | is_define=DefineUsage) ';' +; + +definition : + tokendef + | contextdef + | spacedef + | varnodedef + | bitrangedef + | pcodeopdef + | valueattach + | nameattach + | varattach +// // | error ';' +; +// +constructorlike: + constructor + | macrodef + //| error '}' // { slgh->resetConstructors(); } +; +// +// +aligndef : + 'define' 'alignment' '=' align=integerValue ';' // { slgh->setAlignment(*$4); delete $4; } +; + +tokendef : + 'define' 'token' ID '(' size=integerValue ')' fields=tokenprop ';' // {} +; +// +tokenprop: + tokens+=( + fielddef + // Don't like allowing macros use internal to blocks... + | macroUse)+ // { $$ = slgh->defineToken($3,$5); } +; + +contextdef: + ('define' 'context' name=[VARSYM]) fields=contextprop ';' // {} +; + +contextprop : + {contextDefs} + (contextDefs+=( + contextfielddef + // Don't like allowing macros use internal to blocks... + |macroUse + ))* +; + +fielddef: + name=ID '=' '(' start=integerValue ',' end=integerValue ')' (signed?='signed' | hex?='hex' | dec?='dec')* //{ $$ = new FieldQuality($1 $4 $6); } +; + +macroUse: + define=macroDefine +; + +contextfielddef: + name=ID '=' '(' start=integerValue ',' end=integerValue ')' (signed?='signed' | noflow?='noflow' | hex?='hex' | dec?='dec')* +; + +spacedef: + spaceprop ';' +; + +spaceprop : + 'define' 'space' space=SPACESYM + (('type' '=' isram?='ram_space' + | 'type' '=' isregister?='register_space' + | 'size' '=' size=integerValue + | 'wordsize' '=' wordsize=integerValue + | isdefault?='default'))* +; + +varnodedef : + 'define' (space=[SPACESYM] | define=DefineUsage) 'offset' '=' offset=integerValue 'size' '=' size=integerValue vars=vardeflist ';' +; + +vardeflist: + '[' varDefList += vardef+ ']' + | varDefList += vardef +; + +vardef: + varname=VARSYM + | isempty?=EMPTYVARSYM + | macroUse +; + +bitrangedef : + 'define' 'bitrange' list=bitrangelist ';'; + +bitrangelist: + bitrangeEntries+=bitrangesingle+ + // | bitrangelist bitrangesingle; +; + +bitrangesingle: + name=ID '=' vnode=[VARSYM] '[' start=integerValue ',' end=integerValue ']' +; + +pcodeopdef : + 'define' 'pcodeop' ops+=(USEROPSYM)+ ';' +; + +valueattach : + 'attach' 'values' valuelist=valuesymlist blist=intblist ';' +; + +nameattach : + 'attach' 'names' valuelist=namesymlist slist=anystringlist ';' +; + +varattach : + 'attach' 'variables' valuelist=varsymlist vlist=varlist ';' +; + +macrodef: + 'macro' name=QualifiedName '(' args=oplist ')' body=rtlbody +; + +QualifiedName: ID ('.' ID)* ; + + +rtlbody: + '{' body=xrtl '}' + | unimpl?='unimpl' +; + +constructor: + baseconstructor | subconstructor +; + +baseconstructor: + ':' print=constructprint match=pequation (cblock=contextblock)? body=rtlbody +; + +subconstructor: + tableName=SUBTABLESYM ':' print=constructprint match=pequation (cblock=contextblock)? body=rtlbody // { slgh->buildConstructor($1,$3,$4,$5); } +; + +constructprint: + {constructprint} + printpieces+=(printpiece)* is=isKeyword +; + +isKeyword: {isKeyword} 'is'; + +printpiece: + str=OP_XOR | str=STRING | str=charsymbol | sym=aliasSym | str=Keywords +; + +Keywords: + 'call' | 'if' | 'define' | 'goto' | 'return' | 'offset' | 'size' | 'round' | 'abs' | 'dec' | 'instruction' +; + +aliasSymID: + aliasSym +; + +aliasSym: + sym=ID +; + +subconstructdef: + SUBTABLESYM +; + +pexpression : + pexprAdd; + +pexprAdd: + pexprSub ({pexprAdd.left=current} op='+' right=pexprSub)*; + +pexprSub: + pexprMult ({pexprSub.left=current} op='-' right=pexprMult)*; + +pexprMult: + pexprLeft ({pexprMult.left=current} op='*' right=pexprLeft)*; + +pexprLeft: + pexprRight ({pexprLeft.left=current} op=OP_LEFT right=pexprRight)*; + +pexprRight: + pexprAnd ({pexprRight.left=current} op=OP_RIGHT right=pexprAnd)*; + +pexprAnd: + pexprOr ({pexprAnd.left=current} (op=OP_DAND | op=OP_AND) right=pexprOr)*; + +pexprOr: + pexprXor ({pexprOr.left=current} (op=OP_DOR | op=OP_OR) right=pexprXor)*; + +pexprXor: + pexprDiv ({pexprXor.left=current} (op=OP_DXOR | op=OP_XOR) right=pexprDiv)*; + +pexprDiv: + pexprNegate ({pexprDiv.left=current} op='/' right=pexprNegate)*; + +pexprNegate: + pexprInvert | ({pexprNegate} op='-' left=pexprInvert); + +pexprInvert: + singlePexpression | ({pexprInvert} op='~' left=singlePexpression); + +singlePexpression: + intval=integerValue // { $$ = new ConstantValue(*$1); delete $1; } + | is_instruction?='instruction' + | is_epsilon?='epsilon' + | sym=pexprSym + | is_paren='(' right=pexpression ')' +; + +constraintPexpression : + constraintAdd; + +constraintAdd: + constraintSub ({constraintAdd.left=current} op='+' right=constraintSub)*; + +constraintSub: + constraintMult ({constraintSub.left=current} op='-' right=constraintMult)*; + +constraintMult: + constraintLeft ({constraintMult.left=current} op='*' right=constraintLeft)*; + +constraintLeft: + constraintRight ({constraintLeft.left=current} op=OP_LEFT right=constraintRight)*; + +constraintRight: + constraintAnd ({constraintRight.left=current} op=OP_RIGHT right=constraintAnd)*; + +constraintAnd: + constraintOr ({constraintAnd.left=current} (op=OP_DAND) right=constraintOr)*; + +constraintOr: + constraintXor ({constraintOr.left=current} (op=OP_DOR) right=constraintXor)*; + +constraintXor: + constraintDiv ({constraintXor.left=current} (op=OP_DXOR) right=constraintDiv)*; + +constraintDiv: + constraintNegate ({constraintDiv.left=current} op='/' right=constraintNegate)*; + +constraintNegate: + constraintInvert | ({constraintNegate} op='-' expr=constraintInvert) +; + +constraintInvert: + constraintSinglePexpression | ({constraintInvert} op='~' expr=constraintSinglePexpression) +; + +constraintSinglePexpression: + intval=integerValue + | is_instruction?='instruction' + | is_epsilon?='epsilon' + | sym=pexprSym + | is_subexpr='(' right=constraintPexpression ')' +; + + +pexprSym: + inst_start?='inst_start' | inst_next?='inst_next' | sym=[specificsymbol] +; + +pequation : + constraints=pNextSet +; + + +pNextSet: + pAnd ({pNextSet.left=current} op=';' right=pAnd)*; + +pAnd: + pOr ({pAnd.left=current} op=OP_AND right=pOr)*; + +pOr: + elleqRight ({pOr.left=current} op=OP_OR right=elleqRight)*; + +elleqRight: + elleqLeft ({elleqRight.left=current} op='...')?; + +elleqLeft: + ('...')? atomic; + +elleq: + ('...') atomic + | atomic ('...') +; + +atomic: + constraint + | define=DefineUsage + | '(' right=pequation ')' +; + +constraint: + sym=[constraintvalue] compareOp='=' value=constraintPexpression + | sym=[constraintvalue] compareOp=OP_NOTEQUAL value=constraintPexpression + | sym=[constraintvalue] compareOp='<' value=constraintPexpression + | sym=[constraintvalue] compareOp=OP_LESSEQUAL value=constraintPexpression + | sym=[constraintvalue] compareOp='>' value=constraintPexpression + | sym=[constraintvalue] compareOp=OP_GREATEQUAL value=constraintPexpression + | sym=[constraintsym] + | isinstruction?='instruction' + | isepsilon?='epsilon' +; + +constraintvalue: + OPERANDSYM + | VALUESYM + | CONTEXTSYM + | NAMESYM + | VARLISTSYM +; + +constraintsym: + OPERANDSYM + | SUBTABLESYM + | CONTEXTSYM + | NAMESYM + | VARLISTSYM +; + +contextblock: + ('[' block=contextlist ']') +; + +contextlist: + (entry+=contextentry ';')+; + +contextentry: + (lhs=[consymref] '=' rhs=pexpression) + | ('globalset' '(' tsym=globalLoc ',' csym=[CONTEXTSYM] ')') + | 'local' OPERANDSYM '=' rhs=pexpression +; + +globalLoc: + inst_start?=STARTSYM | inst_next?=ENDSYM | tsym=[globalLocRef] +; + +globalLocRef: + // familysymbol + VALUESYM + | CONTEXTSYM + | NAMESYM + | VARLISTSYM + // specificsymbol + | VARSYM + | LOCALSYM + | CONTEXTSYM | TOKENSYM // should really be special, must appear in match pattern + | SPECSYM + | OPERANDSYM + | STARTSYM + | ENDSYM + | SUBTABLESYM + | aliasSym +; + +consymref: + CONTEXTSYM | OPERANDSYM | aliasSym +; + +section_def: + OP_LEFT SECTIONSYM OP_RIGHT +; + + +xrtl: + statements=rtlmid + ( export=exportStmt (additionalStatements=rtlmid))? +; + +exportStmt: + 'export' (resultsize=sizedstar)? result=exportedSym ';' +; + +exportedSym: + symref=[exportvarnode] + | is_start?='inst_start' + | is_next?='inst_next' + | isaddrof?=OP_AND varnode=varnode + | isaddrof?=OP_AND sizeOpColon size=integerValue varnode=varnode + | const=integerValue sizeOpColon size=integerValue + | define=DefineUsage +; + +sizeOpColon: + ':' +; + +rtlmid: + {rtlmid} + (rtllist+=statement | macro+=macroUse)* + // Don't like allowing macros use internal to blocks... +; + +statement : + section_name=section_def + | lhs=assignSym '=' rhs=expr semi=';' + | ldef=localDefine semi=';' + | ptrsize=sizedstar lhsexpr=expr '=' rhs=expr semi=';' + | lhs=assignSym '[' start=integerValue ',' end=integerValue ']' '=' rhs=expr semi=';' + | isbuild?='build' (is_instr?='instruction' | def=[SUBTABLESYM]) semi=';' + | iscross?='crossbuild' crossvnode=varnode ',' (crossname=[SECTIONSYM] | crossstring=STRING) semi=';' + | isdelay?='delayslot' '(' delayslot=integerValue ')' semi=';' + | isgoto?='goto' dest=jumpdest semi=';' + | isif?='if' ifexpr=expr 'goto' dest=jumpdest semi=';' + | isgoto?='goto' '[' gotodest=expr ']' semi=';' + | iscall?='call' dest=jumpdest semi=';' + | iscallind?='call' '[' dest=expr ']' semi=';' + | isreturn?='return' semi=';' + | isreturn?='return' '[' dest=expr ']' semi=';' + | macro=[macroOrPcode] args=paramlist semi=';' + | label=label +; + +assignSym: + symref=[lhsvarnode] | local=localDefine | define=DefineUsage +; + +localDefine: + 'local' sym=LOCALSYM | 'local'? sym=LOCALSYM sizeOpColon size=integerValue +// hasLocalDef?='local' sym=LOCALSYM | hasLocalDef?='local'? sym=LOCALSYM sizeOpColon size=integerValue +; + +macroOrPcode: + MACROSYM + | USEROPSYM + | BITSYM + | VARSYM + | LOCALSYM + | SPECSYM + | OPERANDSYM + | SUBTABLESYM + | MACROPARAMSYM + | TOKENSYM // allow subpiece + | aliasSym +; + +expr returns Expression: + exprAdd; + +exprAdd returns Expression: + exprMinus ({exprrAdd.left=current} '+' right=exprMinus)*; + +exprMinus returns Expression: + exprEqual ({exprMinus.left=current} '-' right=exprEqual)*; + +exprEqual returns Expression: + exprNotEqual ({exprEqual.left=current} OP_EQUAL right=exprNotEqual)*; + +exprNotEqual returns Expression: + exprLess ({exprNotEqual.left=current} OP_NOTEQUAL right=exprLess)*; + +exprLess returns Expression: + exprGtEqual ({exprLess.left=current} '<' right=exprGtEqual)*; + +exprGtEqual returns Expression: + exprLtEqual ({exprGtEqual.left=current} OP_GREATEQUAL right=exprLtEqual)*; + +exprLtEqual returns Expression: + exprGt ({exprLtEqual.left=current} OP_LESSEQUAL right=exprGt)*; + +exprGt returns Expression: + exprSLess ({exprGt.left=current} '>' right=exprSLess)*; + +exprSLess returns Expression: + exprSGtEqual ({exprSLess.left=current} OP_SLESS right=exprSGtEqual)*; + +exprSGtEqual returns Expression: + exprSLtEqual ({exprSGtEqual.left=current} OP_SGREATEQUAL right=exprSLtEqual)*; + +exprSLtEqual returns Expression: + exprSGt ({exprSLtEqual.left=current} OP_SLESSEQUAL right=exprSGt)*; + +exprSGt returns Expression: + exprXor ({exprSGt.left=current} OP_SGREAT right=exprXor)*; + +exprXor returns Expression: + exprAnd ({exprXor.left=current} OP_XOR right=exprAnd)*; + +exprAnd returns Expression: + exprOr ({exprAnd.left=current} OP_AND right=exprOr)*; + +exprOr returns Expression: + exprLeft ({exprOr.left=current} OP_OR right=exprLeft)*; + +exprLeft returns Expression: + exprRight ({exprLeft.left=current} OP_LEFT right=exprRight)*; + +exprRight returns Expression: + exprSRight ({exprRight.left=current} OP_RIGHT right=exprSRight)*; + +exprSRight returns Expression: + exprMult ({exprSRight.left=current} OP_SRIGHT right=exprMult)*; + +exprMult returns Expression: + exprDiv ({exprMult.left=current} '*' right=exprDiv)*; + +exprDiv returns Expression: + exprSDiv ({exprDiv.left=current} '/' right=exprSDiv)*; + +exprSDiv returns Expression: + exprRem ({exprSDiv.left=current} OP_SDIV right=exprRem)*; + +exprRem returns Expression: + exprSRem ({exprRem.left=current} '%' right=exprSRem)*; + +exprSRem returns Expression: + exprBoolXor ({exprSRem.left=current} OP_SREM right=exprBoolXor)*; + +exprBoolXor returns Expression: + exprBoolAnd ({exprBoolXor.left=current} OP_BOOL_XOR right=exprBoolAnd)*; + +exprBoolAnd returns Expression: + exprBoolOr ({exprBoolAnd.left=current} OP_BOOL_AND right=exprBoolOr)*; + +exprBoolOr returns Expression: + exprFEqual ({exprBoolOr.left=current} OP_BOOL_OR right=exprFEqual)*; + +exprFEqual returns Expression: + exprFNotEqual ({exprFEqual.left=current} OP_FEQUAL right=exprFNotEqual)*; + +exprFNotEqual returns Expression: + exprFLess ({exprFNotEqual.left=current} OP_FNOTEQUAL right=exprFLess)*; + +exprFLess returns Expression: + exprFGt ({exprFLess.left=current} OP_FLESS right=exprFGt)*; + +exprFGt returns Expression: + exprFLessEqual ({exprFGt.left=current} OP_FGREAT right=exprFLessEqual)*; + +exprFLessEqual returns Expression: + exprFGtEqual ({exprFLessEqual.left=current} OP_FLESSEQUAL right=exprFGtEqual)*; + +exprFGtEqual returns Expression: + exprFAdd ({exprFGtEqual.left=current} OP_FGREATEQUAL right=exprFAdd)*; + +exprFAdd returns Expression: + exprFSub ( {exprFAdd.left=current} OP_FADD right=exprFSub)*; + +exprFSub returns Expression: + exprFMult ({exprFSub.left=current} OP_FSUB right=exprFMult)*; + +exprFMult returns Expression: + exprFDiv ({exprFMult.left=current} OP_FMULT right=exprFDiv)*; + +exprFDiv returns Expression: + exprNegate ({exprFDiv.left=current} OP_FDIV right=exprNegate)*; + +exprNegate returns Expression: + exprFNegate | ({exprNegate} '-' expr=exprFNegate) +; + +exprFNegate returns Expression: + exprInvert | ({exprFNegate} OP_FSUB expr=exprInvert) +; + +exprInvert returns Expression: + exprNot | ({exprNegate} '~' expr=exprNot) +; + +exprNot returns Expression: + exprLoad | ({exprNegate} '!' expr=exprLoad) +; + +exprLoad returns Expression: + exprSingle | ({exprLoad} loc=sizedstar expr=exprSingle) +; + +exprSingle returns Expression: + vnode=exprSym + | '(' right=expr ')' + | pcodeop='unordered' '(' op1=expr ',' op2=expr ')' + | pcodeop='abs' '(' right=expr ')' + | pcodeop='sqrt' '(' right=expr ')' + | pcodeop='sext' '(' right=expr ')' + | pcodeop='zext' '(' right=expr ')' + | pcodeop='carry' '(' op1=expr ',' op2=expr ')' + | pcodeop='scarry' '(' op1=expr ',' op2=expr ')' + | pcodeop='sborrow' '(' op1=expr ',' op2=expr ')' + | pcodeop='float2float' '(' op1=expr ')' + | pcodeop='int2float' '(' op1=expr ')' + | pcodeop='nan' '(' op1=expr ')' + | pcodeop='trunc' '(' op1=expr ')' + | pcodeop='ceil' '(' op1=expr ')' + | pcodeop='floor' '(' op1=expr ')' + | pcodeop='round' '(' op1=expr ')' + | pcodeop='cpool' '(' op1=expr ',' op2=expr ',' op3=expr ')' + | pcodeop='newobject' '(' op1=newObjParams ')' + | op=[macroOrPcode] op1=paramlist +; + +newObjParams: + ((parameters+=expr) (',' parameters+=expr)*) +; + +exprSym: + vnode=[vnoderef] + | vnode=[specificsymbol] sizeOpColon size=integerValue + | vnode=[specificsymbol] '[' start=integerValue ',' end=integerValue ']' + | inode=integervarnode +; + +vnoderef: + BITSYM + | VARSYM + | LOCALSYM + | SPECSYM + | OPERANDSYM + | assignSym + | aliasSym +; + + +sizedstar: + '*' '[' space=spacename ']' sizeOpColon size=integerValue + | '*' '[' space=spacename']' + | '*' sizeOpColon size=integerValue + | isdefault?='*' +; + +spacename: + const?='const' | space=[SPACESYM] +; + +jumpdest: + inst_start=STARTSYM + | inst_end=ENDSYM + | const=integerValue + | const=integerValue '[' space=spacename ']' + | dest=[SUBTABLESYM] + | label='<' dest=[label] '>' +; + +varnode: + val=[specificsymbol] + | integervarnode +; + +integervarnode: + reladdr=STARTSYM + | reladdr=ENDSYM + | const=integerValue + | const=integerValue sizeOpColon size=integerValue + | isaddrof=OP_AND vnode=[specificsymbol] + | isaddrof=OP_AND sizeOpColon size=integerValue (inode=instSymbol | vnode=[specificsymbol]) +; + +instSymbol: + STARTSYM | ENDSYM +; + +lhsvarnode: + VARSYM + // have to be crossed checked another way | VARLISTSYM + | CONTEXTSYM | TOKENSYM + | SPECSYM + | OPERANDSYM + | BITSYM + | LOCALSYM + | SUBTABLESYM + | MACROPARAMSYM +; + +label: + '<' name=ID '>' +; + +exportvarnode: + VARSYM + | SUBTABLESYM + | SPECSYM + | OPERANDSYM + | STARTSYM + | ENDSYM + // These will need to be checked for valid VARLIST tokens + | CONTEXTSYM | TOKENSYM + | LOCALSYM + | assignSym + | aliasSym +; + +familysymbol: + VALUESYM + | CONTEXTSYM + | NAMESYM + | VARLISTSYM +; + +specificsymbol: + VARSYM + | LOCALSYM + | CONTEXTSYM | TOKENSYM // should really be special, must appear in match pattern + | SPECSYM + | OPERANDSYM + | STARTSYM + | ENDSYM + | SUBTABLESYM + | MACROPARAMSYM + | aliasSym + ; + +//specificsymbol: +// (vardef | contextfielddef | bitrange | MACROSYM) +// | sym=[SPECSYM] +// | sym=[OPERANDSYM] +// | sym=[STARTSYM] +// | sym=[ENDSYM] +//; + +intblist: + {intblist} '[' args+=intbpart+ ']' + | args+= intbpart +; + +intbpart: + value=integerValue + | isnegative?='-' value=integerValue + | isempty?=EMPTYVARSYM +; + +anystringlist: + '[' namelist+=anystringpart+ ']' +; + +anystringpart: + str = STRING + | sym = STRINGNAME + | isempty?=EMPTYVARSYM +; + +STRINGNAME: + name=ID; + +valuesymlist: + '[' valuelist+=valuepart+ ']' + | value=valuepart +; + +valuepart: + VALUESYM; + +VALUESYM: + sym=[mapdef] +; + +namesymlist: + '[' valuelist+=NAMESYM+ ']' + | value=NAMESYM // { $$ = new vector; $$->push back($1); } +// | value=[CONTEXTSYM] // { $$ = new vector; $$->push_back($1); } +; + +NAMESYM: + sym=[mapdef] +; + +varsymlist: + '[' valuelist+=valuepartdef+ ']' + | valuelist+=valuepartdef +; + +valuepartdef: + sym=[mapdef] +; + +VARLISTSYM: + name=ID +; + +mapdef: + TOKENSYM | CONTEXTSYM +; + +varlist: + '[' varDefList+=varpart+ ']' + | varDefList+=varpart +; + +varpart: + varpart=[VARSYM] | hasunder?=EMPTYVARSYM // TODO: somehow '_' is OK at head of STRING? + | macroUse +; + +paramlist: + {paramlist} + '(' ((parameters+=expr)? (',' parameters+=expr)*) ')' +; + +oplist: + {oplist} + ((args+=MACROPARAMSYM (',' args+=MACROPARAMSYM)*))? +; + +MACROPARAMSYM: + name=ID; + +anysymbol: + sym=SPACESYM + | sym=SECTIONSYM + | sym=TOKENSYM + | sym=USEROPSYM + | sym=MACROSYM + | sym=SUBTABLESYM + | sym=VALUESYM +// | sym=VALUEMAPSYM + | sym=CONTEXTSYM + | sym=NAMESYM + | sym=VARNODESYM + | sym=VARLISTSYM + | sym=OPERANDSYM + | sym=STARTSYM + | sym=ENDSYM + | sym=BITSYM + | sym=LOCALSYM + | sym=MACROPARAMSYM +; + +LOCALSYM: + name=ID; + +SPACESYM: + spacesymbol; + +spacesymbol: + name=ID; + +SECTIONSYM: + sectionsymbol; + +sectionsymbol: + name=ID; + +VarnodeSymbol: + VARSYM; + +VARSYM: + name=ID; + +TOKENGROUPSYM: + tokengroup; + +tokengroup: + ID; + +USEROPSYM: + name=ID; + +TOKENSYM: + fielddef; + +CONTEXTSYM: + contextfielddef; + +VARNODESYM: + varsymbol; + +varsymbol: + name=ID; + +EMPTYVARSYM: + '_' +; + +BITSYM: + bitrangesingle; + +SPECSYM: + specsymbol; + +specsymbol: + name=ID; + +OPERANDSYM: + name=ID; + +STARTSYM: + name='inst_start'; + +startsymbol: + name=ID; + +ENDSYM: + name='inst_next'; + +endsymbol: + name=ID; + +MACROSYM: + macrodef; + +LABELSYM: + labelsymbol; + +labelsymbol: + name=ID; + +SUBTABLESYM: + name=ID; + + +charsymbol: + ('!' | '@' | '#' | '$' | '%' | OP_AND | '*' | '(' | ')' | '-' | '=' | '+' | '[' | ']' | '{' | '}' | OP_OR | ';' | ':' | '<' + | '>' | '?' | ',' | '/' | NUMVAL ); + +DefineSym: + name=ID; + +DefineUsage: + '$' '(' symref=[DefineSym] ')' +; + +integerValue: + value=intvalue | sym=DefineUsage + ; + +intvalue: + HEXVAL | BINVAL | NUMVAL + ; + +terminal NUMVAL returns ecore::EBigInteger: + (DIGIT)+ +; + +terminal HEXVAL returns ecore::EBigInteger: + '0x' HEX_DIGIT+ +; + +terminal fragment HEX_DIGIT: + (DIGIT | 'a'..'f' | 'A'..'F') +; + +terminal BINVAL returns ecore::EBigInteger: + '0b' BIN_DIGIT+ +; + +terminal fragment BIN_DIGIT: + ('0' | '1') +; + +terminal fragment DIGIT: + ('0'..'9') +; + +//terminal MACRO_KEY: +////macro {BEGIN(macroblock); return MACRO_KEY; } +// 'macro'; +// +//terminal DEFINE_KEY: +// 'define'; +// define { BEGIN(defblock); return DEFINE_KEY; } + + +//terminal ATTACH_KEY: +//// 'attach' { BEGIN(defblock); slgh->calcContextLayout(); return ATTACH_KEY; } +// 'attach'; +terminal ID returns ecore::EString: +//[a-zA-Z_.][a-zA-Z0-9_.]* { return find_symbol(); } { return yytext[0]; } + ('a'..'z' | 'A'..'Z' | '.' | '_') ('a'..'z' | 'A'..'Z' | '.' | '_' | '0'..'9')*; + +terminal OP_RIGHT: + '>>'; + +terminal OP_LEFT: + '<<'; + +terminal OP_NOTEQUAL: + '!='; + +terminal OP_LESSEQUAL: + '<='; + +terminal OP_GREATEQUAL: + '>='; + +terminal OP_DAND: + '$and'; + +terminal OP_DOR: + '$or'; + +terminal OP_DXOR: + '$xor'; + +terminal OP_AND: + '&'; + +terminal OP_OR: + '|'; + +terminal OP_XOR: + '^'; + +terminal OP_BOOL_OR: + '||'; + +terminal OP_BOOL_AND: + '&&'; + +terminal OP_BOOL_XOR: + '^^'; + +terminal OP_EQUAL: + '=='; + +terminal OP_SDIV: + 's/'; + +terminal OP_SREM: + 's%'; + +terminal OP_SRIGHT: + 's>>'; + +terminal OP_SLESS: + 's<'; + +terminal OP_SGREAT: + 's>'; + +terminal OP_SLESSEQUAL: + 's<='; + +terminal OP_SGREATEQUAL: + 's>='; + +terminal OP_FADD: + 'f+'; + +terminal OP_FSUB: + 'f-'; + +terminal OP_FMULT: + 'f*'; + +terminal OP_FDIV: + 'f/'; + +terminal OP_FEQUAL: + 'f=='; + +terminal OP_FNOTEQUAL: + 'f!='; + +terminal OP_FLESS: + 'f<'; + +terminal OP_FGREAT: + 'f>'; + +terminal OP_FLESSEQUAL: + 'f<='; + +terminal OP_FGREATEQUAL: + 'f>='; + +terminal STRING : + '"' ( '\\' . /* 'b'|'t'|'n'|'f'|'r'|'u'|'"'|"'"|'\\' */ | !('\\'|'"') )* '"' | + "'" ( '\\' . /* 'b'|'t'|'n'|'f'|'r'|'u'|'"'|"'"|'\\' */ | !('\\'|"'") )* "'" + ; +terminal ML_COMMENT : '/*' -> '*/'; +terminal SL_COMMENT : '#' !('\n'|'\r')* ('\r'? '\n')?; + +terminal WS : (' '|'\t'|'\r'|'\n')+; + +//terminal ANY_OTHER: .; +// +//terminal DEFINENAME: 'synthetic:DEFINENAME'; +//terminal BEGINDEFINE: 'synthetic:BEGINDEFINE'; +//terminal ENDDEFINE: 'synthetic:ENDDEFINE'; \ No newline at end of file diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/SleighRuntimeModule.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/SleighRuntimeModule.xtend new file mode 100644 index 0000000000..f74d164dee --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/SleighRuntimeModule.xtend @@ -0,0 +1,23 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh + + +/** + * Use this class to register components to be used at runtime / without the Equinox extension registry. + */ +class SleighRuntimeModule extends AbstractSleighRuntimeModule { +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/SleighStandaloneSetup.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/SleighStandaloneSetup.xtend new file mode 100644 index 0000000000..d18900e600 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/SleighStandaloneSetup.xtend @@ -0,0 +1,27 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh + + +/** + * Initialization support for running Xtext languages without Equinox extension registry. + */ +class SleighStandaloneSetup extends SleighStandaloneSetupGenerated { + + def static void doSetup() { + new SleighStandaloneSetup().createInjectorAndDoEMFRegistration() + } +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/converter/IntValueConverter.java b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/converter/IntValueConverter.java new file mode 100644 index 0000000000..be2a598caf --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/converter/IntValueConverter.java @@ -0,0 +1,67 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.converter; + +import java.math.BigInteger; +import java.util.Map; + +import org.antlr.runtime.Token; +import org.antlr.runtime.TokenSource; +import org.eclipse.xtext.AbstractRule; +import org.eclipse.xtext.conversion.ValueConverterException; +import org.eclipse.xtext.conversion.impl.AbstractLexerBasedConverter; +import org.eclipse.xtext.nodemodel.INode; +import org.eclipse.xtext.parser.antlr.ITokenDefProvider; +import org.eclipse.xtext.parser.antlr.Lexer; +import org.eclipse.xtext.util.Strings; + +import com.google.inject.Provider; + +public class IntValueConverter extends AbstractLexerBasedConverter { + + @Override + protected String toEscapedString(BigInteger value) { + return value.toString(); + } + + @Override + protected void assertValidValue(BigInteger value) { + super.assertValidValue(value); + if (value.compareTo(BigInteger.ZERO) < 0) + throw new ValueConverterException(getRuleName() + "-value may not be negative (value: " + value + ").", null, null); + } + + public BigInteger toValue(String string, INode node) { + if (Strings.isEmpty(string)) + throw new ValueConverterException("Couldn't convert empty string to an int value.", node, null); + try { + String parseString = string; + int radix = 10; + if (parseString.startsWith("0x") || parseString.startsWith("0X")) { + parseString = string.substring(2); + radix=16; + } + if (parseString.startsWith("0b") || parseString.startsWith("0B")) { + parseString = string.substring(2); + radix=2; + } + return new BigInteger(parseString,radix); + } catch (NumberFormatException e) { + throw new ValueConverterException("Couldn't convert '" + string + "' to a BigInteger value.", node, e); + } + } + +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/converter/SleighValueConverter.java b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/converter/SleighValueConverter.java new file mode 100644 index 0000000000..69a28301eb --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/converter/SleighValueConverter.java @@ -0,0 +1,55 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.converter; + +import java.math.BigInteger; + +import org.eclipse.xtext.common.services.DefaultTerminalConverters; +import org.eclipse.xtext.conversion.IValueConverter; +import org.eclipse.xtext.conversion.ValueConverter; +import org.eclipse.xtext.conversion.ValueConverterException; +import org.eclipse.xtext.conversion.impl.INTValueConverter; +import org.eclipse.xtext.nodemodel.INode; +import org.eclipse.xtext.util.Strings; + +import com.google.inject.Inject; + +public class SleighValueConverter extends DefaultTerminalConverters { + + @Inject + private IntValueConverter hexValueConverter; + + @ValueConverter(rule = "HEXVAL") + public IValueConverter HEXVAL() { + return hexValueConverter; + } + + @Inject + private IntValueConverter numValueConverter; + + @ValueConverter(rule = "NUMVAL") + public IValueConverter NUMVAL() { + return numValueConverter; + } + + @Inject + private IntValueConverter binValueConverter; + + @ValueConverter(rule = "BINVAL") + public IValueConverter BINVAL() { + return binValueConverter; + } +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/formatting2/SleighFormatter.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/formatting2/SleighFormatter.xtend new file mode 100644 index 0000000000..2f157db10a --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/formatting2/SleighFormatter.xtend @@ -0,0 +1,1234 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.formatting2 + +import com.google.common.base.Strings +import com.google.inject.Inject +import ghidra.xtext.sleigh.services.SleighGrammarAccess +import ghidra.xtext.sleigh.sleigh.DefineTest +import ghidra.xtext.sleigh.sleigh.Expression +import ghidra.xtext.sleigh.sleigh.MACROPARAMSYM +import ghidra.xtext.sleigh.sleigh.Model +import ghidra.xtext.sleigh.sleigh.NAMESYM +import ghidra.xtext.sleigh.sleigh.OPERANDSYM +import ghidra.xtext.sleigh.sleigh.USEROPSYM +import ghidra.xtext.sleigh.sleigh.aligndef +import ghidra.xtext.sleigh.sleigh.anystringlist +import ghidra.xtext.sleigh.sleigh.anystringpart +import ghidra.xtext.sleigh.sleigh.anysymbol +import ghidra.xtext.sleigh.sleigh.assignSym +import ghidra.xtext.sleigh.sleigh.atomic +import ghidra.xtext.sleigh.sleigh.baseconstructor +import ghidra.xtext.sleigh.sleigh.bitrangedef +import ghidra.xtext.sleigh.sleigh.bitrangelist +import ghidra.xtext.sleigh.sleigh.bitrangesingle +import ghidra.xtext.sleigh.sleigh.constraint +import ghidra.xtext.sleigh.sleigh.constraintAdd +import ghidra.xtext.sleigh.sleigh.constraintAnd +import ghidra.xtext.sleigh.sleigh.constraintDiv +import ghidra.xtext.sleigh.sleigh.constraintInvert +import ghidra.xtext.sleigh.sleigh.constraintLeft +import ghidra.xtext.sleigh.sleigh.constraintMult +import ghidra.xtext.sleigh.sleigh.constraintNegate +import ghidra.xtext.sleigh.sleigh.constraintOr +import ghidra.xtext.sleigh.sleigh.constraintRight +import ghidra.xtext.sleigh.sleigh.constraintSinglePexpression +import ghidra.xtext.sleigh.sleigh.constraintSub +import ghidra.xtext.sleigh.sleigh.constraintXor +import ghidra.xtext.sleigh.sleigh.constructprint +import ghidra.xtext.sleigh.sleigh.contextDefs +import ghidra.xtext.sleigh.sleigh.contextblock +import ghidra.xtext.sleigh.sleigh.contextdef +import ghidra.xtext.sleigh.sleigh.contextentry +import ghidra.xtext.sleigh.sleigh.contextfielddef +import ghidra.xtext.sleigh.sleigh.contextlist +import ghidra.xtext.sleigh.sleigh.elleqRight +import ghidra.xtext.sleigh.sleigh.endiandef +import ghidra.xtext.sleigh.sleigh.exportStmt +import ghidra.xtext.sleigh.sleigh.exportedSym +import ghidra.xtext.sleigh.sleigh.exprAnd +import ghidra.xtext.sleigh.sleigh.exprBoolAnd +import ghidra.xtext.sleigh.sleigh.exprBoolOr +import ghidra.xtext.sleigh.sleigh.exprBoolXor +import ghidra.xtext.sleigh.sleigh.exprDiv +import ghidra.xtext.sleigh.sleigh.exprEqual +import ghidra.xtext.sleigh.sleigh.exprFAdd +import ghidra.xtext.sleigh.sleigh.exprFDiv +import ghidra.xtext.sleigh.sleigh.exprFEqual +import ghidra.xtext.sleigh.sleigh.exprFGt +import ghidra.xtext.sleigh.sleigh.exprFGtEqual +import ghidra.xtext.sleigh.sleigh.exprFLess +import ghidra.xtext.sleigh.sleigh.exprFLessEqual +import ghidra.xtext.sleigh.sleigh.exprFMult +import ghidra.xtext.sleigh.sleigh.exprFNegate +import ghidra.xtext.sleigh.sleigh.exprFNotEqual +import ghidra.xtext.sleigh.sleigh.exprFSub +import ghidra.xtext.sleigh.sleigh.exprGt +import ghidra.xtext.sleigh.sleigh.exprGtEqual +import ghidra.xtext.sleigh.sleigh.exprLeft +import ghidra.xtext.sleigh.sleigh.exprLess +import ghidra.xtext.sleigh.sleigh.exprLoad +import ghidra.xtext.sleigh.sleigh.exprLtEqual +import ghidra.xtext.sleigh.sleigh.exprMinus +import ghidra.xtext.sleigh.sleigh.exprMult +import ghidra.xtext.sleigh.sleigh.exprNegate +import ghidra.xtext.sleigh.sleigh.exprNotEqual +import ghidra.xtext.sleigh.sleigh.exprOr +import ghidra.xtext.sleigh.sleigh.exprRem +import ghidra.xtext.sleigh.sleigh.exprRight +import ghidra.xtext.sleigh.sleigh.exprSDiv +import ghidra.xtext.sleigh.sleigh.exprSGt +import ghidra.xtext.sleigh.sleigh.exprSGtEqual +import ghidra.xtext.sleigh.sleigh.exprSLess +import ghidra.xtext.sleigh.sleigh.exprSLtEqual +import ghidra.xtext.sleigh.sleigh.exprSRem +import ghidra.xtext.sleigh.sleigh.exprSRight +import ghidra.xtext.sleigh.sleigh.exprSym +import ghidra.xtext.sleigh.sleigh.exprXor +import ghidra.xtext.sleigh.sleigh.exprrAdd +import ghidra.xtext.sleigh.sleigh.fielddef +import ghidra.xtext.sleigh.sleigh.intblist +import ghidra.xtext.sleigh.sleigh.intbpart +import ghidra.xtext.sleigh.sleigh.integerValue +import ghidra.xtext.sleigh.sleigh.integervarnode +import ghidra.xtext.sleigh.sleigh.jumpdest +import ghidra.xtext.sleigh.sleigh.localDefine +import ghidra.xtext.sleigh.sleigh.macroDefine +import ghidra.xtext.sleigh.sleigh.macroUse +import ghidra.xtext.sleigh.sleigh.macrodef +import ghidra.xtext.sleigh.sleigh.nameattach +import ghidra.xtext.sleigh.sleigh.namesymlist +import ghidra.xtext.sleigh.sleigh.oplist +import ghidra.xtext.sleigh.sleigh.pAnd +import ghidra.xtext.sleigh.sleigh.pNextSet +import ghidra.xtext.sleigh.sleigh.pOr +import ghidra.xtext.sleigh.sleigh.paramlist +import ghidra.xtext.sleigh.sleigh.pcodeopdef +import ghidra.xtext.sleigh.sleigh.pequation +import ghidra.xtext.sleigh.sleigh.pexprAdd +import ghidra.xtext.sleigh.sleigh.pexprAnd +import ghidra.xtext.sleigh.sleigh.pexprDiv +import ghidra.xtext.sleigh.sleigh.pexprInvert +import ghidra.xtext.sleigh.sleigh.pexprLeft +import ghidra.xtext.sleigh.sleigh.pexprMult +import ghidra.xtext.sleigh.sleigh.pexprNegate +import ghidra.xtext.sleigh.sleigh.pexprOr +import ghidra.xtext.sleigh.sleigh.pexprRight +import ghidra.xtext.sleigh.sleigh.pexprSub +import ghidra.xtext.sleigh.sleigh.pexprXor +import ghidra.xtext.sleigh.sleigh.printpiece +import ghidra.xtext.sleigh.sleigh.rtlbody +import ghidra.xtext.sleigh.sleigh.rtlmid +import ghidra.xtext.sleigh.sleigh.singlePexpression +import ghidra.xtext.sleigh.sleigh.sizedstar +import ghidra.xtext.sleigh.sleigh.spaceprop +import ghidra.xtext.sleigh.sleigh.statement +import ghidra.xtext.sleigh.sleigh.subconstructor +import ghidra.xtext.sleigh.sleigh.tokendef +import ghidra.xtext.sleigh.sleigh.tokenprop +import ghidra.xtext.sleigh.sleigh.valueattach +import ghidra.xtext.sleigh.sleigh.valuepart +import ghidra.xtext.sleigh.sleigh.valuepartdef +import ghidra.xtext.sleigh.sleigh.valuesymlist +import ghidra.xtext.sleigh.sleigh.varattach +import ghidra.xtext.sleigh.sleigh.vardef +import ghidra.xtext.sleigh.sleigh.vardeflist +import ghidra.xtext.sleigh.sleigh.varlist +import ghidra.xtext.sleigh.sleigh.varnodedef +import ghidra.xtext.sleigh.sleigh.varpart +import ghidra.xtext.sleigh.sleigh.varsymlist +import ghidra.xtext.sleigh.sleigh.xrtl +import org.eclipse.emf.ecore.EObject +import org.eclipse.xtext.formatting2.AbstractFormatter2 +import org.eclipse.xtext.formatting2.IFormattableDocument + +class SleighFormatter extends AbstractFormatter2 { + @Inject extension SleighGrammarAccess + + var constructorPrintLenMap = newHashMap("" -> 0) + var constructorPatternLenMap = newHashMap("" -> 0) + var constructorContextLenMap = newHashMap("" -> 0) + + def dispatch void format(Model model, extension IFormattableDocument document) { + constructorPrintLenMap = newHashMap("" -> 0); // map names to printpiece + constructorPatternLenMap = newHashMap("" -> 0); // map names to pattern len + constructorContextLenMap = newHashMap("" -> 0); // map names to context len + + var EObject prev; + for (spec : model.elements) { + if (prev !== null) { + if (!spec.class.equals(prev.class) && !(prev instanceof macroDefine)) { + prev.append[newLines = 2 priority = 2] + } + } + format(spec, document); + + prev = spec; + } + + // For Debugging formatting + // println(regionAccess.toString()) + var constructors = model.eAllContents.filter(typeof(subconstructor)) + var lastName = "" + while (constructors.hasNext()) { + var constLike = constructors.next() + var name = constLike.tableName.name + // TODO: make preference for max IS column + var is = constLike.print.is + + var printRegion = constLike.print.regionForEObject; + // if print region is, good + if (printRegion !== null) { + + var matchLen = 0; + var matchOffset = 0; + if (constLike.match.constraints.immediatelyPreceding !== null) { + var matchRegion = constLike.match.constraints.regionForEObject; + matchLen = matchRegion.length; + matchOffset = matchRegion.offset; + } else { + var matchRegion = constLike.match.regionForEObject; + matchLen = matchRegion.length; + matchOffset = matchRegion.offset; + } + + var contextLen = 0; + if (constLike.cblock.immediatelyPreceding !== null) { + if (constLike.cblock !== null) { + contextLen = constLike.cblock.regionForEObject.length + } + } + + var truncName = stripDigit(name); + val printMaxLen = constructorPrintLenMap.get(truncName) + val contextMaxLen = constructorContextLenMap.get(truncName) + val matchMaxLen = constructorPatternLenMap.get(truncName) + + var printRegionlen = printRegion.length; + var isprlen = is.regionFor.keyword('is').previousHiddenRegion.length + if (printRegionlen == 2) { + // region is just 'is' empty print piece + isprlen = 0 + printRegionlen = 1 + } + + var totalLen = name.length + printRegionlen - isprlen + if (totalLen < printMaxLen) { + // put the space before the 'is' + val prLen = totalLen; + is.prepend[space = Strings.repeat(" ", printMaxLen - prLen + 2)] + totalLen += (printMaxLen - prLen) + 2; + } else { + is.prepend[space = ' '] + totalLen += 2; + } + totalLen += matchLen + contextLen; + val maxLBLen = printMaxLen + matchMaxLen + contextMaxLen + 2 + if (totalLen < maxLBLen && maxLBLen < 120) { + val prLen = totalLen + constLike.getBody().regionFor.keyword("{").prepend [ + priority = 1 + space = Strings.repeat(" ", maxLBLen - prLen + 1) + ] + } else { + constLike.getBody().regionFor.keyword("{").prepend[priority = 1 space = ' '] + } + // if different subtable name, add 2 newlines + if (!lastName.equals(truncName)) { + constLike.prepend[newLines = 2 priority = 1] + } + lastName = truncName; + } + } + + var baseconstructors = model.eAllContents.filter(typeof(baseconstructor)) + var name = "" // name of BaseConstructors + val printMaxLen = constructorPrintLenMap.get(name) + while (baseconstructors.hasNext()) { + var constLike = baseconstructors.next() + var is = constLike.print.is + var printRegion = constLike.print.regionForEObject; + if (printRegion !== null) { + var totalLen = name.length + 1 + printRegion.length - + is.regionFor.keyword('is').previousHiddenRegion.length + if (totalLen < printMaxLen) { + // put the space before the 'is' + val prLen = totalLen; + is.prepend[space = Strings.repeat(" ", printMaxLen - prLen)] + totalLen += (printMaxLen - prLen) + 3; + } else if (totalLen > printMaxLen) { + is.prepend[space = ' '] + totalLen += 3; + } + } + } + } + + def void computePrintLength(String name, constructprint print) { + var truncName = stripDigit(name); + + // length before the 'is' + var prLen = constructorPrintLenMap.getOrDefault(truncName, Integer.valueOf(0)) + var is = print.is + var printRegion = print.regionForEObject; + var baseLen = 0; + // if print region is not empty + if (printRegion !== null) { + val curPrLen = printRegion.length + val curPrWhiteSpace = is.regionFor.keyword('is').previousHiddenRegion + baseLen = name.toString.length + curPrLen - curPrWhiteSpace.length + } + if(baseLen > 40) baseLen = 0; + if(baseLen >= prLen) constructorPrintLenMap.put(truncName, baseLen) + } + + def stripDigit(String str) { + var retStr = str; + while (Character.isDigit(retStr.charAt(retStr.length - 1))) { + retStr = retStr.substring(0, retStr.length - 1) + } + return retStr; + } + + def void computeMatchLength(String name, pequation match, contextblock context) { + var truncName = stripDigit(name); + + // length of match pattern + var allMatchLen = constructorPatternLenMap.getOrDefault(truncName, Integer.valueOf(0)) + if (match === null || match.constraints === null) { + return; // something wrong with syntax, can't format + } + var matchLen = 0; + var matchOffset = 0; + if (match.constraints !== null && match.constraints.immediatelyPreceding !== null) { + var matchRegion = match.constraints.regionForEObject; + matchLen = matchRegion.length; + matchOffset = matchRegion.offset; + } else { + var matchRegion = match.regionForEObject; + matchLen = matchRegion.length; + matchOffset = matchRegion.offset; + } + if(matchLen >= allMatchLen) constructorPatternLenMap.put(truncName, matchLen) + + // length of context block + var allContextLen = constructorContextLenMap.getOrDefault(truncName, Integer.valueOf(0)) + var contextLen = 0; + if (context !== null && context.immediatelyPreceding !== null) { + var contextRegion = context.regionForEObject; + contextLen = contextRegion.length; + if(matchOffset == 0) contextLen = 0; + } + if(contextLen >= allContextLen) constructorContextLenMap.put(truncName, contextLen) + } + + def dispatch void format(macroDefine macroDefine, extension IFormattableDocument document) { + macroDefine.definename.format + macroDefine.tests.format + macroDefine.sym.format + for (isDefined : macroDefine.isdefined) { + isDefined.format + } + macroDefine.symref.format + } + + def dispatch void format(DefineTest definetest, extension IFormattableDocument document) { + format(definetest.getTest(), document); + format(definetest.getSymref(), document); + format(definetest.getIsdefined(), document); + format(definetest.getAndtest(), document); + format(definetest.getOrtest(), document); + } + + def dispatch void format(endiandef endiandef, extension IFormattableDocument document) { + format(endiandef.getIs_define(), document); + } + + def dispatch void format(aligndef aligndef, extension IFormattableDocument document) { + format(aligndef.getAlign(), document); + } + + def dispatch void format(tokendef tokendef, extension IFormattableDocument document) { + tokendef.surround[setNewLines(1, 2, 3)] + format(tokendef.getSize(), document); + format(tokendef.getFields(), document); + tokendef.regionFor.keyword(";").prepend[newLine] + } + + var maxTokenNameLen = 0; + var maxStartLen = 0; + var maxEndLen = 0; + var maxFound = false; + var maxtag = 0; + + def dispatch void format(tokenprop tokenprop, extension IFormattableDocument document) { + maxTokenNameLen = 0 + maxStartLen = 0 + maxEndLen = 0 + maxFound = false + maxtag = 0 + for (EObject tokens : tokenprop.getTokens()) { + format(tokens, document); + } + maxFound = true + for (EObject tokens : tokenprop.getTokens()) { + format(tokens, document); + } + } + + def dispatch void format(contextdef contextdef, extension IFormattableDocument document) { + format(contextdef.getFields(), document); + } + + def dispatch void format(contextDefs contextdefs, extension IFormattableDocument document) { + maxTokenNameLen = 0 + maxStartLen = 0 + maxEndLen = 0 + maxFound = false + maxtag = 0 + for (EObject contextDefs : contextdefs.getContextDefs()) { + format(contextDefs, document); + } + maxFound = true + for (EObject contextDefs : contextdefs.getContextDefs()) { + format(contextDefs, document); + } + } + + def dispatch void format(fielddef fielddef, extension IFormattableDocument document) { + format(fielddef.getStart(), document); + format(fielddef.getEnd(), document); + val len = fielddef.name.length + val slen = fielddef.start.value.length + val elen = fielddef.end.value.length + val hastag = fielddef.signed || fielddef.hex || fielddef.dec; + if (maxFound) { + val padlen = maxTokenNameLen - len + 1; + fielddef.prepend[setNewLines(1, 1, 2)].surround[indent] + fielddef.regionFor.keyword("=").prepend[space = Strings.repeat(" ", padlen)] + fielddef.regionFor.keyword("(").append[space = Strings.repeat(" ", maxStartLen - slen)] + fielddef.regionFor.keyword(",").append[space = Strings.repeat(" ", maxEndLen - elen)].prepend[noSpace] + + if (!hastag) { + fielddef.regionFor.keyword(")").prepend[noSpace].append[space = Strings.repeat(" ", maxtag + 1)] + } else { + fielddef.regionFor.keyword(")").prepend[noSpace] + } + fielddef.regionFor.keyword("=").append[space = " "] + fielddef.regionFor.keyword("signed").prepend[oneSpace] + } else if (len > maxTokenNameLen) { + maxTokenNameLen = len + } + if (maxStartLen < slen) { + maxStartLen = slen + } + if (maxEndLen < elen) { + maxEndLen = elen + } + if (fielddef.signed) { + maxtag = 6; + } else if (fielddef.hex || fielddef.dec) { + maxtag = 3; + } + } + + def dispatch void format(macroUse macrouse, extension IFormattableDocument document) { + format(macrouse.getDefine(), document); + } + + def dispatch void format(contextfielddef contextfielddef, extension IFormattableDocument document) { + format(contextfielddef.getStart(), document); + format(contextfielddef.getEnd(), document); + val len = contextfielddef.name.length + val slen = contextfielddef.start.value.length + val elen = contextfielddef.end.value.length + val hastag = contextfielddef.signed || contextfielddef.noflow || contextfielddef.hex || contextfielddef.dec; + if (maxFound) { + val padlen = maxTokenNameLen - len + 1; + contextfielddef.prepend[setNewLines(1, 1, 2)].surround[indent] + contextfielddef.regionFor.keyword("=").prepend[space = Strings.repeat(" ", padlen)] + contextfielddef.regionFor.keyword("(").append[space = Strings.repeat(" ", maxStartLen - slen)] + contextfielddef.regionFor.keyword(",").append[space = Strings.repeat(" ", maxEndLen - elen)].prepend [ + noSpace + ] + contextfielddef.regionFor.keyword(")").prepend[noSpace] + contextfielddef.regionFor.keyword("=").append[space = " "] + contextfielddef.regionFor.keyword("signed").prepend[oneSpace] + contextfielddef.regionFor.keyword("noflow").prepend[oneSpace] + if (!hastag) { + contextfielddef.regionFor.keyword(")").prepend[noSpace].append[space = Strings.repeat(" ", maxtag + 1)] + } else { + contextfielddef.regionFor.keyword(")").prepend[noSpace] + } + } else if (len > maxTokenNameLen) { + maxTokenNameLen = len + } + if (maxStartLen < slen) { + maxStartLen = slen + } + if (maxEndLen < elen) { + maxEndLen = elen + } + if (contextfielddef.signed || contextfielddef.noflow) { + maxtag = 6; + } else if (contextfielddef.hex || contextfielddef.dec) { + maxtag = 3; + } + } + + def dispatch void format(spaceprop spaceprop, extension IFormattableDocument document) { + format(spaceprop.getSpace(), document); + format(spaceprop.getSize(), document); + format(spaceprop.getWordsize(), document); + } + + def dispatch void format(varnodedef varnodedef, extension IFormattableDocument document) { + format(varnodedef.getOffset(), document); + format(varnodedef.getSize(), document); + format(varnodedef.getVars(), document); + } + + def dispatch void format(vardeflist vars, extension IFormattableDocument document) { + for (vardef varDefList : vars.getVarDefList()) { + format(varDefList, document); + } + // format multi-line variable attach definitions + if (vars.isMultiline) { + var open = vars.regionFor.keyword('[') + var close = vars.regionFor.keyword(']') + interior(open, close)[indent] + open.append[newLine] + close.prepend[newLine] + var vlist = vars.varDefList; + var maxLen = 0; + for (v : vlist) { + var len = 1; + if (!v.isIsempty) { + len = v.varname.name.length; + } + if (len > maxLen) { + maxLen = len; + } + } + if(maxLen > 20) maxLen = 20; + var previousLen = 0; + for (v : vlist) { + var len = 1; + if (!v.isIsempty) { + len = v.varname.name.length; + } + + if (v.nextHiddenRegion !== null && v.nextHiddenRegion.isMultiline) { + v.append[newLine] + } + if (previousLen != 0) { + val prevLen = previousLen + v.prepend[space = Strings.repeat(" ", prevLen)] + previousLen = 0 + } + if (v.isIsempty) { + previousLen = maxLen - 1 + 1; + } else if (len < maxLen) { + val spaceLen = maxLen - len + 1; + previousLen = spaceLen; + // v.append[space = Strings.repeat(" ", spaceLen)] + } else { + previousLen = 1; + } + } + } + } + + def dispatch void format(vardef vardef, extension IFormattableDocument document) { + format(vardef.getVarname(), document); + } + + def dispatch void format(bitrangedef bitrangedef, extension IFormattableDocument document) { + format(bitrangedef.getList(), document); + } + + def dispatch void format(bitrangelist bitrangelist, extension IFormattableDocument document) { + for (bitrangesingle bitrangeEntries : bitrangelist.getBitrangeEntries()) { + format(bitrangeEntries, document); + } + } + + def dispatch void format(bitrangesingle bitrangesingle, extension IFormattableDocument document) { + format(bitrangesingle.getStart(), document); + format(bitrangesingle.getEnd(), document); + } + + def dispatch void format(pcodeopdef pcodeopdef, extension IFormattableDocument document) { + for (USEROPSYM ops : pcodeopdef.getOps()) { + format(ops, document); + } + pcodeopdef.regionFor.keyword(";").prepend[noSpace] +// pcodeopdef.surround[setNewLines(1,2,3)] + } + + def dispatch void format(valueattach valueattach, extension IFormattableDocument document) { + format(valueattach.getValuelist(), document); + format(valueattach.getBlist(), document); + } + + def dispatch void format(nameattach nameattach, extension IFormattableDocument document) { + format(nameattach.getValuelist(), document); + format(nameattach.getSlist(), document); + } + + def dispatch void format(varattach varattach, extension IFormattableDocument document) { + format(varattach.getValuelist(), document); + format(varattach.getVlist(), document); + } + + def dispatch void format(macrodef macrodef, extension IFormattableDocument document) { + format(macrodef.getArgs(), document); + format(macrodef.getBody(), document); + } + + def dispatch void format(rtlbody rtlbody, extension IFormattableDocument document) { + var body = rtlbody.getBody(); + + if (body !== null) { + format(body, document); + } + + var open = rtlbody.regionFor.keyword('{') + var close = rtlbody.regionFor.keyword('}') + interior(open, close)[indent priority=3] + + if (rtlbody.isMultiline) { + open.prepend[oneSpace] + close.prepend[newLine] + } + + if (rtlbody.isUnimpl) { + rtlbody.prepend[newLine indent priority=3] + } + } + + def dispatch void format(baseconstructor baseconstructor, extension IFormattableDocument document) { + baseconstructor.regionFor.keyword(":").append[noSpace] + + format(baseconstructor.getPrint(), document); + format(baseconstructor.getMatch(), document); + format(baseconstructor.cblock, document); + format(baseconstructor.getBody(), document); + + var allBaseLen = constructorPrintLenMap.getOrDefault("", Integer.valueOf(0)) + var is = baseconstructor.print.is + var printRegion = baseconstructor.print.regionForEObject; + // if print region is bad, need to bail + if (printRegion === null) { + return + } + var baseLen = printRegion.length - is.regionFor.keyword('is').previousHiddenRegion.length + if(baseLen > 40) baseLen = 0; + if(baseLen >= allBaseLen) constructorPrintLenMap.put("", baseLen) + + } + + def dispatch void format(subconstructor sub, extension IFormattableDocument document) { + sub.regionFor.keyword(":").prepend[noSpace] + + //sub.surround[setNewLines(1, 2, 3)] + + format(sub.tableName, document); + format(sub.print, document); + format(sub.match, document); + format(sub.cblock, document); + format(sub.body, document); + + // format short body, long bodies, force to newline, full formating + var open = sub.body.regionFor.keyword('{') + var close = sub.body.regionFor.keyword('}') + var body = sub.body; + var bodyLen = 3 + if (open !== null && close !== null) { + bodyLen = body.regionForEObject.length; + if (!sub.body.isMultiline) { + open.prepend[newLines = 0].append[oneSpace] + close.prepend[oneSpace] + body.body.statements.rtllist.forEach [ + regionFor.keywords(';').forEach[it.prepend[space = ''].append[space = ' ']] + ] + body.body.export.regionFor.keywords(';').forEach [ + it.prepend[space = ''].append[space = ' '] + ] + body.body.statements.rtllist.forEach [ + regionFor.keywords(';').forEach[it.prepend[space = ''].append[space = ' ']] + ] + } else if (sub.body.body.regionForEObject.length > 0 && sub.body.body.isMultiline) { + body.body.statements.rtllist.forEach [ + regionFor.keywords(';').forEach [ + if (it.nextHiddenRegion !== null && it.nextHiddenRegion.isMultiline) { + it.append[newLine] + } else { + it.append[space = ' '] + } + ] + ] + body.body.export.regionFor.keywords(';').forEach [ + if (it.nextHiddenRegion !== null && it.nextHiddenRegion.isMultiline) { + it.append[newLine] + } else { + it.append[space = ' '] + } + ] + body.body.statements.rtllist.forEach [ + if (it.nextHiddenRegion !== null && it.nextHiddenRegion.isMultiline) { + it.append[newLine] + } else { + it.append[space = ' '] + } + ] + } + } + + // length of printpiece + computePrintLength(sub.tableName.name, sub.print); + + // length of match pattern + computeMatchLength(sub.tableName.name, sub.match, sub.cblock); + } + + def dispatch void format(constructprint constructprint, extension IFormattableDocument document) { + for (printpiece printpieces : constructprint.getPrintpieces()) { + format(printpieces, document); + } + format(constructprint.getIs(), document); + } + + def dispatch void format(printpiece printpiece, extension IFormattableDocument document) { + format(printpiece.getSym(), document); + } + + def dispatch void format(pexprAdd pexpradd, extension IFormattableDocument document) { + format(pexpradd.getRight(), document); + format(pexpradd.getLeft(), document); + } + + def dispatch void format(pexprSub pexprsub, extension IFormattableDocument document) { + format(pexprsub.getRight(), document); + format(pexprsub.getLeft(), document); + } + + def dispatch void format(pexprMult pexprmult, extension IFormattableDocument document) { + format(pexprmult.getRight(), document); + format(pexprmult.getLeft(), document); + } + + def dispatch void format(pexprLeft pexprleft, extension IFormattableDocument document) { + format(pexprleft.getRight(), document); + format(pexprleft.getLeft(), document); + } + + def dispatch void format(pexprRight pexprright, extension IFormattableDocument document) { + format(pexprright.getRight(), document); + format(pexprright.getLeft(), document); + } + + def dispatch void format(pexprAnd pexprand, extension IFormattableDocument document) { + format(pexprand.getRight(), document); + format(pexprand.getLeft(), document); + } + + def dispatch void format(pexprOr pexpror, extension IFormattableDocument document) { + format(pexpror.getRight(), document); + format(pexpror.getLeft(), document); + } + + def dispatch void format(pexprXor pexprxor, extension IFormattableDocument document) { + format(pexprxor.getRight(), document); + format(pexprxor.getLeft(), document); + } + + def dispatch void format(pexprDiv pexprdiv, extension IFormattableDocument document) { + format(pexprdiv.getRight(), document); + format(pexprdiv.getLeft(), document); + } + + def dispatch void format(pexprNegate pexprnegate, extension IFormattableDocument document) { + format(pexprnegate.getLeft(), document); + } + + def dispatch void format(pexprInvert pexprinvert, extension IFormattableDocument document) { + format(pexprinvert.getLeft(), document); + } + + def dispatch void format(singlePexpression singlepexpression, extension IFormattableDocument document) { + format(singlepexpression.getIntval(), document); + format(singlepexpression.getSym(), document); + format(singlepexpression.getRight(), document); + } + + def dispatch void format(constraintAdd constraintadd, extension IFormattableDocument document) { + format(constraintadd.getRight(), document); + format(constraintadd.getLeft(), document); + } + + def dispatch void format(constraintSub constraintsub, extension IFormattableDocument document) { + format(constraintsub.getRight(), document); + format(constraintsub.getLeft(), document); + } + + def dispatch void format(constraintMult constraintmult, extension IFormattableDocument document) { + format(constraintmult.getRight(), document); + format(constraintmult.getLeft(), document); + } + + def dispatch void format(constraintLeft constraintleft, extension IFormattableDocument document) { + format(constraintleft.getRight(), document); + format(constraintleft.getLeft(), document); + } + + def dispatch void format(constraintRight constraintright, extension IFormattableDocument document) { + format(constraintright.getRight(), document); + format(constraintright.getLeft(), document); + } + + def dispatch void format(constraintAnd constraintand, extension IFormattableDocument document) { + format(constraintand.getRight(), document); + format(constraintand.getLeft(), document); + } + + def dispatch void format(constraintOr constraintor, extension IFormattableDocument document) { + format(constraintor.getRight(), document); + format(constraintor.getLeft(), document); + } + + def dispatch void format(constraintXor constraintxor, extension IFormattableDocument document) { + format(constraintxor.getRight(), document); + format(constraintxor.getLeft(), document); + } + + def dispatch void format(constraintDiv constraintdiv, extension IFormattableDocument document) { + format(constraintdiv.getRight(), document); + format(constraintdiv.getLeft(), document); + } + + def dispatch void format(constraintNegate constraintnegate, extension IFormattableDocument document) { + format(constraintnegate.getExpr(), document); + } + + def dispatch void format(constraintInvert constraintinvert, extension IFormattableDocument document) { + format(constraintinvert.getExpr(), document); + } + + def dispatch void format(constraintSinglePexpression constraintsinglepexpression, + extension IFormattableDocument document) { + format(constraintsinglepexpression.getIntval(), document); + format(constraintsinglepexpression.getSym(), document); + format(constraintsinglepexpression.getRight(), document); + } + + def dispatch void format(pequation pequation, extension IFormattableDocument document) { + format(pequation.getConstraints(), document); + } + + def dispatch void format(pNextSet pnextset, extension IFormattableDocument document) { + format(pnextset.getRight(), document); + format(pnextset.getLeft(), document); + } + + def dispatch void format(pAnd pand, extension IFormattableDocument document) { + format(pand.getRight(), document); + format(pand.getLeft(), document); + } + + def dispatch void format(pOr por, extension IFormattableDocument document) { + format(por.getRight(), document); + format(por.getLeft(), document); + } + + def dispatch void format(atomic atomic, extension IFormattableDocument document) { + format(atomic.getDefine(), document); + format(atomic.getRight(), document); + } + + def dispatch void format(constraint constraint, extension IFormattableDocument document) { + format(constraint.getValue(), document); + } + + def dispatch void format(contextblock contextblock, extension IFormattableDocument document) { + format(contextblock.getBlock(), document); + } + + def dispatch void format(contextlist contextlist, extension IFormattableDocument document) { + for (contextentry entry : contextlist.getEntry()) { + format(entry, document); + } + } + + def dispatch void format(contextentry contextentry, extension IFormattableDocument document) { + format(contextentry.getRhs(), document); + format(contextentry.getTsym(), document); + } + + def dispatch void format(OPERANDSYM operandsym, extension IFormattableDocument document) { + format(operandsym.getRhs(), document); + } + + def dispatch void format(xrtl xrtl, extension IFormattableDocument document) { + format(xrtl.getStatements(), document); + format(xrtl.getExport(), document); + format(xrtl.getAdditionalStatements(), document); + } + + def dispatch void format(exportStmt exportstmt, extension IFormattableDocument document) { + format(exportstmt.getResultsize(), document); + format(exportstmt.getResult(), document); + } + + def dispatch void format(exportedSym exportedsym, extension IFormattableDocument document) { + format(exportedsym.getVarnode(), document); + format(exportedsym.getSize(), document); + format(exportedsym.getConst(), document); + } + + def dispatch void format(rtlmid rtlmid, extension IFormattableDocument document) { + for (statement rtllist : rtlmid.getRtllist()) { + format(rtllist, document); + } + for (macroUse macro : rtlmid.getMacro()) { + format(macro, document); + } + } + + def dispatch void format(statement statement, extension IFormattableDocument document) { + statement.prepend[setNewLines(0,1,2)] + format(statement.getSection_name(), document); + format(statement.getLhs(), document); + format(statement.getRhs(), document); + format(statement.getPtrsize(), document); + format(statement.getLhsexpr(), document); + format(statement.getStart(), document); + format(statement.getEnd(), document); + format(statement.getCrossvnode(), document); + format(statement.getDelayslot(), document); + format(statement.getDest(), document); + format(statement.getIfexpr(), document); + format(statement.getGotodest(), document); + format(statement.getArgs(), document); + format(statement.getLabel(), document); + } + + def dispatch void format(assignSym assignsym, extension IFormattableDocument document) { + format(assignsym.getLocal(), document); + format(assignsym.getDefine(), document); + } + + def dispatch void format(localDefine localdefine, extension IFormattableDocument document) { + format(localdefine.getSym(), document); + format(localdefine.getSize(), document); + } + + def dispatch void format(exprrAdd exprradd, extension IFormattableDocument document) { + format(exprradd.getRight(), document); + format(exprradd.getLeft(), document); + } + + def dispatch void format(exprMinus exprminus, extension IFormattableDocument document) { + format(exprminus.getRight(), document); + format(exprminus.getLeft(), document); + } + + def dispatch void format(exprEqual exprequal, extension IFormattableDocument document) { + format(exprequal.getRight(), document); + format(exprequal.getLeft(), document); + } + + def dispatch void format(exprNotEqual exprnotequal, extension IFormattableDocument document) { + format(exprnotequal.getRight(), document); + format(exprnotequal.getLeft(), document); + } + + def dispatch void format(exprLess exprless, extension IFormattableDocument document) { + format(exprless.getRight(), document); + format(exprless.getLeft(), document); + } + + def dispatch void format(exprGtEqual exprgtequal, extension IFormattableDocument document) { + format(exprgtequal.getRight(), document); + format(exprgtequal.getLeft(), document); + } + + def dispatch void format(exprLtEqual exprltequal, extension IFormattableDocument document) { + format(exprltequal.getRight(), document); + format(exprltequal.getLeft(), document); + } + + def dispatch void format(exprGt exprgt, extension IFormattableDocument document) { + format(exprgt.getRight(), document); + format(exprgt.getLeft(), document); + } + + def dispatch void format(exprSLess exprsless, extension IFormattableDocument document) { + format(exprsless.getRight(), document); + format(exprsless.getLeft(), document); + } + + def dispatch void format(exprSGtEqual exprsgtequal, extension IFormattableDocument document) { + format(exprsgtequal.getRight(), document); + format(exprsgtequal.getLeft(), document); + } + + def dispatch void format(exprSLtEqual exprsltequal, extension IFormattableDocument document) { + format(exprsltequal.getRight(), document); + format(exprsltequal.getLeft(), document); + } + + def dispatch void format(exprSGt exprsgt, extension IFormattableDocument document) { + format(exprsgt.getRight(), document); + format(exprsgt.getLeft(), document); + } + + def dispatch void format(exprXor exprxor, extension IFormattableDocument document) { + format(exprxor.getRight(), document); + format(exprxor.getLeft(), document); + } + + def dispatch void format(exprAnd exprand, extension IFormattableDocument document) { + format(exprand.getRight(), document); + format(exprand.getLeft(), document); + } + + def dispatch void format(exprOr expror, extension IFormattableDocument document) { + format(expror.getRight(), document); + format(expror.getLeft(), document); + } + + def dispatch void format(exprLeft exprleft, extension IFormattableDocument document) { + format(exprleft.getRight(), document); + format(exprleft.getLeft(), document); + } + + def dispatch void format(exprRight exprright, extension IFormattableDocument document) { + format(exprright.getRight(), document); + format(exprright.getLeft(), document); + } + + def dispatch void format(exprSRight exprsright, extension IFormattableDocument document) { + format(exprsright.getRight(), document); + format(exprsright.getLeft(), document); + } + + def dispatch void format(exprMult exprmult, extension IFormattableDocument document) { + format(exprmult.getRight(), document); + format(exprmult.getLeft(), document); + } + + def dispatch void format(exprDiv exprdiv, extension IFormattableDocument document) { + format(exprdiv.getRight(), document); + format(exprdiv.getLeft(), document); + } + + def dispatch void format(exprSDiv exprsdiv, extension IFormattableDocument document) { + format(exprsdiv.getRight(), document); + format(exprsdiv.getLeft(), document); + } + + def dispatch void format(exprRem exprrem, extension IFormattableDocument document) { + format(exprrem.getRight(), document); + format(exprrem.getLeft(), document); + } + + def dispatch void format(exprSRem exprsrem, extension IFormattableDocument document) { + format(exprsrem.getRight(), document); + format(exprsrem.getLeft(), document); + } + + def dispatch void format(exprBoolXor exprboolxor, extension IFormattableDocument document) { + format(exprboolxor.getRight(), document); + format(exprboolxor.getLeft(), document); + } + + def dispatch void format(exprBoolAnd exprbooland, extension IFormattableDocument document) { + format(exprbooland.getRight(), document); + format(exprbooland.getLeft(), document); + } + + def dispatch void format(exprBoolOr exprboolor, extension IFormattableDocument document) { + format(exprboolor.getRight(), document); + format(exprboolor.getLeft(), document); + } + + def dispatch void format(exprFEqual exprfequal, extension IFormattableDocument document) { + format(exprfequal.getRight(), document); + format(exprfequal.getLeft(), document); + } + + def dispatch void format(exprFNotEqual exprfnotequal, extension IFormattableDocument document) { + format(exprfnotequal.getRight(), document); + format(exprfnotequal.getLeft(), document); + } + + def dispatch void format(exprFLess exprfless, extension IFormattableDocument document) { + format(exprfless.getRight(), document); + format(exprfless.getLeft(), document); + } + + def dispatch void format(exprFGt exprfgt, extension IFormattableDocument document) { + format(exprfgt.getRight(), document); + format(exprfgt.getLeft(), document); + } + + def dispatch void format(exprFLessEqual exprflessequal, extension IFormattableDocument document) { + format(exprflessequal.getRight(), document); + format(exprflessequal.getLeft(), document); + } + + def dispatch void format(exprFGtEqual exprfgtequal, extension IFormattableDocument document) { + format(exprfgtequal.getRight(), document); + format(exprfgtequal.getLeft(), document); + } + + def dispatch void format(exprFAdd exprfadd, extension IFormattableDocument document) { + format(exprfadd.getRight(), document); + format(exprfadd.getLeft(), document); + } + + def dispatch void format(exprFSub exprfsub, extension IFormattableDocument document) { + format(exprfsub.getRight(), document); + format(exprfsub.getLeft(), document); + } + + def dispatch void format(exprFMult exprfmult, extension IFormattableDocument document) { + format(exprfmult.getRight(), document); + format(exprfmult.getLeft(), document); + } + + def dispatch void format(exprFDiv exprfdiv, extension IFormattableDocument document) { + format(exprfdiv.getRight(), document); + format(exprfdiv.getLeft(), document); + } + + def dispatch void format(exprNegate exprnegate, extension IFormattableDocument document) { + format(exprnegate.getExpr(), document); + } + + def dispatch void format(exprFNegate exprfnegate, extension IFormattableDocument document) { + format(exprfnegate.getExpr(), document); + } + + def dispatch void format(exprLoad exprload, extension IFormattableDocument document) { + format(exprload.getLoc(), document); + format(exprload.getExpr(), document); + } + + def dispatch void format(Expression expression, extension IFormattableDocument document) { + format(expression.getVnode(), document); + format(expression.getRight(), document); + format(expression.getOp1(), document); + format(expression.getOp2(), document); + } + + def dispatch void format(exprSym exprsym, extension IFormattableDocument document) { + format(exprsym.getSize(), document); + format(exprsym.getStart(), document); + format(exprsym.getEnd(), document); + format(exprsym.getInode(), document); + } + + def dispatch void format(sizedstar sizedstar, extension IFormattableDocument document) { + format(sizedstar.getSpace(), document); + format(sizedstar.getSize(), document); + } + + def dispatch void format(jumpdest jumpdest, extension IFormattableDocument document) { + format(jumpdest.getInst_start(), document); + format(jumpdest.getInst_end(), document); + format(jumpdest.getConst(), document); + format(jumpdest.getSpace(), document); + } + + def dispatch void format(integervarnode integervarnode, extension IFormattableDocument document) { + format(integervarnode.getReladdr(), document); + format(integervarnode.getConst(), document); + format(integervarnode.getSize(), document); + format(integervarnode.getInode(), document); + } + + def dispatch void format(intblist intblist, extension IFormattableDocument document) { + for (intbpart args : intblist.getArgs()) { + format(args, document); + } + } + + def dispatch void format(intbpart intbpart, extension IFormattableDocument document) { + format(intbpart.getValue(), document); + } + + def dispatch void format(anystringlist anystringlist, extension IFormattableDocument document) { + for (anystringpart namelist : anystringlist.getNamelist()) { + format(namelist, document); + } + } + + def dispatch void format(anystringpart anystringpart, extension IFormattableDocument document) { + format(anystringpart.getSym(), document); + } + + def dispatch void format(valuesymlist valuesymlist, extension IFormattableDocument document) { + for (valuepart valuelist : valuesymlist.getValuelist()) { + format(valuelist, document); + } + format(valuesymlist.getValue(), document); + } + + def dispatch void format(namesymlist namesymlist, extension IFormattableDocument document) { + for (NAMESYM valuelist : namesymlist.getValuelist()) { + format(valuelist, document); + } + format(namesymlist.getValue(), document); + } + + def dispatch void format(varsymlist varsymlist, extension IFormattableDocument document) { + for (valuepartdef valuelist : varsymlist.getValuelist()) { + format(valuelist, document); + } + } + + def dispatch void format(varlist varlist, extension IFormattableDocument document) { + for (varpart varDefList : varlist.getVarDefList()) { + format(varDefList, document); + } + } + + def dispatch void format(paramlist paramlist, extension IFormattableDocument document) { + for (Expression parameters : paramlist.getParameters()) { + format(parameters, document); + } + } + + def dispatch void format(oplist oplist, extension IFormattableDocument document) { + for (MACROPARAMSYM args : oplist.getArgs()) { + format(args, document); + } + } + + def dispatch void format(anysymbol anysymbol, extension IFormattableDocument document) { + format(anysymbol.getSym(), document); + } + + def dispatch void format(integerValue integervalue, extension IFormattableDocument document) { + format(integervalue.getSym(), document); + } + + def dispatch void format(elleqRight elleqright, extension IFormattableDocument document) { + format(elleqright.getLeft(), document); + } +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/generator/SleighGenerator.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/generator/SleighGenerator.xtend new file mode 100644 index 0000000000..20d6025615 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/generator/SleighGenerator.xtend @@ -0,0 +1,32 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.generator + +import org.eclipse.emf.ecore.resource.Resource +import org.eclipse.xtext.generator.AbstractGenerator +import org.eclipse.xtext.generator.IFileSystemAccess2 +import org.eclipse.xtext.generator.IGeneratorContext + +/** + * Generates code from your model files on save. + * + * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#code-generation + */ +class SleighGenerator extends AbstractGenerator { + + override void doGenerate(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) { + } +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/scoping/SleighScopeProvider.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/scoping/SleighScopeProvider.xtend new file mode 100644 index 0000000000..67078b6bff --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/scoping/SleighScopeProvider.xtend @@ -0,0 +1,237 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.scoping + + +import com.google.common.base.Function +import com.google.common.base.Predicate +import java.util.ArrayList +import java.util.List +import org.eclipse.emf.ecore.EObject +import org.eclipse.emf.ecore.EReference +import org.eclipse.xtext.naming.QualifiedName +import org.eclipse.xtext.resource.IEObjectDescription +import org.eclipse.xtext.scoping.IScope +import org.eclipse.xtext.scoping.Scopes +import org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider +import org.eclipse.xtext.scoping.impl.FilteringScope +import org.eclipse.xtext.scoping.impl.ScopeBasedSelectable +import org.eclipse.xtext.scoping.impl.SelectableBasedScope +import ghidra.xtext.sleigh.sleigh.LOCALSYM +import ghidra.xtext.sleigh.sleigh.aliasSym +import ghidra.xtext.sleigh.sleigh.assignSym +import ghidra.xtext.sleigh.sleigh.constraint +import ghidra.xtext.sleigh.sleigh.constructor +import ghidra.xtext.sleigh.sleigh.contextblock +import ghidra.xtext.sleigh.sleigh.contextentry +import ghidra.xtext.sleigh.sleigh.exportedSym +import ghidra.xtext.sleigh.sleigh.exprSym +import ghidra.xtext.sleigh.sleigh.globalLoc +import ghidra.xtext.sleigh.sleigh.macrodef +import ghidra.xtext.sleigh.sleigh.pexprSym +import ghidra.xtext.sleigh.sleigh.rtlbody +import ghidra.xtext.sleigh.sleigh.rtlmid +import ghidra.xtext.sleigh.sleigh.statement +import ghidra.xtext.sleigh.sleigh.xrtl + +import static extension org.eclipse.xtext.EcoreUtil2.* + +/** + * This class contains custom scoping description. + * + * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#scoping + * on how and when to use it. + */ +public class SleighScopeProvider extends AbstractDeclarativeScopeProvider { + + override getScope(EObject context, EReference ref) { + //System.out.println(context.class.name + " - " + ref.name + " : ") + var scope = super.getScope(context, ref) + //System.out.println(" " + scope.toString) + return scope + } + + def IScope scope_assignSym_symref(assignSym context, EReference eReference) { + var localScope = context.eContainer.symbolsDefinedBefore(context) + var cont = context.getContainerOfType(typeof(rtlbody)); + var superscope = super.getDelegate().getScope(cont, eReference) + return createFilteredLocalScope(superscope, localScope, eReference) + } + + def IScope scope_exprSym_vnode(exprSym context, EReference eReference) { + var localScope = context.eContainer.symbolsDefinedBefore(context) + var cont = context.getContainerOfType(typeof(rtlbody)); + var superscope = super.getDelegate().getScope(cont, eReference) + return createFilteredLocalScope(superscope, localScope, eReference) + } + + def IScope scope_exportedSym_symref(exportedSym context, EReference eReference) { + var localScope = context.eContainer.symbolsDefinedBefore(context) + var cont = context.getContainerOfType(typeof(rtlbody)); + var superscope = super.getDelegate().getScope(cont, eReference) + createFilteredLocalScope(superscope, localScope, eReference) + } + + + def IScope scope_pexprSym_sym(pexprSym context, EReference eReference) { + var localScope = context.eContainer.symbolsDefinedBefore(context) + var cont = context.getContainerOfType(typeof(constructor)); + var superscope = super.getDelegate().getScope(cont, eReference) + createFilteredLocalScope(superscope, localScope, eReference) + } + + + def IScope scope_constraint_sym(constraint context, EReference eReference) { + var cont = context.getContainerOfType(typeof(constructor)); + var superscope = super.getDelegate().getScope(cont, eReference) + var scope= createFilteredLocalScope(superscope, IScope.NULLSCOPE, eReference) + scope + } + + def IScope scope_aliasSym_symref(aliasSym context, EReference eReference) { + var cont = context.getContainerOfType(typeof(constructor)); + var localScope = printPieceScope(cont,IScope.NULLSCOPE); + localScope + } + + def IScope scope_contextentry_lhs(contextentry context, EReference eReference) { + var cont = context.getContainerOfType(typeof(constructor)); + var localScope = printPieceScope(cont,IScope.NULLSCOPE); + var superscope = super.getDelegate().getScope(cont, eReference) + createFilteredLocalScope(superscope, localScope, eReference) + } + + def IScope scope_globalLoc_tsym(globalLoc context, EReference eReference) { + var cont = context.getContainerOfType(typeof(constructor)); + var localScope = printPieceScope(cont,IScope.NULLSCOPE); + var superscope = super.getDelegate().getScope(cont, eReference) + createFilteredLocalScope(superscope, localScope, eReference) + } + + def IScope createFilteredLocalScope(IScope supscope, IScope localScope, EReference eReference) { + var filtscope = new FilteringScope(supscope, new Predicate() { + override apply(IEObjectDescription input) { + val sym = input.getEObjectOrProxy() + var notAliasOrLocal = !((sym instanceof LOCALSYM) || (sym instanceof aliasSym)) + return notAliasOrLocal + } + }); + + // Do scope in reverse, aliasSyms are just and alias, choose global scope over alias + // The global scope has all LOCALSYM and aliasSym filtered out. + // This may not be the most efficient method, but works. + // Also for LOCALSYM, a Global sym may shadow it. Not quite right + // Should really be (LOCALSYM, Global(outerscope), AliasSym) + var scope = SelectableBasedScope.createScope(localScope, new ScopeBasedSelectable(filtscope), + eReference.getEReferenceType(), false) + scope + } + + def dispatch IScope symbolsDefinedBefore(EObject context, EObject o) { + context.eContainer.symbolsDefinedBefore(o) + } + + def dispatch IScope symbolsDefinedBefore(macrodef context, EObject o) { + Scopes::scopeFor( + context.args.args, + context.symbolsDefinedBefore(o.eContainer) + ) + } + + def dispatch IScope symbolsDefinedBefore(constructor s, EObject o) { + var scope = Scopes::scopeFor(s.eContents) + printPieceScope(s,scope); + } + + def dispatch IScope symbolsDefinedBefore(contextblock s, EObject o) { + var scope = Scopes::scopeFor(s.eContents, s.eContainer.symbolsDefinedBefore(o.eContainer)) + var cont = s.getContainerOfType(typeof(constructor)) + printPieceScope(cont,scope); + } + + def dispatch IScope symbolsDefinedBefore(rtlbody b, EObject o) { + var scope = Scopes::scopeFor( + b.body.statements.rtllist.variablesDeclaredBefore(o) + ) + var cont = b.getContainerOfType(typeof(constructor)); + printPieceScope(cont,scope); + } + + def dispatch IScope symbolsDefinedBefore(rtlmid b, EObject o) { + return symbolsDefinedBefore(b.eContainer, o); + } + + def dispatch IScope symbolsDefinedBefore(xrtl b, EObject o) { + var syms = b.statements.rtllist.variablesDeclaredBefore(null); + if (b.additionalStatements != null) { + syms.addAll(b.additionalStatements.rtllist.variablesDeclaredBefore(null)) + } + var scope = Scopes::scopeFor(syms) + var cont = b.getContainerOfType(typeof(constructor)); + printPieceScope(cont,scope); + } + + // Create a scope for all ID symbols in printpiece + def printPieceScope(constructor cont, IScope outerScope) { + if (cont == null) return outerScope + var vars = cont.variablesDeclaredIn() + var q = QualifiedName.wrapper(new Function() { + + override apply(aliasSym input) { + if (input == null) return null; + input.sym + } + }) + var localScope = Scopes.scopeFor(vars, q, outerScope) + localScope + } + + // things in context block must be in printpieces + def private variablesDeclaredIn(constructor b) { + var iter = b.print.printpieces.iterator; + var List list = new ArrayList(); + while (iter.hasNext) { + var piece = iter.next; + if (piece.sym instanceof aliasSym) { + list.add(piece.sym) + } + } + return list + } + + def private variablesDeclaredBefore(List list, EObject o) { + var end = list.size - 1; + if (o != null) { + end = list.indexOf(o); + } + val sublist = list.subList(0, end + 1); + var iter = sublist.iterator; + var List locList = new ArrayList(); + while (iter.hasNext) { + var obj = iter.next; + if (obj instanceof statement) { + var stmt = obj as statement; + if (stmt.lhs != null && stmt.lhs.local != null && stmt.lhs.local.sym instanceof LOCALSYM) { + locList.add(stmt.lhs.local.sym as LOCALSYM); + } + if (stmt.ldef != null && stmt.ldef.sym instanceof LOCALSYM) { + locList.add(stmt.ldef.sym as LOCALSYM); + } + } + } + return locList; + } +} diff --git a/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/validation/SleighValidator.xtend b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/validation/SleighValidator.xtend new file mode 100644 index 0000000000..b2e46bbd62 --- /dev/null +++ b/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh/src/ghidra/xtext/sleigh/validation/SleighValidator.xtend @@ -0,0 +1,169 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.xtext.sleigh.validation + + + +import java.util.HashMap +import java.util.HashSet +import org.eclipse.xtext.validation.Check +import ghidra.xtext.sleigh.sleigh.Model +import ghidra.xtext.sleigh.sleigh.SleighPackage +import ghidra.xtext.sleigh.sleigh.VARSYM +import ghidra.xtext.sleigh.sleigh.constraint +import ghidra.xtext.sleigh.sleigh.contextdef +import ghidra.xtext.sleigh.sleigh.contextfielddef +import ghidra.xtext.sleigh.sleigh.fielddef +import ghidra.xtext.sleigh.sleigh.tokendef +import ghidra.xtext.sleigh.sleigh.vardef +import ghidra.xtext.sleigh.sleigh.varnodedef + +import static extension org.eclipse.emf.ecore.util.EcoreUtil.* +import static extension org.eclipse.xtext.EcoreUtil2.* + +/** + * This class contains custom validation rules. + * + * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#validation + */ +class SleighValidator extends AbstractSleighValidator { + + var HashMap>> typeMap; + + @Check + def void checkModelInitialize(Model m) { + // model should be validated each time before the sub objects + // are validated, so initialize the cache + typeMap = new HashMap(); + } + + /** + * Add a name entry to the set of names->definitions Object map + */ + def addNameEntryToSet(HashMap> map, String name, Object other) { + var HashSet set = map.get(name); + if (set == null) { + set = new HashSet(); + map.put(name,set); + } + set.add(other) + } + + @Check + def void checkTokenNameIsUnique(fielddef f) { + if (checkDuplicate(f)) { + warning("token field names have to be unique", SleighPackage.eINSTANCE.getfielddef_Name); + return; + } + } + + def boolean checkDuplicate(fielddef f) { + var type = typeof(tokendef) + var HashMap> map = typeMap.get(type); + if (map == null) { + map = new HashMap>(); + typeMap.put(type,map); + var defList = f.getRootContainer(true).getAllContentsOfType(type) + var iter = defList.iterator; + while (iter.hasNext()) { + var def = iter.next(); + var fiter = def.getAllContentsOfType(typeof(fielddef)).iterator; + while (fiter.hasNext()) { + var other = fiter.next(); + var name = other.getName(); + addNameEntryToSet(map, name, other); + } + } + } + var HashSet set = map.get(f.name); + return (set != null && set.size > 1) + } + + @Check + def void checkTokenNameIsUnique(contextfielddef f) { + if (checkDuplicate(f)) { + warning("context field names have to be unique", SleighPackage.eINSTANCE.getcontextfielddef_Name); + return; + } + } + + def boolean checkDuplicate(contextfielddef f) { + var type = typeof(contextdef) + var HashMap> map = typeMap.get(type); + // if map hasn't been initialized, initialize it + if (map == null) { + map = new HashMap>() + typeMap.put(type,map) + var defList = f.getRootContainer(true).getAllContentsOfType(type) + var iter = defList.iterator + while (iter.hasNext()) { + var def = iter.next() + var fiter = def.getAllContentsOfType(typeof(contextfielddef)).iterator + while (fiter.hasNext()) { + var other = fiter.next() + var name = other.getName() + addNameEntryToSet(map, name, other) + } + } + } + var HashSet set = map.get(f.name); + return (set != null && set.size > 1) + } + + @Check + def void checkTokenNameIsUnique(VARSYM v) { + if (checkDuplicate(v)) { + warning("var names have to be unique", SleighPackage.eINSTANCE.VARSYM_Name); + return; + } + } + + def boolean checkDuplicate(VARSYM v) { + var type = typeof(varnodedef) + var HashMap> map = typeMap.get(type); + if (map == null) { + map = new HashMap>(); + typeMap.put(type,map); + var defList = v.getRootContainer(true).getAllContentsOfType(type) + var iter = defList.iterator; + while (iter.hasNext()) { + var def = iter.next(); + var fiter = def.getAllContentsOfType(typeof(vardef)).iterator; + while (fiter.hasNext()) { + var other = fiter.next(); + var name = other.varname.name; + addNameEntryToSet(map, name, other); + } + } + } + var HashSet set = map.get(v.name); + return (set != null && set.size > 1) + } + + @Check + def void checkWarnExpensiveOperation(constraint c) { + var op = c.compareOp + if (op == null || op.equals('=')) { + return; + } + // TODO: Could check if the op token size is small, don't warn + // For token sizes, this should not be so expensive 2,3 + + // comparison operations can be expensive + warning("comparison can be expensive, and should be used sparingly", SleighPackage.eINSTANCE.getconstraint_CompareOp) + } +} +