C++ bindings (#9)

* start making c++ bindings

* Add sanity checks

* add descriptor methods

* setup making c++ library

* cpp test

* format (not tidy because it breaks everything and the result looks dumb)

* Fixes

* add missing alias

* move stuff to their own files

* InstructionRsp bindings

* r5900 bindings

* almost there

* binding for analysis stuff

* setters
This commit is contained in:
Anghelo Carvajal 2022-10-09 17:51:47 -03:00 committed by GitHub
parent 874863ab77
commit acee144578
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 2096 additions and 21 deletions

View File

@ -3,13 +3,19 @@ DEBUG ?= 0
WERROR ?= 0
ASAN ?= 0
EXPERIMENTAL ?= 0
SANITY_CHECKS ?= 1
CC := clang
CXX := clang++
AR := ar
IINC := -I include
IINC_XX := -I include -I cplusplus/include
CSTD := -std=c11
CXXSTD := -std=c++17
CFLAGS := -fPIC
CXXFLAGS := -fPIC
LDFLAGS := -Lbuild -lrabbitizer
LDXXFLAGS := -Lbuild -lrabbitizerpp
WARNINGS := -Wall -Wextra -Wpedantic
# WARNINGS := -Wall -Wextra -Wpedantic -Wpadded
WARNINGS += -Werror=implicit-function-declaration -Werror=incompatible-pointer-types -Werror=vla -Werror=switch -Werror=implicit-fallthrough -Werror=unused-function -Werror=unused-parameter -Werror=shadow
@ -19,10 +25,11 @@ ifeq ($(CC),gcc)
endif
ifeq ($(DEBUG),0)
OPTFLAGS := -O2 -g
OPTFLAGS := -Os -g
else
OPTFLAGS := -O0 -g3
CFLAGS += -DDEVELOPMENT=1
CXXFLAGS += -DDEVELOPMENT=1
endif
ifneq ($(WERROR),0)
@ -31,10 +38,17 @@ endif
ifneq ($(ASAN),0)
CFLAGS += -fsanitize=address -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined
CXXFLAGS += -fsanitize=address -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined
endif
ifneq ($(EXPERIMENTAL),0)
CFLAGS += -DEXPERIMENTAL
CXXFLAGS += -DEXPERIMENTAL
endif
ifneq ($(SANITY_CHECKS),0)
CFLAGS += -DRAB_SANITY_CHECKS=1
CXXFLAGS += -DRAB_SANITY_CHECKS=1
endif
@ -42,21 +56,41 @@ SRC_DIRS := $(shell find src -type d)
C_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.c))
H_FILES := $(foreach dir,$(IINC),$(wildcard $(dir)/**/*.h))
O_FILES := $(foreach f,$(C_FILES:.c=.o),build/$f)
DEP_FILES := $(O_FILES:%.o=%.d)
SRCXX_DIRS := $(shell find cplusplus/src -type d)
CXX_FILES := $(foreach dir,$(SRCXX_DIRS),$(wildcard $(dir)/*.cpp))
HXX_FILES := $(foreach dir,$(IINC_XX),$(wildcard $(dir)/**/*.hpp))
OXX_FILES := $(foreach f,$(CXX_FILES:.cpp=.o),build/$f)
DEP_FILES := $(O_FILES:%.o=%.d) $(OXX_FILES:%.o=%.d)
TESTS_DIRS := $(shell find tests -type d)
STATIC_LIB := build/librabbitizer.a
DYNAMIC_LIB := build/librabbitizer.so
STATIC_LIB_XX := build/librabbitizerpp.a
DYNAMIC_LIB_XX := build/librabbitizerpp.so
# create build directories
$(shell mkdir -p $(foreach dir,$(SRC_DIRS),build/$(dir)))
$(shell mkdir -p $(foreach dir,$(SRC_DIRS) $(SRCXX_DIRS) $(TESTS_DIRS),build/$(dir)))
# Dependencies of libraries
$(STATIC_LIB): $(O_FILES)
$(DYNAMIC_LIB): $(O_FILES)
$(STATIC_LIB_XX): $(O_FILES) $(OXX_FILES)
$(DYNAMIC_LIB_XX): $(O_FILES) $(OXX_FILES)
#### Main Targets ###
all: static tests
static: $(STATIC_LIB)
dynamic: $(DYNAMIC_LIB)
static: $(STATIC_LIB) $(STATIC_LIB_XX)
dynamic: $(DYNAMIC_LIB) $(DYNAMIC_LIB_XX)
clean:
$(RM) -rf build
@ -66,11 +100,12 @@ distclean: clean
format:
clang-format-11 -i -style=file $(C_FILES)
clang-format-11 -i -style=file $(CXX_FILES)
tidy:
clang-tidy-11 -p . --fix --fix-errors $(C_FILES) $(H_FILES) -- $(CSTD) $(OPTFLAGS) $(IINC) $(WARNINGS) $(CFLAGS)
tests: build/test.elf build/rsptest.elf build/r5900test.elf build/registersTrackerTest.elf
tests: build/test.elf build/rsptest.elf build/r5900test.elf build/registersTrackerTest.elf build/tests/cplusplus/test.elf
.PHONY: all clean distclean format tidy tests
.DEFAULT_GOAL := all
@ -82,15 +117,22 @@ tests: build/test.elf build/rsptest.elf build/r5900test.elf build/registersTrack
build/%.elf: %.c | $(STATIC_LIB)
$(CC) -MMD $(CSTD) $(OPTFLAGS) $(IINC) $(WARNINGS) $(CFLAGS) -o $@ $^ $(LDFLAGS)
build/%.a: $(O_FILES)
build/%.elf: %.cpp | $(STATIC_LIB_XX)
$(CXX) -MMD $(CXXSTD) $(OPTFLAGS) $(IINC_XX) $(WARNINGS) $(CXXFLAGS) -o $@ $^ $(LDXXFLAGS)
build/%.a:
$(AR) rcs $@ $^
build/%.so: $(O_FILES)
build/%.so:
$(CC) -shared -o $@ $^
build/%.o: %.c
# The -MMD flags additionaly creates a .d file with the same name as the .o file.
$(CC) -MMD -c $(CSTD) $(OPTFLAGS) $(IINC) $(WARNINGS) $(CFLAGS) -o $@ $<
build/%.o: %.cpp
# The -MMD flags additionaly creates a .d file with the same name as the .o file.
$(CXX) -MMD -c $(CXXSTD) $(OPTFLAGS) $(IINC_XX) $(WARNINGS) $(CXXFLAGS) -o $@ $<
-include $(DEP_FILES)

View File

@ -0,0 +1,36 @@
/* SPDX-FileCopyrightText: © 2022 Decompollaborate */
/* SPDX-License-Identifier: MIT */
#ifndef RABBITIZER_LO_PAIRING_INFO_HPP
#define RABBITIZER_LO_PAIRING_INFO_HPP
#pragma once
#include "analysis/RabbitizerLoPairingInfo.h"
namespace rabbitizer {
class LoPairingInfo {
protected:
RabbitizerLoPairingInfo pairingInfo;
public:
LoPairingInfo();
LoPairingInfo(const RabbitizerLoPairingInfo &pairingInfo);
/**
* Returns a pointer to the inner RabbitizerLoPairingInfo.
* It is recommended to not mess with it unless you know what you are doing.
*/
RabbitizerLoPairingInfo *getCPtr();
const RabbitizerLoPairingInfo *getCPtr() const;
int getInstrOffset() const;
int64_t getValue() const;
bool shouldProcess() const;
bool isGpRel() const;
bool isGpGot() const;
};
};
#endif

View File

@ -0,0 +1,49 @@
/* SPDX-FileCopyrightText: © 2022 Decompollaborate */
/* SPDX-License-Identifier: MIT */
#ifndef RABBITIZER_REGISTERS_TRACKER_HPP
#define RABBITIZER_REGISTERS_TRACKER_HPP
#pragma once
#include "analysis/RabbitizerRegistersTracker.h"
#include "analysis/LoPairingInfo.hpp"
#include "instructions/InstructionBase.hpp"
namespace rabbitizer {
class RegistersTracker {
protected:
RabbitizerRegistersTracker tracker;
public:
RegistersTracker();
RegistersTracker(const RegistersTracker &other);
virtual ~RegistersTracker();
/**
* Returns a pointer to the inner RabbitizerRegistersTracker.
* It is recommended to not mess with it unless you know what you are doing.
*/
RabbitizerRegistersTracker *getCPtr();
const RabbitizerRegistersTracker *getCPtr() const;
bool moveRegisters(const InstructionBase &instr);
void overwriteRegisters(const InstructionBase &instr, int instrOffset);
void unsetRegistersAfterFuncCall(const InstructionBase &instr, const InstructionBase &prevInstr);
bool getAddressIfCanSetType(const InstructionBase &instr, int instrOffset, uint32_t *dstAddress) const;
bool getJrInfo(const InstructionBase &instr, int *dstOffset, uint32_t *dstAddress) const;
void processLui(const InstructionBase &instr, int instrOffset);
void processLui(const InstructionBase &instr, int instrOffset, const InstructionBase &prevInstr);
void processGpLoad(const InstructionBase &instr, int instrOffset);
bool getLuiOffsetForConstant(const InstructionBase &instr, int *dstOffset) const;
void processConstant(const InstructionBase &instr, uint32_t value, int offset);
LoPairingInfo preprocessLoAndGetInfo(const InstructionBase &instr, int instrOffset);
void processLo(const InstructionBase &instr, uint32_t value, int offset);
bool hasLoButNoHi(const InstructionBase &instr) const;
};
};
#endif

View File

@ -0,0 +1,38 @@
/* SPDX-FileCopyrightText: © 2022 Decompollaborate */
/* SPDX-License-Identifier: MIT */
#ifndef RABBITIZER_INSTRID_HPP
#define RABBITIZER_INSTRID_HPP
#pragma once
#include <string>
namespace rabbitizer {
namespace InstrId {
#define RABBITIZER_DEF_INSTR_ID(prefix, caseBits, name, ...) \
prefix##_##name,
#define RABBITIZER_DEF_INSTR_ID_ALTNAME(prefix, caseBits, name, altname, ...) \
RABBITIZER_DEF_INSTR_ID(prefix, caseBits, name, __VA_ARGS__)
enum class UniqueId {
#include "instructions/instr_id/RabbitizerInstrId_cpu.inc"
#include "instructions/instr_id/RabbitizerInstrId_rsp.inc"
#include "instructions/instr_id/RabbitizerInstrId_r5900.inc"
ALL_MAX = RABBITIZER_DEF_INSTR_ID(r5900, , MAX, )
};
#undef RABBITIZER_DEF_INSTR_ID
#undef RABBITIZER_DEF_INSTR_ID_ALTNAME
std::string getOpcodeName(UniqueId uniqueId);
};
};
#endif

View File

@ -0,0 +1,251 @@
/* SPDX-FileCopyrightText: © 2022 Decompollaborate */
/* SPDX-License-Identifier: MIT */
#ifndef RABBITIZER_INSTRUCTION_BASE_HPP
#define RABBITIZER_INSTRUCTION_BASE_HPP
#pragma once
#include <string>
#include <string_view>
#include "instructions/RabbitizerInstruction.h"
#include "instructions/Registers.hpp"
#include "instructions/OperandType.hpp"
#include "instructions/InstrId.hpp"
namespace rabbitizer {
class InstructionBase {
protected:
RabbitizerInstruction instr;
InstructionBase() = default;
virtual ~InstructionBase() = default;
public:
/**
* Returns a pointer to the inner RabbitizerInstruction.
* It is recommended to not mess with it unless you know what you are doing.
*/
RabbitizerInstruction *getCPtr();
const RabbitizerInstruction *getCPtr() const;
/* getters */
uint8_t Get_opcode() const;
uint8_t Get_sa() const;
uint8_t Get_function() const;
Registers::Cpu::GprO32 GetO32_rs() const;
Registers::Cpu::GprO32 GetO32_rt() const;
Registers::Cpu::GprO32 GetO32_rd() const;
Registers::Cpu::GprN32 GetN32_rs() const;
Registers::Cpu::GprN32 GetN32_rt() const;
Registers::Cpu::GprN32 GetN32_rd() const;
Registers::Cpu::Cop0 Get_cop0d() const;
uint32_t Get_instr_index() const;
uint16_t Get_immediate() const;
Registers::Cpu::Cop1O32 GetO32_fs() const;
Registers::Cpu::Cop1O32 GetO32_ft() const;
Registers::Cpu::Cop1O32 GetO32_fd() const;
Registers::Cpu::Cop1N32 GetN32_fs() const;
Registers::Cpu::Cop1N32 GetN32_ft() const;
Registers::Cpu::Cop1N32 GetN32_fd() const;
Registers::Cpu::Cop1N64 GetN64_fs() const;
Registers::Cpu::Cop1N64 GetN64_ft() const;
Registers::Cpu::Cop1N64 GetN64_fd() const;
Registers::Cpu::Cop1Control Get_cop1cs() const;
Registers::Cpu::Cop2 Get_cop2t() const;
uint8_t Get_op() const;
uint32_t Get_code() const;
uint32_t Get_code_upper() const;
uint32_t Get_code_lower() const;
uint32_t Get_copraw() const;
uint8_t Get_fmt() const;
uint8_t Get_fc() const;
uint8_t Get_cond() const;
uint8_t Get_tf() const;
uint8_t Get_nd() const;
uint8_t Get_bc_fmt() const;
uint8_t Get_stype() const;
/* getters */
/* setters */
void Set_opcode(uint8_t val);
void Set_sa(uint8_t val);
void Set_function(uint8_t val);
void Set_rs(Registers::Cpu::GprO32 val);
void Set_rt(Registers::Cpu::GprO32 val);
void Set_rd(Registers::Cpu::GprO32 val);
void Set_rs(Registers::Cpu::GprN32 val);
void Set_rt(Registers::Cpu::GprN32 val);
void Set_rd(Registers::Cpu::GprN32 val);
void Set_cop0d(Registers::Cpu::Cop0 val);
void Set_instr_index(uint32_t val);
void Set_immediate(uint16_t val);
void Set_fs(Registers::Cpu::Cop1O32 val);
void Set_ft(Registers::Cpu::Cop1O32 val);
void Set_fd(Registers::Cpu::Cop1O32 val);
void Set_fs(Registers::Cpu::Cop1N32 val);
void Set_ft(Registers::Cpu::Cop1N32 val);
void Set_fd(Registers::Cpu::Cop1N32 val);
void Set_fs(Registers::Cpu::Cop1N64 val);
void Set_ft(Registers::Cpu::Cop1N64 val);
void Set_fd(Registers::Cpu::Cop1N64 val);
void Set_cop1cs(Registers::Cpu::Cop1Control val);
void Set_cop2t(Registers::Cpu::Cop2 val);
void Set_op(uint8_t val);
void Set_code(uint32_t val);
void Set_copraw(uint32_t val);
void Set_fmt(uint8_t val);
void Set_fc(uint8_t val);
void Set_cond(uint8_t val);
void Set_tf(uint8_t val);
void Set_nd(uint8_t val);
void Set_bc_fmt(uint8_t val);
void Set_stype(uint8_t val);
/* setters */
/* more getters */
uint32_t getRaw() const;
InstrId::UniqueId getUniqueId() const;
uint32_t getVram() const;
bool isInHandwrittenFunction() const;
int32_t getProcessedImmediate() const;
uint32_t getInstrIndexAsVram() const;
int32_t getBranchOffset() const;
int32_t getGenericBranchOffset(uint32_t currentVram) const;
std::string getOpcodeName() const;
/* more getters */
/* */
void blankOut();
/* Instruction examination */
bool isImplemented() const;
bool isLikelyHandwritten() const;
bool isNop() const;
bool isUnconditionalBranch() const;
bool isJrRa() const;
bool isJrNotRa() const;
bool hasDelaySlot() const;
std::string mapInstrToType() const;
bool sameOpcode(const InstructionBase &other) const;
bool sameOpcodeButDifferentArguments(const InstructionBase &other) const;
bool hasOperand(OperandType operand) const;
bool hasOperandAlias(OperandType operand) const;
uint32_t getValidBits() const;
bool isValid() const;
/* Instruction examination */
/* Instruction descriptor */
bool isUnknownType() const;
bool isJType() const;
bool isIType() const;
bool isRType() const;
bool isRegimmType() const;
// TODO
// RabbitizerInstrSuffix instrSuffix() const;
bool isBranch() const;
bool isBranchLikely() const;
bool isJump() const;
bool isTrap() const;
bool isFloat() const;
bool isDouble() const;
bool isUnsigned() const;
bool modifiesRt() const;
bool modifiesRd() const;
bool notEmitedByCompilers() const;
bool canBeHi() const;
bool canBeLo() const;
bool doesLink() const;
bool doesDereference() const;
bool doesLoad() const;
bool doesStore() const;
bool maybeIsMove() const;
bool isPseudo() const;
/* Instruction descriptor */
/* Disassembly */
bool mustDisasmAsData() const;
std::string disassembleOperands() const;
std::string disassembleOperands(std::string_view immOverride) const;
std::string disassembleInstruction(int extraLJust) const;
std::string disassembleInstruction(int extraLJust, std::string_view immOverride) const;
std::string disassembleAsData(int extraLJust) const;
std::string disassemble(int extraLJust) const;
std::string disassemble(int extraLJust, std::string_view immOverride) const;
/* Disassembly */
};
};
#endif

View File

@ -0,0 +1,20 @@
/* SPDX-FileCopyrightText: © 2022 Decompollaborate */
/* SPDX-License-Identifier: MIT */
#ifndef RABBITIZER_INSTRUCTION_CPU_HPP
#define RABBITIZER_INSTRUCTION_CPU_HPP
#pragma once
#include "InstructionBase.hpp"
namespace rabbitizer {
class InstructionCpu : public InstructionBase {
public:
InstructionCpu(uint32_t word, uint32_t vram);
virtual ~InstructionCpu();
};
};
#endif

View File

@ -0,0 +1,41 @@
/* SPDX-FileCopyrightText: © 2022 Decompollaborate */
/* SPDX-License-Identifier: MIT */
#ifndef RABBITIZER_INSTRUCTION_R5900_HPP
#define RABBITIZER_INSTRUCTION_R5900_HPP
#pragma once
#include "InstructionBase.hpp"
namespace rabbitizer {
class InstructionR5900 : public InstructionBase {
public:
InstructionR5900(uint32_t word, uint32_t vram);
virtual ~InstructionR5900();
Registers::R5900::VF GetR5900_vfs() const;
Registers::R5900::VF GetR5900_vft() const;
Registers::R5900::VF GetR5900_vfd() const;
Registers::R5900::VI GetR5900_vis() const;
Registers::R5900::VI GetR5900_vit() const;
Registers::R5900::VI GetR5900_vid() const;
uint8_t GetR5900_mmi_function() const;
uint8_t GetR5900_fhi_flo() const;
uint8_t GetR5900_xyzw_x() const;
uint8_t GetR5900_xyzw_y() const;
uint8_t GetR5900_xyzw_z() const;
uint8_t GetR5900_xyzw_w() const;
uint8_t GetR5900_n() const;
uint8_t GetR5900_l() const;
uint8_t GetR5900_m() const;
uint8_t GetR5900_imm5() const;
};
};
#endif

View File

@ -0,0 +1,40 @@
/* SPDX-FileCopyrightText: © 2022 Decompollaborate */
/* SPDX-License-Identifier: MIT */
#ifndef RABBITIZER_INSTRUCTION_RSP_HPP
#define RABBITIZER_INSTRUCTION_RSP_HPP
#pragma once
#include "InstructionBase.hpp"
namespace rabbitizer {
class InstructionRsp : public InstructionBase {
public:
InstructionRsp(uint32_t word, uint32_t vram);
virtual ~InstructionRsp();
Registers::Rsp::Gpr GetRsp_rs() const;
Registers::Rsp::Gpr GetRsp_rt() const;
Registers::Rsp::Gpr GetRsp_rd() const;
Registers::Rsp::Cop0 GetRsp_cop0d() const;
Registers::Rsp::Cop2 GetRsp_cop2t() const;
Registers::Rsp::Cop2Control GetRsp_cop2cd() const;
Registers::Rsp::Vector GetRsp_vs() const;
Registers::Rsp::Vector GetRsp_vt() const;
Registers::Rsp::Vector GetRsp_vd() const;
uint8_t GetRsp_elementhigh() const;
uint8_t GetRsp_elementlow() const;
uint8_t GetRsp_index() const;
uint8_t GetRsp_de() const;
};
};
#endif

View File

@ -0,0 +1,27 @@
/* SPDX-FileCopyrightText: © 2022 Decompollaborate */
/* SPDX-License-Identifier: MIT */
#ifndef RABBITIZER_OPERAND_TYPE_HPP
#define RABBITIZER_OPERAND_TYPE_HPP
#pragma once
namespace rabbitizer {
#define RAB_DEF_OPERAND(prefix, operand) \
prefix##_##operand,
enum class OperandType {
RAB_DEF_OPERAND(ALL, INVALID)
#include "instructions/operands/RabbitizerOperandType_cpu.inc"
#include "instructions/operands/RabbitizerOperandType_rsp.inc"
#include "instructions/operands/RabbitizerOperandType_r5900.inc"
RAB_DEF_OPERAND(ALL, MAX)
};
#undef RAB_DEF_OPERAND
};
#endif

View File

@ -0,0 +1,94 @@
/* SPDX-FileCopyrightText: © 2022 Decompollaborate */
/* SPDX-License-Identifier: MIT */
#ifndef RABBITIZER_REGISTER_HPP
#define RABBITIZER_REGISTER_HPP
#pragma once
namespace rabbitizer {
namespace Registers {
#define RABBITIZER_DEF_REG(prefix, name, numeric) \
prefix##_##name
#define RABBITIZER_DEF_REG_NODOLLAR(prefix, name, numeric) \
prefix##_##name
namespace Cpu {
enum class GprO32 {
#include "instructions/registers/RabbitizerRegister_GprO32.inc"
};
enum class GprN32 {
#include "instructions/registers/RabbitizerRegister_GprN32.inc"
};
enum class Cop0 {
#include "instructions/registers/RabbitizerRegister_Cop0.inc"
};
// Float registers
enum class Cop1O32 {
#include "instructions/registers/RabbitizerRegister_Cop1O32.inc"
};
enum class Cop1N32 {
#include "instructions/registers/RabbitizerRegister_Cop1N32.inc"
};
enum class Cop1N64 {
#include "instructions/registers/RabbitizerRegister_Cop1N64.inc"
};
enum class Cop1Control {
#include "instructions/registers/RabbitizerRegister_Cop1Control.inc"
};
enum class Cop2 {
#include "instructions/registers/RabbitizerRegister_Cop2.inc"
};
};
namespace Rsp {
enum class Gpr {
#include "instructions/registers/RabbitizerRegister_RspGpr.inc"
};
enum class Cop0 {
#include "instructions/registers/RabbitizerRegister_RspCop0.inc"
};
enum class Cop2 {
#include "instructions/registers/RabbitizerRegister_RspCop2.inc"
};
enum class Cop2Control {
#include "instructions/registers/RabbitizerRegister_RspCop2Control.inc"
};
enum class Vector {
#include "instructions/registers/RabbitizerRegister_RspVector.inc"
};
};
namespace R5900 {
enum class VF {
#include "instructions/registers/RabbitizerRegister_R5900VF.inc"
};
enum class VI {
#include "instructions/registers/RabbitizerRegister_R5900VI.inc"
};
};
#undef RABBITIZER_DEF_REG
#undef RABBITIZER_DEF_REG_NODOLLAR
};
};
#endif

View File

@ -0,0 +1,26 @@
/* SPDX-FileCopyrightText: © 2022 Decompollaborate */
/* SPDX-License-Identifier: MIT */
#ifndef RABBITIZER_HPP
#define RABBITIZER_HPP
#pragma once
#include "common/RabbitizerVersion.h"
#include "common/RabbitizerConfig.h"
#include "instructions/OperandType.hpp"
#include "instructions/InstrId.hpp"
//#include "instructions/InstrSuffix.hpp"
//#include "instructions/InstrDescriptor.hpp"
#include "instructions/Registers.hpp"
#include "instructions/InstructionBase.hpp"
#include "instructions/InstructionCpu.hpp"
#include "instructions/InstructionRsp.hpp"
#include "instructions/InstructionR5900.hpp"
#include "analysis/LoPairingInfo.hpp"
#include "analysis/RegistersTracker.hpp"
#endif

View File

@ -0,0 +1,37 @@
/* SPDX-FileCopyrightText: © 2022 Decompollaborate */
/* SPDX-License-Identifier: MIT */
#include "analysis/LoPairingInfo.hpp"
using namespace rabbitizer;
LoPairingInfo::LoPairingInfo() {
}
LoPairingInfo::LoPairingInfo(const RabbitizerLoPairingInfo &pairingInfo) {
this->pairingInfo = pairingInfo;
}
RabbitizerLoPairingInfo *LoPairingInfo::getCPtr() {
return &this->pairingInfo;
}
const RabbitizerLoPairingInfo *LoPairingInfo::getCPtr() const{
return &this->pairingInfo;
}
int LoPairingInfo::getInstrOffset() const {
return this->pairingInfo.instrOffset;
}
int64_t LoPairingInfo::getValue() const {
return this->pairingInfo.value;
}
bool LoPairingInfo::shouldProcess() const {
return this->pairingInfo.shouldProcess;
}
bool LoPairingInfo::isGpRel() const {
return this->pairingInfo.isGpRel;
}
bool LoPairingInfo::isGpGot() const {
return this->pairingInfo.isGpGot;
}

View File

@ -0,0 +1,67 @@
/* SPDX-FileCopyrightText: © 2022 Decompollaborate */
/* SPDX-License-Identifier: MIT */
#include "analysis/RegistersTracker.hpp"
using namespace rabbitizer;
RegistersTracker::RegistersTracker() {
RabbitizerRegistersTracker_init(&this->tracker, NULL);
}
RegistersTracker::RegistersTracker(const RegistersTracker &other) {
RabbitizerRegistersTracker_init(&this->tracker, &other.tracker);
}
RegistersTracker::~RegistersTracker() {
RabbitizerRegistersTracker_destroy(&this->tracker);
}
RabbitizerRegistersTracker *RegistersTracker::getCPtr() {
return &this->tracker;
}
const RabbitizerRegistersTracker *RegistersTracker::getCPtr() const {
return &this->tracker;
}
bool RegistersTracker::moveRegisters(const InstructionBase &instr) {
return RabbitizerRegistersTracker_moveRegisters(&this->tracker, instr.getCPtr());
}
void RegistersTracker::overwriteRegisters(const InstructionBase &instr, int instrOffset) {
RabbitizerRegistersTracker_overwriteRegisters(&this->tracker, instr.getCPtr(), instrOffset);
}
void RegistersTracker::unsetRegistersAfterFuncCall(const InstructionBase &instr, const InstructionBase &prevInstr) {
RabbitizerRegistersTracker_unsetRegistersAfterFuncCall(&this->tracker, instr.getCPtr(), prevInstr.getCPtr());
}
bool RegistersTracker::getAddressIfCanSetType(const InstructionBase &instr, int instrOffset, uint32_t *dstAddress) const {
return RabbitizerRegistersTracker_getAddressIfCanSetType(&this->tracker, instr.getCPtr(), instrOffset, dstAddress);
}
bool RegistersTracker::getJrInfo(const InstructionBase &instr, int *dstOffset, uint32_t *dstAddress) const {
return RabbitizerRegistersTracker_getJrInfo(&this->tracker, instr.getCPtr(), dstOffset, dstAddress);
}
void RegistersTracker::processLui(const InstructionBase &instr, int instrOffset) {
RabbitizerRegistersTracker_processLui(&this->tracker, instr.getCPtr(), instrOffset, NULL);
}
void RegistersTracker::processLui(const InstructionBase &instr, int instrOffset, const InstructionBase &prevInstr) {
RabbitizerRegistersTracker_processLui(&this->tracker, instr.getCPtr(), instrOffset, prevInstr.getCPtr());
}
void RegistersTracker::processGpLoad(const InstructionBase &instr, int instrOffset) {
RabbitizerRegistersTracker_processGpLoad(&this->tracker, instr.getCPtr(), instrOffset);
}
bool RegistersTracker::getLuiOffsetForConstant(const InstructionBase &instr, int *dstOffset) const {
return RabbitizerRegistersTracker_getLuiOffsetForConstant(&this->tracker, instr.getCPtr(), dstOffset);
}
void RegistersTracker::processConstant(const InstructionBase &instr, uint32_t value, int offset) {
RabbitizerRegistersTracker_processConstant(&this->tracker, instr.getCPtr(), value, offset);
}
LoPairingInfo RegistersTracker::preprocessLoAndGetInfo(const InstructionBase &instr, int instrOffset) {
return RabbitizerRegistersTracker_preprocessLoAndGetInfo(&this->tracker, instr.getCPtr(), instrOffset);
}
void RegistersTracker::processLo(const InstructionBase &instr, uint32_t value, int offset) {
RabbitizerRegistersTracker_processLo(&this->tracker, instr.getCPtr(), value, offset);
}
bool RegistersTracker::hasLoButNoHi(const InstructionBase &instr) const {
return RabbitizerRegistersTracker_hasLoButNoHi(&this->tracker, instr.getCPtr());
}

View File

@ -0,0 +1,14 @@
/* SPDX-FileCopyrightText: © 2022 Decompollaborate */
/* SPDX-License-Identifier: MIT */
#include "instructions/InstrId.hpp"
#include "instructions/RabbitizerInstrId.h"
using namespace rabbitizer;
std::string InstrId::getOpcodeName(InstrId::UniqueId uniqueId) {
RabbitizerInstrId id = static_cast<RabbitizerInstrId>(uniqueId);
return std::string(RabbitizerInstrId_getOpcodeName(id));
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,16 @@
/* SPDX-FileCopyrightText: © 2022 Decompollaborate */
/* SPDX-License-Identifier: MIT */
#include "instructions/InstructionCpu.hpp"
using namespace rabbitizer;
InstructionCpu::InstructionCpu(uint32_t word, uint32_t vram) : InstructionBase() {
RabbitizerInstruction_init(&this->instr, word, vram);
RabbitizerInstruction_processUniqueId(&this->instr);
}
InstructionCpu::~InstructionCpu() {
RabbitizerInstruction_destroy(&this->instr);
}

View File

@ -0,0 +1,121 @@
/* SPDX-FileCopyrightText: © 2022 Decompollaborate */
/* SPDX-License-Identifier: MIT */
#include "instructions/InstructionR5900.hpp"
#include <stdexcept>
#include "instructions/RabbitizerInstructionR5900.h"
using namespace rabbitizer;
InstructionR5900::InstructionR5900(uint32_t word, uint32_t vram) : InstructionBase() {
RabbitizerInstructionR5900_init(&this->instr, word, vram);
RabbitizerInstructionR5900_processUniqueId(&this->instr);
}
InstructionR5900::~InstructionR5900() {
RabbitizerInstructionR5900_destroy(&this->instr);
}
Registers::R5900::VF InstructionR5900::GetR5900_vfs() const {
#ifdef RAB_SANITY_CHECKS
if (!hasOperandAlias(OperandType::rsp_rs)) {
// TODO: make a rabbitizer exception class
throw std::runtime_error("Instruction '" + getOpcodeName() + "' does not have 'vfs' operand.");
}
#endif
return static_cast<Registers::R5900::VF>(RAB_INSTR_R5900_GET_vfs(&this->instr));
}
Registers::R5900::VF InstructionR5900::GetR5900_vft() const {
#ifdef RAB_SANITY_CHECKS
if (!hasOperandAlias(OperandType::rsp_rt)) {
// TODO: make a rabbitizer exception class
throw std::runtime_error("Instruction '" + getOpcodeName() + "' does not have 'vft' operand.");
}
#endif
return static_cast<Registers::R5900::VF>(RAB_INSTR_R5900_GET_vft(&this->instr));
}
Registers::R5900::VF InstructionR5900::GetR5900_vfd() const {
#ifdef RAB_SANITY_CHECKS
if (!hasOperandAlias(OperandType::rsp_rd)) {
// TODO: make a rabbitizer exception class
throw std::runtime_error("Instruction '" + getOpcodeName() + "' does not have 'vfd' operand.");
}
#endif
return static_cast<Registers::R5900::VF>(RAB_INSTR_R5900_GET_vfd(&this->instr));
}
Registers::R5900::VI InstructionR5900::GetR5900_vis() const {
#ifdef RAB_SANITY_CHECKS
if (!hasOperandAlias(OperandType::rsp_rs)) {
// TODO: make a rabbitizer exception class
throw std::runtime_error("Instruction '" + getOpcodeName() + "' does not have 'vis' operand.");
}
#endif
return static_cast<Registers::R5900::VI>(RAB_INSTR_R5900_GET_vis(&this->instr));
}
Registers::R5900::VI InstructionR5900::GetR5900_vit() const {
#ifdef RAB_SANITY_CHECKS
if (!hasOperandAlias(OperandType::rsp_rt)) {
// TODO: make a rabbitizer exception class
throw std::runtime_error("Instruction '" + getOpcodeName() + "' does not have 'vit' operand.");
}
#endif
return static_cast<Registers::R5900::VI>(RAB_INSTR_R5900_GET_vit(&this->instr));
}
Registers::R5900::VI InstructionR5900::GetR5900_vid() const {
#ifdef RAB_SANITY_CHECKS
if (!hasOperandAlias(OperandType::rsp_rd)) {
// TODO: make a rabbitizer exception class
throw std::runtime_error("Instruction '" + getOpcodeName() + "' does not have 'vid' operand.");
}
#endif
return static_cast<Registers::R5900::VI>(RAB_INSTR_R5900_GET_vid(&this->instr));
}
uint8_t InstructionR5900::GetR5900_mmi_function() const {
return RAB_INSTR_R5900_GET_mmi_function(&this->instr);
}
uint8_t InstructionR5900::GetR5900_fhi_flo() const {
return RAB_INSTR_R5900_GET_fhi_flo(&this->instr);
}
uint8_t InstructionR5900::GetR5900_xyzw_x() const {
return RAB_INSTR_R5900_GET_xyzw_x(&this->instr);
}
uint8_t InstructionR5900::GetR5900_xyzw_y() const {
return RAB_INSTR_R5900_GET_xyzw_y(&this->instr);
}
uint8_t InstructionR5900::GetR5900_xyzw_z() const {
return RAB_INSTR_R5900_GET_xyzw_z(&this->instr);
}
uint8_t InstructionR5900::GetR5900_xyzw_w() const {
return RAB_INSTR_R5900_GET_xyzw_w(&this->instr);
}
uint8_t InstructionR5900::GetR5900_n() const {
return RAB_INSTR_R5900_GET_n(&this->instr);
}
uint8_t InstructionR5900::GetR5900_l() const {
return RAB_INSTR_R5900_GET_l(&this->instr);
}
uint8_t InstructionR5900::GetR5900_m() const {
return RAB_INSTR_R5900_GET_m(&this->instr);
}
uint8_t InstructionR5900::GetR5900_imm5() const {
return RAB_INSTR_R5900_GET_imm5(&this->instr);
}

View File

@ -0,0 +1,130 @@
/* SPDX-FileCopyrightText: © 2022 Decompollaborate */
/* SPDX-License-Identifier: MIT */
#include "instructions/InstructionRsp.hpp"
#include <stdexcept>
#include "instructions/RabbitizerInstructionRsp.h"
using namespace rabbitizer;
InstructionRsp::InstructionRsp(uint32_t word, uint32_t vram) : InstructionBase() {
RabbitizerInstructionRsp_init(&this->instr, word, vram);
RabbitizerInstructionRsp_processUniqueId(&this->instr);
}
InstructionRsp::~InstructionRsp() {
RabbitizerInstructionRsp_destroy(&this->instr);
}
Registers::Rsp::Gpr InstructionRsp::GetRsp_rs() const {
#ifdef RAB_SANITY_CHECKS
if (!hasOperandAlias(OperandType::rsp_rs)) {
// TODO: make a rabbitizer exception class
throw std::runtime_error("Instruction '" + getOpcodeName() + "' does not have 'rs' operand.");
}
#endif
return static_cast<Registers::Rsp::Gpr>(RAB_INSTR_GET_rs(&this->instr));
}
Registers::Rsp::Gpr InstructionRsp::GetRsp_rt() const {
#ifdef RAB_SANITY_CHECKS
if (!hasOperandAlias(OperandType::rsp_rt)) {
// TODO: make a rabbitizer exception class
throw std::runtime_error("Instruction '" + getOpcodeName() + "' does not have 'rt' operand.");
}
#endif
return static_cast<Registers::Rsp::Gpr>(RAB_INSTR_GET_rt(&this->instr));
}
Registers::Rsp::Gpr InstructionRsp::GetRsp_rd() const {
#ifdef RAB_SANITY_CHECKS
if (!hasOperandAlias(OperandType::rsp_rd)) {
// TODO: make a rabbitizer exception class
throw std::runtime_error("Instruction '" + getOpcodeName() + "' does not have 'rd' operand.");
}
#endif
return static_cast<Registers::Rsp::Gpr>(RAB_INSTR_GET_rd(&this->instr));
}
Registers::Rsp::Cop0 InstructionRsp::GetRsp_cop0d() const {
#ifdef RAB_SANITY_CHECKS
if (!hasOperandAlias(OperandType::rsp_cop0d)) {
// TODO: make a rabbitizer exception class
throw std::runtime_error("Instruction '" + getOpcodeName() + "' does not have 'cop0d' operand.");
}
#endif
return static_cast<Registers::Rsp::Cop0>(RAB_INSTR_GET_cop0d(&this->instr));
}
Registers::Rsp::Cop2 InstructionRsp::GetRsp_cop2t() const {
#ifdef RAB_SANITY_CHECKS
if (!hasOperandAlias(OperandType::rsp_cop2t)) {
// TODO: make a rabbitizer exception class
throw std::runtime_error("Instruction '" + getOpcodeName() + "' does not have 'cop2t' operand.");
}
#endif
return static_cast<Registers::Rsp::Cop2>(RAB_INSTR_RSP_GET_cop2t(&this->instr));
}
Registers::Rsp::Cop2Control InstructionRsp::GetRsp_cop2cd() const {
#ifdef RAB_SANITY_CHECKS
if (!hasOperandAlias(OperandType::rsp_cop2t)) {
// TODO: make a rabbitizer exception class
throw std::runtime_error("Instruction '" + getOpcodeName() + "' does not have 'cop2cd' operand.");
}
#endif
return static_cast<Registers::Rsp::Cop2Control>(RAB_INSTR_RSP_GET_cop2cd(&this->instr));
}
Registers::Rsp::Vector InstructionRsp::GetRsp_vs() const {
#ifdef RAB_SANITY_CHECKS
if (!hasOperandAlias(OperandType::rsp_vs)) {
// TODO: make a rabbitizer exception class
throw std::runtime_error("Instruction '" + getOpcodeName() + "' does not have 'vs' operand.");
}
#endif
return static_cast<Registers::Rsp::Vector>(RAB_INSTR_RSP_GET_vs(&this->instr));
}
Registers::Rsp::Vector InstructionRsp::GetRsp_vt() const {
#ifdef RAB_SANITY_CHECKS
if (!hasOperandAlias(OperandType::rsp_vt)) {
// TODO: make a rabbitizer exception class
throw std::runtime_error("Instruction '" + getOpcodeName() + "' does not have 'vt' operand.");
}
#endif
return static_cast<Registers::Rsp::Vector>(RAB_INSTR_RSP_GET_vt(&this->instr));
}
Registers::Rsp::Vector InstructionRsp::GetRsp_vd() const {
#ifdef RAB_SANITY_CHECKS
if (!hasOperandAlias(OperandType::rsp_vd)) {
// TODO: make a rabbitizer exception class
throw std::runtime_error("Instruction '" + getOpcodeName() + "' does not have 'vd' operand.");
}
#endif
return static_cast<Registers::Rsp::Vector>(RAB_INSTR_RSP_GET_vd(&this->instr));
}
uint8_t InstructionRsp::GetRsp_elementhigh() const {
return RAB_INSTR_RSP_GET_elementhigh(&this->instr);
}
uint8_t InstructionRsp::GetRsp_elementlow() const {
return RAB_INSTR_RSP_GET_elementlow(&this->instr);
}
uint8_t InstructionRsp::GetRsp_index() const {
return RAB_INSTR_RSP_GET_index(&this->instr);
}
uint8_t InstructionRsp::GetRsp_de() const {
return RAB_INSTR_RSP_GET_de(&this->instr);
}

View File

@ -14,11 +14,14 @@
extern "C" {
#endif
#define RAB_REGISTERS_COUNT 32
typedef struct RabbitizerRegistersTracker {
RabbitizerTrackedRegisterState registers[32];
RabbitizerTrackedRegisterState registers[RAB_REGISTERS_COUNT];
} RabbitizerRegistersTracker;
// TODO: Change functions which use parameters as a way to return values into actual structs returned by the functions
NON_NULL(1)
void RabbitizerRegistersTracker_init(RabbitizerRegistersTracker *self, const RabbitizerRegistersTracker *other);

View File

@ -3,6 +3,7 @@
#ifndef RABBITIZER_H
#define RABBITIZER_H
#pragma once
#include "common/Utils.h"
#include "common/RabbitizerVersion.h"

View File

@ -21,18 +21,6 @@ setup(
extra_compile_args = [
"-std=c11",
"-Wall",
#"-Wextra",
# "-Wpedantic", # binary constants :s
#"-Wno-cast-function-type",
#"-Werror=implicit-function-declaration",
#"-Werror=incompatible-pointer-types",
#"-Werror=vla",
#"-Werror=switch",
#"-Werror=implicit-fallthrough",
#"-Werror=unused-function",
#"-Werror=unused-parameter",
#"-Werror=shadow",
# "-Werror",
"-g",
],
),

View File

@ -155,6 +155,9 @@ bool RabbitizerInstruction_hasOperandAlias(const RabbitizerInstruction *self, Ra
if (RabbitizerInstruction_hasOperand(self, RAB_OPERAND_cpu_immediate_base)) {
return true;
}
if (RabbitizerInstruction_hasOperand(self, RAB_OPERAND_cpu_branch_target_label)) {
return true;
}
if (RabbitizerInstruction_hasOperand(self, RAB_OPERAND_rsp_immediate_base)) {
return true;
}

16
tests/cplusplus/test.cpp Normal file
View File

@ -0,0 +1,16 @@
/* SPDX-FileCopyrightText: © 2022 Decompollaborate */
/* SPDX-License-Identifier: MIT */
#include "instructions/InstructionCpu.hpp"
int main() {
uint32_t word = 0x8D4A7E18; // lw
uint32_t vram = 0x80000000;
int extraLJust = 5;
rabbitizer::InstructionCpu instr(word, vram);
printf("%08X: %s\n", word, instr.disassemble(extraLJust).c_str());
return 0;
}