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>
258 lines
13 KiB
C++
258 lines
13 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.
|
|
*/
|
|
#include "slaformat.hh"
|
|
|
|
namespace ghidra {
|
|
namespace sla {
|
|
const int4 FORMAT_SCOPE = 1;
|
|
const int4 FORMAT_VERSION = 4;
|
|
|
|
// ATTRIB_CONTEXT = 1 is reserved
|
|
AttributeId ATTRIB_VAL = AttributeId("val", 2, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_ID = AttributeId("id", 3, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_SPACE = AttributeId("space", 4, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_S = AttributeId("s", 5, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_OFF = AttributeId("off", 6, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_CODE = AttributeId("code", 7, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_MASK = AttributeId("mask", 8, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_INDEX = AttributeId("index", 9, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_NONZERO = AttributeId("nonzero", 10, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_PIECE = AttributeId("piece", 11, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_NAME = AttributeId("name", 12, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_SCOPE = AttributeId("scope", 13, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_STARTBIT = AttributeId("startbit", 14, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_SIZE = AttributeId("size", 15, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_TABLE = AttributeId("table", 16, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_CT = AttributeId("ct", 17, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_MINLEN = AttributeId("minlen", 18, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_BASE = AttributeId("base", 19, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_NUMBER = AttributeId("number", 20, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_CONTEXT = AttributeId("context", 21, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_PARENT = AttributeId("parent", 22, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_SUBSYM = AttributeId("subsym", 23, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_LINE = AttributeId("line", 24, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_SOURCE = AttributeId("source", 25, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_LENGTH = AttributeId("length", 26, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_FIRST = AttributeId("first", 27, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_PLUS = AttributeId("plus", 28, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_SHIFT = AttributeId("shift", 29, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_ENDBIT = AttributeId("endbit", 30, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_SIGNBIT = AttributeId("signbit", 31, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_ENDBYTE = AttributeId("endbyte", 32, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_STARTBYTE = AttributeId("startbyte", 33, FORMAT_SCOPE);
|
|
|
|
AttributeId ATTRIB_VERSION = AttributeId("version", 34, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_BIGENDIAN = AttributeId("bigendian", 35, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_ALIGN = AttributeId("align", 36, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_UNIQBASE = AttributeId("uniqbase", 37, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_MAXDELAY = AttributeId("maxdelay", 38, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_UNIQMASK = AttributeId("uniqmask", 39, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_NUMSECTIONS = AttributeId("numsections", 40, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_DEFAULTSPACE = AttributeId("defaultspace", 41, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_DELAY = AttributeId("delay", 42, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_WORDSIZE = AttributeId("wordsize", 43, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_PHYSICAL = AttributeId("physical", 44, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_SCOPESIZE = AttributeId("scopesize", 45, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_SYMBOLSIZE = AttributeId("symbolsize", 46, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_VARNODE = AttributeId("varnode", 47, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_LOW = AttributeId("low", 48, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_HIGH = AttributeId("high", 49, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_FLOW = AttributeId("flow", 50, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_CONTAIN = AttributeId("contain", 51, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_I = AttributeId("i", 52, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_NUMCT = AttributeId("numct", 53, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_SECTION = AttributeId("section", 54, FORMAT_SCOPE);
|
|
AttributeId ATTRIB_LABELS = AttributeId("labels", 55, FORMAT_SCOPE);
|
|
|
|
ElementId ELEM_CONST_REAL = ElementId("const_real", 1, FORMAT_SCOPE);
|
|
ElementId ELEM_VARNODE_TPL = ElementId("varnode_tpl", 2, FORMAT_SCOPE);
|
|
ElementId ELEM_CONST_SPACEID = ElementId("const_spaceid", 3, FORMAT_SCOPE);
|
|
ElementId ELEM_CONST_HANDLE = ElementId("const_handle", 4, FORMAT_SCOPE);
|
|
ElementId ELEM_OP_TPL = ElementId("op_tpl", 5, FORMAT_SCOPE);
|
|
ElementId ELEM_MASK_WORD = ElementId("mask_word", 6, FORMAT_SCOPE);
|
|
ElementId ELEM_PAT_BLOCK = ElementId("pat_block", 7, FORMAT_SCOPE);
|
|
ElementId ELEM_PRINT = ElementId("print", 8, FORMAT_SCOPE);
|
|
ElementId ELEM_PAIR = ElementId("pair", 9, FORMAT_SCOPE);
|
|
ElementId ELEM_CONTEXT_PAT = ElementId("context_pat", 10, FORMAT_SCOPE);
|
|
ElementId ELEM_NULL = ElementId("null", 11, FORMAT_SCOPE);
|
|
ElementId ELEM_OPERAND_EXP = ElementId("operand_exp", 12, FORMAT_SCOPE);
|
|
ElementId ELEM_OPERAND_SYM = ElementId("operand_sym", 13, FORMAT_SCOPE);
|
|
ElementId ELEM_OPERAND_SYM_HEAD = ElementId("operand_sym_head", 14, FORMAT_SCOPE);
|
|
ElementId ELEM_OPER = ElementId("oper", 15, FORMAT_SCOPE);
|
|
ElementId ELEM_DECISION = ElementId("decision", 16, FORMAT_SCOPE);
|
|
ElementId ELEM_OPPRINT = ElementId("opprint", 17, FORMAT_SCOPE);
|
|
ElementId ELEM_INSTRUCT_PAT = ElementId("instruct_pat", 18, FORMAT_SCOPE);
|
|
ElementId ELEM_COMBINE_PAT = ElementId("combine_pat", 19, FORMAT_SCOPE);
|
|
ElementId ELEM_CONSTRUCTOR = ElementId("constructor", 20, FORMAT_SCOPE);
|
|
ElementId ELEM_CONSTRUCT_TPL = ElementId("construct_tpl", 21, FORMAT_SCOPE);
|
|
ElementId ELEM_SCOPE = ElementId("scope", 22, FORMAT_SCOPE);
|
|
ElementId ELEM_VARNODE_SYM = ElementId("varnode_sym", 23, FORMAT_SCOPE);
|
|
ElementId ELEM_VARNODE_SYM_HEAD = ElementId("varnode_sym_head", 24, FORMAT_SCOPE);
|
|
ElementId ELEM_USEROP = ElementId("userop", 25, FORMAT_SCOPE);
|
|
ElementId ELEM_USEROP_HEAD = ElementId("userop_head", 26, FORMAT_SCOPE);
|
|
ElementId ELEM_TOKENFIELD = ElementId("tokenfield", 27, FORMAT_SCOPE);
|
|
ElementId ELEM_VAR = ElementId("var", 28, FORMAT_SCOPE);
|
|
ElementId ELEM_CONTEXTFIELD = ElementId("contextfield", 29, FORMAT_SCOPE);
|
|
ElementId ELEM_HANDLE_TPL = ElementId("handle_tpl", 30, FORMAT_SCOPE);
|
|
ElementId ELEM_CONST_RELATIVE = ElementId("const_relative", 31, FORMAT_SCOPE);
|
|
ElementId ELEM_CONTEXT_OP = ElementId("context_op", 32, FORMAT_SCOPE);
|
|
|
|
ElementId ELEM_SLEIGH = ElementId("sleigh", 33, FORMAT_SCOPE);
|
|
ElementId ELEM_SPACES = ElementId("spaces", 34, FORMAT_SCOPE);
|
|
ElementId ELEM_SOURCEFILES = ElementId("sourcefiles", 35, FORMAT_SCOPE);
|
|
ElementId ELEM_SOURCEFILE = ElementId("sourcefile", 36, FORMAT_SCOPE);
|
|
ElementId ELEM_SPACE = ElementId("space", 37, FORMAT_SCOPE);
|
|
ElementId ELEM_SYMBOL_TABLE = ElementId("symbol_table", 38, FORMAT_SCOPE);
|
|
ElementId ELEM_VALUE_SYM = ElementId("value_sym", 39, FORMAT_SCOPE);
|
|
ElementId ELEM_VALUE_SYM_HEAD = ElementId("value_sym_head", 40, FORMAT_SCOPE);
|
|
ElementId ELEM_CONTEXT_SYM = ElementId("context_sym", 41, FORMAT_SCOPE);
|
|
ElementId ELEM_CONTEXT_SYM_HEAD = ElementId("context_sym_head", 42, FORMAT_SCOPE);
|
|
ElementId ELEM_END_SYM = ElementId("end_sym", 43, FORMAT_SCOPE);
|
|
ElementId ELEM_END_SYM_HEAD = ElementId("end_sym_head", 44, FORMAT_SCOPE);
|
|
ElementId ELEM_SPACE_OTHER = ElementId("space_other", 45, FORMAT_SCOPE);
|
|
ElementId ELEM_SPACE_UNIQUE = ElementId("space_unique", 46, FORMAT_SCOPE);
|
|
ElementId ELEM_AND_EXP = ElementId("and_exp", 47, FORMAT_SCOPE);
|
|
ElementId ELEM_DIV_EXP = ElementId("div_exp", 48, FORMAT_SCOPE);
|
|
ElementId ELEM_LSHIFT_EXP = ElementId("lshift_exp", 49, FORMAT_SCOPE);
|
|
ElementId ELEM_MINUS_EXP = ElementId("minus_exp", 50, FORMAT_SCOPE);
|
|
ElementId ELEM_MULT_EXP = ElementId("mult_exp", 51, FORMAT_SCOPE);
|
|
ElementId ELEM_NOT_EXP = ElementId("not_exp", 52, FORMAT_SCOPE);
|
|
ElementId ELEM_OR_EXP = ElementId("or_exp", 53, FORMAT_SCOPE);
|
|
ElementId ELEM_PLUS_EXP = ElementId("plus_exp", 54, FORMAT_SCOPE);
|
|
ElementId ELEM_RSHIFT_EXP = ElementId("rshift_exp", 55, FORMAT_SCOPE);
|
|
ElementId ELEM_SUB_EXP = ElementId("sub_exp", 56, FORMAT_SCOPE);
|
|
ElementId ELEM_XOR_EXP = ElementId("xor_exp", 57, FORMAT_SCOPE);
|
|
ElementId ELEM_INTB = ElementId("intb", 58, FORMAT_SCOPE);
|
|
ElementId ELEM_END_EXP = ElementId("end_exp", 59, FORMAT_SCOPE);
|
|
ElementId ELEM_NEXT2_EXP = ElementId("next2_exp", 60, FORMAT_SCOPE);
|
|
ElementId ELEM_START_EXP = ElementId("start_exp", 61, FORMAT_SCOPE);
|
|
ElementId ELEM_EPSILON_SYM = ElementId("epsilon_sym", 62, FORMAT_SCOPE);
|
|
ElementId ELEM_EPSILON_SYM_HEAD = ElementId("epsilon_sym_head", 63, FORMAT_SCOPE);
|
|
ElementId ELEM_NAME_SYM = ElementId("name_sym", 64, FORMAT_SCOPE);
|
|
ElementId ELEM_NAME_SYM_HEAD = ElementId("name_sym_head", 65, FORMAT_SCOPE);
|
|
ElementId ELEM_NAMETAB = ElementId("nametab", 66, FORMAT_SCOPE);
|
|
ElementId ELEM_NEXT2_SYM = ElementId("next2_sym", 67, FORMAT_SCOPE);
|
|
ElementId ELEM_NEXT2_SYM_HEAD = ElementId("next2_sym_head", 68, FORMAT_SCOPE);
|
|
ElementId ELEM_START_SYM = ElementId("start_sym", 69, FORMAT_SCOPE);
|
|
ElementId ELEM_START_SYM_HEAD = ElementId("start_sym_head", 70, FORMAT_SCOPE);
|
|
ElementId ELEM_SUBTABLE_SYM = ElementId("subtable_sym", 71, FORMAT_SCOPE);
|
|
ElementId ELEM_SUBTABLE_SYM_HEAD = ElementId("subtable_sym_head", 72, FORMAT_SCOPE);
|
|
ElementId ELEM_VALUEMAP_SYM = ElementId("valuemap_sym", 73, FORMAT_SCOPE);
|
|
ElementId ELEM_VALUEMAP_SYM_HEAD = ElementId("valuemap_sym_head", 74, FORMAT_SCOPE);
|
|
ElementId ELEM_VALUETAB = ElementId("valuetab", 75, FORMAT_SCOPE);
|
|
ElementId ELEM_VARLIST_SYM = ElementId("varlist_sym", 76, FORMAT_SCOPE);
|
|
ElementId ELEM_VARLIST_SYM_HEAD = ElementId("varlist_sym_head", 77, FORMAT_SCOPE);
|
|
ElementId ELEM_OR_PAT = ElementId("or_pat", 78, FORMAT_SCOPE);
|
|
ElementId ELEM_COMMIT = ElementId("commit", 79, FORMAT_SCOPE);
|
|
ElementId ELEM_CONST_START = ElementId("const_start", 80, FORMAT_SCOPE);
|
|
ElementId ELEM_CONST_NEXT = ElementId("const_next", 81, FORMAT_SCOPE);
|
|
ElementId ELEM_CONST_NEXT2 = ElementId("const_next2", 82, FORMAT_SCOPE);
|
|
ElementId ELEM_CONST_CURSPACE = ElementId("const_curspace", 83, FORMAT_SCOPE);
|
|
ElementId ELEM_CONST_CURSPACE_SIZE = ElementId("const_curspace_size", 84, FORMAT_SCOPE);
|
|
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);
|
|
|
|
/// 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.
|
|
/// \param s is the given stream
|
|
/// \return \b true if a valid header is present
|
|
bool isSlaFormat(istream &s)
|
|
|
|
{
|
|
uint1 header[4];
|
|
s.read((char *)header,4);
|
|
if (!s)
|
|
return false;
|
|
if (header[0] != 's' || header[1] != 'l' || header[2] != 'a')
|
|
return false;
|
|
if (header[3] != FORMAT_VERSION)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
/// A valid header, including the format version number, is written to the stream.
|
|
/// \param s is the given stream
|
|
void writeSlaHeader(ostream &s)
|
|
|
|
{
|
|
char header[4];
|
|
header[0] = 's';
|
|
header[1] = 'l';
|
|
header[2] = 'a';
|
|
header[3] = FORMAT_VERSION;
|
|
s.write(header,4);
|
|
}
|
|
|
|
/// \param s is the backing stream that will receive the final bytes of the .sla file
|
|
/// \param level is the compression level
|
|
FormatEncode::FormatEncode(ostream &s,int4 level)
|
|
: PackedEncode(compStream), compBuffer(s,level), compStream(&compBuffer)
|
|
{
|
|
writeSlaHeader(s);
|
|
}
|
|
|
|
void FormatEncode::flush(void)
|
|
|
|
{
|
|
compStream.flush();
|
|
}
|
|
|
|
const int4 FormatDecode::IN_BUFFER_SIZE = 4096;
|
|
|
|
/// \param spcManager is the (uninitialized) manager that will hold decoded address spaces
|
|
FormatDecode::FormatDecode(const AddrSpaceManager *spcManager)
|
|
: PackedDecode(spcManager)
|
|
{
|
|
inBuffer = new uint1[IN_BUFFER_SIZE];
|
|
}
|
|
|
|
FormatDecode::~FormatDecode(void)
|
|
|
|
{
|
|
delete [] inBuffer;
|
|
}
|
|
|
|
void FormatDecode::ingestStream(istream &s)
|
|
|
|
{
|
|
if (!isSlaFormat(s))
|
|
throw LowlevelError("Missing SLA format header");
|
|
Decompress decompressor;
|
|
uint1 *outBuf;
|
|
int4 outAvail = 0;
|
|
|
|
while(!decompressor.isFinished()) {
|
|
s.read((char *)inBuffer,IN_BUFFER_SIZE);
|
|
int4 gcount = s.gcount();
|
|
if (gcount == 0)
|
|
break;
|
|
decompressor.input(inBuffer,gcount);
|
|
do {
|
|
if (outAvail == 0) {
|
|
outBuf = allocateNextInputBuffer(0);
|
|
outAvail = BUFFER_SIZE;
|
|
}
|
|
outAvail = decompressor.inflate(outBuf + (BUFFER_SIZE - outAvail), outAvail);
|
|
} while(outAvail == 0);
|
|
|
|
}
|
|
endIngest(BUFFER_SIZE - outAvail);
|
|
}
|
|
|
|
} // End sla namespace
|
|
} // End ghidra namespace
|