Merge remote-tracking branch 'origin/ghidra1_Emulator'

Conflicts:
	gradle/root/eclipse.gradle
This commit is contained in:
ghidra1
2019-07-12 16:14:17 -04:00
257 changed files with 32702 additions and 232 deletions

View File

@@ -0,0 +1,49 @@
##VERSION: 2.0
ghidra.xtext.sleigh.feature/build.gradle||GHIDRA||||END|
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.gradle||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.gradle||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.gradle||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.gradle||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/console/ConsoleHyperlinking.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/GhidraSleighEditor_README.html||GHIDRA||||END|
ghidra.xtext.sleigh/META-INF/MANIFEST.MF||GHIDRA||||END|
ghidra.xtext.sleigh/build.gradle||GHIDRA||||END|
ghidra.xtext.sleigh/build.properties||GHIDRA||||END|
ghidra.xtext.sleigh/build_README.txt||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|

View File

@@ -0,0 +1,12 @@
// This project requires the Eclipse DSL plugin. To create Eclipse files for this project, run
// "gradle eclipse -PeclipseDSL"
if (hasProperty("eclipseDSL")) {
apply plugin: 'eclipse'
eclipse {
project {
name = 'Eclipse SleighEditor Feature'
buildCommand 'org.eclipse.pde.FeatureBuilder'
natures 'org.eclipse.pde.FeatureNature'
}
}
}

View File

@@ -0,0 +1,2 @@
bin.includes = feature.xml,\
category.xml

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<site>
<feature url="features/ghidra.xtext.sleigh.feature_1.0.0.qualifier.jar" id="ghidra.xtext.sleigh.feature" version="1.0.0.qualifier">
<category name="ghidra.xtext.sleigh.editor"/>
</feature>
<category-def name="ghidra.xtext.sleigh.editor" label="Ghidra"/>
</site>

View File

@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<feature
id="ghidra.xtext.sleigh.feature"
label="Ghidra Sleigh Editor"
version="1.0.0.qualifier"
provider-name="Ghidra">
<copyright>
None
</copyright>
<license url="">
Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
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 &quot;AS IS&quot; 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.
</license>
<requires>
<import plugin="org.eclipse.xtext"/>
<import plugin="org.eclipse.xtext.xbase"/>
<import plugin="org.eclipse.xtext.ide"/>
<import plugin="org.eclipse.xtext.xbase.ide"/>
<import plugin="org.eclipse.xtext.ui"/>
<import plugin="org.eclipse.xtext.builder"/>
</requires>
<plugin
id="ghidra.xtext.sleigh"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="ghidra.xtext.sleigh.ide"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="ghidra.xtext.sleigh.ui"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
</feature>

View File

@@ -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: Ghidra
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-1.8
Export-Package: ghidra.xtext.sleigh.ide.contentassist.antlr,
ghidra.xtext.sleigh.ide.contentassist.antlr.internal

View File

@@ -0,0 +1,40 @@
apply plugin: 'java'
// This project requires the Eclipse DSL plugin. To create Eclipse files for this project, run
// "gradle eclipse -PeclipseDSL"
if (hasProperty("eclipseDSL")) {
apply plugin: 'eclipse'
eclipse {
project {
name = 'Eclipse SleighEditor IDE'
buildCommand 'org.eclipse.pde.ManifestBuilder'
buildCommand 'org.eclipse.pde.SchemaBuilder'
buildCommand 'org.eclipse.xtext.ui.shared.xtextBuilder'
natures 'org.eclipse.pde.PluginNature'
natures 'org.eclipse.xtext.ui.shared.xtextNature'
classpath.file {
def requiredPlugins = 'org.eclipse.pde.core.requiredPlugins'
beforeMerged { classpath ->
classpath.entries.removeAll { entry ->
entry.path == requiredPlugins
}
}
whenMerged { classpath ->
withXml {
def node = it.asNode()
node.appendNode('classpathentry', [kind: 'con', path: requiredPlugins])
}
}
}
}
}
sourceSets {
main {
java {
srcDir 'src'
srcDir 'src-gen'
srcDir 'xtend-gen'
}
}
}
}

View File

@@ -0,0 +1,6 @@
source.. = src/,\
src-gen/,\
xtend-gen/
bin.includes = .,\
META-INF/
bin.excludes = **/*.xtend

View File

@@ -0,0 +1,23 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
* 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 &quot;AS IS&quot; 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 {
}

View File

@@ -0,0 +1,32 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
* 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 &quot;AS IS&quot; 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))
}
}

View File

@@ -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: Ghidra
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-1.8
Export-Package: ghidra.xtext.sleigh.tests;x-internal=true

View File

@@ -0,0 +1,40 @@
apply plugin: 'java'
// This project requires the Eclipse DSL plugin. To create Eclipse files for this project, run
// "gradle eclipse -PeclipseDSL"
if (hasProperty("eclipseDSL")) {
apply plugin: 'eclipse'
eclipse {
project {
name = 'Eclipse SleighEditor Tests'
buildCommand 'org.eclipse.pde.ManifestBuilder'
buildCommand 'org.eclipse.pde.SchemaBuilder'
buildCommand 'org.eclipse.xtext.ui.shared.xtextBuilder'
natures 'org.eclipse.pde.PluginNature'
natures 'org.eclipse.xtext.ui.shared.xtextNature'
classpath.file {
def requiredPlugins = 'org.eclipse.pde.core.requiredPlugins'
beforeMerged { classpath ->
classpath.entries.removeAll { entry ->
entry.path == requiredPlugins
}
}
whenMerged { classpath ->
withXml {
def node = it.asNode()
node.appendNode('classpathentry', [kind: 'con', path: requiredPlugins])
}
}
}
}
}
sourceSets {
main {
java {
srcDir 'src'
srcDir 'src-gen'
srcDir 'xtend-gen'
}
}
}
}

View File

@@ -0,0 +1,6 @@
source.. = src/,\
src-gen/,\
xtend-gen/
bin.includes = .,\
META-INF/
bin.excludes = **/*.xtend

View File

@@ -0,0 +1,171 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
* 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 &quot;AS IS&quot; 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<Model>
@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 {
<label1>
tmp:1 = N;
if (tmp == 0) goto <label1>;
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;
<<LOOP>>
pc = 0;
goto [pc];
}
:L is op=0x999 {
build Parallel32;
<<COMMIT>>
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
}
}

View File

@@ -0,0 +1,89 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
* 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 &quot;AS IS&quot; 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<Model>
@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'."
)
}
}

View File

@@ -0,0 +1,194 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
* 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 &quot;AS IS&quot; 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<Model> 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
}
}

View File

@@ -0,0 +1,301 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
* 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 &quot;AS IS&quot; 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<Model> parser
@Inject extension ValidationTestHelper validationTester
@Inject
private Provider<XtextResourceSet> 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)
]
}
}

View File

@@ -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: Ghidra
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-1.8
Export-Package: ghidra.xtext.sleigh.ui.tests;x-internal=true

View File

@@ -0,0 +1,40 @@
apply plugin: 'java'
// This project requires the Eclipse DSL plugin. To create Eclipse files for this project, run
// "gradle eclipse -PeclipseDSL"
if (hasProperty("eclipseDSL")) {
apply plugin: 'eclipse'
eclipse {
project {
name = 'Eclipse SleighEditor UI Tests'
buildCommand 'org.eclipse.pde.ManifestBuilder'
buildCommand 'org.eclipse.pde.SchemaBuilder'
buildCommand 'org.eclipse.xtext.ui.shared.xtextBuilder'
natures 'org.eclipse.pde.PluginNature'
natures 'org.eclipse.xtext.ui.shared.xtextNature'
classpath.file {
def requiredPlugins = 'org.eclipse.pde.core.requiredPlugins'
beforeMerged { classpath ->
classpath.entries.removeAll { entry ->
entry.path == requiredPlugins
}
}
whenMerged { classpath ->
withXml {
def node = it.asNode()
node.appendNode('classpathentry', [kind: 'con', path: requiredPlugins])
}
}
}
}
}
sourceSets {
main {
java {
srcDir 'src'
srcDir 'src-gen'
srcDir 'xtend-gen'
}
}
}
}

View File

@@ -0,0 +1,6 @@
source.. = src/,\
src-gen/,\
xtend-gen/
bin.includes = .,\
META-INF/
bin.excludes = **/*.xtend

View File

@@ -0,0 +1,27 @@
Manifest-Version: 1.0
Automatic-Module-Name: ghidra.xtext.sleigh.ui
Bundle-ManifestVersion: 2
Bundle-Name: ghidra.xtext.sleigh.ui
Bundle-Vendor: Ghidra
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,
org.eclipse.ui.console
Import-Package: org.apache.log4j
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
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

View File

@@ -0,0 +1,40 @@
apply plugin: 'java'
// This project requires the Eclipse DSL plugin. To create Eclipse files for this project, run
// "gradle eclipse -PeclipseDSL"
if (hasProperty("eclipseDSL")) {
apply plugin: 'eclipse'
eclipse {
project {
name = 'Eclipse SleighEditor UI'
buildCommand 'org.eclipse.pde.ManifestBuilder'
buildCommand 'org.eclipse.pde.SchemaBuilder'
buildCommand 'org.eclipse.xtext.ui.shared.xtextBuilder'
natures 'org.eclipse.pde.PluginNature'
natures 'org.eclipse.xtext.ui.shared.xtextNature'
classpath.file {
def requiredPlugins = 'org.eclipse.pde.core.requiredPlugins'
beforeMerged { classpath ->
classpath.entries.removeAll { entry ->
entry.path == requiredPlugins
}
}
whenMerged { classpath ->
withXml {
def node = it.asNode()
node.appendNode('classpathentry', [kind: 'con', path: requiredPlugins])
}
}
}
}
}
sourceSets {
main {
java {
srcDir 'src'
srcDir 'src-gen'
srcDir 'xtend-gen'
}
}
}
}

View File

@@ -0,0 +1,7 @@
source.. = src/,\
src-gen/,\
xtend-gen/
bin.includes = .,\
META-INF/,\
plugin.xml
bin.excludes = **/*.xtend

View File

@@ -0,0 +1,571 @@
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.0"?>
<plugin>
<extension
point="org.eclipse.ui.editors">
<editor
class="ghidra.xtext.sleigh.ui.SleighExecutableExtensionFactory:org.eclipse.xtext.ui.editor.XtextEditor"
contributorClass="org.eclipse.ui.editors.text.TextEditorActionContributor"
default="true"
extensions="slaspec,sinc"
id="ghidra.xtext.sleigh.Sleigh"
name="Sleigh Editor">
</editor>
</extension>
<extension
point="org.eclipse.ui.handlers">
<handler
class="ghidra.xtext.sleigh.ui.SleighExecutableExtensionFactory:org.eclipse.xtext.ui.editor.hyperlinking.OpenDeclarationHandler"
commandId="org.eclipse.xtext.ui.editor.hyperlinking.OpenDeclaration">
<activeWhen>
<reference
definitionId="ghidra.xtext.sleigh.Sleigh.Editor.opened">
</reference>
</activeWhen>
</handler>
<handler
class="ghidra.xtext.sleigh.ui.SleighExecutableExtensionFactory:org.eclipse.xtext.ui.editor.handler.ValidateActionHandler"
commandId="ghidra.xtext.sleigh.Sleigh.validate">
<activeWhen>
<reference
definitionId="ghidra.xtext.sleigh.Sleigh.Editor.opened">
</reference>
</activeWhen>
</handler>
<!-- copy qualified name -->
<handler
class="ghidra.xtext.sleigh.ui.SleighExecutableExtensionFactory:org.eclipse.xtext.ui.editor.copyqualifiedname.EditorCopyQualifiedNameHandler"
commandId="org.eclipse.xtext.ui.editor.copyqualifiedname.EditorCopyQualifiedName">
<activeWhen>
<reference definitionId="ghidra.xtext.sleigh.Sleigh.Editor.opened" />
</activeWhen>
</handler>
<handler
class="ghidra.xtext.sleigh.ui.SleighExecutableExtensionFactory:org.eclipse.xtext.ui.editor.copyqualifiedname.OutlineCopyQualifiedNameHandler"
commandId="org.eclipse.xtext.ui.editor.copyqualifiedname.OutlineCopyQualifiedName">
<activeWhen>
<and>
<reference definitionId="ghidra.xtext.sleigh.Sleigh.XtextEditor.opened" />
<iterate>
<adapt type="org.eclipse.xtext.ui.editor.outline.IOutlineNode" />
</iterate>
</and>
</activeWhen>
</handler>
</extension>
<extension point="org.eclipse.core.expressions.definitions">
<definition id="ghidra.xtext.sleigh.Sleigh.Editor.opened">
<and>
<reference definitionId="isActiveEditorAnInstanceOfXtextEditor"/>
<with variable="activeEditor">
<test property="org.eclipse.xtext.ui.editor.XtextEditor.languageName"
value="ghidra.xtext.sleigh.Sleigh"
forcePluginActivation="true"/>
</with>
</and>
</definition>
<definition id="ghidra.xtext.sleigh.Sleigh.XtextEditor.opened">
<and>
<reference definitionId="isXtextEditorActive"/>
<with variable="activeEditor">
<test property="org.eclipse.xtext.ui.editor.XtextEditor.languageName"
value="ghidra.xtext.sleigh.Sleigh"
forcePluginActivation="true"/>
</with>
</and>
</definition>
</extension>
<extension
point="org.eclipse.ui.preferencePages">
<page
class="ghidra.xtext.sleigh.ui.SleighExecutableExtensionFactory:org.eclipse.xtext.ui.editor.preferences.LanguageRootPreferencePage"
id="ghidra.xtext.sleigh.Sleigh"
name="Sleigh">
<keywordReference id="ghidra.xtext.sleigh.ui.keyword_Sleigh"/>
</page>
<page
category="ghidra.xtext.sleigh.Sleigh"
class="ghidra.xtext.sleigh.ui.SleighExecutableExtensionFactory:org.eclipse.xtext.ui.editor.syntaxcoloring.SyntaxColoringPreferencePage"
id="ghidra.xtext.sleigh.Sleigh.coloring"
name="Syntax Coloring">
<keywordReference id="ghidra.xtext.sleigh.ui.keyword_Sleigh"/>
</page>
<page
category="ghidra.xtext.sleigh.Sleigh"
class="ghidra.xtext.sleigh.ui.SleighExecutableExtensionFactory:org.eclipse.xtext.ui.editor.templates.XtextTemplatePreferencePage"
id="ghidra.xtext.sleigh.Sleigh.templates"
name="Templates">
<keywordReference id="ghidra.xtext.sleigh.ui.keyword_Sleigh"/>
</page>
</extension>
<extension
point="org.eclipse.ui.propertyPages">
<page
class="ghidra.xtext.sleigh.ui.SleighExecutableExtensionFactory:org.eclipse.xtext.ui.editor.preferences.LanguageRootPreferencePage"
id="ghidra.xtext.sleigh.Sleigh"
name="Sleigh">
<keywordReference id="ghidra.xtext.sleigh.ui.keyword_Sleigh"/>
<enabledWhen>
<adapt type="org.eclipse.core.resources.IProject"/>
</enabledWhen>
<filter name="projectNature" value="org.eclipse.xtext.ui.shared.xtextNature"/>
</page>
</extension>
<extension
point="org.eclipse.ui.keywords">
<keyword
id="ghidra.xtext.sleigh.ui.keyword_Sleigh"
label="Sleigh"/>
</extension>
<extension
point="org.eclipse.ui.commands">
<command
description="Trigger expensive validation"
id="ghidra.xtext.sleigh.Sleigh.validate"
name="Validate">
</command>
<!-- copy qualified name -->
<command
id="org.eclipse.xtext.ui.editor.copyqualifiedname.EditorCopyQualifiedName"
categoryId="org.eclipse.ui.category.edit"
description="Copy the qualified name for the selected element"
name="Copy Qualified Name">
</command>
<command
id="org.eclipse.xtext.ui.editor.copyqualifiedname.OutlineCopyQualifiedName"
categoryId="org.eclipse.ui.category.edit"
description="Copy the qualified name for the selected element"
name="Copy Qualified Name">
</command>
</extension>
<extension point="org.eclipse.ui.menus">
<menuContribution
locationURI="popup:#TextEditorContext?after=group.edit">
<command
commandId="ghidra.xtext.sleigh.Sleigh.validate"
style="push"
tooltip="Trigger expensive validation">
<visibleWhen checkEnabled="false">
<reference
definitionId="ghidra.xtext.sleigh.Sleigh.Editor.opened">
</reference>
</visibleWhen>
</command>
</menuContribution>
<!-- copy qualified name -->
<menuContribution locationURI="popup:#TextEditorContext?after=copy">
<command commandId="org.eclipse.xtext.ui.editor.copyqualifiedname.EditorCopyQualifiedName"
style="push" tooltip="Copy Qualified Name">
<visibleWhen checkEnabled="false">
<reference definitionId="ghidra.xtext.sleigh.Sleigh.Editor.opened" />
</visibleWhen>
</command>
</menuContribution>
<menuContribution locationURI="menu:edit?after=copy">
<command commandId="org.eclipse.xtext.ui.editor.copyqualifiedname.EditorCopyQualifiedName"
style="push" tooltip="Copy Qualified Name">
<visibleWhen checkEnabled="false">
<reference definitionId="ghidra.xtext.sleigh.Sleigh.Editor.opened" />
</visibleWhen>
</command>
</menuContribution>
<menuContribution locationURI="popup:org.eclipse.xtext.ui.outline?after=additions">
<command commandId="org.eclipse.xtext.ui.editor.copyqualifiedname.OutlineCopyQualifiedName"
style="push" tooltip="Copy Qualified Name">
<visibleWhen checkEnabled="false">
<and>
<reference definitionId="ghidra.xtext.sleigh.Sleigh.XtextEditor.opened" />
<iterate>
<adapt type="org.eclipse.xtext.ui.editor.outline.IOutlineNode" />
</iterate>
</and>
</visibleWhen>
</command>
</menuContribution>
</extension>
<extension point="org.eclipse.ui.menus">
<menuContribution locationURI="popup:#TextEditorContext?endof=group.find">
<command commandId="org.eclipse.xtext.ui.editor.FindReferences">
<visibleWhen checkEnabled="false">
<reference definitionId="ghidra.xtext.sleigh.Sleigh.Editor.opened">
</reference>
</visibleWhen>
</command>
</menuContribution>
</extension>
<extension point="org.eclipse.ui.handlers">
<handler
class="ghidra.xtext.sleigh.ui.SleighExecutableExtensionFactory:org.eclipse.xtext.ui.editor.findrefs.FindReferencesHandler"
commandId="org.eclipse.xtext.ui.editor.FindReferences">
<activeWhen>
<reference
definitionId="ghidra.xtext.sleigh.Sleigh.Editor.opened">
</reference>
</activeWhen>
</handler>
</extension>
<extension point="org.eclipse.core.contenttype.contentTypes">
<content-type
base-type="org.eclipse.core.runtime.text"
file-extensions="slaspec,sinc"
id="ghidra.xtext.sleigh.Sleigh.contenttype"
name="Sleigh File"
priority="normal">
</content-type>
</extension>
<!-- adding resource factories -->
<extension
point="org.eclipse.emf.ecore.extension_parser">
<parser
class="ghidra.xtext.sleigh.ui.SleighExecutableExtensionFactory:org.eclipse.xtext.resource.IResourceFactory"
type="slaspec">
</parser>
</extension>
<extension point="org.eclipse.xtext.extension_resourceServiceProvider">
<resourceServiceProvider
class="ghidra.xtext.sleigh.ui.SleighExecutableExtensionFactory:org.eclipse.xtext.ui.resource.IResourceUIServiceProvider"
uriExtension="slaspec">
</resourceServiceProvider>
</extension>
<extension
point="org.eclipse.emf.ecore.extension_parser">
<parser
class="ghidra.xtext.sleigh.ui.SleighExecutableExtensionFactory:org.eclipse.xtext.resource.IResourceFactory"
type="sinc">
</parser>
</extension>
<extension point="org.eclipse.xtext.extension_resourceServiceProvider">
<resourceServiceProvider
class="ghidra.xtext.sleigh.ui.SleighExecutableExtensionFactory:org.eclipse.xtext.ui.resource.IResourceUIServiceProvider"
uriExtension="sinc">
</resourceServiceProvider>
</extension>
<!-- marker definitions for ghidra.xtext.sleigh.Sleigh -->
<extension
id="sleigh.check.fast"
name="Sleigh Problem"
point="org.eclipse.core.resources.markers">
<super type="org.eclipse.xtext.ui.check.fast"/>
<persistent value="true"/>
</extension>
<extension
id="sleigh.check.normal"
name="Sleigh Problem"
point="org.eclipse.core.resources.markers">
<super type="org.eclipse.xtext.ui.check.normal"/>
<persistent value="true"/>
</extension>
<extension
id="sleigh.check.expensive"
name="Sleigh Problem"
point="org.eclipse.core.resources.markers">
<super type="org.eclipse.xtext.ui.check.expensive"/>
<persistent value="true"/>
</extension>
<extension point="org.eclipse.ui.preferencePages">
<page
category="ghidra.xtext.sleigh.Sleigh"
class="ghidra.xtext.sleigh.ui.SleighExecutableExtensionFactory:org.eclipse.xtext.ui.validation.ValidatorPreferencePage"
id="ghidra.xtext.sleigh.Sleigh.validator.preferencePage"
name="Errors/Warnings">
<keywordReference id="ghidra.xtext.sleigh.ui.keyword_Sleigh"/>
</page>
</extension>
<extension point="org.eclipse.xtext.builder.participant">
<participant
class="ghidra.xtext.sleigh.ui.SleighExecutableExtensionFactory:org.eclipse.xtext.builder.IXtextBuilderParticipant"
fileExtensions="slaspec,sinc"/>
</extension>
<extension point="org.eclipse.ui.preferencePages">
<page
category="ghidra.xtext.sleigh.Sleigh"
class="ghidra.xtext.sleigh.ui.SleighExecutableExtensionFactory:org.eclipse.xtext.builder.preferences.BuilderPreferencePage"
id="ghidra.xtext.sleigh.Sleigh.compiler.preferencePage"
name="Compiler">
<keywordReference id="ghidra.xtext.sleigh.ui.keyword_Sleigh"/>
</page>
</extension>
<extension point="org.eclipse.ui.propertyPages">
<page
category="ghidra.xtext.sleigh.Sleigh"
class="ghidra.xtext.sleigh.ui.SleighExecutableExtensionFactory:org.eclipse.xtext.builder.preferences.BuilderPreferencePage"
id="ghidra.xtext.sleigh.Sleigh.compiler.propertyPage"
name="Compiler">
<keywordReference id="ghidra.xtext.sleigh.ui.keyword_Sleigh"/>
<enabledWhen>
<adapt type="org.eclipse.core.resources.IProject"/>
</enabledWhen>
<filter name="projectNature" value="org.eclipse.xtext.ui.shared.xtextNature"/>
</page>
</extension>
<extension point="org.eclipse.ui.menus">
<menuContribution locationURI="popup:#TextEditorContext?after=xtext.ui.openDeclaration">
<command
commandId="org.eclipse.xtext.ui.OpenGeneratedFileCommand"
id="ghidra.xtext.sleigh.Sleigh.OpenGeneratedCode"
style="push">
<visibleWhen checkEnabled="false">
<reference definitionId="ghidra.xtext.sleigh.Sleigh.Editor.opened" />
</visibleWhen>
</command>
</menuContribution>
</extension>
<extension point="org.eclipse.ui.handlers">
<handler
class="ghidra.xtext.sleigh.ui.SleighExecutableExtensionFactory:org.eclipse.xtext.ui.generator.trace.OpenGeneratedFileHandler"
commandId="org.eclipse.xtext.ui.OpenGeneratedFileCommand">
<activeWhen>
<reference definitionId="ghidra.xtext.sleigh.Sleigh.Editor.opened" />
</activeWhen>
</handler>
</extension>
<!-- Quick Outline -->
<extension
point="org.eclipse.ui.handlers">
<handler
class="ghidra.xtext.sleigh.ui.SleighExecutableExtensionFactory:org.eclipse.xtext.ui.editor.outline.quickoutline.ShowQuickOutlineActionHandler"
commandId="org.eclipse.xtext.ui.editor.outline.QuickOutline">
<activeWhen>
<reference
definitionId="ghidra.xtext.sleigh.Sleigh.Editor.opened">
</reference>
</activeWhen>
</handler>
</extension>
<extension
point="org.eclipse.ui.commands">
<command
description="Open the quick outline."
id="org.eclipse.xtext.ui.editor.outline.QuickOutline"
name="Quick Outline">
</command>
</extension>
<extension point="org.eclipse.ui.menus">
<menuContribution
locationURI="popup:#TextEditorContext?after=group.open">
<command commandId="org.eclipse.xtext.ui.editor.outline.QuickOutline"
style="push"
tooltip="Open Quick Outline">
<visibleWhen checkEnabled="false">
<reference definitionId="ghidra.xtext.sleigh.Sleigh.Editor.opened"/>
</visibleWhen>
</command>
</menuContribution>
</extension>
<!-- quickfix marker resolution generator for ghidra.xtext.sleigh.Sleigh -->
<extension
point="org.eclipse.ui.ide.markerResolution">
<markerResolutionGenerator
class="ghidra.xtext.sleigh.ui.SleighExecutableExtensionFactory:org.eclipse.xtext.ui.editor.quickfix.MarkerResolutionGenerator"
markerType="ghidra.xtext.sleigh.ui.sleigh.check.fast">
<attribute
name="FIXABLE_KEY"
value="true">
</attribute>
</markerResolutionGenerator>
<markerResolutionGenerator
class="ghidra.xtext.sleigh.ui.SleighExecutableExtensionFactory:org.eclipse.xtext.ui.editor.quickfix.MarkerResolutionGenerator"
markerType="ghidra.xtext.sleigh.ui.sleigh.check.normal">
<attribute
name="FIXABLE_KEY"
value="true">
</attribute>
</markerResolutionGenerator>
<markerResolutionGenerator
class="ghidra.xtext.sleigh.ui.SleighExecutableExtensionFactory:org.eclipse.xtext.ui.editor.quickfix.MarkerResolutionGenerator"
markerType="ghidra.xtext.sleigh.ui.sleigh.check.expensive">
<attribute
name="FIXABLE_KEY"
value="true">
</attribute>
</markerResolutionGenerator>
</extension>
<!-- Rename Refactoring -->
<extension point="org.eclipse.ui.handlers">
<handler
class="ghidra.xtext.sleigh.ui.SleighExecutableExtensionFactory:org.eclipse.xtext.ui.refactoring.ui.DefaultRenameElementHandler"
commandId="org.eclipse.xtext.ui.refactoring.RenameElement">
<activeWhen>
<reference
definitionId="ghidra.xtext.sleigh.Sleigh.Editor.opened">
</reference>
</activeWhen>
</handler>
</extension>
<extension point="org.eclipse.ui.menus">
<menuContribution
locationURI="popup:#TextEditorContext?after=group.edit">
<command commandId="org.eclipse.xtext.ui.refactoring.RenameElement"
style="push">
<visibleWhen checkEnabled="false">
<reference
definitionId="ghidra.xtext.sleigh.Sleigh.Editor.opened">
</reference>
</visibleWhen>
</command>
</menuContribution>
</extension>
<extension point="org.eclipse.ui.preferencePages">
<page
category="ghidra.xtext.sleigh.Sleigh"
class="ghidra.xtext.sleigh.ui.SleighExecutableExtensionFactory:org.eclipse.xtext.ui.refactoring.ui.RefactoringPreferencePage"
id="ghidra.xtext.sleigh.Sleigh.refactoring"
name="Refactoring">
<keywordReference id="ghidra.xtext.sleigh.ui.keyword_Sleigh"/>
</page>
</extension>
<extension point="org.eclipse.compare.contentViewers">
<viewer id="ghidra.xtext.sleigh.Sleigh.compare.contentViewers"
class="ghidra.xtext.sleigh.ui.SleighExecutableExtensionFactory:org.eclipse.xtext.ui.compare.InjectableViewerCreator"
extensions="slaspec,sinc">
</viewer>
<contentTypeBinding
contentTypeId="ghidra.xtext.sleigh.Sleigh.contenttype"
contentViewerId="ghidra.xtext.sleigh.Sleigh.compare.contentViewers" />
</extension>
<extension point="org.eclipse.compare.contentMergeViewers">
<viewer id="ghidra.xtext.sleigh.Sleigh.compare.contentMergeViewers"
class="ghidra.xtext.sleigh.ui.SleighExecutableExtensionFactory:org.eclipse.xtext.ui.compare.InjectableViewerCreator"
extensions="slaspec,sinc" label="Sleigh Compare">
</viewer>
<contentTypeBinding
contentTypeId="ghidra.xtext.sleigh.Sleigh.contenttype"
contentMergeViewerId="ghidra.xtext.sleigh.Sleigh.compare.contentMergeViewers" />
</extension>
<extension point="org.eclipse.ui.editors.documentProviders">
<provider id="ghidra.xtext.sleigh.Sleigh.editors.documentProviders"
class="ghidra.xtext.sleigh.ui.SleighExecutableExtensionFactory:org.eclipse.xtext.ui.editor.model.XtextDocumentProvider"
extensions="slaspec,sinc">
</provider>
</extension>
<extension point="org.eclipse.team.core.fileTypes">
<fileTypes
extension="slaspec"
type="text">
</fileTypes>
<fileTypes
extension="sinc"
type="text">
</fileTypes>
</extension>
<!-- quickfix marker resolution generator for ghidra.xtext.sleigh.Sleigh -->
<extension
point="org.eclipse.ui.ide.markerResolution">
<markerResolutionGenerator
class="ghidra.xtext.sleigh.ui.SleighExecutableExtensionFactory:org.eclipse.xtext.ui.editor.quickfix.MarkerResolutionGenerator"
markerType="ghidra.xtext.sleigh.ui.sleigh.check.fast">
<attribute
name="FIXABLE_KEY"
value="true">
</attribute>
</markerResolutionGenerator>
<markerResolutionGenerator
class="ghidra.xtext.sleigh.ui.SleighExecutableExtensionFactory:org.eclipse.xtext.ui.editor.quickfix.MarkerResolutionGenerator"
markerType="ghidra.xtext.sleigh.ui.sleigh.check.normal">
<attribute
name="FIXABLE_KEY"
value="true">
</attribute>
</markerResolutionGenerator>
<markerResolutionGenerator
class="ghidra.xtext.sleigh.ui.SleighExecutableExtensionFactory:org.eclipse.xtext.ui.editor.quickfix.MarkerResolutionGenerator"
markerType="ghidra.xtext.sleigh.ui.sleigh.check.expensive">
<attribute
name="FIXABLE_KEY"
value="true">
</attribute>
</markerResolutionGenerator>
</extension>
<!-- Rename Refactoring -->
<extension point="org.eclipse.ui.handlers">
<handler
class="ghidra.xtext.sleigh.ui.SleighExecutableExtensionFactory:org.eclipse.xtext.ui.refactoring.ui.DefaultRenameElementHandler"
commandId="org.eclipse.xtext.ui.refactoring.RenameElement">
<activeWhen>
<reference
definitionId="ghidra.xtext.sleigh.Sleigh.Editor.opened">
</reference>
</activeWhen>
</handler>
</extension>
<extension point="org.eclipse.ui.menus">
<menuContribution
locationURI="popup:#TextEditorContext?after=group.edit">
<command commandId="org.eclipse.xtext.ui.refactoring.RenameElement"
style="push">
<visibleWhen checkEnabled="false">
<reference
definitionId="ghidra.xtext.sleigh.Sleigh.Editor.opened">
</reference>
</visibleWhen>
</command>
</menuContribution>
</extension>
<extension point="org.eclipse.ui.preferencePages">
<page
category="ghidra.xtext.sleigh.Sleigh"
class="ghidra.xtext.sleigh.ui.SleighExecutableExtensionFactory:org.eclipse.xtext.ui.refactoring.ui.RefactoringPreferencePage"
id="ghidra.xtext.sleigh.Sleigh.refactoring"
name="Refactoring">
<keywordReference id="ghidra.xtext.sleigh.ui.keyword_Sleigh"/>
</page>
</extension>
<!-- Console Extensions -->
<extension
point="org.eclipse.debug.ui.consoleLineTrackers">
<consoleLineTracker
class="ghidra.xtext.sleigh.ui.console.ConsoleLineTracker"
processType="org.eclipse.ant.ui.antProcess"
id="ghidra.xtext.sleigh.taskLineTracker">
</consoleLineTracker>
</extension>
<extension
point="org.eclipse.ui.console.consolePatternMatchListeners">
<consolePatternMatchListener
class="ghidra.xtext.sleigh.ui.console.ConsoleHyperlinking"
id="ghidra.xtext.sleigh.ui.consoleHyperlinking.Compiling"
qualifier="javac"
regex="Compiling .*.slaspec(:\d+)">
<enablement>
<test property="org.eclipse.debug.ui.processTypeTest" value="org.eclipse.ant.ui.antProcess"/>
</enablement>
</consolePatternMatchListener>
<consolePatternMatchListener
class="ghidra.xtext.sleigh.ui.console.ConsoleHyperlinking"
id="ghidra.xtext.sleigh.ui.console.ConsoleHyperlinking.All"
regex="\[java\] .*\.slaspec failed to compile">
<enablement>
<or>
<test property="org.eclipse.ui.console.consoleTypeTest" value="javaStackTraceConsole"/>
<test property="org.eclipse.debug.ui.processTypeTest" value="java"/>
<test property="org.eclipse.debug.ui.processTypeTest" value="org.eclipse.ant.ui.antProcess"/>
</or>
</enablement>
</consolePatternMatchListener>
<consolePatternMatchListener
class="ghidra.xtext.sleigh.ui.console.ConsoleHyperlinking"
id="ghidra.xtext.sleigh.ui.console.ConsoleHyperlinking.All"
regex="Compiling .*\.slaspec">
<enablement>
<or>
<test property="org.eclipse.ui.console.consoleTypeTest" value="javaStackTraceConsole"/>
<test property="org.eclipse.debug.ui.processTypeTest" value="java"/>
<test property="org.eclipse.debug.ui.processTypeTest" value="org.eclipse.ant.ui.antProcess"/>
</or>
</enablement>
</consolePatternMatchListener>
<consolePatternMatchListener
class="ghidra.xtext.sleigh.ui.console.ConsoleHyperlinking"
id="ghidra.xtext.sleigh.ui.console.ConsoleHyperlinking.All"
regex="\w+\.slaspec(:\d+)|\w+\.sinc(:\d+)">
<enablement>
<or>
<test property="org.eclipse.ui.console.consoleTypeTest" value="javaStackTraceConsole"/>
<test property="org.eclipse.debug.ui.processTypeTest" value="java"/>
<test property="org.eclipse.debug.ui.processTypeTest" value="org.eclipse.ant.ui.antProcess"/>
</or>
</enablement>
</consolePatternMatchListener>
</extension>
</plugin>

View File

@@ -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
}
}

View File

@@ -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 = " <b>" + label + "</b>";
}
return str;
}
override String getLabel(EObject element) {
switch element {
DefineSym:
return " <b>" + element.name + "</b>"
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 + "<p style=\"color:red;line-height:50%;\">" + "0b" + valueOf.toString(2) + "</p>\n"
retStr = retStr + "<p style=\"color:red;line-height:50%;\">" + "0x" + valueOf.toString(16) + "</p>\n"
retStr = retStr + "<p style=\"color:red;line-height:50%;\">" + " " + valueOf.toString(10) + "</p>\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 + "<p style=\"color:red;line-height:100%;\">" + next.value + "</p>\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 + "<p style=\"color:red;line-height:100%;\">" + formatString(next.print.printpieces) +
" is " + formatConstraintString(next.match.constraints) + "</p>\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 + "<p style=\"color:red;line-height:100%;\">" + formatString(next.print.printpieces) +
" is " + formatConstraintString(next.match.constraints) + "</p>\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 + "<p style=\"color:red;line-height:100%;\">" + next.value + "</p>\n"
}
}
}
if (retStr.length == 0) {
return element.sym;
}
return retStr;
}
def String formatString(EList<printpiece> list) {
var str = "<span style=\"color:#0000FF;\">";
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 += "</span>"
str
}
def String formatConstraintString(EObject o) {
var node = NodeModelUtils.getNode(o);
return node.text
}
}

View File

@@ -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<INode> 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 = "<no-grammar>";
String semantic = "<no-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<INode> 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<INode> it) {
INode n = null;
while (it.hasNext()
&& (n = it.next()).getClass() == HiddenLeafNode.class)
processHiddenNode(acceptor, (HiddenLeafNode) n);
return n;
}
INode skipWhiteSpaceBackwards(IHighlightedPositionAcceptor acceptor,
BidiIterator<INode> 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);
}
}
}
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -0,0 +1,53 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
* 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 &quot;AS IS&quot; 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<? extends IHighlightingConfiguration> bindIHighlightingConfiguration() {
return SleighHighlightingConfiguration
}
def Class<? extends ISemanticHighlightingCalculator> bindISemanticHighlightingCalculator() {
return SleighHighlightingCalculator
}
def Class<? extends IEObjectHoverProvider> bindIEObjectHoverProvider() {
return SleighEObjectHoverProvider
}
def Class<? extends ITextEditComposer> bindITextEditComposer() {
return SleighTextEditComposer
}
}

View File

@@ -0,0 +1,105 @@
package ghidra.xtext.sleigh.ui.console
import java.util.HashMap
import java.util.Map
import org.eclipse.core.resources.IFile
import org.eclipse.core.resources.ResourcesPlugin
import org.eclipse.core.runtime.Path
import org.eclipse.debug.ui.console.FileLink
import org.eclipse.jface.text.BadLocationException
import org.eclipse.ui.console.IPatternMatchListenerDelegate
import org.eclipse.ui.console.PatternMatchEvent
import org.eclipse.ui.console.TextConsole
class ConsoleHyperlinking implements IPatternMatchListenerDelegate {
static final String compilingBase = "Compiling ";
static final String failedBase = " failed to compile";
static final String javaPrefix = "[java] ";
Map<String, IFile> fFileNameToIFile = new HashMap();
static String lastBase = ""; // last full path base name found
TextConsole console
override matchFound(PatternMatchEvent event) {
try {
var offset = event.getOffset();
var length = event.getLength();
var _str = console.document.get(offset, length);
var setBase = false;
if (_str.indexOf(compilingBase) != -1) {
_str = _str.replace(compilingBase, "");
setBase = true;
offset += compilingBase.length
length -= compilingBase.length
}
if (_str.indexOf(failedBase) != -1) {
_str = _str.replace(failedBase, "");
_str = _str.replace(javaPrefix, "");
setBase = true;
offset += javaPrefix.length
length -= failedBase.length + javaPrefix.length
}
// get filename and optional linenumber after ':'
val indexOfColon = _str.indexOf(":")
var fileName = ""
var lineNumber = 1
if (indexOfColon != -1) {
fileName = _str.substring(0, indexOfColon)
lineNumber = Integer.valueOf(_str.substring(indexOfColon + 1))
} else {
fileName = _str
}
var file = getIFile(fileName, setBase);
if (file !== null) {
val link = new FileLink(file, null, -1, -1, lineNumber);
console.addHyperlink(link, offset, length);
}
} catch (BadLocationException | NumberFormatException e) {
}
}
override connect(TextConsole console) {
this.console = console
lastBase = ""
}
override disconnect() {
this.console = null
fFileNameToIFile.clear();
}
def IFile getIFile(String filePath, boolean setBase) {
if (filePath === null) {
return null;
}
// check the name to IFile cache
var file = fFileNameToIFile.get(filePath);
if (file === null) {
var f = new Path(filePath).toFile()
var uri = f.toURI();
var files = ResourcesPlugin.getWorkspace().getRoot().findFilesForLocationURI(uri);
if (files.length <= 0) {
// didn't find the file, try tacking on the lastbase path
f = new Path(lastBase + Path.SEPARATOR + filePath).toFile()
f.toURI();
uri = f.toURI()
files = ResourcesPlugin.getWorkspace().getRoot().findFilesForLocationURI(uri);
}
if (files.length > 0) {
file = files.get(0);
fFileNameToIFile.put(filePath, file);
if (setBase) {
lastBase = f.parent
}
}
}
return file;
}
}

View File

@@ -0,0 +1,47 @@
/* ###
* 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.console;
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;
//import org.eclipse.ant.internal.ui.launchConfigurations.TaskLinkManager;
public class ConsoleLineTracker implements IConsoleLineTracker {
private IConsole fConsole;
/**
* @see org.eclipse.debug.ui.console.IConsoleLineTracker#init(org.eclipse.debug.ui.console.IConsole)
*/
@Override
public void init(IConsole console) {
IProcess process = console.getProcess();
}
@Override
public void lineAppended(IRegion line) {
// TaskLinkManager.processNewLine(fConsole, line);
}
@Override
public void dispose() {
fConsole = null;
}
}

View File

@@ -0,0 +1,24 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
* 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 &quot;AS IS&quot; 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 {
}

View File

@@ -0,0 +1,83 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
* 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 &quot;AS IS&quot; 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'
}
}

View File

@@ -0,0 +1,248 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
* 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 &quot;AS IS&quot; 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<varattach> 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<printpiece> 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)
}
}
}

View File

@@ -0,0 +1,82 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
* 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 &quot;AS IS&quot; 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<IOutlineNode>();
}
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 <T> getAdapter(Class<T> adapter) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override <Result> readOnly(IUnitOfWork<Result, EObject> work) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
}
}
}
}

View File

@@ -0,0 +1,323 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
* 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 &quot;AS IS&quot; 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<XtextResource>() {
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;
}
}

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.emf.mwe2.launch.Mwe2LaunchConfigurationType">
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/ghidra.xtext.sleigh"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="4"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
</listAttribute>
<stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${working_set:&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#10;&lt;resources&gt;&#10;&lt;item path=&quot;/ghidra.xtext.sleigh&quot; type=&quot;4&quot;/&gt;&#10;&lt;item path=&quot;/ghidra.xtext.sleigh.ide&quot; type=&quot;4&quot;/&gt;&#10;&lt;item path=&quot;/ghidra.xtext.sleigh.ui&quot; type=&quot;4&quot;/&gt;&#10;&lt;item path=&quot;/ghidra.xtext.sleigh.feature&quot; type=&quot;4&quot;/&gt;&#10;&lt;item path=&quot;/ghidra.xtext.sleigh.tests&quot; type=&quot;4&quot;/&gt;&#10;&lt;item path=&quot;/ghidra.xtext.sleigh.ui.tests&quot; type=&quot;4&quot;/&gt;&#10;&lt;item path=&quot;/ghidra.xtext.sleigh.tests&quot; type=&quot;4&quot;/&gt;&#10;&lt;item path=&quot;/ghidra.xtext.sleigh.ui.tests&quot; type=&quot;4&quot;/&gt;&#10;;&lt;/resources&gt;}"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.eclipse.emf.mwe2.launch.runtime.Mwe2Launcher"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="ghidra.xtext.sleigh.GenerateSleigh"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="ghidra.xtext.sleigh"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx512m"/>
</launchConfiguration>

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.pde.ui.RuntimeWorkbench">
<booleanAttribute key="append.args" value="true"/>
<booleanAttribute key="askclear" value="true"/>
<booleanAttribute key="automaticAdd" value="true"/>
<booleanAttribute key="automaticValidate" value="false"/>
<stringAttribute key="bad_container_name" value="/ghidra.xtext.sleigh/.launch/"/>
<stringAttribute key="bootstrap" value=""/>
<stringAttribute key="checked" value="[NONE]"/>
<booleanAttribute key="clearConfig" value="false"/>
<booleanAttribute key="clearws" value="false"/>
<booleanAttribute key="clearwslog" value="false"/>
<stringAttribute key="configLocation" value="${workspace_loc}/.metadata/.plugins/org.eclipse.pde.core/Launch Runtime Eclipse"/>
<booleanAttribute key="default" value="true"/>
<booleanAttribute key="includeOptional" value="true"/>
<stringAttribute key="location" value="${workspace_loc}/../runtime-EclipseXtext"/>
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
</listAttribute>
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl}"/>
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms40m -Xmx512m"/>
<stringAttribute key="pde.version" value="3.3"/>
<stringAttribute key="product" value="org.eclipse.platform.ide"/>
<booleanAttribute key="show_selected_only" value="false"/>
<stringAttribute key="templateConfig" value="${target_home}/configuration/config.ini"/>
<booleanAttribute key="tracing" value="false"/>
<booleanAttribute key="useDefaultConfig" value="true"/>
<booleanAttribute key="useDefaultConfigArea" value="true"/>
<booleanAttribute key="useProduct" value="true"/>
<booleanAttribute key="usefeatures" value="false"/>
</launchConfiguration>

View File

@@ -0,0 +1,201 @@
<!DOCTYPE html>
<html>
<head>
<title>GhidraSleighEditor README</title>
<style name="text/css">
li { font-family:times new roman; font-size:14pt; font-family:times new roman; font-size:14pt; margin-bottom: 12px; }
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
h2 { padding-top:30px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
p { font-family:times new roman; font-size:14pt; }
td { font-family:times new roman; font-size:14pt; padding-left:10px; padding-right:10px; }
th { font-family:times new roman; font-size:14pt; font-weight:bold; padding-left:10px; padding-right:10px; }
code { color:black; font-family:courier new font-size: 14pt; }
span.code { font-family:courier new font-size: 14pt; color:#000000; }
</style>
</head>
<body>
<h1>GhidraSleighEditor README</h1>
<p>GhidraSleighEditor makes developing and modifying Ghidra Sleigh processor modules much more enjoyable by providing a modern
day context sensitive editor with syntax highlighting, navigation, context sensitive error notation, quick fixes, and more. The
editor is built with the excellent XTEXT DSL framework within Eclipse.
</p>
<p>The information provided in this document is effective as of Ghidra Sleigh Editor 1.0.0 and is subject to
change with future releases.</p>
<ul>
<li><a href="#MinimumRequirements">Minimum Requirements</a></li>
<li><a href="#Install">Installing</a></li>
<ul>
<li><a href="#InstallpreBuilt">Installation pre-build editor in Eclipse</a></li>
<li><a href="#Building">Building Eclipse Sleigh Editor</a></li>
</ul>
<li><a href="#Uninstall">Uninstalling</a></li>
<li><a href="#Upgrade">Upgrading</a></li>
<li><a href="#Features">Sleigh Editor Features</a></li>
<ul>
<li><a href="#Hilite">Syntax Highlighting</a></li>
<li><a href="#Validate">Validation</a></li>
<li><a href="#QuickFix">QuickFix</a></li>
<li><a href="#Hover">Hover</a></li>
<li><a href="#References">Find References</a></li>
<li><a href="#Rename">Renaming</a></li>
<li><a href="#Format">Code Formating</a></li>
</ul>
<li><a href="#ChangeHistory">Change History</a></li>
</ul>
<h2><a name="MinimumRequirements"></a>Minimum Requirements</h2>
<ul>
<li>Eclipse 2019-3 with DSL and XTEXT 2.17 or later</li>
<li>Ghidra 9.0 or later</li>
</ul>
<p>(<a href="#top">Back to Top</a>)</p>
<h2><a name="Install"></a>Installing GhidraSleighEditor</h2>
<p>GhidraSleighEditor is installed manually into Eclipse and should be installed by anyone interested in working with
processor module sleigh specifications. The Sleigh Editor must be manually installed in Eclipse. In the future the extension
may be installed automatically along with the GhidraDev Eclipse plugin when setting up Eclipse for Ghidra scripting and plugin development.</p>
<h3><a name="InstallpreBuilt"></a>Install pre-Built</h3>
<p>GhidraSleighEditor can be installed into an existing installation of Eclipse the same way most Eclipse
plugins are installed. From Eclipse:</p>
<ol>
<li>Click <b>Help &#8594; Install New Software...</b></li>
<li>Click <b>Add...</b></li>
<li>Click <b>Archive...</b></li>
<li>
Select GhidraSleighEditor zip file from <i>&lt;GhidraInstallDir&gt;</i>/Extensions/Eclipse/GhidraSleighEditor/
</li>
<li>Click <b>OK</b> (name field can be blank)</li>
<li>Check <b>Ghidra</b> category (or <b>Ghidra Sleigh Editor</b> entry)</li>
<li>Click <b>Next</b></li>
<li>Click <b>Next</b></li>
<li>Accept the terms of the license agreement</li>
<li>Click <b>Finish</b></li>
<li>Click <b>Install anyway</b></li>
<li>Click <b>Restart Now</b></li>
</ol>
<h3><a name="Building"></a>Building Eclipse Sleigh Editor</h3>
<ol>
<p>To build the Sleigh Editor, follow the instructions in ghidra/DevGuide.md to setup eclipse
for development. Then follow the directions in
<i>ghidra/GhidraBuild/EclipsePlugins/GhidraSleighEditor/ghidra.xtext.sleigh.feature/build_README.txt</i>.</p>
</ol>
<h2><a name="Uninstall"></a>Uninstalling</h2>
<p>GhidraSleighEditor can be uninstalled as follows from
Eclipse:</p>
<ol>
<li>Click <b>Help &#8594; About Eclipse</b></li>
<ul>
<li><i>For macOS:</i> <b>Eclipse &#8594; About Eclipse</b></li>
</ul>
<li>Click <b>Installation Details</b></li>
<li>Select Ghidra Sleigh Editor</li>
<li>Click <b>Uninstall...</b></li>
<li>Select Ghidra Sleigh Editor</li>
<li>Click <b>Finish</b></li>
<li>Click <b>Restart Now</b></li>
</ol>
<p>(<a href="#top">Back to Top</a>)</p>
<h2><a name="Upgrade"></a>Upgrading</h2>
<p> GhidraSleighEditor can be upgraded the same way it was initially installed.</p>
<p>(<a href="#top">Back to Top</a>)</p>
<h2><a name="Features"></a>Sleigh Editor Features</h2>
<p>The Ghidra Sleigh Editor provides a variety of features one would expect in any modern IDE to make viewing, modifying, debugging,
and creating Sleigh processor specifications as painless as possible.
Once installed, any .sinc or .slaspec file that is edited will be brought up in the sleigh editor.</p>
<p>The editor provides the following capabilities:</p>
<ul>
<li><a name="Hilite"></a>Syntax Highlighting</li>
<ul>
<p>Keywords, Tokens, Sub-constructor names, Comments, Instruction Formats, Strings, Variables, and more can be colorized to make
the sliegh specification more readable. In the <b>Window &#8594; Preferences &#8594; Sleigh</b> preferences panel, the color and font style can be changed
for any sleigh file tokens.</p>
</ul>
<li><a name="Validate"></a>Validation</li>
<ul>
<p>The structure of a sleigh file while fairly simple can lend itself to errors when using a straight text editor. The editor understands
the syntax and all constructs of a sleigh file. Instead of waiting for the sleigh compiler to produce an error, many but not all syntax
errors can be caught and displayed with a red error marker.</p>
<p>The editor validates the definition of variables including locals.
Though legal in the sleigh compiler, it has been found that not declaring local variables leads to
errors that are not be caught by the sleigh compiler. For example, assigning to a variable 'ro' when the actual register name is 'r0' may go
unnoticed. All local variables must be defined with with the 'local' keyword or with an initial ':size'.</p>
<p>Warnings on duplicate names of tokens is marked in yellow. Complex matching patterns such as <i>'!='&nbsp&nbsp'&lt'&nbsp&nbsp'&gt'</i> are warnings as well. Using
comparison matching operators can cause the generated .sla file to be much larger than necessary. Comparison matching should really never be used on any
tokens that are bigger than a few bits as the number of match cases generated will be large. Their use is unavoidable in some cases.<p>
<p>There are some artificial enforcements in the editor that, while valid sleigh syntax, cause the syntax to be unparsable. Because the sleigh
Domain Specific Language (DSL) is a context sensitive grammer, as well as using define-like pre-processing expansion, the editor only allows define
<b>$()</b> variables at certain locations where a single token would reside. The most common flagged error is embedding a connecting '&' in a define and then
using it an a match pattern:
<ul>
<p><b>:MOV ax, bx is t1=1 $(BadDefine) {}</b> is not allowed, and instead should be <b>:MOV ax, bx is t1=1 & $(GoodDefine) {}</b>.</p>
</ul>
</ul>
<li><a name="QuickFix"></a>QuickFix</li>
<ul>
<p>Some simple syntax errors can be fixed quickly with QuickFix suggestions. Pressing Crtl-1 on an error will bring up available quick-fixes.</p>
<li>Undefined local variable - insert 'local' or the ':size" form if the size can be detected.</li>
<li>Undefined user pcodeop - can insert a user pcodeop definition for an unknown identifier</li>
<li>Undefined macro - can insert a macro definition for an unknown identifier</li>
<li>Add token field definition - for an unknown token in the match pattern</li>
</ul>
<p>More quick-fixes may be added in the future. Please note quickfixes can be slow on large files such as the AARCH64.</p>
<li><a name="Hover"></a>Hover</li>
<ul>
<p>There are many constructs in a sleigh file that, when hovered over, will display additional information. This is especially useful for tokens to get their
size without having to navigate to the token field definition. More hovers will be added.<p>
<li>Sub-Constructors will display all the defined sub-constructors with the same name.</li>
<li>Token field definitions will display their size, and if attached, the set of registers.</li>
<li>Registers display their size.</li>
<li>Numeric values will display in Hex, Binary, and Decimal.</li>
<li>$(Defines) display all the possible defines for the name, since the actual define used can't be known.</li>
</ul>
<li><a name="Navigate"></a>Navigation</li>
<p>If you have edited a sleigh processor specification in a regular text editor, you will appreciate the forward and backward navigation supported on
various variable name use and their associated definition. Navigation is supported on sub-constructor names, field token names, registers, macros names, local variables, define names, and user
define pcodeop's.</p>
<p>Navigate by pressing <b>&ltF3&gt</b> on a variable, using the forward/backward navigation arrows, or my favorite the &lt-* that will navigate
back to the last edit location.<p>
<li><a name="References"></a>Find References</li>
<p>Instead of keyword searching, the editor provides a find all uses of a variable. Each found use is listed in a search window with the text of the line where it is used displayed.
Each found location can also be navigated to by double clicking on the found reference.</p>
<p>Use the editor popup menu <b>Find References</b> action.</p>
<li><a name="Rename"></a>Renaming</li>
<p>The name of variables can be very important, and instead of doing a search and replace on a string, the editor can refactor a name and change all other uses of that name. The name
is even changed in other .sinc and .slaspec files.<p>
<p>Use the editor popup menu <b>Rename Element</b> action.</p>
<li><a name="Format"></a>Code Formating</li>
<p>Sleigh files can get large and messy during development. Instead of paying much attention to format, or trying to format by hand you can use the Source Format action.
Common constructs are lined up, for example the token definitions will find the longest token and line up all other tokens and their definition. All sub-constructors of the
same name will be lined up on the 'is' keyword, the match pattern, and the semantic definitions. All constructors 'is' keywords will be generally lined up based on the longest
print peice for each constructor. Statements will also be indented consistently. Multi-line attach definitions will have each entry lined up.
Formatting can be restricted to a selection of lines to stop formatting from entirely re-formatting carefully formatted files.
Additional formatting may be added in the future, and the formatter may become more configurable in the future.<p>
<p>Use the editor popup menu <b>Source &#8594; Format</b> action.</p>
</ul>
<h2><a name="ChangeHistory"></a>Change History</h2>
<p><u><b>1.0.0</b>:</u> Initial release in Ghidra 9.1</p>
<p>(<a href="#top">Back to Top</a>)</p>
<!-- Some padding -->
<br>
<br>
<br>
</body>
</html>

View File

@@ -0,0 +1,31 @@
Manifest-Version: 1.0
Automatic-Module-Name: ghidra.xtext.sleigh
Bundle-ManifestVersion: 2
Bundle-Name: ghidra.xtext.sleigh
Bundle-Vendor: Ghidra
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-1.8
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

View File

@@ -0,0 +1,40 @@
apply plugin: 'java'
// This project requires the Eclipse DSL plugin. To create Eclipse files for this project, run
// "gradle eclipse -PeclipseDSL"
if (hasProperty("eclipseDSL")) {
apply plugin: 'eclipse'
eclipse {
project {
name = 'Eclipse SleighEditor'
buildCommand 'org.eclipse.pde.ManifestBuilder'
buildCommand 'org.eclipse.pde.SchemaBuilder'
buildCommand 'org.eclipse.xtext.ui.shared.xtextBuilder'
natures 'org.eclipse.pde.PluginNature'
natures 'org.eclipse.xtext.ui.shared.xtextNature'
classpath.file {
def requiredPlugins = 'org.eclipse.pde.core.requiredPlugins'
beforeMerged { classpath ->
classpath.entries.removeAll { entry ->
entry.path == requiredPlugins
}
}
whenMerged { classpath ->
withXml {
def node = it.asNode()
node.appendNode('classpathentry', [kind: 'con', path: requiredPlugins])
}
}
}
}
}
sourceSets {
main {
java {
srcDir 'src'
srcDir 'src-gen'
srcDir 'xtend-gen'
}
}
}
}

View File

@@ -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

View File

@@ -0,0 +1,83 @@
The Ghidra Sleigh Editor for Eclipse is currently built from Eclipse and checked into the bin repo.
Ideally we will use Gradle one day, but we aren't there yet. We do rely on Gradle prepDev to generate
the Eclipse project and build GhidraSleighEditor's dependencies though, hence the build.gradle file.
Required: Eclipse IDE with Java and DSL version 2019-03 or later, XTEXT 2.17 or later.
The following instructions assume that you have setup Eclipse.
It is also suggested that you use the Eclipse IDE with DSL extensions already installed if you will
use the GhidraSleighEditor. You can build the GhidraSleighEditor installation zip with the XTEXT runtime
in the plugin. The XTEXT runtime was not included in the distribution build because it would
have added 80Meg.
Importing GhidraSleighEditor Eclipse projects (they are deactivated by default):
1) Uncomment the line in settings.gradle that includes the GhidraSleighEditor project.
2) Run "gradle eclipse -PSleighEditor" to generate the GhidraSleighEditor Eclipse projects.
3) From Eclipse, File --> Import --> General --> Existing Projects into Workspace
4) From the ghidra repo, import all "Eclipse GhidraSleighEditor *" projects.
Generating all Sleigh XTEXT generated files:
1) open ghidra.xtext.sleigh project
2) navigate to the file src --> ghidra.xtext.sleigh --> GenerateSleigh.mwe2
3) NOTE: the following will download a jar file from the internet (not from NSA)
unless you pre-download.
3a) Download the file http://download.itemis.com/antlr-generator-3.2.0-patch.jar
3b) Put the file in ghidra/GhidraBuild/EclipsePlugins/SleighEditor/ghidra.xtext.sleigh
3c) Rename the file to .antlr-generator-3.2.0-patch.jar
3) From the popup menu RunAs --> MWE2 Workflow
- Files in xtend-gen and src-gen will be created
- The project should rebuild, and there should be no red Problem errors
Try out the Sleigh Editor
1) Navigate to the 'Eclipse SleighEditor' and chose RunAs --> Eclipse Runtime
2) Add a sleigh processor module
2a) File --> NewJavaProject...
- Uncheck default location and navigate to a processor in Ghidra/Processors/<X>
- The project be automatically named <X>
- Finish
- Cancel Module creation
- Navigate to a <X>/data/languages/<file>.sinc or <file>.slaspec
- On the popup asking to convert to an XTEXT project, choose "Yes"
2b) -OR-
- drop a .slaspec or .sinc file from the file browser on eclipse
- this is good for quick viewing, however navigation across files may not work.
Optional: Changing version number (GhidraSleighEditor is versioned independently of Ghidra):
1) Open feature.xml in the GhidraSleighEditor Feature project.
2) In the "Overview" tab, update the "Version" field to x.y.z.qualifier and save.
3) Open category.xml in the GhidraSleighEditor Feature project.
4) Highlight ghidra.xtext.sleigh.editor (x.y.z.qualifier), and click "Remove".
5) Highlight ghidra.xtext.sleigh.editor, and click "Add Feature".
6) Select ghidra.ghidradev (x.y.z.qualifer), click "OK", and save.
7) Update GhidraDev_README.html "Change History" section if necessary.
Optional: Including the XTEXT runtime
You can include the XTEXT runtime or redist module in the .zip file which will negate the need
to have Eclipse with the DSL in the Eclipse into which the Eclipse Sleigh Editor is installed to run.
1) Navigate to the ghidra.xtext.sleigh.feature
2) bring up the feature.xml with the Feature Manager Editor (dbl-click on it).
3) Go to the Included Features tab
4) Add...
5) Filter by 'redist' and add org.eclipse.xtext.redist
Creating an installation zip file to install in Eclipse:
1) Do a Gradle prepDev to ensure GhidraDev's dependencies are up-to-date.
2) File --> Export --> Plug-in Development --> Deployable plugins and fragments
4) Select "Archive file" and choose a directory to save it to. It must end up in
ghidra.bin/GhidraBuild/Eclipse/GhidraDev/. Name it GhidraDev-x.y.z.zip.
5) In the "Options" tab make sure things look like this:
- Export source: UNCHECKED
- Package as individual JAR archives: CHECKED
- Generate p2 repository: CHECKED
- Categorize repository: CHECKED.
- Qualifier replacement: CHECKED + clear field so default is used
- Save as Ant script: UNCHECKED
- Allow for binary cycles in target platform: CHECKED
- Use class files compiled in the workspace: UNCHECKED
6) Finish

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.0"?>
<plugin>
<extension point="org.eclipse.emf.ecore.generated_package">
<package
uri = "http://www.xtext.ghidra/sleigh/Sleigh"
class = "ghidra.xtext.sleigh.sleigh.SleighPackage"
genModel = "model/generated/Sleigh.genmodel" />
</extension>
</plugin>

View File

@@ -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"
}
}
}
}

View File

@@ -0,0 +1,23 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
* 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 &quot;AS IS&quot; 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 {
}

View File

@@ -0,0 +1,27 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
* 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 &quot;AS IS&quot; 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()
}
}

View File

@@ -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<BigInteger> {
@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);
}
}
}

View File

@@ -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<BigInteger> HEXVAL() {
return hexValueConverter;
}
@Inject
private IntValueConverter numValueConverter;
@ValueConverter(rule = "NUMVAL")
public IValueConverter<BigInteger> NUMVAL() {
return numValueConverter;
}
@Inject
private IntValueConverter binValueConverter;
@ValueConverter(rule = "BINVAL")
public IValueConverter<BigInteger> BINVAL() {
return binValueConverter;
}
}

View File

@@ -0,0 +1,32 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
* 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 &quot;AS IS&quot; 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) {
}
}

View File

@@ -0,0 +1,237 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
* 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 &quot;AS IS&quot; 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<IEObjectDescription>() {
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<aliasSym, String>() {
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<aliasSym> list = new ArrayList<aliasSym>();
while (iter.hasNext) {
var piece = iter.next;
if (piece.sym instanceof aliasSym) {
list.add(piece.sym)
}
}
return list
}
def private variablesDeclaredBefore(List<statement> 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<LOCALSYM> locList = new ArrayList<LOCALSYM>();
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;
}
}

View File

@@ -0,0 +1,169 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
* 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 &quot;AS IS&quot; 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<Object,HashMap<String,HashSet<Object>>> 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<String, HashSet<Object>> map, String name, Object other) {
var HashSet<Object> set = map.get(name);
if (set == null) {
set = new HashSet<Object>();
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<String,HashSet<Object>> map = typeMap.get(type);
if (map == null) {
map = new HashMap<String,HashSet<Object>>();
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<Object> 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<String,HashSet<Object>> map = typeMap.get(type);
// if map hasn't been initialized, initialize it
if (map == null) {
map = new HashMap<String,HashSet<Object>>()
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<Object> 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<String,HashSet<Object>> map = typeMap.get(type);
if (map == null) {
map = new HashMap<String,HashSet<Object>>();
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<Object> 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)
}
}