diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ConstantPropagationAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ConstantPropagationAnalyzer.java index 83c1f6dda7..3bbebfbc22 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ConstantPropagationAnalyzer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ConstantPropagationAnalyzer.java @@ -150,7 +150,13 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer { // unless there is a good data type at the location boolean isHarvard = program.getLanguage().getDefaultSpace() != program.getLanguage().getDefaultDataSpace(); checkPointerParamRefsOption = program.getDefaultPointerSize() <= 2 || isHarvard; + + checkStoredRefsOption = program.getDefaultPointerSize() > 2 && !isHarvard; + long size = program.getAddressFactory().getDefaultAddressSpace().getSize(); + minSpeculativeRefAddress = size * 16; + maxSpeculativeRefAddress = size * 8; + checkParamRefsOption = !(program.getAddressFactory() .getDefaultAddressSpace() instanceof SegmentedAddressSpace); @@ -570,12 +576,9 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer { options.registerOption(MIN_KNOWN_REFADDRESS_OPTION_NAME, minStoreLoadRefAddress, null, MIN_KNOWN_REFADDRESS_OPTION_DESCRIPTION); - long size = program.getAddressFactory().getDefaultAddressSpace().getSize(); - minSpeculativeRefAddress = size * 16; options.registerOption(MIN_SPECULATIVE_REFADDRESS_OPTION_NAME, minSpeculativeRefAddress, null, MIN_SPECULATIVE_REFADDRESS_OPTION_DESCRIPTION); - maxSpeculativeRefAddress = size * 8; options.registerOption(MAX_SPECULATIVE_REFADDRESS_OPTION_NAME, maxSpeculativeRefAddress, null, MAX_SPECULATIVE_REFADDRESS_OPTION_DESCRIPTION); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/VarnodeContext.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/VarnodeContext.java index 0dbe506d16..580072b8f4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/VarnodeContext.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/VarnodeContext.java @@ -4,9 +4,9 @@ * 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. @@ -76,6 +76,7 @@ public class VarnodeContext implements ProcessorContext { private final int BAD_OFFSET_SPACEID; // address space for offsets from an unknown value; + static final String SUSPECT_CONST_NAME = "SuspectConst"; private final int SUSPECT_OFFSET_SPACEID; // address space for suspect constant values public final Address SUSPECT_ZERO_ADDRESS; @@ -109,7 +110,7 @@ public class VarnodeContext implements ProcessorContext { /* Suspect constants act like constants, but are in a SuspectConst * address space instead of the constant space. */ - SUSPECT_ZERO_ADDRESS = addrFactory.getAddress(getAddressSpace("SuspectConst"), 0); + SUSPECT_ZERO_ADDRESS = addrFactory.getAddress(getAddressSpace(SUSPECT_CONST_NAME), 0); SUSPECT_OFFSET_SPACEID = SUSPECT_ZERO_ADDRESS.getAddressSpace().getSpaceID(); this.programContext = programContext; @@ -1754,6 +1755,20 @@ class OffsetAddressFactory extends DefaultAddressFactory { } } } + try { + // Use JOIN type space for suspect constants, it is used by the decompiler, so can + // be repurposed for this algorithm. + // Hack for current storage allows suspect constants to fit in a byte. The current + // algorithm is sensitive to the space ID value and must be less than 0x7f. Only types that are + // between 0-16 will work correctly because of how the spaceID is calculated based on the space type. + // The spaceID is computed using the type. + AddressSpace suspectConstspc = new GenericAddressSpace(VarnodeContext.SUSPECT_CONST_NAME, 64, + AddressSpace.TYPE_JOIN, 0); + addAddressSpace(suspectConstspc); + } + catch (DuplicateNameException e) { + throw new AssertException("Duplicate name should not occur."); + } try { addAddressSpace(AddressSpace.EXTERNAL_SPACE); } diff --git a/Ghidra/Processors/PIC/data/languages/pic16.ldefs b/Ghidra/Processors/PIC/data/languages/pic16.ldefs index af82b20edb..94d988f255 100644 --- a/Ghidra/Processors/PIC/data/languages/pic16.ldefs +++ b/Ghidra/Processors/PIC/data/languages/pic16.ldefs @@ -14,7 +14,6 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -40,6 +136,14 @@ + + + + + + + + diff --git a/Ghidra/Processors/PIC/data/languages/pic16.sinc b/Ghidra/Processors/PIC/data/languages/pic16.sinc index d7144dae17..68207af119 100644 --- a/Ghidra/Processors/PIC/data/languages/pic16.sinc +++ b/Ghidra/Processors/PIC/data/languages/pic16.sinc @@ -2,28 +2,6 @@ # PIC-16 Main Section # includes constants, memory space and common register space definitions # - -# STATUS bit definitions -@define STATUS_IRP_BIT 7 -@define STATUS_RP0_BIT 5 -@define STATUS_Z_BIT 2 -@define STATUS_DC_BIT 1 -@define STATUS_C_BIT 0 - -# STATUS bit masks used for setting -@define STATUS_IRP_MASK 0x80 -@define STATUS_RP_MASK 0x60 -@define STATUS_Z_MASK 0x04 -@define STATUS_DC_MASK 0x02 -@define STATUS_C_MASK 0x01 - -# STATUS bit masks used for clearing -@define STATUS_IRP_CLEARMASK 0x7F -@define STATUS_RP_CLEARMASK 0x9F -@define STATUS_Z_CLEARMASK 0xFB -@define STATUS_DC_CLEARMASK 0xFD -@define STATUS_C_CLEARMASK 0xFE - define endian=little; define alignment=2; @@ -50,18 +28,37 @@ define register offset=0x0002 size=1 [ STKPTR ]; define register offset=0x0003 size=1 [ W SkipNext ]; # Status bit registers (these do not really exist and must get reflected into the STATUS byte register) -@if PROCESSOR == "PIC_16" define register offset=0x0007 size=1 [ IRP RP ]; -@elif PROCESSOR == "PIC_16F" -define register offset=0x0007 size=1 [ IRP RP ]; -@endif @define C "STATUS[0,1]" @define DC "STATUS[1,1]" @define Z "STATUS[2,1]" @define PD "STATUS[3,1]" @define TO "STATUS[4,1]" -@define PA0 "STATUS[5,1]" +@define RP "STATUS[5,2]" +@define IRP "STATUS[7,1]" + +# STATUS bit definitions +@define STATUS_IRP_BIT 7 +@define STATUS_RP_BIT 5 +@define STATUS_Z_BIT 2 +@define STATUS_DC_BIT 1 +@define STATUS_C_BIT 0 + +# STATUS bit masks used for setting +@define STATUS_IRP_MASK 0x80 +@define STATUS_RP_MASK 0x60 +@define STATUS_Z_MASK 0x04 +@define STATUS_DC_MASK 0x02 +@define STATUS_C_MASK 0x01 + +# STATUS bit masks used for clearing +@define STATUS_IRP_CLEARMASK 0x7F +@define STATUS_RP_CLEARMASK 0x9F +@define STATUS_Z_CLEARMASK 0xFB +@define STATUS_DC_CLEARMASK 0xFD +@define STATUS_C_CLEARMASK 0xFE + # # WARNING! - Reflection of these DATA-based registers with the corresponding register @@ -80,16 +77,13 @@ define register offset=0x0007 size=1 [ IRP RP ]; # @if PROCESSOR == "PIC_16" define DATA offset=0x0000 size=1 [ - INDF TMR0 PCL STATUS FSR PORTA PORTB PORTC PORTD PORTE PCLATH INTCON PIR1 PIR2 TMR1L TMR1H + INDF _ PCL STATUS FSR _ _ _ _ _ PCLATH INTCON _ _ _ _ ]; - @elif PROCESSOR == "PIC_16F" define DATA offset=0x0000 size=1 [ - INDF0 INDF1 PCL STATUS FSR0L FSR0H FSR1L FSR1H BSR WREG PCLATH INTCON _ _ _ _ + INDF0 INDF1 PCL STATUS FSR0L FSR0H FSR1L FSR1H BSR WREG PCLATH INTCON _ _ _ _ ]; - define DATA offset=0x0004 size=2 [ FSR0 FSR1 ]; - @endif # Additional Data Bank data registers are defined in the .PSPEC file. diff --git a/Ghidra/Processors/PIC/data/languages/pic16_instructions.sinc b/Ghidra/Processors/PIC/data/languages/pic16_instructions.sinc index 4bec48f478..4d31346ed3 100644 --- a/Ghidra/Processors/PIC/data/languages/pic16_instructions.sinc +++ b/Ghidra/Processors/PIC/data/languages/pic16_instructions.sinc @@ -25,7 +25,6 @@ define token instr16(16) uf7 = (4,6) fsr = (2,2) fsrk = (6,6) - fregCore = (0,3) k5 = (0,4) k6 = (0,5) k7 = (0,6) @@ -44,15 +43,7 @@ define context contextreg ; -@if PROCESSOR == "PIC_16" -attach variables [ fregCore ] [ - INDF TMR0 PCL STATUS FSR PORTA PORTB PORTC PORTD PORTE PCLATH INTCON _ _ _ _ -]; - -@elif PROCESSOR == "PIC_16F" -attach variables [ fregCore ] [ - INDF0 INDF1 PCL STATUS FSR0L FSR0H FSR1L FSR1H BSR W PCLATH INTCON _ _ _ _ -]; +@if PROCESSOR == "PIC_16F" attach names [IntConBits] [ IOCIF INTF TMR0IF IOCIE INTE TMR0IE PEIE GIE ]; @@ -178,31 +169,45 @@ srcREG: fv is uf7=0x7 & lf7 [fv = 0x70 + lf7; ] { export *[DATA]:1 addr; } +# The registers listed here are explicitly defined as registers in sleigh. +# There are other registers but they are named in the .pspec file. +# The reason this is done is to have cross references created to certain registers, and to have +# only the registers that must be accessed directly in sleigh (e.g. PCL, FSR) defined in sleigh. +# Register explicitly defined in sleigh will not have xref's created to them. +# Registers named only in the .pspec file will have xref's to them in most cases. +# +# Also, these registers ignore RP, or BSR which allow more registers to be in a different register bank. +# +# PIC16 : INDF _ PCL STATUS FSR _ _ _ _ _ PCLATH INTCON _ _ _ _ +# PIC16F: INDF0 INDF1 PCL STATUS FSR0L FSR0H FSR1L FSR1H BSR W PCLATH INTCON _ _ _ _ + # File register index (f7=0): INDF use implies indirect data access using FSR value and IRP bit in STATUS reg @if PROCESSOR == "PIC_16" -srcREG: fregCore is f7=0 & fregCore { +srcREG: INDF is f7=0 & INDF { addr:2 = (zext(IRP) << 8) + zext(FSR); export *[DATA]:1 addr; } -srcREG: fregCore is f7=1 & fregCore { - rpval:2 = zext(RP == 1) + zext(RP == 2); - addr:2 = (zext(rpval) << 7) + 1; - export *[DATA]:1 addr; +srcREG: lf7 is f7=1 & lf7 { + rpval:2 = zext(RP == 1) + zext(RP == 3); + addr:2 = (zext(rpval) << 7) + 1; + export *[DATA]:1 addr; } + @elif PROCESSOR == "PIC_16F" -srcREG: fregCore is f7=0 & fregCore { + +srcREG: INDF0 is f7=0 & INDF0 { addr:2 = FSR0; export *[DATA]:1 addr; } -srcREG: fregCore is f7=1 & fregCore { +srcREG: INDF1 is f7=1 & INDF1 { addr:2 = FSR1; export *[DATA]:1 addr; } @endif # Special File Registers always mapped to Bank-0 -srcREG: fregCore is f7=0x02 & fregCore { +srcREG: PCL is f7=0x02 & PCL { # PCL and PCLATH must be latched addr:2 = inst_start >> 1; # Compensate for CODE wordsize PCL = addr:1; @@ -210,17 +215,19 @@ srcREG: fregCore is f7=0x02 & fregCore { export PCL; } -srcREG: fregCore is f7=0x03 & fregCore { export fregCore; } -srcREG: fregCore is f7=0x04 & fregCore { export fregCore; } -@if PROCESSOR == "PIC_16F" -srcREG: fregCore is f7=0x05 & fregCore { export fregCore; } -srcREG: fregCore is f7=0x06 & fregCore { export fregCore; } -srcREG: fregCore is f7=0x07 & fregCore { export fregCore; } -srcREG: fregCore is f7=0x08 & fregCore { export fregCore; } -srcREG: fregCore is f7=0x09 & fregCore { export fregCore; } +srcREG: STATUS is f7=0x03 & STATUS { export STATUS; } +@if PROCESSOR == "PIC_16" +srcREG: FSR is f7=0x04 & FSR { export FSR; } +@elif PROCESSOR == "PIC_16F" +srcREG: FSR0L is f7=0x04 & FSR0L { export FSR0L; } +srcREG: FSR0H is f7=0x05 & FSR0H { export FSR0H; } +srcREG: FSR1L is f7=0x06 & FSR1L { export FSR1L; } +srcREG: FSR1H is f7=0x07 & FSR1H { export FSR1H; } +srcREG: BSR is f7=0x08 & BSR { export BSR; } +srcREG: W is f7=0x09 & W { export W; } @endif -srcREG: fregCore is f7=0x0a & fregCore { export fregCore; } -srcREG: fregCore is f7=0x0b & fregCore { export fregCore; } +srcREG: PCLATH is f7=0x0a & PCLATH { export PCLATH; } +srcREG: INTCON is f7=0x0b & INTCON { export INTCON; } # Destination register (either srcREG or W) @@ -230,7 +237,7 @@ destREG: "0" is d=0 { export W; } destREG: "1" is d=1 & f7 & srcREG { export srcREG; } # Destination register: Special File Registers always mapped to Bank-0 -destREG: "1" is d=1 & f7=0x02 & fregCore { export fregCore; } # PCL (special behavior reqd) +destREG: "1" is d=1 & f7=0x02 { export PCL; } # PCL (special behavior reqd) # Destination operand representation (w: W register is destination; f: specified srcREG is destination) D: "w" is d=0 { } @@ -238,13 +245,13 @@ D: "f" is d=1 { } # Absolute address generated from k11 and PCLATH<4:3> absAddr11: k11 is k11 { - addr:2 = ((zext(PCLATH) & 0x78) << 8) + k11; + addr:2 = ((zext(PCLATH) & 0x18) << 8) | k11; export addr; } @if PROCESSOR == "PIC_16F" -# Absolute address generated from k11 and PCLATH<4:3> +# Relative address relAddr9: addr is sk9 [ addr = inst_next + sk9; ] { export *[CODE]:2 addr; } @@ -327,7 +334,7 @@ trisREG: "7" is l5=7 { local trl:2 = 0x10E; export *[DATA]:1 trl; } # tmp:1 = addr:1; setAddFlags(tmp, W); tmp = tmp + W; - addr = (zext(PCLATH) << 8) + zext(tmp); + addr = ((zext(PCLATH) & 0x1F) << 8) | zext(tmp); PCL = tmp; setResultFlags(tmp); goto [addr]; @@ -365,7 +372,7 @@ trisREG: "7" is l5=7 { local trl:2 = 0x10E; export *[DATA]:1 trl; } # $(C) = $(C) | tc; val = val + tmpC; - addr = (zext(PCLATH) << 8) + zext(val); + addr = ((zext(PCLATH) & 0x1F) << 8) | zext(val); PCL = val; setResultFlags(val); goto [addr]; @@ -799,7 +806,7 @@ srcFSRk: sk6"["fsrk"]" is fsrk & sk6 { } :MOVLP imm7 is op7=0x63 & imm7 { - PCLATH = imm7; + PCLATH = imm7 & 0x1F; } @endif @@ -831,7 +838,7 @@ srcFSRk: sk6"["fsrk"]" is fsrk & sk6 { # --00 0000 1fff ffff # 0000 0000 1000 0010 -> MOVWF PCL PCL = W; - addr:2 = (zext(PCLATH) << 8) + zext(PCL); + addr:2 = ((zext(PCLATH) & 0x1F) << 8) | zext(PCL); goto [addr]; } diff --git a/Ghidra/Processors/PIC/data/languages/pic16f.pspec b/Ghidra/Processors/PIC/data/languages/pic16f.pspec index 44a15b649d..a821ddbec2 100644 --- a/Ghidra/Processors/PIC/data/languages/pic16f.pspec +++ b/Ghidra/Processors/PIC/data/languages/pic16f.pspec @@ -10,9 +10,102 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Ghidra/Processors/PIC/src/main/java/ghidra/app/plugin/core/analysis/Pic16Analyzer.java b/Ghidra/Processors/PIC/src/main/java/ghidra/app/plugin/core/analysis/Pic16Analyzer.java index 64fd79747f..2a42b481b3 100644 --- a/Ghidra/Processors/PIC/src/main/java/ghidra/app/plugin/core/analysis/Pic16Analyzer.java +++ b/Ghidra/Processors/PIC/src/main/java/ghidra/app/plugin/core/analysis/Pic16Analyzer.java @@ -53,6 +53,9 @@ public class Pic16Analyzer extends ConstantPropagationAnalyzer { @Override public boolean canAnalyze(Program p) { + if (!super.canAnalyze(p)) { + return false; + } Language lang = p.getLanguage(); statusReg = p.getRegister("STATUS"); pclathReg = p.getRegister("PCLATH"); @@ -63,6 +66,10 @@ public class Pic16Analyzer extends ConstantPropagationAnalyzer { rpStatusReg = p.getRegister("RP"); irpStatusReg = p.getRegister("IRP"); + // set default analysis options + minSpeculativeRefAddress = 4; + minStoreLoadRefAddress = 4; + return lang.getProcessor() == PicProcessor.PROCESSOR_PIC_16 && pclathReg != null; } @@ -82,25 +89,6 @@ public class Pic16Analyzer extends ConstantPropagationAnalyzer { // use context to fill out addresses on certain instructions ConstantPropagationContextEvaluator eval = new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) { - @Override - public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, Address address, - int size, DataType dataType, RefType refType) { - AddressSpace space = address.getAddressSpace(); - - if (address.isExternalAddress()) { - return true; - } - - if (space.hasMappedRegisters()) { - return true; - } - boolean isCodeSpace = address.getAddressSpace().getName().equals(CODE_SPACE_NAME); - if (refType.isComputed() && refType.isFlow() && isCodeSpace) { - return true; - } - return super.evaluateReference(context, instr, pcodeop, address, size, dataType, refType); - } - @Override public boolean evaluateDestination(VarnodeContext context, Instruction instruction) { FlowType flowType = instruction.getFlowType(); @@ -111,11 +99,9 @@ public class Pic16Analyzer extends ConstantPropagationAnalyzer { Reference[] refs = instruction.getReferencesFrom(); if (refs.length == 1 && refs[0].getReferenceType().isFlow()) { writeContext(refs[0].getToAddress(), context); - Address dest = refs[0].getToAddress(); - disassemblyPoints.addRange(dest, dest); } - return false; + return super.evaluateDestination(context, instruction); } private void writeContext(Address dest, VarnodeContext context) { @@ -157,11 +143,6 @@ public class Pic16Analyzer extends ConstantPropagationAnalyzer { AddressSet result = symEval.flowConstants(flowStart, flowSet, eval, true, monitor); - if (!disassemblyPoints.isEmpty()) { - AutoAnalysisManager mgr = AutoAnalysisManager.getAnalysisManager(program); - mgr.disassemble(disassemblyPoints); - } - return result; }