mirror of
https://github.com/lifting-bits/remill
synced 2026-06-21 13:56:07 +00:00
fb018c96e9
* Add skeleton for PPC
* Copyright notices
* Fill in some details for the PPC arch
* Start building a (wrong) PPC runtime
* Begin populating state structure
* First pass for EIS state structure
* Map registers to Sleigh register names
* More fixes
* add optional param
* Create handle unsupported and invalid instruction isels
* Correct typo
* Get a basic `remill-lift` invocation running without failure
* Fix capitalisation
* Set vle context reg
* Fix SleighDecoder signatures
* Set VLE context register in the Sleigh engine in addition to our
internal context reg mapping
* Capitalize reg names
* Add the flag registers for XER and CR
* Rename bitflag structures in PPC state
* PPC Sleigh patches (#643)
* Modified sleigh patch script to generate patches for multiple .sinc files
* update README with new examples of sleigh patch script invocation
* add ppc register definition
* add ppc sleigh patches
* fix issue with remill_insn_size definition
* regenerate sleigh patches for PPC
* update CMakeLists.txt to include PPC patches
* Add TEA signal as a register in the PPC state
* Uppercase the stack pointer register name
* Fix PPC instruction sizes
* initial PPC tests
* remove duplicate tests
* fix tests for e_stmvgprw/e_ldmvgprw
* add tests for loading/storing from special registers
* add tests with internal conditionals in pcode
* fix for pc reg and addr width not being the same... I suspect this issue is going to come up elsewhere
* add heuristic for flow from normal intrainstruction flow
* rework tests to allow testing for different sized registers
* add tests for overflow and record add
* fix bug with log printout
* add intrafunction control flow lifting
* handle edge case where there is no pcode op at the zero index
* Fix another inconsistency with mismatching address and PC reg size
* Allocate unique ptrs in the entry block
* Fix `INT_LEFT` and `INT_RIGHT` impl where shift exceeds bit width
* fix supiece lift?
* Add PPC emulate instruction to hyper call
* fix for pc reg and addr width not being the same... I suspect this issue is going to come up elsewhere
* add heuristic for flow from normal intrainstruction flow
* add intrafunction control flow lifting
* handle edge case where there is no pcode op at the zero index
* Fix another inconsistency with mismatching address and PC reg size
* fix supiece lift?
* Allocate unique ptrs in the entry block
* Fix `INT_LEFT` and `INT_RIGHT` impl where shift exceeds bit width
* fix int2float semantics
should use appropriate sized float based on the output size
* add tests for lifting int2float
* fix INT_{LEFT,RIGHT} semantics
should be `ICmpSGE` instead of `ICmpSGT`
* add cr0-7 registers
* fix formatting
* fix conditional branch test
* add test for compare
* re-enable rotate left word immediate and mask test
* genericize TestSpecOutput
* explicit instruction data size
* add test for syscall/callother (disabled)
* add tests for store/load word
* add test to convert from float to int
* specify intrinsic arg type, fixes null deref
* Add PPC emulate instruction to hyper call
* add headers + formatting
* remove old comment
* Map CRALL register
* Add basic LLVM data layout that specifies 32-bit addresses
* Remove unused variables
* convert auto* to auto when possible
* RegisterPrecondition -> RegisterCondition
* fix variable name
* convert any to variant
* use std::move
* bump to c++20, use concepts
* set arch in constructor since class isn't generic anyways
* formatting
* make type aliases
* bump cxx-common
* add comment
* clang format
* throw exception if register not found
* use const ref
* use shorthand for lambda capture values
* Add more detail to data layout to include proper stack alignment
* Compare to the correct size for SUBPIECE impl
* Add Sleigh message to error
* throw exception in else case
* throw runtime error if register value has incorrect type
* use reference instead of value
* get rid of unnecessary type alias
* formatting
* Propagate VLE context reg value into Sleigh
* Remove unnecessary whitespace
* Remove stale TODO and NOTE comments
* add additional parameter to test runner to specify decoding context
* drop llvm 14, bump macos version
* bump cxx-common, fix ci.yml mac build
* add test for unconditional relative negative branch
* add missing space to pcode debug log
* fix bug due to unordered_map, iteration order matters
* add error log in case we aren't able to adjust PC value
* use helper for getting register reference
* Revert "add optional param"
This reverts commit 51ed49f8cf.
* Remove remaining LLVM 14 compatibility code and configuration
* Add padding between CR and XER flags
* Use `enum class`
* Remove void cast
* Remove unnecessary variable
* Use initialiser lists where appropriate
* Remove redundant `else`
* Prefer `CHECK` over `assert`
* Polish PowerPC function initialisation with lambda
* zero out xer_so to fix tests
* log error when we see claim_eq with no usages
* Collapse namespace blocks
* Remove unnecessary `this->`
* Use `auto` where appropriate
* Remove unnecessary `else`
* Use `emplace` over `insert` for `std::map`
Co-authored-by: lkorenc <lukas.korencik@trailofbits.com>
* Use `constexpr` for VLE reg name
* Use module verification util
* Add `VerifyFunction` util and use where applicable
* Extract lambda to improve readability of flow categorisation
* Use type alias for context values
* Introduce type alias for block exit
* Create type alias for optional branch taken
* Refactor `PcodeCFGBuilder`
* Use lambda to avoid conditional mutation
* Extract duplicated bit-shift code generation into helper
* Simplify flow with ternary
* Add `GetBlock` helper
* Rename variables
* Move statement for clarity
* Create helpers for working with Sleigh context register values
* Convert loop to `std::copy`
* Add a comment explaining the use of set to de-duplicate and sort
* Refactor `IntraProcTransferCollector`
* Expose static method to easily use `IntraProcTransferCollector`
* Rename PPC related variables to include address width
* add docs to intrainstructionindex
* remove llvm 14 ifdefs
* don't log error if no claim_eqs were used
* update comments
* Cleanup exit visitors
---------
Co-authored-by: 2over12 <ian.smith@trailofbits.com>
Co-authored-by: William Tan <1284324+Ninja3047@users.noreply.github.com>
Co-authored-by: lkorenc <lukas.korencik@trailofbits.com>
164 lines
4.3 KiB
C++
164 lines
4.3 KiB
C++
#include <remill/BC/PCodeCFG.h>
|
|
|
|
#include <algorithm>
|
|
#include <cstddef>
|
|
#include <map>
|
|
#include <sleigh/op.hh>
|
|
#include <sleigh/opcodes.hh>
|
|
#include <sleigh/pcoderaw.hh>
|
|
#include <variant>
|
|
#include <vector>
|
|
|
|
#include "lib/Arch/Sleigh/ControlFlowStructuring.h"
|
|
|
|
namespace remill {
|
|
namespace sleigh {
|
|
|
|
PcodeCFG CreateCFG(const std::vector<RemillPcodeOp> &linear_ops) {
|
|
return PcodeCFGBuilder(linear_ops).Build();
|
|
}
|
|
|
|
|
|
std::vector<size_t> PcodeCFGBuilder::GetBlockStarts() const {
|
|
std::vector<size_t> res = {0};
|
|
|
|
for (size_t curr_index = 0; curr_index < linear_ops.size(); curr_index += 1) {
|
|
auto interproc = GetIntraProcTargets(curr_index);
|
|
res.insert(res.end(), interproc.begin(), interproc.end());
|
|
}
|
|
return res;
|
|
}
|
|
|
|
PcodeBlock PcodeCFGBuilder::BuildBlock(size_t start_ind,
|
|
size_t next_start) const {
|
|
std::vector<RemillPcodeOp> ops;
|
|
|
|
std::copy(linear_ops.begin() + start_ind, linear_ops.begin() + next_start,
|
|
std::back_inserter(ops));
|
|
|
|
return PcodeBlock(start_ind, std::move(ops),
|
|
GetBlockExitsForIndex(next_start - 1));
|
|
}
|
|
|
|
|
|
namespace {
|
|
struct IntraProcTransferCollector {
|
|
|
|
static std::vector<size_t> CollectIntraProcTransfers(const BlockExit &exit) {
|
|
IntraProcTransferCollector collector;
|
|
std::visit(collector, exit);
|
|
return collector.targets;
|
|
}
|
|
|
|
std::vector<size_t> targets;
|
|
|
|
void operator()(const IntrainstructionIndex &ex) {
|
|
targets.push_back(ex.target_block_index);
|
|
}
|
|
|
|
void operator()(const Exit &ex) {
|
|
std::visit(*this, ex);
|
|
}
|
|
|
|
void operator()(const ConditionalExit &ex) {
|
|
std::visit(*this, ex.true_branch);
|
|
std::visit(*this, ex.false_branch);
|
|
}
|
|
};
|
|
} // namespace
|
|
|
|
std::vector<size_t> PcodeCFGBuilder::GetIntraProcTargets(size_t index) const {
|
|
auto ex = GetBlockExitsForIndex(index);
|
|
return IntraProcTransferCollector::CollectIntraProcTransfers(ex);
|
|
}
|
|
|
|
BlockExit PcodeCFGBuilder::GetBlockExitsForIndex(size_t index) const {
|
|
CHECK(index < linear_ops.size());
|
|
const auto &curr_op = linear_ops[index];
|
|
|
|
auto build_direct_target_exit = [](VarnodeData target,
|
|
size_t curr_ind) -> Exit {
|
|
if (isVarnodeInConstantSpace(target)) {
|
|
// need to treat as signed?
|
|
return IntrainstructionIndex{curr_ind + target.offset};
|
|
}
|
|
return InstrExit{};
|
|
};
|
|
switch (curr_op.op) {
|
|
case CPUI_BRANCH:
|
|
case CPUI_CALL: {
|
|
return Exit{build_direct_target_exit(curr_op.vars[0], index)};
|
|
}
|
|
case CPUI_CBRANCH: {
|
|
|
|
auto fallthrough_exit = [this, index]() -> Exit {
|
|
// if we are not the last pcodeop then we have an intraproc fallthrough
|
|
if (index < linear_ops.size() - 1) {
|
|
return IntrainstructionIndex{index + 1};
|
|
}
|
|
return InstrExit{};
|
|
}();
|
|
|
|
auto taken_exit = build_direct_target_exit(curr_op.vars[0], index);
|
|
|
|
return ConditionalExit{taken_exit, fallthrough_exit};
|
|
}
|
|
case CPUI_CALLIND:
|
|
case CPUI_BRANCHIND: {
|
|
return Exit{InstrExit{}};
|
|
}
|
|
|
|
default: {
|
|
return Exit{InstrExit{}};
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
PcodeBlock::PcodeBlock(size_t base_index)
|
|
: base_index(base_index),
|
|
ops(),
|
|
block_exit(Exit{InstrExit{}}) {}
|
|
|
|
PcodeCFG PcodeCFGBuilder::Build() const {
|
|
|
|
auto starts = GetBlockStarts();
|
|
|
|
// De-duplicate and sort the block starts. We want to iterate in order.
|
|
std::set s(starts.begin(), starts.end());
|
|
starts.assign(s.begin(), s.end());
|
|
|
|
std::map<size_t, PcodeBlock> blocks;
|
|
|
|
if (linear_ops.empty()) {
|
|
// There is no insturction at 0 to build a block at
|
|
// build an empty block so we transfer through to exit by terminating the block
|
|
blocks.emplace(0, PcodeBlock(0));
|
|
return blocks;
|
|
}
|
|
|
|
for (size_t i = 0; i < starts.size(); i++) {
|
|
auto next_start =
|
|
(i + 1) < starts.size() ? starts[i + 1] : linear_ops.size();
|
|
blocks.emplace(starts[i], BuildBlock(starts[i], next_start));
|
|
}
|
|
|
|
return PcodeCFG(blocks);
|
|
}
|
|
|
|
|
|
PcodeCFGBuilder::PcodeCFGBuilder(const std::vector<RemillPcodeOp> &linear_ops)
|
|
: linear_ops(linear_ops) {}
|
|
|
|
PcodeCFG::PcodeCFG(std::map<size_t, PcodeBlock> blocks)
|
|
: blocks(std::move(blocks)) {}
|
|
|
|
PcodeBlock::PcodeBlock(size_t base_index, std::vector<RemillPcodeOp> ops,
|
|
BlockExit block_exit)
|
|
: base_index(base_index),
|
|
ops(std::move(ops)),
|
|
block_exit(std::move(block_exit)) {}
|
|
|
|
} // namespace sleigh
|
|
} // namespace remill
|