diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/pcodeparse.y b/Ghidra/Features/Decompiler/src/decompile/cpp/pcodeparse.y index 87cd725974b..27667bf777b 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/pcodeparse.y +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/pcodeparse.y @@ -741,6 +741,7 @@ int4 PcodeSnippet::lex(void) yylval.operandsym = (OperandSymbol *)sym; return OPERANDSYM; case SleighSymbol::start_symbol: + case SleighSymbol::offset_symbol: case SleighSymbol::end_symbol: case SleighSymbol::next2_symbol: case SleighSymbol::flowdest_symbol: diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/semantics.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/semantics.cc index cd9b9835b18..d9b02eea184 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/semantics.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/semantics.cc @@ -121,6 +121,8 @@ uintb ConstTpl::fix(const ParserWalker &walker) const switch(type) { case j_start: return walker.getAddr().getOffset(); // Fill in starting address placeholder with real address + case j_offset: + return walker.getAddr().getOffset(); // Fill in starting address placeholder with real address case j_next: return walker.getNaddr().getOffset(); // Fill in next address placeholder with real address case j_next2: @@ -318,6 +320,10 @@ void ConstTpl::encode(Encoder &encoder) const encoder.openElement(sla::ELEM_CONST_START); encoder.closeElement(sla::ELEM_CONST_START); break; + case j_offset: + encoder.openElement(sla::ELEM_CONST_OFFSET); + encoder.closeElement(sla::ELEM_CONST_OFFSET); + break; case j_next: encoder.openElement(sla::ELEM_CONST_NEXT); encoder.closeElement(sla::ELEM_CONST_NEXT); @@ -417,6 +423,9 @@ void ConstTpl::decode(Decoder &decoder) else if (el == sla::ELEM_CONST_FLOWDEST_SIZE) { type = j_flowdest_size; } + else if (el == sla::ELEM_CONST_OFFSET) { + type = j_offset; + } else throw LowlevelError("Bad constant type"); decoder.closeElement(el); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/semantics.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/semantics.hh index e0b069959db..c8ca5478565 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/semantics.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/semantics.hh @@ -35,7 +35,7 @@ class ConstTpl { public: enum const_type { real=0, handle=1, j_start=2, j_next=3, j_next2=4, j_curspace=5, j_curspace_size=6, spaceid=7, j_relative=8, - j_flowref=9, j_flowref_size=10, j_flowdest=11, j_flowdest_size=12 }; + j_flowref=9, j_flowref_size=10, j_flowdest=11, j_flowdest_size=12, j_offset=13 }; enum v_field { v_space=0, v_offset=1, v_size=2, v_offset_plus=3 }; private: const_type type; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/slaformat.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/slaformat.cc index f8b3bcfa731..59269347fff 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/slaformat.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/slaformat.cc @@ -166,6 +166,10 @@ ElementId ELEM_CONST_FLOWREF = ElementId("const_flowref", 85, FORMAT_SCOPE); ElementId ELEM_CONST_FLOWREF_SIZE = ElementId("const_flowref_size", 86, FORMAT_SCOPE); ElementId ELEM_CONST_FLOWDEST = ElementId("const_flowdest", 87, FORMAT_SCOPE); ElementId ELEM_CONST_FLOWDEST_SIZE = ElementId("const_flowdest_size", 88, FORMAT_SCOPE); +ElementId ELEM_OFFSET_EXP = ElementId("offset_exp", 89, FORMAT_SCOPE); +ElementId ELEM_OFFSET_SYM = ElementId("offset_sym", 90, FORMAT_SCOPE); +ElementId ELEM_OFFSET_SYM_HEAD = ElementId("offset_sym_head", 91, FORMAT_SCOPE); +ElementId ELEM_CONST_OFFSET = ElementId("const_offset", 92, FORMAT_SCOPE); /// The bytes of the header are read from the stream and verified against the required form and current version. /// If the form matches, \b true is returned. No additional bytes are read. diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/slaformat.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/slaformat.hh index a8eb11b63c8..7034cf794e6 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/slaformat.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/slaformat.hh @@ -172,6 +172,10 @@ extern ElementId ELEM_CONST_FLOWREF; ///< SLA format element "const_flowref" extern ElementId ELEM_CONST_FLOWREF_SIZE; ///< SLA format element "const_flowref_size" extern ElementId ELEM_CONST_FLOWDEST; ///< SLA format element "const_flowdest" extern ElementId ELEM_CONST_FLOWDEST_SIZE; ///< SLA format element "const_flowdest_size" +extern ElementId ELEM_OFFSET_EXP; ///< SLA format element "offset_exp" +extern ElementId ELEM_OFFSET_SYM; ///< SLA format element "operand_offset_sym" +extern ElementId ELEM_OFFSET_SYM_HEAD; ///< SLA format element "operand_offset_sym_head" +extern ElementId ELEM_CONST_OFFSET; ///< SLA format element "offset_start" extern bool isSlaFormat(istream &s); ///< Verify a .sla file header at the current point of the given stream extern void writeSlaHeader(ostream &s); ///< Write a .sla file header to the given stream diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/slgh_compile.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/slgh_compile.cc index 50d85e22ba2..6f311f230c7 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/slgh_compile.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/slgh_compile.cc @@ -1796,7 +1796,7 @@ SleighCompile::SleighCompile(void) } /// Create the address spaces: \b const, \b unique, and \b other. -/// Define the special symbols: \b inst_start, \b inst_next, \b inst_next2, \b epsilon. +/// Define the special symbols: \b inst_start, \b operand_offset, \b inst_next, \b inst_next2, \b epsilon. /// Define the root subtable symbol: \b instruction void SleighCompile::predefinedSymbols(void) @@ -1818,6 +1818,8 @@ void SleighCompile::predefinedSymbols(void) symtab.addSymbol(spacesym); StartSymbol *startsym = new StartSymbol("inst_start",getConstantSpace()); symtab.addSymbol(startsym); + OffsetSymbol *offsetsym = new OffsetSymbol("operand_offset",getConstantSpace()); + symtab.addSymbol(offsetsym); EndSymbol *endsym = new EndSymbol("inst_next",getConstantSpace()); symtab.addSymbol(endsym); Next2Symbol *next2sym = new Next2Symbol("inst_next2",getConstantSpace()); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/slghpatexpress.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/slghpatexpress.cc index 94109785953..e16bf18b742 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/slghpatexpress.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/slghpatexpress.cc @@ -502,6 +502,8 @@ PatternExpression *PatternExpression::decodeExpression(Decoder &decoder,Translat res = new MinusExpression(); else if (el == sla::ELEM_NOT_EXP) res = new NotExpression(); + else if (el == sla::ELEM_OFFSET_EXP) + res = new OffsetInstructionValue(); else return (PatternExpression *)0; @@ -711,6 +713,20 @@ void StartInstructionValue::decode(Decoder &decoder,Translate *trans) decoder.closeElement(el); } +void OffsetInstructionValue::encode(Encoder &encoder) const + +{ + encoder.openElement(sla::ELEM_OFFSET_EXP); + encoder.closeElement(sla::ELEM_OFFSET_EXP); +} + +void OffsetInstructionValue::decode(Decoder &decoder,Translate *trans) + +{ + uint4 el = decoder.openElement(sla::ELEM_OFFSET_EXP); + decoder.closeElement(el); +} + void EndInstructionValue::encode(Encoder &encoder) const { diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/slghpatexpress.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/slghpatexpress.hh index 118fe3cc943..6e264ded3fd 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/slghpatexpress.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/slghpatexpress.hh @@ -153,6 +153,20 @@ public: virtual void encode(Encoder &encoder) const; virtual void decode(Decoder &decoder,Translate *trans); }; + +class OffsetInstructionValue : public PatternValue { +public: + OffsetInstructionValue(void) {} + virtual intb getValue(ParserWalker &walker) const { + return (intb)walker.getOffset(-1); + } + virtual TokenPattern genMinPattern(const vector &ops) const { return TokenPattern(); } + virtual TokenPattern genPattern(intb val) const { return TokenPattern(); } + virtual intb minValue(void) const { return (intb)0; } + virtual intb maxValue(void) const { return (intb)0; } + virtual void encode(Encoder &encoder) const; + virtual void decode(Decoder &decoder,Translate *trans); +}; class EndInstructionValue : public PatternValue { public: diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/slghsymbol.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/slghsymbol.cc index b35dd6ec797..7c9f2abe69e 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/slghsymbol.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/slghsymbol.cc @@ -1,4 +1,4 @@ -/* ### +#/* ### * IP: GHIDRA * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -224,6 +224,8 @@ void SymbolTable::decodeSymbolHeader(Decoder &decoder) sym = new OperandSymbol(); else if (el == sla::ELEM_START_SYM_HEAD) sym = new StartSymbol(); + else if (el == sla::ELEM_OFFSET_SYM_HEAD) + sym = new OffsetSymbol(); else if (el == sla::ELEM_END_SYM_HEAD) sym = new EndSymbol(); else if (el == sla::ELEM_NEXT2_SYM_HEAD) @@ -1137,6 +1139,71 @@ void StartSymbol::decode(Decoder &decoder,SleighBase *trans) decoder.closeElement(sla::ELEM_START_SYM.getId()); } +OffsetSymbol::OffsetSymbol(const string &nm,AddrSpace *cspc) : SpecificSymbol(nm) + +{ + const_space = cspc; + patexp = new OffsetInstructionValue(); + patexp->layClaim(); +} + +OffsetSymbol::~OffsetSymbol(void) + +{ + if (patexp != (PatternExpression *)0) + PatternExpression::release(patexp); +} + +VarnodeTpl *OffsetSymbol::getVarnode(void) const + +{ // Returns current operand offset as a constant + ConstTpl spc(const_space); + ConstTpl off(ConstTpl::j_offset); + ConstTpl sz_zero; + return new VarnodeTpl(spc,off,sz_zero); +} + +void OffsetSymbol::getFixedHandle(FixedHandle &hand,ParserWalker &walker) const + +{ + hand.space = walker.getCurSpace(); + hand.offset_space = (AddrSpace *)0; + hand.offset_offset = walker.getAddr().getOffset(); // Get starting address of instruction + hand.size = hand.space->getAddrSize(); +} + +void OffsetSymbol::print(ostream &s,ParserWalker &walker) const + +{ + intb val = (intb) walker.getAddr().getOffset(); + s << "0x" << std::hex << val << std::dec; +} + +void OffsetSymbol::encode(Encoder &encoder) const + +{ + encoder.openElement(sla::ELEM_OFFSET_SYM); + encoder.writeUnsignedInteger(sla::ATTRIB_ID, getId()); + encoder.closeElement(sla::ELEM_OFFSET_SYM); +} + +void OffsetSymbol::encodeHeader(Encoder &encoder) const + +{ + encoder.openElement(sla::ELEM_OFFSET_SYM_HEAD); + SleighSymbol::encodeHeader(encoder); + encoder.closeElement(sla::ELEM_OFFSET_SYM_HEAD); +} + +void OffsetSymbol::decode(Decoder &decoder,SleighBase *trans) + +{ + const_space = trans->getConstantSpace(); + patexp = new StartInstructionValue(); + patexp->layClaim(); + decoder.closeElement(sla::ELEM_OFFSET_SYM.getId()); +} + EndSymbol::EndSymbol(const string &nm,AddrSpace *cspc) : SpecificSymbol(nm) { diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/slghsymbol.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/slghsymbol.hh index 5e8b4d3dfdc..e460a43bac3 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/slghsymbol.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/slghsymbol.hh @@ -27,7 +27,7 @@ class SleighSymbol { public: enum symbol_type { space_symbol, token_symbol, userop_symbol, value_symbol, valuemap_symbol, name_symbol, varnode_symbol, varnodelist_symbol, operand_symbol, - start_symbol, end_symbol, next2_symbol, subtable_symbol, macro_symbol, section_symbol, + start_symbol, offset_symbol, end_symbol, next2_symbol, subtable_symbol, macro_symbol, section_symbol, bitrange_symbol, context_symbol, epsilon_symbol, label_symbol, flowdest_symbol, flowref_symbol, dummy_symbol }; private: @@ -373,6 +373,23 @@ public: virtual void decode(Decoder &decoder,SleighBase *trans); }; +class OffsetSymbol : public SpecificSymbol { + AddrSpace *const_space; + PatternExpression *patexp; +public: + OffsetSymbol(void) { patexp = (PatternExpression *)0; } // For use with decode + OffsetSymbol(const string &nm,AddrSpace *cspc); + virtual ~OffsetSymbol(void); + virtual VarnodeTpl *getVarnode(void) const; + virtual PatternExpression *getPatternExpression(void) const { return patexp; } + virtual void getFixedHandle(FixedHandle &hand,ParserWalker &walker) const; + virtual void print(ostream &s,ParserWalker &walker) const; + virtual symbol_type getType(void) const { return offset_symbol; } + virtual void encode(Encoder &encoder) const; + virtual void encodeHeader(Encoder &encoder) const; + virtual void decode(Decoder &decoder,SleighBase *trans); +}; + class EndSymbol : public SpecificSymbol { AddrSpace *const_space; PatternExpression *patexp; diff --git a/Ghidra/Features/Decompiler/src/main/doc/sleigh.xml b/Ghidra/Features/Decompiler/src/main/doc/sleigh.xml index d4af0e85992..a36cf1f3088 100644 --- a/Ghidra/Features/Decompiler/src/main/doc/sleigh.xml +++ b/Ghidra/Features/Decompiler/src/main/doc/sleigh.xml @@ -1097,6 +1097,10 @@ We list all of the symbols that are predefined by SLEIGH. epsilon A special identifier indicating an empty bit pattern. + + operand_offset + Offset of the address of the current operand. Useful for variable-length instructions. + @@ -1113,6 +1117,9 @@ identifiers are address spaces. The epsilon identifier is inherited from SLED and is a specific symbol equivalent to the constant zero. The instruction identifier is the root instruction table. +operand_offset was introduced to support VAX +variable-length, multi-operand instructions. PC-relative addressing in +VAX is relative to the operand address, not the instruction address. diff --git a/Ghidra/Framework/SoftwareModeling/src/main/antlr/ghidra/sleigh/grammar/SleighCompiler.g b/Ghidra/Framework/SoftwareModeling/src/main/antlr/ghidra/sleigh/grammar/SleighCompiler.g index d254d2bd920..46d32ef4294 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/antlr/ghidra/sleigh/grammar/SleighCompiler.g +++ b/Ghidra/Framework/SoftwareModeling/src/main/antlr/ghidra/sleigh/grammar/SleighCompiler.g @@ -342,6 +342,7 @@ specific_symbol[String purpose] returns [SpecificSymbol symbol] if (sym == null) { unknownSymbolError($s.getText(), find($s), "start, end, next2, operand, epsilon, or varnode", purpose); } else if(sym.getType() != symbol_type.start_symbol + && sym.getType() != symbol_type.offset_symbol && sym.getType() != symbol_type.end_symbol && sym.getType() != symbol_type.next2_symbol && sym.getType() != symbol_type.flowdest_symbol @@ -841,6 +842,7 @@ pattern_symbol[String purpose] returns [PatternExpression expr] } $expr = os.getPatternExpression(); } else if(sym.getType() == symbol_type.start_symbol + || sym.getType() == symbol_type.offset_symbol || sym.getType() == symbol_type.end_symbol || sym.getType() == symbol_type.next2_symbol || sym.getType() == symbol_type.flowdest_symbol @@ -876,6 +878,7 @@ pattern_symbol2[String purpose] returns [PatternExpression expr] if (sym == null) { unknownSymbolError($s.getText(), find($s), "start, end, next2, operand, epsilon, or varnode", purpose); } else if(sym.getType() == symbol_type.start_symbol + || sym.getType() == symbol_type.offset_symbol || sym.getType() == symbol_type.end_symbol || sym.getType() == symbol_type.next2_symbol || sym.getType() == symbol_type.flowdest_symbol @@ -949,6 +952,7 @@ cstatement[VectorSTL r] || sym.getType() == symbol_type.name_symbol || sym.getType() == symbol_type.varnodelist_symbol || sym.getType() == symbol_type.start_symbol + || sym.getType() == symbol_type.offset_symbol || sym.getType() == symbol_type.end_symbol || sym.getType() == symbol_type.next2_symbol || sym.getType() == symbol_type.flowdest_symbol @@ -1184,6 +1188,7 @@ assignment returns [VectorSTL value] bitSym.getBitOffset(), bitSym.numBits(),e); } else if(sym.getType() != symbol_type.start_symbol + && sym.getType() != symbol_type.offset_symbol && sym.getType() != symbol_type.end_symbol && sym.getType() != symbol_type.next2_symbol && sym.getType() != symbol_type.flowdest_symbol @@ -1528,6 +1533,7 @@ expr_apply returns [Object value] pcode.reportError(find($t), "macro invocation not allowed as expression"); } } else if(sym.getType() == symbol_type.start_symbol + || sym.getType() == symbol_type.offset_symbol || sym.getType() == symbol_type.end_symbol || sym.getType() == symbol_type.next2_symbol || sym.getType() == symbol_type.flowdest_symbol diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/OffsetInstructionValue.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/OffsetInstructionValue.java new file mode 100644 index 00000000000..c04bd7412ac --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/OffsetInstructionValue.java @@ -0,0 +1,73 @@ +/* ### + * 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. + */ +/* + * Created on Feb 8, 2005 + * + */ +package ghidra.app.plugin.processors.sleigh.expression; + +import static ghidra.pcode.utils.SlaFormat.*; + +import ghidra.app.plugin.processors.sleigh.ParserWalker; +import ghidra.app.plugin.processors.sleigh.SleighLanguage; +import ghidra.program.model.address.Address; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; + +/** + * The offset value of the current instructions address + */ +public class OffsetInstructionValue extends PatternValue { + private static final int HASH = "[inst_offset]".hashCode(); + + @Override + public int hashCode() { + return HASH; + } + + @Override + public boolean equals(Object obj) { + return obj instanceof OffsetInstructionValue; + } + + @Override + public long minValue() { + return 0; + } + + @Override + public long maxValue() { + return 0; + } + + @Override + public long getValue(ParserWalker walker) throws MemoryAccessException { + return walker.getOffset(-1); + } + + @Override + public void decode(Decoder decoder, SleighLanguage lang) throws DecoderException { + int el = decoder.openElement(ELEM_OFFSET_EXP); + decoder.closeElement(el); + // Nothing to do + } + + @Override + public String toString() { + return "[inst_offset]"; + } +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/PatternExpression.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/PatternExpression.java index 3818f96ee1d..f91fe4122d7 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/PatternExpression.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/expression/PatternExpression.java @@ -54,6 +54,9 @@ else if (el == ELEM_OPERAND_EXP.id()) { else if (el == ELEM_START_EXP.id()) { res = new StartInstructionValue(); } + else if (el == ELEM_OFFSET_EXP.id()) { + res = new OffsetInstructionValue(); + } else if (el == ELEM_END_EXP.id()) { res = new EndInstructionValue(); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/OffsetSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/OffsetSymbol.java new file mode 100644 index 00000000000..042e7277db8 --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/OffsetSymbol.java @@ -0,0 +1,73 @@ +/* ### + * IP: GHIDRA + * REVIEWED: YES + * + * 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. + */ +/* + * Created on Feb 8, 2005 + * + */ +package ghidra.app.plugin.processors.sleigh.symbol; + +import static ghidra.pcode.utils.SlaFormat.*; + +import java.util.ArrayList; + +import ghidra.app.plugin.processors.sleigh.*; +import ghidra.app.plugin.processors.sleigh.expression.PatternExpression; +import ghidra.app.plugin.processors.sleigh.expression.OffsetInstructionValue; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.pcode.Decoder; +import ghidra.program.model.pcode.DecoderException; + +/** + * TripleSymbol with semantic value equal to offset of instruction's + * operand current address + */ +public class OffsetSymbol extends SpecificSymbol { + + private PatternExpression patexp; + + @Override + public PatternExpression getPatternExpression() { + return patexp; + } + + @Override + public void getFixedHandle(FixedHandle hand, ParserWalker walker) { + hand.space = walker.getCurSpace(); + hand.offset_space = null; + hand.offset_offset = walker.getAddr().getOffset(); + hand.size = hand.space.getPointerSize(); + } + + @Override + public String print(ParserWalker walker) throws MemoryAccessException { + long val = walker.getAddr().getOffset(); + return "0x" + Long.toHexString(val); + } + + @Override + public void printList(ParserWalker walker, ArrayList list) { + list.add(walker.getParentHandle()); + } + + @Override + public void decode(Decoder decoder, SleighLanguage sleigh) throws DecoderException { +// int element = decoder.openElement(ELEM_OFFSET_SYM); + patexp = new OffsetInstructionValue(); + decoder.closeElement(ELEM_OFFSET_SYM.id()); + } + +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/SymbolTable.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/SymbolTable.java index 1b3f1ae1beb..d77f1b5021c 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/SymbolTable.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/symbol/SymbolTable.java @@ -174,6 +174,9 @@ else if (el == ELEM_OPERAND_SYM_HEAD.id()) { else if (el == ELEM_START_SYM_HEAD.id()) { sym = new StartSymbol(); } + else if (el == ELEM_OFFSET_SYM_HEAD.id()) { + sym = new OffsetSymbol(); + } else if (el == ELEM_END_SYM_HEAD.id()) { sym = new EndSymbol(); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/template/ConstTpl.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/template/ConstTpl.java index 75cc37f1e27..73e90e92fb6 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/template/ConstTpl.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/template/ConstTpl.java @@ -46,6 +46,7 @@ public class ConstTpl { public static final int J_FLOWREF_SIZE = 10; public static final int J_FLOWDEST = 11; public static final int J_FLOWDEST_SIZE = 12; + public static final int J_OFFSET = 13; public static final int V_SPACE = 0; public static final int V_OFFSET = 1; @@ -140,6 +141,8 @@ public long fix(ParserWalker walker) { switch (type) { case J_START: return walker.getAddr().getOffset(); + case J_OFFSET: + return walker.getAddr().getOffset(); case J_NEXT: return walker.getNaddr().getOffset(); case J_NEXT2: @@ -302,6 +305,9 @@ else if (el == ELEM_CONST_HANDLE.id()) { else if (el == ELEM_CONST_START.id()) { type = J_START; } + else if (el == ELEM_CONST_OFFSET.id()) { + type = J_OFFSET; + } else if (el == ELEM_CONST_NEXT.id()) { type = J_NEXT; } @@ -376,6 +382,8 @@ public String toString() { return "[next2]"; case J_START: return "[start]"; + case J_OFFSET: + return "[offset]"; case J_RELATIVE: return "[rel:" + Long.toHexString(value_real) + "]"; } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/util/pcode/AbstractPcodeFormatter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/util/pcode/AbstractPcodeFormatter.java index e0a52013d6e..808dd4596b7 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/util/pcode/AbstractPcodeFormatter.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/util/pcode/AbstractPcodeFormatter.java @@ -173,6 +173,9 @@ protected void formatVarnode(A appender, int opcode, int opIndex, VarnodeTpl vTp if (offset.getType() == ConstTpl.J_START) { appender.appendLabel("inst_start"); } + else if (offset.getType() == ConstTpl.J_OFFSET) { + appender.appendLabel("operand_offset"); + } else if (offset.getType() == ConstTpl.J_NEXT) { appender.appendLabel("inst_next"); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/utils/SlaFormat.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/utils/SlaFormat.java index 742341daa63..7209f25a61b 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/utils/SlaFormat.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/utils/SlaFormat.java @@ -191,6 +191,10 @@ public class SlaFormat { public static final ElementId ELEM_CONST_FLOWDEST = new ElementId("const_flowdest", 87); public static final ElementId ELEM_CONST_FLOWDEST_SIZE = new ElementId("const_flowdest_size", 88); + public static final ElementId ELEM_OFFSET_EXP = new ElementId("offset_exp", 89); + public static final ElementId ELEM_OFFSET_SYM = new ElementId("offset_sym", 90); + public static final ElementId ELEM_OFFSET_SYM_HEAD = new ElementId("offset_sym_head",91); + public static final ElementId ELEM_CONST_OFFSET = new ElementId("const_offset",92); /** * Try to read the header bytes of the .sla format from the given stream. If the header bytes diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/semantics/ConstTpl.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/semantics/ConstTpl.java index 4c84b4d94ec..88b28eff013 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/semantics/ConstTpl.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/semantics/ConstTpl.java @@ -45,7 +45,8 @@ public enum const_type { j_flowref, j_flowref_size, j_flowdest, - j_flowdest_size + j_flowdest_size, + j_offset } public enum v_field { @@ -263,6 +264,10 @@ public void encode(Encoder encoder) throws IOException { encoder.openElement(ELEM_CONST_START); encoder.closeElement(ELEM_CONST_START); break; + case j_offset: + encoder.openElement(ELEM_CONST_OFFSET); + encoder.closeElement(ELEM_CONST_OFFSET); + break; case j_next: encoder.openElement(ELEM_CONST_NEXT); encoder.closeElement(ELEM_CONST_NEXT); @@ -307,5 +312,4 @@ public void encode(Encoder encoder) throws IOException { break; } } - } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slgh_compile/SleighCompile.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slgh_compile/SleighCompile.java index a953e401fff..1fb0b64069b 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slgh_compile/SleighCompile.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slgh_compile/SleighCompile.java @@ -290,6 +290,8 @@ private void predefinedSymbols() { symtab.addSymbol(spacesym); StartSymbol startsym = new StartSymbol(location, "inst_start", getConstantSpace()); symtab.addSymbol(startsym); + OffsetSymbol offsetsym = new OffsetSymbol(location, "operand_offset", getConstantSpace()); + symtab.addSymbol(offsetsym); EndSymbol endsym = new EndSymbol(location, "inst_next", getConstantSpace()); symtab.addSymbol(endsym); Next2Symbol next2sym = new Next2Symbol(location, "inst_next2", getConstantSpace()); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slgh_compile/Yylval.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slgh_compile/Yylval.java index f165ca6b8b3..dc574000152 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slgh_compile/Yylval.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slgh_compile/Yylval.java @@ -30,6 +30,7 @@ class Yylval { VarnodeListSymbol varlistsym; OperandSymbol operandsym; StartSymbol startsym; + OffsetSymbol offsetsym; EndSymbol endsym; Next2Symbol next2sym; SubtableSymbol subtablesym; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/OffsetInstructionValue.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/OffsetInstructionValue.java new file mode 100644 index 00000000000..8684da38301 --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/OffsetInstructionValue.java @@ -0,0 +1,59 @@ +/* ### + * IP: GHIDRA + * REVIEWED: YES + * + * 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.pcodeCPort.slghpatexpress; + +import static ghidra.pcode.utils.SlaFormat.*; + +import java.io.IOException; + +import generic.stl.VectorSTL; +import ghidra.program.model.pcode.Encoder; +import ghidra.sleigh.grammar.Location; + +public class OffsetInstructionValue extends PatternValue { + + public OffsetInstructionValue(Location location) { + super(location); + } + + @Override + public TokenPattern genMinPattern(VectorSTL ops) { + return new TokenPattern(location); + } + + @Override + public TokenPattern genPattern(long val) { + return new TokenPattern(location); + } + + @Override + public long minValue() { + return 0; + } + + @Override + public long maxValue() { + return 0; + } + + @Override + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_OFFSET_EXP); + encoder.closeElement(ELEM_OFFSET_EXP); + } + +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/PatternExpression.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/PatternExpression.java index 12955493ddf..38651b908a1 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/PatternExpression.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghpatexpress/PatternExpression.java @@ -60,5 +60,4 @@ public static void release(PatternExpression p) { p.dispose(); } } - } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/OffsetSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/OffsetSymbol.java new file mode 100644 index 00000000000..9b753b8d668 --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/OffsetSymbol.java @@ -0,0 +1,87 @@ +/* ### + * IP: GHIDRA + * REVIEWED: YES + * + * 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.pcodeCPort.slghsymbol; + +import static ghidra.pcode.utils.SlaFormat.*; + +import java.io.IOException; + +import ghidra.pcodeCPort.semantics.ConstTpl; +import ghidra.pcodeCPort.semantics.VarnodeTpl; +import ghidra.pcodeCPort.slghpatexpress.PatternExpression; +import ghidra.pcodeCPort.slghpatexpress.OffsetInstructionValue; +import ghidra.pcodeCPort.space.AddrSpace; +import ghidra.program.model.pcode.Encoder; +import ghidra.sleigh.grammar.Location; + +public class OffsetSymbol extends SpecificSymbol { + private AddrSpace const_space; + private PatternExpression patexp; + + OffsetSymbol(Location location) { + super(location); + patexp = null; + } + + @Override + public PatternExpression getPatternExpression() { + return patexp; + } + + @Override + public symbol_type getType() { + return symbol_type.offset_symbol; + } + + public OffsetSymbol(Location location, String nm, AddrSpace cspc) { + super(location, nm); + const_space = cspc; + patexp = new OffsetInstructionValue(location); + patexp.layClaim(); + } + + @Override + public void dispose() { + if (patexp != null) { + PatternExpression.release(patexp); + } + } + +// Returns current operand offset as a constant + @Override + public VarnodeTpl getVarnode() { + ConstTpl spc = new ConstTpl(const_space); + ConstTpl off = new ConstTpl(ConstTpl.const_type.j_offset); + ConstTpl sz_zero = new ConstTpl(); + return new VarnodeTpl(location, spc, off, sz_zero); + } + + @Override + public void encode(Encoder encoder) throws IOException { + encoder.openElement(ELEM_OFFSET_SYM); + encoder.writeUnsignedInteger(ATTRIB_ID, id); + encoder.closeElement(ELEM_OFFSET_SYM); + } + + @Override + public void encodeHeader(Encoder encoder) throws IOException { + encoder.openElement(ELEM_OFFSET_SYM_HEAD); + encodeSleighSymbolHeader(encoder); + encoder.closeElement(ELEM_OFFSET_SYM_HEAD); + } + +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/symbol_type.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/symbol_type.java index b29cc3f238e..1c14a38090b 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/symbol_type.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcodeCPort/slghsymbol/symbol_type.java @@ -26,6 +26,7 @@ public enum symbol_type { varnodelist_symbol, operand_symbol, start_symbol, // inst_start, inst_ref, inst_def + offset_symbol, end_symbol, // inst_next next2_symbol, // inst_next2 subtable_symbol, diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PcodeParser.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PcodeParser.java index 8166b87ef8b..eee777c6134 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PcodeParser.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PcodeParser.java @@ -84,6 +84,7 @@ private void initializeSymbols() { Location internalLoc = Location.INTERNALLY_DEFINED; symbolMap.put("inst_start", new StartSymbol(internalLoc, "inst_start", getConstantSpace())); + symbolMap.put("operand_offset", new OffsetSymbol(internalLoc, "operand_offset", getConstantSpace())); symbolMap.put("inst_next", new EndSymbol(internalLoc, "inst_next", getConstantSpace())); symbolMap.put("inst_next2", new Next2Symbol(internalLoc, "inst_next2", getConstantSpace())); symbolMap.put("inst_ref", new FlowRefSymbol(internalLoc, "inst_ref", getConstantSpace())); diff --git a/GhidraDocs/languages/html/sleigh_symbols.html b/GhidraDocs/languages/html/sleigh_symbols.html index 70598b7310e..f5ee18878e0 100644 --- a/GhidraDocs/languages/html/sleigh_symbols.html +++ b/GhidraDocs/languages/html/sleigh_symbols.html @@ -186,6 +186,10 @@ epsilon A special identifier indicating an empty bit pattern. + + operand_offset + Offset of the address of the current operand. Useful for variable-length instructions. + @@ -205,6 +209,9 @@ identifier is inherited from SLED and is a specific symbol equivalent to the constant zero. The instruction identifier is the root instruction table. +operand_offset was introduced to support VAX +variable-length, multi-operand instructions. PC-relative addressing in +VAX is relative to the operand address, not the instruction address.