fold/third_party/ghidra-decompiler/cpp/slghpattern.hh
trvon 5152d0c9f7
feat(binary): vendor Ghidra 12.1 decompiler + validate P-Code lifting (Phase 0-1)
Foundation for replacing fold's dead/abstract binary encoder with a real
SSA P-Code frontend. Verified root-cause gap: serializeBinaryIR() emits only
data-discovery nodes (sections/strings/imports/exports); the control-flow
BinaryExprKind values (BasicBlock/CallSite/...) are never constructed, so the
Z3-BB encoder's encodable filter is always empty and encodeBinaryBBs never
runs — hence 0 binary Z3 findings. The P-Code pipeline supersedes that path.

Phase 0 — docs/internal/ghidra-pcode-integration-research.md: P-Code opcode
core, the decompiler C++ embedding API (LoadImage/SleighArchitecture/Funcdata),
the CORE+DECCORE+SLEIGH source sets, no-bison finding, and pypcode as build
reference.

Phase 1 — vendored Ghidra decompiler at pinned commit (Ghidra_12.1_build,
7e89d94e34...) under third_party/ghidra-decompiler/ (cpp + AArch64 specs +
Apache-2.0 LICENSE + VENDOR.md + .gitignore for build artifacts). Validated by
hand on this clang-21/macOS toolchain:
  - full SSA engine (CORE+DECCORE+SLEIGH, 80 files incl. heritage/funcdata/
    action) compiles clean, -std=c++11 -O2, NO BFD, NO bison (generated
    parsers are committed upstream; ruleparse isn't in the lib set);
  - sleigh compiler builds; AArch64 .slaspec -> .sla compiles;
  - tools/pcode_dump.cpp (custom LoadImage, no BFD) lifts the real arm64
    sym._div_by_zero_direct to correct P-Code: `mov w9,#0 -> COPY(const 0)`,
    `sdiv -> INT_SDIV(w8,w9)` — divisor zero-ness explicit in the data flow,
    so the Phase-3 encoder proves div-by-zero trivially, multi-arch.

Not yet meson-wired (next step) and no fold-side IR/encoder yet (Phase 2-3);
this commit is the validated vendor + smoke tool.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 17:32:47 -04:00

174 lines
7.9 KiB
C++

/* ###
* 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.
*/
#ifndef __SLGHPATTERN_HH__
#define __SLGHPATTERN_HH__
#include "context.hh"
namespace ghidra {
// A mask/value pair viewed as two bitstreams
class PatternBlock {
int4 offset; // Offset to non-zero byte of mask
int4 nonzerosize; // Last byte(+1) containing nonzero mask
vector<uintm> maskvec; // Mask
vector<uintm> valvec; // Value
void normalize(void);
public:
PatternBlock(int4 off,uintm msk,uintm val);
PatternBlock(bool tf);
PatternBlock(const PatternBlock *a,const PatternBlock *b);
PatternBlock(vector<PatternBlock *> &list);
PatternBlock *commonSubPattern(const PatternBlock *b) const;
PatternBlock *intersect(const PatternBlock *b) const;
bool specializes(const PatternBlock *op2) const;
bool identical(const PatternBlock *op2) const;
PatternBlock *clone(void) const;
void shift(int4 sa) { offset += sa; normalize(); }
int4 getLength(void) const { return offset+nonzerosize; }
uintm getMask(int4 startbit,int4 size) const;
uintm getValue(int4 startbit,int4 size) const;
bool alwaysTrue(void) const { return (nonzerosize==0); }
bool alwaysFalse(void) const { return (nonzerosize==-1); }
bool isInstructionMatch(ParserWalker &walker) const;
bool isContextMatch(ParserWalker &walker) const;
void encode(Encoder &encoder) const;
void decode(Decoder &decoder);
};
class DisjointPattern;
class Pattern {
public:
virtual ~Pattern(void) {}
virtual Pattern *simplifyClone(void) const=0;
virtual void shiftInstruction(int4 sa)=0;
virtual Pattern *doOr(const Pattern *b,int4 sa) const=0;
virtual Pattern *doAnd(const Pattern *b,int4 sa) const=0;
virtual Pattern *commonSubPattern(const Pattern *b,int4 sa) const=0;
virtual bool isMatch(ParserWalker &walker) const=0; // Does this pattern match context
virtual int4 numDisjoint(void) const=0;
virtual DisjointPattern *getDisjoint(int4 i) const=0;
virtual bool alwaysTrue(void) const=0;
virtual bool alwaysFalse(void) const=0;
virtual bool alwaysInstructionTrue(void) const=0;
virtual void encode(Encoder &encoder) const=0;
virtual void decode(Decoder &decoder)=0;
};
class DisjointPattern : public Pattern { // A pattern with no ORs in it
virtual PatternBlock *getBlock(bool context) const=0;
public:
virtual int4 numDisjoint(void) const { return 0; }
virtual DisjointPattern *getDisjoint(int4 i) const { return (DisjointPattern *)0; }
uintm getMask(int4 startbit,int4 size,bool context) const;
uintm getValue(int4 startbit,int4 size,bool context) const;
int4 getLength(bool context) const;
bool specializes(const DisjointPattern *op2) const;
bool identical(const DisjointPattern *op2) const;
bool resolvesIntersect(const DisjointPattern *op1,const DisjointPattern *op2) const;
static DisjointPattern *decodeDisjoint(Decoder &decoder);
};
class InstructionPattern : public DisjointPattern { // Matches the instruction bitstream
PatternBlock *maskvalue;
virtual PatternBlock *getBlock(bool context) const { return context ? (PatternBlock *)0 : maskvalue; }
public:
InstructionPattern(void) { maskvalue = (PatternBlock *)0; } // For use with decode
InstructionPattern(PatternBlock *mv) { maskvalue = mv; }
InstructionPattern(bool tf) { maskvalue = new PatternBlock(tf); }
PatternBlock *getBlock(void) { return maskvalue; }
virtual ~InstructionPattern(void) { if (maskvalue != (PatternBlock *)0) delete maskvalue; }
virtual Pattern *simplifyClone(void) const { return new InstructionPattern(maskvalue->clone()); }
virtual void shiftInstruction(int4 sa) { maskvalue->shift(sa); }
virtual Pattern *doOr(const Pattern *b,int4 sa) const;
virtual Pattern *doAnd(const Pattern *b,int4 sa) const;
virtual Pattern *commonSubPattern(const Pattern *b,int4 sa) const;
virtual bool isMatch(ParserWalker &walker) const { return maskvalue->isInstructionMatch(walker); }
virtual bool alwaysTrue(void) const { return maskvalue->alwaysTrue(); }
virtual bool alwaysFalse(void) const { return maskvalue->alwaysFalse(); }
virtual bool alwaysInstructionTrue(void) const { return maskvalue->alwaysTrue(); }
virtual void encode(Encoder &encoder) const;
virtual void decode(Decoder &decoder);
};
class ContextPattern : public DisjointPattern { // Matches the context bitstream
PatternBlock *maskvalue;
virtual PatternBlock *getBlock(bool context) const { return context ? maskvalue : (PatternBlock *)0; }
public:
ContextPattern(void) { maskvalue = (PatternBlock *)0; } // For use with decode
ContextPattern(PatternBlock *mv) { maskvalue = mv; }
PatternBlock *getBlock(void) { return maskvalue; }
virtual ~ContextPattern(void) { if (maskvalue != (PatternBlock *)0) delete maskvalue; }
virtual Pattern *simplifyClone(void) const { return new ContextPattern(maskvalue->clone()); }
virtual void shiftInstruction(int4 sa) { } // do nothing
virtual Pattern *doOr(const Pattern *b,int4 sa) const;
virtual Pattern *doAnd(const Pattern *b,int4 sa) const;
virtual Pattern *commonSubPattern(const Pattern *b,int4 sa) const;
virtual bool isMatch(ParserWalker &walker) const { return maskvalue->isContextMatch(walker); }
virtual bool alwaysTrue(void) const { return maskvalue->alwaysTrue(); }
virtual bool alwaysFalse(void) const { return maskvalue->alwaysFalse(); }
virtual bool alwaysInstructionTrue(void) const { return true; }
virtual void encode(Encoder &encoder) const;
virtual void decode(Decoder &decoder);
};
// A pattern with a context piece and an instruction piece
class CombinePattern : public DisjointPattern {
ContextPattern *context; // Context piece
InstructionPattern *instr; // Instruction piece
virtual PatternBlock *getBlock(bool cont) const { return cont ? context->getBlock() : instr->getBlock(); }
public:
CombinePattern(void) { context = (ContextPattern *)0; instr = (InstructionPattern *)0; }
CombinePattern(ContextPattern *con,InstructionPattern *in) {
context = con; instr = in; }
virtual ~CombinePattern(void);
virtual Pattern *simplifyClone(void) const;
virtual void shiftInstruction(int4 sa) { instr->shiftInstruction(sa); }
virtual bool isMatch(ParserWalker &walker) const;
virtual bool alwaysTrue(void) const;
virtual bool alwaysFalse(void) const;
virtual bool alwaysInstructionTrue(void) const { return instr->alwaysInstructionTrue(); }
virtual Pattern *doOr(const Pattern *b,int4 sa) const;
virtual Pattern *doAnd(const Pattern *b,int4 sa) const;
virtual Pattern *commonSubPattern(const Pattern *b,int4 sa) const;
virtual void encode(Encoder &encoder) const;
virtual void decode(Decoder &decoder);
};
class OrPattern : public Pattern {
vector<DisjointPattern *> orlist;
public:
OrPattern(void) {} // For use with decode
OrPattern(DisjointPattern *a,DisjointPattern *b);
OrPattern(const vector<DisjointPattern *> &list);
virtual ~OrPattern(void);
virtual Pattern *simplifyClone(void) const;
virtual void shiftInstruction(int4 sa);
virtual bool isMatch(ParserWalker &walker) const;
virtual int4 numDisjoint(void) const { return orlist.size(); }
virtual DisjointPattern *getDisjoint(int4 i) const { return orlist[i]; }
virtual bool alwaysTrue(void) const;
virtual bool alwaysFalse(void) const;
virtual bool alwaysInstructionTrue(void) const;
virtual Pattern *doOr(const Pattern *b,int4 sa) const;
virtual Pattern *doAnd(const Pattern *b,int4 sa) const;
virtual Pattern *commonSubPattern(const Pattern *b,int4 sa) const;
virtual void encode(Encoder &encoder) const;
virtual void decode(Decoder &decoder);
};
} // End namespace ghidra
#endif