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>
396 lines
12 KiB
C++
396 lines
12 KiB
C++
/*
|
|
* Copyright (c) 2022 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.
|
|
*/
|
|
|
|
#if defined(__x86_64__)
|
|
# include "remill/Arch/X86/Runtime/State.h"
|
|
# define REMILL_HYPERCALL_AMD64 1
|
|
#elif defined(__i386__) || defined(_M_X86)
|
|
# include "remill/Arch/X86/Runtime/State.h"
|
|
# define REMILL_HYPERCALL_X86 1
|
|
#elif defined(__arm__)
|
|
# include "remill/Arch/AArch32/Runtime/State.h"
|
|
# define REMILL_HYPERCALL_ARM 1
|
|
#elif defined(__aarch64__)
|
|
# include "remill/Arch/AArch64/Runtime/State.h"
|
|
# define REMILL_HYPERCALL_AARCH64 1
|
|
#elif defined(__sparc__)
|
|
# if ADDRESS_SIZE_BITS == 32
|
|
# include "remill/Arch/SPARC32/Runtime/State.h"
|
|
# define REMILL_HYPERCALL_SPARC32 1
|
|
# elif ADDRESS_SIZE_BITS == 64
|
|
# include "remill/Arch/SPARC64/Runtime/State.h"
|
|
# define REMILL_HYPERCALL_SPARC64 1
|
|
# else
|
|
# error "Cannot deduce hyper call SPARC variant"
|
|
# endif
|
|
#elif defined(__PPC__)
|
|
# include "remill/Arch/PPC/Runtime/State.h"
|
|
# define REMILL_HYPERCALL_PPC 1
|
|
#else
|
|
# error "Cannot deduce hyper call architecture"
|
|
#endif
|
|
|
|
#include "remill/Arch/Runtime/Intrinsics.h"
|
|
|
|
Memory *__remill_sync_hyper_call(State &state, Memory *mem,
|
|
SyncHyperCall::Name call) {
|
|
|
|
#if REMILL_HYPERCALL_X86
|
|
register uint32_t esp asm("esp") = state.gpr.rsp.dword;
|
|
register uint32_t ebp asm("ebp") = state.gpr.rbp.dword;
|
|
#elif REMILL_HYPERCALL_AMD64
|
|
register uint64_t rsp asm("rsp") = state.gpr.rsp.qword;
|
|
register uint64_t rbp asm("rbp") = state.gpr.rbp.qword;
|
|
register uint64_t r8 asm("r8") = state.gpr.r8.qword;
|
|
register uint64_t r9 asm("r9") = state.gpr.r9.qword;
|
|
register uint64_t r10 asm("r10") = state.gpr.r10.qword;
|
|
register uint64_t r11 asm("r11") = state.gpr.r11.qword;
|
|
register uint64_t r12 asm("r12") = state.gpr.r12.qword;
|
|
register uint64_t r13 asm("r13") = state.gpr.r13.qword;
|
|
register uint64_t r14 asm("r14") = state.gpr.r14.qword;
|
|
register uint64_t r15 asm("r15") = state.gpr.r15.qword;
|
|
#endif
|
|
|
|
switch (call) {
|
|
|
|
#if REMILL_HYPERCALL_X86 || REMILL_HYPERCALL_AMD64
|
|
|
|
case SyncHyperCall::kX86CPUID:
|
|
asm volatile("cpuid"
|
|
: "=a"(state.gpr.rax.aword), "=b"(state.gpr.rbx.aword),
|
|
"=c"(state.gpr.rcx.aword), "=d"(state.gpr.rdx.aword)
|
|
: "a"(state.gpr.rax.aword), "b"(state.gpr.rbx.aword),
|
|
"c"(state.gpr.rcx.aword), "d"(state.gpr.rdx.aword));
|
|
break;
|
|
|
|
case SyncHyperCall::kX86ReadTSC:
|
|
asm volatile("rdtsc"
|
|
: "=a"(state.gpr.rax.dword), "=d"(state.gpr.rdx.dword));
|
|
break;
|
|
|
|
case SyncHyperCall::kX86ReadTSCP:
|
|
asm volatile("rdtscp"
|
|
: "=a"(state.gpr.rax.aword), "=c"(state.gpr.rcx.aword),
|
|
"=d"(state.gpr.rdx.aword)
|
|
: "a"(state.gpr.rax.aword), "c"(state.gpr.rcx.aword),
|
|
"d"(state.gpr.rdx.aword));
|
|
break;
|
|
|
|
case SyncHyperCall::kX86LoadGlobalDescriptorTable: {
|
|
const auto read =
|
|
__remill_read_memory_64(mem, static_cast<addr_t>(state.addr_to_load));
|
|
struct GdtrRecord {
|
|
uint16_t *length;
|
|
void *base;
|
|
} __attribute__((packed));
|
|
const auto *gdtr = reinterpret_cast<const GdtrRecord *>(&read);
|
|
asm volatile("lgdt %0" : : "m"(gdtr));
|
|
break;
|
|
}
|
|
|
|
case SyncHyperCall::kX86LoadInterruptDescriptorTable: {
|
|
const auto read =
|
|
__remill_read_memory_64(mem, static_cast<addr_t>(state.addr_to_load));
|
|
struct IdtrRecord {
|
|
uint16_t length;
|
|
void *base;
|
|
} __attribute__((packed));
|
|
const auto *idtr = reinterpret_cast<const IdtrRecord *>(&read);
|
|
asm volatile("lidt %0" : : "m"(idtr));
|
|
break;
|
|
}
|
|
|
|
case SyncHyperCall::kX86ReadModelSpecificRegister:
|
|
asm volatile("rdmsr"
|
|
: "=c"(state.gpr.rcx.dword)
|
|
: "a"(state.gpr.rax.dword), "d"(state.gpr.rdx.dword));
|
|
break;
|
|
|
|
case SyncHyperCall::kX86WriteModelSpecificRegister:
|
|
asm volatile("wrmsr"
|
|
: "=c"(state.gpr.rcx.dword)
|
|
: "a"(state.gpr.rax.dword), "d"(state.gpr.rdx.dword));
|
|
break;
|
|
|
|
case SyncHyperCall::kX86WriteBackInvalidate:
|
|
asm volatile("wbinvd" :);
|
|
break;
|
|
|
|
case SyncHyperCall::kX86SetSegmentES:
|
|
mem = __remill_x86_set_segment_es(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kX86SetSegmentSS:
|
|
mem = __remill_x86_set_segment_ss(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kX86SetSegmentDS:
|
|
mem = __remill_x86_set_segment_ds(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kX86SetSegmentFS:
|
|
mem = __remill_x86_set_segment_fs(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kX86SetSegmentGS:
|
|
mem = __remill_x86_set_segment_gs(mem);
|
|
break;
|
|
|
|
# if REMILL_HYPERCALL_X86
|
|
|
|
case SyncHyperCall::kX86SetDebugReg:
|
|
mem = __remill_x86_set_debug_reg(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kX86SetControlReg0:
|
|
mem = __remill_x86_set_control_reg_0(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kX86SetControlReg1:
|
|
mem = __remill_x86_set_control_reg_1(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kX86SetControlReg2:
|
|
mem = __remill_x86_set_control_reg_2(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kX86SetControlReg3:
|
|
mem = __remill_x86_set_control_reg_3(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kX86SetControlReg4:
|
|
mem = __remill_x86_set_control_reg_4(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kX86SysCall:
|
|
asm volatile("syscall"
|
|
: "=a"(state.gpr.rax.dword), "=r"(esp)
|
|
: "a"(state.gpr.rax.dword), "b"(state.gpr.rbx.dword),
|
|
"c"(state.gpr.rcx.dword), "d"(state.gpr.rdx.dword),
|
|
"S"(state.gpr.rsi.dword), "D"(state.gpr.rdi.dword),
|
|
"r"(esp), "r"(ebp));
|
|
break;
|
|
|
|
case SyncHyperCall::kX86SysEnter:
|
|
asm volatile("sysenter"
|
|
: "=a"(state.gpr.rax.dword), "=r"(esp)
|
|
: "a"(state.gpr.rax.dword), "b"(state.gpr.rbx.dword),
|
|
"c"(state.gpr.rcx.dword), "d"(state.gpr.rdx.dword),
|
|
"S"(state.gpr.rsi.dword), "D"(state.gpr.rdi.dword),
|
|
"r"(esp), "r"(ebp));
|
|
break;
|
|
|
|
|
|
case SyncHyperCall::kX86SysExit:
|
|
asm volatile("sysexit"
|
|
: "=a"(state.gpr.rax.dword), "=r"(esp)
|
|
: "a"(state.gpr.rax.dword), "b"(state.gpr.rbx.dword),
|
|
"c"(state.gpr.rcx.dword), "d"(state.gpr.rdx.dword),
|
|
"S"(state.gpr.rsi.dword), "D"(state.gpr.rdi.dword),
|
|
"r"(esp), "r"(ebp));
|
|
break;
|
|
|
|
# elif REMILL_HYPERCALL_AMD64
|
|
|
|
case SyncHyperCall::kAMD64SetDebugReg:
|
|
mem = __remill_amd64_set_debug_reg(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kAMD64SetControlReg0:
|
|
mem = __remill_amd64_set_control_reg_0(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kAMD64SetControlReg1:
|
|
mem = __remill_amd64_set_control_reg_1(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kAMD64SetControlReg2:
|
|
mem = __remill_amd64_set_control_reg_2(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kAMD64SetControlReg3:
|
|
mem = __remill_amd64_set_control_reg_3(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kAMD64SetControlReg4:
|
|
mem = __remill_amd64_set_control_reg_4(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kAMD64SetControlReg8:
|
|
mem = __remill_amd64_set_control_reg_8(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kX86SysCall:
|
|
asm volatile("syscall"
|
|
: "=a"(state.gpr.rax.qword), "=r"(rsp)
|
|
: "a"(state.gpr.rax.qword), "b"(state.gpr.rbx.qword),
|
|
"c"(state.gpr.rcx.qword), "d"(state.gpr.rdx.qword),
|
|
"S"(state.gpr.rsi.qword), "D"(state.gpr.rdi.qword),
|
|
"r"(rsp), "r"(rbp), "r"(r8), "r"(r9), "r"(r10), "r"(r11),
|
|
"r"(r12), "r"(r13), "r"(r14), "r"(r15));
|
|
break;
|
|
|
|
case SyncHyperCall::kX86SysEnter:
|
|
asm volatile("sysenter"
|
|
: "=a"(state.gpr.rax.qword), "=r"(rsp)
|
|
: "a"(state.gpr.rax.qword), "b"(state.gpr.rbx.qword),
|
|
"c"(state.gpr.rcx.qword), "d"(state.gpr.rdx.qword),
|
|
"S"(state.gpr.rsi.qword), "D"(state.gpr.rdi.qword),
|
|
"r"(rsp), "r"(rbp), "r"(r8), "r"(r9), "r"(r10), "r"(r11),
|
|
"r"(r12), "r"(r13), "r"(r14), "r"(r15));
|
|
break;
|
|
|
|
|
|
case SyncHyperCall::kX86SysExit:
|
|
asm volatile("sysexit"
|
|
: "=a"(state.gpr.rax.qword), "=r"(rsp)
|
|
: "a"(state.gpr.rax.qword), "b"(state.gpr.rbx.qword),
|
|
"c"(state.gpr.rcx.qword), "d"(state.gpr.rdx.qword),
|
|
"S"(state.gpr.rsi.qword), "D"(state.gpr.rdi.qword),
|
|
"r"(rsp), "r"(rbp), "r"(r8), "r"(r9), "r"(r10), "r"(r11),
|
|
"r"(r12), "r"(r13), "r"(r14), "r"(r15));
|
|
break;
|
|
|
|
# endif
|
|
|
|
#elif REMILL_HYPERCALL_ARM
|
|
|
|
case SyncHyperCall::kAArch32EmulateInstruction:
|
|
mem = __remill_aarch32_emulate_instruction(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kAArch32CheckNotEL2:
|
|
mem = __remill_aarch32_check_not_el2(mem);
|
|
break;
|
|
|
|
#elif REMILL_HYPERCALL_AARCH64
|
|
|
|
case SyncHyperCall::kAArch64EmulateInstruction:
|
|
mem = __remill_aarch64_emulate_instruction(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kAArch64Breakpoint: asm volatile("bkpt" :); break;
|
|
|
|
#elif REMILL_HYPERCALL_SPARC32 || REMILL_HYPERCALL_SPARC64
|
|
|
|
case SyncHyperCall::kSPARCSetAsiRegister:
|
|
mem = __remill_sparc_set_asi_register(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kSPARCUnimplementedInstruction:
|
|
mem = __remill_sparc_unimplemented_instruction(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kSPARCUnhandledDCTI:
|
|
mem = __remill_sparc_unhandled_dcti(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kSPARCWindowUnderflow:
|
|
mem = __remill_sparc_window_underflow(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kSPARCTrapCondA:
|
|
mem = __remill_sparc_trap_cond_a(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kSPARCTrapCondN:
|
|
mem = __remill_sparc_trap_cond_n(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kSPARCTrapCondNE:
|
|
mem = __remill_sparc_trap_cond_ne(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kSPARCTrapCondE:
|
|
mem = __remill_sparc_trap_cond_e(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kSPARCTrapCondG:
|
|
mem = __remill_sparc_trap_cond_g(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kSPARCTrapCondLE:
|
|
mem = __remill_sparc_trap_cond_le(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kSPARCTrapCondGE:
|
|
mem = __remill_sparc_trap_cond_ge(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kSPARCTrapCondL:
|
|
mem = __remill_sparc_trap_cond_l(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kSPARCTrapCondGU:
|
|
mem = __remill_sparc_trap_cond_gu(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kSPARCTrapCondLEU:
|
|
mem = __remill_sparc_trap_cond_leu(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kSPARCTrapCondCC:
|
|
mem = __remill_sparc_trap_cond_cc(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kSPARCTrapCondCS:
|
|
mem = __remill_sparc_trap_cond_cs(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kSPARCTrapCondPOS:
|
|
mem = __remill_sparc_trap_cond_pos(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kSPARCTrapCondNEG:
|
|
mem = __remill_sparc_trap_cond_neg(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kSPARCTrapCondVC:
|
|
mem = __remill_sparc_trap_cond_vc(mem);
|
|
break;
|
|
|
|
case SyncHyperCall::kSPARCTrapCondVS:
|
|
mem = __remill_sparc_trap_cond_vs(mem);
|
|
break;
|
|
|
|
# if defined(REMILL_HYPERCALL_SPARC32)
|
|
|
|
case SyncHyperCall::kSPARC32EmulateInstruction:
|
|
mem = __remill_sparc32_emulate_instruction(mem);
|
|
break;
|
|
|
|
# elif defined(REMILL_HYPERCALL_SPARC64)
|
|
|
|
case SyncHyperCall::kSPARC64EmulateInstruction:
|
|
mem = __remill_sparc64_emulate_instruction(mem);
|
|
break;
|
|
|
|
# endif
|
|
|
|
#elif defined(REMILL_HYPERCALL_PPC)
|
|
|
|
case SyncHyperCall::kPPCEmulateInstruction:
|
|
mem = __remill_ppc_emulate_instruction(mem);
|
|
break;
|
|
|
|
#endif
|
|
|
|
default: __builtin_unreachable(); break;
|
|
}
|
|
|
|
return mem;
|
|
}
|