diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/script/JythonStubScriptProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/script/JythonStubScriptProvider.java new file mode 100644 index 0000000000..0c55f01e85 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/script/JythonStubScriptProvider.java @@ -0,0 +1,64 @@ +/* ### + * 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.app.script; + +import java.io.PrintWriter; + +import generic.jar.ResourceFile; +import ghidra.util.classfinder.ExtensionPointProperties; + +/** + * A stub {@link GhidraScriptProvider} used to give feedback to a user trying to run a Jython + * script when the Jython Extension is not installed. + *
+ * Uses a sub-{@link ExtensionPointProperties#DEFAULT_PRIORITY default} priority so the Jython
+ * Extension can get prioritized over this if it's installed.
+ */
+@ExtensionPointProperties(priority = ExtensionPointProperties.DEFAULT_PRIORITY - 1)
+public class JythonStubScriptProvider extends AbstractPythonScriptProvider {
+
+ @Override
+ public String getDescription() {
+ return "Jython";
+ }
+
+ @Override
+ public String getRuntimeEnvironmentName() {
+ return "Jython";
+ }
+
+ @Override
+ public GhidraScript getScriptInstance(ResourceFile sourceFile, PrintWriter writer)
+ throws JythonStubException {
+ throw new JythonStubException();
+ }
+
+ /**
+ * A special type of {@link GhidraScriptLoadException} used to indicate that the Jython
+ * Extension is not installed.
+ */
+ public static class JythonStubException extends GhidraScriptLoadException {
+
+ /**
+ * Construct an new {@link JythonStubException}
+ */
+ public JythonStubException() {
+ super("Jython script failed. " +
+ "In order to use Jython based scripts, you must install the Jython Ghidra " +
+ "Extension, or (recommended) port your script to PyGhidra or Java.");
+ }
+ }
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/headless/HeadlessAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/headless/HeadlessAnalyzer.java
index fbd30a53e1..9f49cb2801 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/headless/HeadlessAnalyzer.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/headless/HeadlessAnalyzer.java
@@ -30,6 +30,7 @@ import ghidra.GhidraJarApplicationLayout;
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
import ghidra.app.plugin.core.osgi.BundleHost;
import ghidra.app.script.*;
+import ghidra.app.script.JythonStubScriptProvider.JythonStubException;
import ghidra.app.util.headless.HeadlessScript.HeadlessContinuationOption;
import ghidra.app.util.importer.ProgramLoader;
import ghidra.app.util.opinion.*;
@@ -960,7 +961,13 @@ public class HeadlessAnalyzer {
}
catch (Exception exc) {
String logErrorMsg = "REPORT SCRIPT ERROR: " + scriptName + " : " + exc.getMessage();
- Msg.error(this, logErrorMsg, exc);
+ if (exc instanceof JythonStubException) {
+ Msg.error(this, logErrorMsg);
+ System.exit(1);
+ }
+ else {
+ Msg.error(this, logErrorMsg, exc);
+ }
}
return retOption;
diff --git a/Ghidra/Processors/8051/certification.manifest b/Ghidra/Processors/8051/certification.manifest
index ab3f5280a2..5dac87b24b 100644
--- a/Ghidra/Processors/8051/certification.manifest
+++ b/Ghidra/Processors/8051/certification.manifest
@@ -14,6 +14,8 @@ data/languages/8051.pspec||GHIDRA||||END|
data/languages/8051.slaspec||GHIDRA||||END|
data/languages/8051_archimedes.cspec||GHIDRA||||END|
data/languages/8051_main.sinc||GHIDRA||||END|
+data/languages/cip-51.slaspec||GHIDRA||||END|
+data/languages/keil-cx51.cspec||GHIDRA||||END|
data/languages/mx51.cspec||GHIDRA||||END|
data/languages/mx51.pspec||GHIDRA||||END|
data/languages/mx51.sinc||GHIDRA||||END|
diff --git a/Ghidra/Processors/8051/data/languages/8051_main.sinc b/Ghidra/Processors/8051/data/languages/8051_main.sinc
index 22700c13ac..2c3ad94af0 100644
--- a/Ghidra/Processors/8051/data/languages/8051_main.sinc
+++ b/Ghidra/Processors/8051/data/languages/8051_main.sinc
@@ -34,7 +34,7 @@ define space BITS type=ram_space size=2;
# EXTERNAL - 0x010000-0x01ffff
# INTERNAL - 0x000000-0x0000ff
-@elif defined(MCS51)
+@elif defined(MCS51) || defined(CIP51)
@if defined(PTRSIZE)
@else
@@ -47,12 +47,64 @@ define space BITS type=ram_space size=2;
#
@define SP_SIZE 1
+define space RAM type=ram_space size=1;
define space CODE type=ram_space size=$(PTRSIZE) default;
define space INTMEM type=ram_space size=1;
define space EXTMEM type=ram_space size=2;
+@if defined(CIP51)
+#
+# CIP-51 allows up to 256 128-byte pages of these, or 32768 bytes, so two address bytes
+# are needed for SFR space.
+#
+# At execution, SFR page selection uses the 8-bit SFRPAGE SFR to provide the page number,
+# which effectively is the upper byte of SFR's full address.
+#
+# The devices covered in the F12x/13x datasheet only have 5 SFR pages and numbers them 0,
+# 1, 2, 3, and F. The datasheet doesn't go into detail about SFRPAGE bits 2 to 6, but
+# I suppose that for Ghidra instruction decoding it would suffice to just decode the full
+# byte. A custom analyzer or script could check for the use of undefined SFRPAGEs.
+#
+define space SFR type=ram_space size=2;
+@else
+#
+# Intel MCS-51 devices have a maximum of 128 SFRs and a byte-wide address suffices
+#
define space SFR type=ram_space size=1;
+@endif
define space BITS type=ram_space size=1;
+@if defined(CIP51)
+# Per the datasheet https://www.silabs.com/documents/public/data-sheets/C8051F12x-13x.pdf
+# (rev 1.4)
+# on-chip (internal) flash program/data memory addresses are
+# 00000 - 1fbff F120/1/2/3/4/5/6/7, F130/1
+# 00000 - 0ffff F132/3
+# All of the 12x/13x chips covered by the datasheet have
+# on-chip scratchpad (i.e. data only) flash:
+# 20000 - 200FF
+# So allowing 3 address bytes for CIP51 will cover the entire address range for the
+# on-chip (internal) flash
+define space IFLASH type=ram_space size=3;
+#
+# As with Intel's original MCS-51 architecture, CIP-51 "internal" ordinary RAM resides on
+# the processor chip and uses single-byte addressing.
+#
+# The lower half of internal RAM can be accessed either directly (by encoding an 8 bit
+# address in the opcode) or indirectly (via an address stored in R0 or R1).
+#
+# The upper half of internal RAM can be accessed only indirectly, again via R0 or R1.
+#
+# 00 - 7f directly and indirectly addressable
+# 80 - ff indirectly addressable only (via R0 or R1)
+#
+# In CIP51 chips, addresses in the upper half of the range (that is, 80 - FF), when used
+# directly, rather than accessing ordinary RAM get mapped to the chip's special function
+# register RAM.
+#
+
+define space XRAM type=ram_space size=2;
+@endif
+
@elif defined(MCS80390)
@define PTRSIZE 3
@@ -117,7 +169,7 @@ define register offset=0x38 size=1 [ R56 DPXL DPH DPL R60 R61 SPH ];
define register offset=0x3A size=2 [ DPTR ];
define register offset=0x38 size=4 [ DPX SPX ];
-@elif defined(MCS51) || defined(MCS80390) || defined(MX51)
+@elif defined(MCS51) || defined(MCS80390) || defined(MX51) || defined(CIP51)
define register offset=0x00 size=4 [ R0R1R2R3 ];
define register offset=0x01 size=3 [ R1R2R3 ]; # Used as R3R2R1
@@ -129,7 +181,7 @@ define register offset=0x05 size=3 [ R5R6R7 ];
define register offset=0x0A size=1 [ B ACC ]; # relocated to facilitate AB 16-bit access
define register offset=0x0A size=2 [ AB ];
-@if defined(MCS51) || defined(MX51)
+@if defined(MCS51) || defined(MX51) || defined(CIP51)
define register offset=0x82 size=2 [ DPTR ];
define register offset=0x82 size=1 [ DPH DPL ]; # relocated to facilitate DPTR 16-bit access
@elif defined(MCS80390)
@@ -192,7 +244,7 @@ define context contextReg
# GROUP3 - MCS251 instructions in 0x60-0xff range
@define GROUP3 "((srcMode=0 & A5Prefix=1) | (srcMode=1 & A5Prefix=0))"
-@elif defined(MCS51) || defined(MCS80390) || defined(MX51)
+@elif defined(MCS51) || defined(MCS80390) || defined(MX51) || defined(CIP51)
@define GROUP1 "epsilon"
@define GROUP2 "epsilon"
@@ -352,7 +404,7 @@ macro push8(val) {
SPX = SPX + 1;
ptr:3 = SPX:3;
*[RAM]:1 ptr = val;
-@elif defined(MCS51) || defined(MCS80390)
+@elif defined(MCS51) || defined(MCS80390) || defined(CIP51)
SP = SP + 1;
*[INTMEM]:1 SP = val;
@elif defined(MX51)
@@ -384,16 +436,16 @@ macro push16(val) {
*[RAM]:1 SPX:3 = al;
SPX = SPX + 1;
*[RAM]:1 SPX:3 = ah;
-
-@elif defined(MCS51)
+
+@elif defined(MCS51) || defined(CIP51)
al:1 = val:1;
ah:1 = val(1);
-
+
SP = SP + 1;
*[INTMEM]:1 SP = al;
- SP = SP + 1;
+ SP = SP + 1;
*[INTMEM]:1 SP = ah;
-
+
@elif defined(MX51)
# dptr push
#ptr:1 = SP + 1;
@@ -432,7 +484,7 @@ macro pop8(val) {
ptr:3 = SPX:3;
val = *[RAM]:1 ptr;
SPX = SPX - 1;
-@elif defined(MCS51) || defined(MCS80390)
+@elif defined(MCS51) || defined(MCS80390) || defined(CIP51)
val = *[INTMEM]:1 SP;
SP = SP - 1;
@elif defined(MX51)
@@ -477,9 +529,9 @@ macro pop16(val) {
SPX = SPX - 1;
val = (zext(ah) << 8) | zext(al);
-
-@elif defined(MCS51)
-
+
+@elif defined(MCS51) || defined(CIP51)
+
ah:1 = *[INTMEM]:1 SP;
SP = SP - 1;
al:1 = *[INTMEM]:1 SP;
@@ -512,7 +564,7 @@ DPTRreg: DPTR is ophi & DPTR { export DPTR; }
@if defined(MCS251)
ADPTR: "@A+"^DPTR is ophi & DPTR { ptr:3 = 0xff0000 + zext(DPTR) + zext(ACC); export ptr; }
-@elif defined(MCS51)
+@elif defined(MCS51) || defined(CIP51)
ADPTR: "@A+"^DPTR is ophi & DPTR { ptr:$(PTRSIZE) = zext(DPTR) + zext(ACC); export ptr; }
@elif defined(MCS80390)
ADPTR: "@A+"^DPTR is ophi & DPTR { ptr:3 = zext(DPTR) + zext(ACC); export ptr; }
@@ -524,7 +576,7 @@ APC: "@A+PC" is epsilon { tmp:$(PTRSIZE) = inst_next + zext(ACC); expor
@if defined(MCS251)
ATDPTR: "@"^DPTR is ophi & DPTR { ptr:3 = 0x010000 + zext(DPTR); export *:1 ptr; } # 8051 External data address mapped into RAM space
-@elif defined(MCS51)
+@elif defined(MCS51) || defined(CIP51)
ATDPTR: "@"^DPTR is ophi & DPTR { ptr:2 = DPTR; export *[EXTMEM]:1 ptr; }
@elif defined(MCS80390)
ATDPTR: "@"^DPTR is ophi & DPTR { ptr:3 = zext(DPTR); export *[EXTMEM]:1 ptr; }
@@ -536,13 +588,13 @@ ATDPTR: "@"^DPTR is ophi & DPTR { ptr:3 = zext(DPTR); export *[RAM]:1 ptr; }
Ri: @ri is ri { ptr:3 = zext(ri); export *[RAM]:1 ptr; }
@elif defined(MX51)
Ri: @ri is ri { ptr:3 = zext(ri) + 0x7f0000; export *[RAM]:1 ptr; }
-@elif defined(MCS51) || defined(MCS80390)
+@elif defined(MCS51) || defined(MCS80390) || defined(CIP51)
Ri: @ri is ri { export *[INTMEM]:1 ri; }
@endif
@if defined(MCS251)
RiX: @ri is ri { ptr:3 = 0x010000 + zext(ri); export *:1 ptr; } # 8051 8-bit External data address mapped into RAM space
-@elif defined(MCS51)
+@elif defined(MCS51) || defined(CIP51)
RiX: @ri is ri { ptr:2 = zext(ri); export *[EXTMEM]:1 ptr; } # limited to 8-bit external data address (I/O state can be used to produce 16-bit addr)
@elif defined(MCS80390)
RiX: @ri is ri { ptr:3 = zext(ri); export *[EXTMEM]:1 ptr; } # tocheck
@@ -560,7 +612,7 @@ Data24: "#"data24 is data24 { export *[const]:3 data24; }
Direct: mainreg is bank=0 & mainreg { export *[RAM]:1 mainreg; }
@elif defined(MX51)
Direct: mainreg is bank=0 & mainreg { tmp:3 = mainreg + 0x7f0000; export *[RAM]:1 tmp; }
-@elif defined(MCS51) || defined(MCS80390)
+@elif defined(MCS51) || defined(MCS80390) || defined(CIP51)
Direct: mainreg is bank=0 & mainreg { export *[INTMEM]:1 mainreg; }
@endif
Direct: direct is bank=1 & direct { export *[SFR]:1 direct; }
@@ -580,7 +632,7 @@ Direct: DPXL is bank=1 & direct=0x84 & DPXL { export DPXL; }
Direct2: mainreg2 is bank2=0 & mainreg2 { export *[RAM]:1 mainreg2; }
@elif defined(MX51)
Direct2: mainreg2 is bank2=0 & mainreg2 { tmp:3 = mainreg2 + 0x7f0000; export *[RAM]:1 tmp; }
-@elif defined(MCS51) || defined(MCS80390)
+@elif defined(MCS51) || defined(MCS80390) || defined(CIP51)
Direct2: mainreg2 is bank2=0 & mainreg2 { export *[INTMEM]:1 mainreg2; }
@endif
Direct2: direct2 is bank2=1 & direct2 { export *[SFR]:1 direct2; }
@@ -601,7 +653,7 @@ BitAddr: bitaddr is bitbank=1 & sfrbyte & sfrbit [ bitaddr =(sfrbyte << 6)+sfrb
BitAddr: bitaddr is bitbank=0 & lowbyte & sfrbit [ bitaddr =(lowbyte << 3)+sfrbit; ] { export *[BITS]:1 bitaddr; }
BitAddr2: "/"bitaddr is bitbank=1 & sfrbyte & sfrbit [ bitaddr =(sfrbyte << 6)+sfrbit; ] { export *[BITS]:1 bitaddr; }
BitAddr2: "/"bitaddr is bitbank=0 & lowbyte & sfrbit [ bitaddr =(lowbyte << 3)+sfrbit; ] { export *[BITS]:1 bitaddr; }
-@elif defined(MCS51) || defined(MCS80390) || defined(MX51)
+@elif defined(MCS51) || defined(MCS80390) || defined(MX51) || defined(CIP51)
##
##TODO !!! 8051 SFRBITS bit overlay block is probably incorrect since there is not a 1:1 mapping to the SFR space
## While the BitAddr is only used for disassembly markup, and labels come from pspec, the underlying data will
@@ -622,7 +674,7 @@ BitByteAddr: PSW is bitbank=1 & sfrbyte=0x1A & sfrbit & PSW { export PSW; }
BitByteAddr: byteaddr is bitbank=0 & lowbyte & sfrbit [ byteaddr = lowbyte + 0x20; ] { export *[RAM]:1 byteaddr; }
@elif defined(MX51)
BitByteAddr: byteaddr is bitbank=0 & lowbyte & sfrbit [ byteaddr = lowbyte + 0x20; ] { tmp:3 = byteaddr + 0x7f0000; export *[RAM]:1 tmp; }
-@elif defined(MCS51) || defined(MCS80390)
+@elif defined(MCS51) || defined(MCS80390) || defined(CIP51)
BitByteAddr: byteaddr is bitbank=0 & lowbyte & sfrbit [ byteaddr = lowbyte + 0x20; ] { export *[INTMEM]:1 byteaddr; }
@endif
@@ -856,21 +908,21 @@ Rel16: relAddr is rel16 [ relAddr=inst_next+rel16; ] { export *:1 relAdd
:PUSH Direct is $(GROUP1) & ophi=12 & oplo=0; Direct { push8(Direct); }
-:RET is $(GROUP1) & ophi=2 & oplo=2 {
+:RET is $(GROUP1) & ophi=2 & oplo=2 {
@if defined(MCS251) || defined(MX51)
-pc:2 = 0; pop16(pc); pc3:3 = (inst_next & 0xff0000) + zext(pc); return[pc3];
-@elif defined(MCS51)
-pc:2 = 0; pop16(pc); return[pc];
+pc:2 = 0; pop16(pc); pc3:3 = (inst_next & 0xff0000) + zext(pc); return[pc3];
+@elif defined(MCS51) || defined(CIP51)
+pc:2 = 0; pop16(pc); return[pc];
@elif defined(MCS80390)
pc:3 = 0; pop24(pc); return[pc];
@endif
}
-:RETI is $(GROUP1) & ophi=3 & oplo=2 {
+:RETI is $(GROUP1) & ophi=3 & oplo=2 {
@if defined(MCS251) || defined(MX51)
-pc:2 = 0; pop16(pc); pc3:3 = (inst_next & 0xff0000) + zext(pc); return[pc3];
-@elif defined(MCS51)
-pc:2 = 0; pop16(pc); return[pc];
+pc:2 = 0; pop16(pc); pc3:3 = (inst_next & 0xff0000) + zext(pc); return[pc3];
+@elif defined(MCS51) || defined(CIP51)
+pc:2 = 0; pop16(pc); return[pc];
@elif defined(MCS80390)
pc:3 = 0; pop24(pc); return[pc];
@endif
diff --git a/Ghidra/Processors/8051/data/languages/cip-51.slaspec b/Ghidra/Processors/8051/data/languages/cip-51.slaspec
new file mode 100644
index 0000000000..737aaf743e
--- /dev/null
+++ b/Ghidra/Processors/8051/data/languages/cip-51.slaspec
@@ -0,0 +1,4 @@
+@define CIP51 ""
+
+@include "8051_main.sinc"
+
diff --git a/Ghidra/Processors/8051/data/languages/keil-cx51.cspec b/Ghidra/Processors/8051/data/languages/keil-cx51.cspec
new file mode 100644
index 0000000000..14efe89087
--- /dev/null
+++ b/Ghidra/Processors/8051/data/languages/keil-cx51.cspec
@@ -0,0 +1,118 @@
+
+