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>
388 lines
7.2 KiB
C
388 lines
7.2 KiB
C
/*
|
|
* Copyright (c) 2022-present Trail of Bits, Inc.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic fatal "-Wpadded"
|
|
|
|
#include "remill/Arch/Runtime/State.h"
|
|
|
|
#if !defined(INCLUDED_FROM_REMILL)
|
|
# include "remill/Arch/Runtime/Types.h"
|
|
#endif
|
|
|
|
struct Reg final {
|
|
union {
|
|
alignas(4) uint32_t dword;
|
|
alignas(8) uint64_t qword;
|
|
} __attribute__((packed));
|
|
} __attribute__((packed));
|
|
|
|
static_assert(sizeof(uint64_t) == sizeof(Reg), "Invalid packing of `Reg`.");
|
|
static_assert(0 == __builtin_offsetof(Reg, dword),
|
|
"Invalid packing of `Reg::dword`.");
|
|
|
|
static_assert(0 == __builtin_offsetof(Reg, qword),
|
|
"Invalid packing of `Reg::qword`.");
|
|
|
|
// General Purpose Registers
|
|
struct alignas(8) GPR final {
|
|
|
|
// Prevents LLVM from casting a `GPR` into an `i64` to access `r0`.
|
|
volatile uint64_t _0;
|
|
Reg r0;
|
|
volatile uint64_t _1;
|
|
Reg r1;
|
|
volatile uint64_t _2;
|
|
Reg r2;
|
|
volatile uint64_t _3;
|
|
Reg r3;
|
|
volatile uint64_t _4;
|
|
Reg r4;
|
|
volatile uint64_t _5;
|
|
Reg r5;
|
|
volatile uint64_t _6;
|
|
Reg r6;
|
|
volatile uint64_t _7;
|
|
Reg r7;
|
|
volatile uint64_t _8;
|
|
Reg r8;
|
|
volatile uint64_t _9;
|
|
Reg r9;
|
|
volatile uint64_t _10;
|
|
Reg r10;
|
|
volatile uint64_t _11;
|
|
Reg r11;
|
|
volatile uint64_t _12;
|
|
Reg r12;
|
|
volatile uint64_t _13;
|
|
Reg r13;
|
|
volatile uint64_t _14;
|
|
Reg r14;
|
|
volatile uint64_t _15;
|
|
Reg r15;
|
|
volatile uint64_t _16;
|
|
Reg r16;
|
|
volatile uint64_t _17;
|
|
Reg r17;
|
|
volatile uint64_t _18;
|
|
Reg r18;
|
|
volatile uint64_t _19;
|
|
Reg r19;
|
|
volatile uint64_t _20;
|
|
Reg r20;
|
|
volatile uint64_t _21;
|
|
Reg r21;
|
|
volatile uint64_t _22;
|
|
Reg r22;
|
|
volatile uint64_t _23;
|
|
Reg r23;
|
|
volatile uint64_t _24;
|
|
Reg r24;
|
|
volatile uint64_t _25;
|
|
Reg r25;
|
|
volatile uint64_t _26;
|
|
Reg r26;
|
|
volatile uint64_t _27;
|
|
Reg r27;
|
|
volatile uint64_t _28;
|
|
Reg r28;
|
|
volatile uint64_t _29;
|
|
Reg r29;
|
|
volatile uint64_t _30;
|
|
Reg r30;
|
|
volatile uint64_t _31;
|
|
Reg r31;
|
|
|
|
} __attribute__((packed));
|
|
|
|
static_assert(512 == sizeof(GPR), "Invalid structure packing of `GPR`.");
|
|
|
|
// Floating Pointer Registers
|
|
struct alignas(8) FPR final {
|
|
|
|
// Prevents LLVM from casting an `FPR` into an `i64` to access `f0`.
|
|
volatile uint64_t _0;
|
|
Reg f0;
|
|
volatile uint64_t _1;
|
|
Reg f1;
|
|
volatile uint64_t _2;
|
|
Reg f2;
|
|
volatile uint64_t _3;
|
|
Reg f3;
|
|
volatile uint64_t _4;
|
|
Reg f4;
|
|
volatile uint64_t _5;
|
|
Reg f5;
|
|
volatile uint64_t _6;
|
|
Reg f6;
|
|
volatile uint64_t _7;
|
|
Reg f7;
|
|
volatile uint64_t _8;
|
|
Reg f8;
|
|
volatile uint64_t _9;
|
|
Reg f9;
|
|
volatile uint64_t _10;
|
|
Reg f10;
|
|
volatile uint64_t _11;
|
|
Reg f11;
|
|
volatile uint64_t _12;
|
|
Reg f12;
|
|
volatile uint64_t _13;
|
|
Reg f13;
|
|
volatile uint64_t _14;
|
|
Reg f14;
|
|
volatile uint64_t _15;
|
|
Reg f15;
|
|
volatile uint64_t _16;
|
|
Reg f16;
|
|
volatile uint64_t _17;
|
|
Reg f17;
|
|
volatile uint64_t _18;
|
|
Reg f18;
|
|
volatile uint64_t _19;
|
|
Reg f19;
|
|
volatile uint64_t _20;
|
|
Reg f20;
|
|
volatile uint64_t _21;
|
|
Reg f21;
|
|
volatile uint64_t _22;
|
|
Reg f22;
|
|
volatile uint64_t _23;
|
|
Reg f23;
|
|
volatile uint64_t _24;
|
|
Reg f24;
|
|
volatile uint64_t _25;
|
|
Reg f25;
|
|
volatile uint64_t _26;
|
|
Reg f26;
|
|
volatile uint64_t _27;
|
|
Reg f27;
|
|
volatile uint64_t _28;
|
|
Reg f28;
|
|
volatile uint64_t _29;
|
|
Reg f29;
|
|
volatile uint64_t _30;
|
|
Reg f30;
|
|
volatile uint64_t _31;
|
|
Reg f31;
|
|
|
|
} __attribute__((packed));
|
|
|
|
static_assert(512 == sizeof(FPR), "Invalid structure packing of `FPR`.");
|
|
|
|
// These are actually bitflags.
|
|
//
|
|
// Remill's notion of registers operates at a byte granularity so these need to
|
|
// take a full byte.
|
|
struct alignas(8) CRFlags final {
|
|
|
|
volatile uint8_t _0;
|
|
uint8_t cr0;
|
|
volatile uint8_t _1;
|
|
uint8_t cr1;
|
|
volatile uint8_t _2;
|
|
uint8_t cr2;
|
|
volatile uint8_t _3;
|
|
uint8_t cr3;
|
|
volatile uint8_t _4;
|
|
uint8_t cr4;
|
|
volatile uint8_t _5;
|
|
uint8_t cr5;
|
|
volatile uint8_t _6;
|
|
uint8_t cr6;
|
|
volatile uint8_t _7;
|
|
uint8_t cr7;
|
|
|
|
} __attribute__((packed));
|
|
|
|
struct alignas(8) XERFlags final {
|
|
|
|
volatile uint8_t _0;
|
|
uint8_t so;
|
|
volatile uint8_t _1;
|
|
uint8_t ov;
|
|
volatile uint8_t _2;
|
|
uint8_t ca;
|
|
volatile uint8_t _3;
|
|
uint8_t sl;
|
|
// uint8_t _padding[2];
|
|
|
|
} __attribute__((packed));
|
|
|
|
// Instruction-Accessible Registers
|
|
struct alignas(8) IAR final {
|
|
|
|
// Prevents LLVM from casting an `IAR` into an `i64` to access `cr`.
|
|
volatile uint64_t _1;
|
|
Reg cr;
|
|
volatile uint64_t _2;
|
|
Reg ctr;
|
|
volatile uint64_t _3;
|
|
Reg lr;
|
|
volatile uint64_t _4;
|
|
Reg xer;
|
|
volatile uint64_t _5;
|
|
Reg spefscr;
|
|
volatile uint64_t _6;
|
|
Reg acc;
|
|
|
|
} __attribute__((packed));
|
|
|
|
// Read-Only Performance Monitor Registers
|
|
struct alignas(8) UPM final {
|
|
|
|
volatile uint64_t _0;
|
|
Reg gc;
|
|
|
|
// Counter registers
|
|
volatile uint64_t _1;
|
|
Reg c0;
|
|
volatile uint64_t _2;
|
|
Reg c1;
|
|
volatile uint64_t _3;
|
|
Reg c2;
|
|
volatile uint64_t _4;
|
|
Reg c3;
|
|
|
|
// Local control registers
|
|
volatile uint64_t _5;
|
|
Reg lca0;
|
|
volatile uint64_t _6;
|
|
Reg lca1;
|
|
volatile uint64_t _7;
|
|
Reg lca2;
|
|
volatile uint64_t _8;
|
|
Reg lca3;
|
|
volatile uint64_t _9;
|
|
Reg lcb0;
|
|
volatile uint64_t _10;
|
|
Reg lcb1;
|
|
volatile uint64_t _11;
|
|
Reg lcb2;
|
|
volatile uint64_t _12;
|
|
Reg lcb3;
|
|
|
|
} __attribute__((packed));
|
|
|
|
// Time-Based Registers
|
|
struct alignas(8) TBR final {
|
|
|
|
volatile uint64_t _0;
|
|
Reg tbl;
|
|
volatile uint64_t _1;
|
|
Reg tbu;
|
|
volatile uint64_t _2;
|
|
Reg atbl;
|
|
volatile uint64_t _3;
|
|
Reg atbu;
|
|
|
|
} __attribute__((packed));
|
|
|
|
// General Special-Purpose Registers
|
|
struct alignas(8) SPRG final {
|
|
|
|
volatile uint64_t _0;
|
|
Reg r3;
|
|
volatile uint64_t _1;
|
|
Reg r4;
|
|
volatile uint64_t _2;
|
|
Reg r5;
|
|
volatile uint64_t _3;
|
|
Reg r6;
|
|
volatile uint64_t _4;
|
|
Reg r7;
|
|
|
|
} __attribute__((packed));
|
|
|
|
// L1 Cache Configuration
|
|
struct alignas(8) L1CFG final {
|
|
|
|
volatile uint64_t _0;
|
|
Reg r0;
|
|
volatile uint64_t _1;
|
|
Reg r1;
|
|
|
|
} __attribute__((packed));
|
|
|
|
// Signals
|
|
//
|
|
// These are signals that are commonly found on PPC devices
|
|
// They are implemented as registers here as Sleigh treats them that way
|
|
struct alignas(8) Signals final {
|
|
volatile uint64_t _0;
|
|
Reg tea; // Transfer Error Acknowledge
|
|
uint8_t _padding[8];
|
|
};
|
|
|
|
struct alignas(8) PPCState : public ArchState {
|
|
|
|
GPR gpr; // 528 bytes.
|
|
|
|
uint64_t _0;
|
|
|
|
FPR fpr;
|
|
|
|
uint64_t _1;
|
|
|
|
IAR iar;
|
|
|
|
uint64_t _2;
|
|
|
|
UPM upm;
|
|
|
|
uint64_t _3;
|
|
|
|
TBR tbr;
|
|
|
|
uint64_t _4;
|
|
|
|
Reg uspr; // User Special-Purpose Register
|
|
|
|
uint64_t _5;
|
|
|
|
SPRG sprg;
|
|
|
|
uint64_t _6;
|
|
|
|
L1CFG l1cfg;
|
|
|
|
uint64_t _7;
|
|
|
|
Reg pc; // This isn't exposed via PPC's API however Sleigh uses a "fake" register to maintain the program counter
|
|
|
|
uint64_t _8;
|
|
|
|
XERFlags xer_flags;
|
|
|
|
uint64_t _9;
|
|
|
|
CRFlags cr_flags;
|
|
|
|
uint64_t _10;
|
|
|
|
Signals signals;
|
|
|
|
} __attribute__((packed));
|
|
|
|
// static_assert((1152 + 16) == sizeof(PPCState),
|
|
// "Invalid packing of `struct State`");
|
|
|
|
struct State : public PPCState {};
|
|
|
|
#pragma clang diagnostic pop
|