Skip to content

Commit

Permalink
SPARC support via Sleigh (#681)
Browse files Browse the repository at this point in the history
* initial WIP sleigh based SPARC32 arch

* add install option to build script

* fix register names

* fix incorrect index into current_bytes in loadFill implementation

* add didrestore register

* dlog register adding

* ignore categories

* remove decompile_mode from llvm

* fix register mapping for flags

* remove nextpc/npc since it doesn't appear to be used and breaks anvill

* overlay NPC with NEXT_PC

* remove next_pc correctly since it was still breaking stuff

* Don't mark instruction as "invalid" when we can't determine a control
flow category

* fix pcode cfg for calls and branches

* add double registers to sparc state structure

* match up with ghidra register names

* fix missing header

* add starts for blocks after control flow ops to guarentee a block split for a term

* remove sparc64_sleigh, fix initialization order

* lift floating point numbers using ghidra names

---------

Co-authored-by: Alex Cameron <[email protected]>
Co-authored-by: 2over12 <[email protected]>
  • Loading branch information
3 people authored Nov 10, 2023
1 parent 0183248 commit 17cff6b
Show file tree
Hide file tree
Showing 30 changed files with 706 additions and 3,070 deletions.
10 changes: 9 additions & 1 deletion include/remill/Arch/Arch.h
Original file line number Diff line number Diff line change
Expand Up @@ -438,13 +438,21 @@ class Arch {
ArchName arch_name);

// Defined in `lib/Arch/SPARC32/Arch.cpp`.
static ArchPtr GetSPARC(llvm::LLVMContext *context, OSName os,
static ArchPtr GetSPARC32(llvm::LLVMContext *context, OSName os,
ArchName arch_name);

// Defined in `lib/Arch/SPARC64/Arch.cpp`.
static ArchPtr GetSPARC64(llvm::LLVMContext *context, OSName os,
ArchName arch_name);

// Defined in `lib/Arch/Sleigh/SPARC32/SPARC32Arch.cpp
static ArchPtr GetSPARC32Sleigh(llvm::LLVMContext *context, OSName os,
ArchName arch_name);

// Defined in `lib/Arch/Sleigh/SPARC64/SPARC64.cpp
static ArchPtr GetSPARC64Sleigh(llvm::LLVMContext *context, OSName os,
ArchName arch_name);

Arch(void) = delete;
};

Expand Down
1 change: 1 addition & 0 deletions include/remill/Arch/Name.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ enum ArchName : uint32_t {

kArchSparc32,
kArchSparc64,
kArchSparc32_SLEIGH,

kArchThumb2LittleEndian,

Expand Down
268 changes: 98 additions & 170 deletions include/remill/Arch/SPARC32/Runtime/State.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,86 +23,57 @@
#include "remill/Arch/Runtime/Types.h"

struct Reg final {
addr_t dword;
uint32_t dword;
} __attribute__((packed));

struct DoubleReg final {
union {
struct {
Reg reg1;
Reg reg2;
};
uint64_t qword;
};
};

union PtrReg final {
addr_t dword;
} __attribute__((packed));

static_assert(sizeof(PtrReg) == 4);
static_assert(sizeof(uint32_t) * 2 == sizeof(DoubleReg), "Invalid packing of `DoubleReg`.");

struct GPR {
DoubleReg i0_1;
volatile uint64_t _2;
DoubleReg i2_3;
volatile uint64_t _3;
DoubleReg i4_5;
volatile uint64_t _5;
DoubleReg fp_7;
volatile uint64_t _6;

// Prevents LLVM from casting a `GPR` into an `i64` to access `I0`.
volatile addr_t _0;
Reg i0;
volatile addr_t _1;
Reg i1;
volatile addr_t _2;
Reg i2;
volatile addr_t _3;
Reg i3;
volatile addr_t _4;
Reg i4;
volatile addr_t _5;
Reg i5;
volatile addr_t _6;
PtrReg i6;
volatile addr_t _7;
Reg i7;

volatile addr_t _8;
Reg l0;
volatile addr_t _9;
Reg l1;
volatile addr_t _10;
Reg l2;
volatile addr_t _11;
Reg l3;
volatile addr_t _12;
Reg l4;
volatile addr_t _13;
Reg l5;
volatile addr_t _14;
Reg l6;
volatile addr_t _15;
Reg l7;
volatile uint64_t _8;
DoubleReg l0_1;
volatile uint64_t _9;
DoubleReg l2_3;
volatile uint64_t _12;
DoubleReg l4_5;
volatile uint64_t _14;
DoubleReg l6_7;

volatile addr_t _16;
Reg o0;
volatile addr_t _17;
Reg o1;
volatile addr_t _18;
Reg o2;
volatile addr_t _19;
Reg o3;
volatile addr_t _20;
Reg o4;
volatile addr_t _21;
Reg o5;
volatile addr_t _22;
PtrReg o6;
volatile addr_t _23;
Reg o7;
volatile uint64_t _16;
DoubleReg o0_1;
volatile uint64_t _18;
DoubleReg o2_3;
volatile uint64_t _20;
DoubleReg o4_5;
volatile uint64_t _22;
DoubleReg sp_7;

volatile addr_t _24;
Reg g0;
volatile addr_t _25;
Reg g1;
volatile addr_t _26;
Reg g2;
volatile addr_t _27;
Reg g3;
volatile addr_t _28;
Reg g4;
volatile addr_t _29;
Reg g5;
volatile addr_t _30;
Reg g6;
volatile addr_t _31;
Reg g7;
volatile uint64_t _24;
DoubleReg g0_1;
volatile uint64_t _25;
DoubleReg g2_3;
volatile uint64_t _28;
DoubleReg g4_5;
volatile uint64_t _30;
DoubleReg g6_7;
};

enum AlternativeSpaceIdentifier : uint32_t {
Expand Down Expand Up @@ -160,18 +131,28 @@ struct FSRReg final {
static_assert(24 == sizeof(struct FSRReg),
"Invalid packing of `struct FSRReg`.");

// Integer condition code register flags
struct ICCRFlags final {
// Condition Codes register flags
struct CCRFlags final {
struct {
volatile uint8_t _0;
bool c;
bool i_cf;
volatile uint8_t _1;
bool v;
bool i_vf;
volatile uint8_t _2;
bool z;
bool i_zf;
volatile uint8_t _3;
bool n;
} __attribute__((packed)) icc, xcc;
bool i_nf;
} __attribute__((packed)) icc;
struct {
volatile uint8_t _0;
bool x_cf;
volatile uint8_t _1;
bool x_vf;
volatile uint8_t _2;
bool x_zf;
volatile uint8_t _3;
bool x_nf;
} __attribute__((packed)) xcc;
} __attribute__((packed));

union GSRFlags final {
Expand All @@ -188,41 +169,31 @@ union GSRFlags final {
} __attribute__((packed));

struct ASR final {
Reg yreg; // ASR 0
volatile uint32_t _0;
ICCRFlags ccr; // ASR 2
volatile addr_t _1;
union {
uint32_t asi_flat;
struct {
uint32_t asi : 8; // ASR 3
uint32_t padding_1 : 24;
} __attribute__((packed));
} __attribute__((packed));
volatile uint64_t _2;
uint64_t tick; // ASR 4
volatile uint64_t _3;
union {
uint32_t fprs_flat;
struct {
uint32_t fprs : 3; // ASR 6
uint32_t padding_2 : 29;
} __attribute__((packed));
} __attribute__((packed));
Reg yreg; // asr 0
volatile uint32_t _1;
Reg ccr; // asr 2
volatile uint32_t _2;
Reg tick; // asr 4
volatile uint32_t _3;
Reg pcr; // asr16
volatile uint32_t _4;
GSRFlags gsr;
volatile uint64_t _5;
addr64_t softint; // ASR 20
volatile uint64_t _6;
addr64_t stick; // ASR 24
volatile uint64_t _7;
addr64_t stick_cmpr; // ASR 25
volatile uint64_t _8;
addr64_t cfr; // ASR 26
volatile uint64_t _9;
addr64_t pause; // ASR 27
volatile uint64_t _10;
addr64_t mwait; // ASR 28
Reg pic; // asr 17
volatile uint32_t _5;
Reg gsr; // asr 19
volatile uint32_t _6;
Reg softint_set; // asr 20
volatile uint32_t _7;
Reg softint_clr; // asr 21
volatile uint32_t _8;
Reg softint; // asr 22
volatile uint32_t _9;
Reg tick_cmpr; // asr 23
volatile uint32_t _10;
Reg stick; // asr 24
volatile uint32_t _11;
Reg stick_cmpr; // asr 25
volatile uint32_t _12;
} __attribute__((packed));

struct CSR {
Expand Down Expand Up @@ -281,72 +252,29 @@ struct PSR {
uint8_t gl;
} __attribute__((packed));

struct RegisterWindow {
volatile addr_t _0;
addr_t l0;
volatile addr_t _1;
addr_t l1;
volatile addr_t _2;
addr_t l2;
volatile addr_t _3;
addr_t l3;
volatile addr_t _4;
addr_t l4;
volatile addr_t _5;
addr_t l5;
volatile addr_t _6;
addr_t l6;
volatile addr_t _7;
addr_t l7;

volatile addr_t _8;
addr_t i0;
volatile addr_t _9;
addr_t i1;
volatile addr_t _10;
addr_t i2;
volatile addr_t _11;
addr_t i3;
volatile addr_t _12;
addr_t i4;
volatile addr_t _13;
addr_t i5;
volatile addr_t _14;
addr_t i6;
volatile addr_t _15;
addr_t i7;
volatile addr_t _16;
RegisterWindow *prev_window;
};

struct alignas(16) SPARC32State : public ArchState {
FPURegs fpreg; // 512 bytes
volatile uint64_t _0;
GPR gpr; // 256 bytes
FPURegs fpreg; // 128 bytes
volatile uint64_t _1;
ASR asr; // 176 bytes
GPR gpr; // 256 bytes
volatile uint64_t _2;
PSR psr; // 56 bytes
volatile uint64_t _3;
FSRReg fsr; // 24 bytes
volatile uint64_t _4;
CSR csr; // 8 bytes
volatile uint64_t _3;
ASR asr; // 168 bytes
volatile uint32_t _4;
CCRFlags ccr;
volatile uint32_t _5;
Reg pc; // 4 bytes
PSR psr; // 56 bytes
volatile uint32_t _6;
Reg next_pc; // 4 bytes
Reg pc; // 4 bytes
volatile uint32_t _7;

// NOTE(pag): This *must* go at the end, as if we change the target arch/data
// layout, then we want to make sure that the offset of this
// remains the same and doesn't shift other things around.
#if defined(INCLUDED_FROM_REMILL)
uint32_t window;
#else
RegisterWindow *window; // smuggled.
static_assert(sizeof(RegisterWindow *) == 4,
"Invalid size of `RegisterWindow`");
#endif
Reg cwp;
// fake register for sleigh
uint8_t decompile_mode;
volatile uint8_t _8;
// fake register for sleigh
uint8_t didrestore;
volatile uint8_t _9;
};

struct State : public SPARC32State {};
Expand Down
46 changes: 46 additions & 0 deletions include/remill/Arch/SPARC32/SPARC32Base.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#pragma once
#include <remill/Arch/Arch.h>
#include <remill/Arch/ArchBase.h>

#include <remill/Arch/SPARC32/Runtime/State.h>

namespace remill {

class SPARC32ArchBase : public virtual ArchBase {
public:
SPARC32ArchBase(llvm::LLVMContext *context_, OSName os_name_,
ArchName arch_name_)
: ArchBase(context_, os_name_, arch_name_) {}

virtual std::string_view StackPointerRegisterName(void) const override;

std::string_view ProgramCounterRegisterName(void) const override;

llvm::CallingConv::ID DefaultCallingConv(void) const override;
llvm::DataLayout DataLayout(void) const override;
llvm::Triple Triple(void) const override;

// Align/Minimum/Maximum number of bytes in an instruction.
uint64_t MinInstructionAlign(const DecodingContext &) const override;
uint64_t MinInstructionSize(const DecodingContext &) const override;
uint64_t MaxInstructionSize(const DecodingContext &,
bool permit_fuse_idioms) const override;
bool MemoryAccessIsLittleEndian(void) const override;
// Returns `true` if a given instruction might have a delay slot.
bool MayHaveDelaySlot(const Instruction &inst) const override;
// Returns `true` if we should lift the semantics of `next_inst` as a delay
// slot of `inst`. The `branch_taken_path` tells us whether we are in the
// context of the taken path of a branch or the not-taken path of a branch.
virtual bool NextInstructionIsDelayed(const Instruction &inst,
const Instruction &next_inst,
bool branch_taken_path) const final;
void PopulateRegisterTable(void) const override;
// Populate a just-initialized lifted function function with architecture-
// specific variables.
void
FinishLiftedFunctionInitialization(llvm::Module *module,
llvm::Function *bb_func) const override;
virtual ~SPARC32ArchBase(void) = default;
};

} // namespace remill
Loading

0 comments on commit 17cff6b

Please sign in to comment.