1 #pragma once
2 
3 #include <memory>
4 #include <functional>
5 #include <algorithm>
6 #include <cstdint>
7 #include <string>
8 #include <vector>
9 #include <deque>
10 #include <unordered_map>
11 #include <map>
12 #include <list>
13 #include <type_traits>
14 #include <set>
15 #include "types/base_types.h"
16 #include "types/buffer/abstractbuffer.h"
17 #include "types/buffer/bufferview.h"
18 #include "support/utils.h"
19 #include "redasm_macros.h"
20 #include "redasm_context.h"
21 
22 #define ENTRY_FUNCTION                             "__redasm_entry__"
23 #define START_FUNCTION                             "__redasm_start__"
24 #define REGISTER_INVALID                           s64(-1)
25 #define BRANCH_DIRECTION(instruction, destination) (static_cast<s64>(destination) - static_cast<s64>(instruction->address))
26 
27 namespace REDasm {
28 
29 constexpr size_t npos = static_cast<size_t>(-1);
30 
log(const std::string & s)31 inline void log(const std::string& s) { Context::settings.logCallback(s); }
problem(const std::string & s)32 inline void problem(const std::string& s) { Context::problem(s); }
logproblem(const std::string & s)33 inline void logproblem(const std::string& s) { REDasm::log(s); Context::problem(s); }
34 
status(const std::string & s)35 inline void status(const std::string& s) {
36     CONTEXT_DEBOUNCE_CHECK
37     Context::settings.statusCallback(s);
38 }
39 
statusProgress(const std::string & s,size_t p)40 inline void statusProgress(const std::string& s, size_t p) {
41     CONTEXT_DEBOUNCE_CHECK
42     Context::settings.statusCallback(s);
43     Context::settings.progressCallback(p);
44 }
45 
statusAddress(const std::string & s,address_t address)46 inline void statusAddress(const std::string& s, address_t address) {
47     CONTEXT_DEBOUNCE_CHECK
48     Context::settings.statusCallback(s + " @ " + REDasm::hex(address));
49 }
50 
makePath(const std::string & p,T...args)51 template<typename... T> std::string makePath(const std::string& p, T... args) {
52     std::string path = p;
53     std::deque<std::string> v = { args... };
54 
55     for(size_t i = 0; i < v.size(); i++)
56     {
57         if(!path.empty() && (path.back() != Context::dirSeparator[0]))
58             path += Context::dirSeparator;
59 
60         path += v[i];
61     }
62 
63     return path;
64 }
65 
66 std::string fileName(const std::string& path);
67 std::string fileNameOnly(const std::string& path);
68 std::string filePath(const std::string& path);
69 
makeRntPath(const std::string & p,T...args)70 template<typename...T> std::string makeRntPath(const std::string& p, T... args) { return REDasm::makePath(Context::settings.searchPath, p, args...); }
makeDbPath(const std::string & p,T...args)71 template<typename...T> std::string makeDbPath(const std::string& p, T... args) { return REDasm::makeRntPath("database", p, args...); }
makeLoaderPath(const std::string & p,T...args)72 template<typename...T> std::string makeLoaderPath(const std::string& p, T... args) { return REDasm::makeDbPath("loaders", p, args...); }
makeSignaturePath(const std::string & p,T...args)73 template<typename...T> std::string makeSignaturePath(const std::string& p, T... args) { return REDasm::makeDbPath("signatures", p, args...); }
74 
75 enum class SegmentType: u32 {
76     None = 0x00000000,
77     Code = 0x00000001,
78     Data = 0x00000002,
79     Bss  = 0x00000004,
80 };
81 
82 ENUM_FLAGS_OPERATORS(SegmentType)
83 
84 enum class InstructionType: u32 {
85     None            = 0x00000000, Stop = 0x00000001, Nop = 0x00000002,
86     Jump            = 0x00000004, Call = 0x00000008,
87     Add             = 0x00000010, Sub  = 0x00000020, Mul = 0x00000040, Div = 0x0000080, Mod = 0x00000100, Lsh = 0x00000200, Rsh = 0x00000400,
88     And             = 0x00000800, Or   = 0x00001000, Xor = 0x00002000, Not = 0x0004000,
89     Push            = 0x00008000, Pop  = 0x00010000,
90     Compare         = 0x00020000, Load = 0x00040000, Store = 0x00080000,
91 
92     Conditional     = 0x01000000, Privileged = 0x02000000,
93     Invalid         = 0x10000000,
94     Branch          = Jump | Call,
95     ConditionalJump = Conditional | Jump,
96     ConditionalCall = Conditional | Call,
97 };
98 
99 ENUM_FLAGS_OPERATORS(InstructionType)
100 
101 enum class OperandType : u32 {
102     None          = 0x00000000,
103     Constant      = 0x00000001,  // Simple constant
104     Register      = 0x00000002,  // Register
105     Immediate     = 0x00000004,  // Immediate Value
106     Memory        = 0x00000008,  // Direct Memory Pointer
107     Displacement  = 0x00000010,  // Indirect Memory Pointer
108 
109     Local         = 0x00010000,  // Local Variable
110     Argument      = 0x00020000,  // Function Argument
111     Target        = 0x00040000,  // Branch destination
112 };
113 
114 ENUM_FLAGS_OPERATORS(OperandType)
115 
116 struct Segment
117 {
SegmentSegment118     Segment(): offset(0), address(0), endaddress(0), type(SegmentType::None) { }
SegmentSegment119     Segment(const std::string& name, offset_t offset, address_t address, u64 psize, u64 vsize, SegmentType type): name(name), offset(offset), endoffset(offset + psize), address(address), endaddress(address + vsize), type(type) { }
sizeSegment120     constexpr s64 size() const { return static_cast<s64>(endaddress - address); }
rawSizeSegment121     constexpr s64 rawSize() const { return static_cast<s64>(endoffset - offset); }
emptySegment122     constexpr bool empty() const { return this->size() <= 0; }
containsSegment123     constexpr bool contains(address_t address) const { return (address >= this->address) && (address < endaddress); }
containsOffsetSegment124     constexpr bool containsOffset(offset_t offset) const { return !is(SegmentType::Bss) && ((offset >= this->offset) && (offset < this->endoffset)); }
isSegment125     constexpr bool is(SegmentType t) const { return type & t; }
isPureCodeSegment126     constexpr bool isPureCode() const { return type == SegmentType::Code; }
127 
128     std::string name;
129     offset_t offset, endoffset;
130     address_t address, endaddress;
131     SegmentType type;
132 };
133 
134 struct RegisterOperand
135 {
RegisterOperandRegisterOperand136     RegisterOperand(): r(REGISTER_INVALID), tag(0) { }
RegisterOperandRegisterOperand137     RegisterOperand(register_id_t r, tag_t tag): r(r), tag(tag) { }
RegisterOperandRegisterOperand138     RegisterOperand(register_id_t r): r(r), tag(0) { }
139 
140     register_id_t r;
141     tag_t tag;
142 
isValidRegisterOperand143     bool isValid() const { return r != REGISTER_INVALID; }
144 };
145 
146 struct DisplacementOperand
147 {
DisplacementOperandDisplacementOperand148     DisplacementOperand(): scale(1), displacement(0) { }
DisplacementOperandDisplacementOperand149     DisplacementOperand(const RegisterOperand& base, const RegisterOperand& index, s64 scale, s64 displacement): base(base), index(index), scale(scale), displacement(displacement) { }
150 
151     RegisterOperand base, index;
152     s64 scale;
153     s64 displacement;
154 };
155 
156 struct Operand
157 {
OperandOperand158     Operand(): type(OperandType::None), tag(0), size(0), index(-1), loc_index(-1), u_value(0) { }
OperandOperand159     Operand(OperandType type, s32 value, s64 idx, tag_t tag): type(type), tag(tag), size(0), index(idx), loc_index(-1), s_value(value) { }
OperandOperand160     Operand(OperandType type, u32 value, s64 idx, tag_t tag): type(type), tag(tag), size(0), index(idx), loc_index(-1), u_value(value) { }
OperandOperand161     Operand(OperandType type, s64 value, s64 idx, tag_t tag): type(type), tag(tag), size(0), index(idx), loc_index(-1), s_value(value) { }
OperandOperand162     Operand(OperandType type, u64 value, s64 idx, tag_t tag): type(type), tag(tag), size(0), index(idx), loc_index(-1), u_value(value) { }
163 
164     OperandType type;
165     tag_t tag;
166     u64 size;
167     s64 index, loc_index;
168     RegisterOperand reg;
169     DisplacementOperand disp;
170     union { s64 s_value; u64 u_value; };
171 
displacementIsDynamicOperand172     constexpr bool displacementIsDynamic() const { return is(OperandType::Displacement) && (disp.base.isValid() || disp.index.isValid()); }
displacementCanBeAddressOperand173     constexpr bool displacementCanBeAddress() const { return is(OperandType::Displacement) && (disp.displacement > 0); }
isCharacterOperand174     constexpr bool isCharacter() const { return is(OperandType::Constant) && (u_value <= 0xFF) && ::isprint(static_cast<u8>(u_value)); }
isNumericOperand175     constexpr bool isNumeric() const { return is(OperandType::Constant) || is(OperandType::Immediate) || is(OperandType::Memory); }
isTargetOperand176     constexpr bool isTarget() const { return type & OperandType::Target; }
isOperand177     constexpr bool is(OperandType t) const { return type & t; }
asTargetOperand178     void asTarget() { type |= OperandType::Target; }
179 
checkCharacterOperand180     bool checkCharacter() {
181         if(!is(OperandType::Immediate) || (u_value > 0xFF) || !::isprint(static_cast<u8>(u_value)))
182             return false;
183 
184         type = OperandType::Constant;
185         return true;
186     }
187 };
188 
189 struct Instruction
190 {
InstructionInstruction191     Instruction(): address(0), type(InstructionType::None), size(0), id(0) { meta.userdata = nullptr; }
~InstructionInstruction192     ~Instruction() { reset(); }
193 
194     std::function<void(void*)> free;
195 
196     std::string mnemonic;
197     std::deque<Operand> operands;
198     address_t address;
199     InstructionType type;
200     u32 size;
201     instruction_id_t id;             // Backend Specific
202 
203     struct {
204         void* userdata;              // It doesn't survive after AssemblerPlugin::decode() by design
205         std::set<address_t> targets; // Precalulated targets
206     } meta;                          // 'meta' is not serialized
207 
isInstruction208     constexpr bool is(InstructionType t) const { return type & t; }
isInvalidInstruction209     constexpr bool isInvalid() const { return type == InstructionType::Invalid; }
opSizeInstruction210     inline void opSize(size_t index, u64 size) { operands[index].size = size; }
opSizeInstruction211     inline u64 opSize(size_t index) const { return operands[index].size; }
endAddressInstruction212     constexpr address_t endAddress() const { return address + size; }
213 
targetsInstruction214     inline std::set<address_t> targets() const { return meta.targets; }
targetInstruction215     inline void target(address_t address) { meta.targets.insert(address); }
216 
targetIdxInstruction217     inline void targetIdx(size_t idx) {
218         if(idx >= operands.size())
219             return;
220 
221         operands[idx].asTarget();
222 
223         if(operands[idx].isNumeric())
224             meta.targets.insert(operands[idx].u_value);
225     }
226 
227     inline Operand* op(size_t idx = 0) { return (idx < operands.size()) ? &operands[idx] : nullptr; }
228     inline Instruction& mem(address_t v, tag_t tag = 0) { operands.emplace_back(OperandType::Memory, v, operands.size(), tag); return *this; }
229     template<typename T> Instruction& cnst(T v, tag_t tag = 0) { operands.emplace_back(OperandType::Constant, v, operands.size(), tag); return *this; }
230     template<typename T> Instruction& imm(T v, tag_t tag = 0) { operands.emplace_back(OperandType::Immediate, v, operands.size(), tag); return *this; }
231     template<typename T> Instruction& disp(register_id_t base, T displacement = 0) { return disp(base, REGISTER_INVALID, displacement); }
dispInstruction232     template<typename T> Instruction& disp(register_id_t base, register_id_t index, T displacement) { return disp(base, index, 1, displacement); }
233     template<typename T> Instruction& disp(register_id_t base, register_id_t index, s64 scale, T displacement);
argInstruction234     template<typename T> Instruction& arg(s64 locindex, register_id_t base, register_id_t index, T displacement) { return local(locindex, base, index, displacement, OperandType::Argument); }
235     template<typename T> Instruction& local(s64 locindex, register_id_t base, register_id_t index, T displacement, OperandType type = OperandType::Local);
236 
237     Instruction& reg(register_id_t r, tag_t tag = 0) {
238         Operand op;
239         op.index = operands.size();
240         op.type = OperandType::Register;
241         op.reg = RegisterOperand(r, tag);
242 
243         operands.emplace_back(op);
244         return *this;
245     }
246 
targetInstruction247     const Operand* target() const {
248         for(const Operand& op : operands) {
249             if(op.isTarget())
250                 return &op;
251         }
252 
253         return nullptr;
254     }
255 
resetInstruction256     void reset() {
257         type = InstructionType::None;
258         size = 0;
259         operands.clear();
260 
261         if(free && meta.userdata) {
262             free(meta.userdata);
263             meta.userdata = nullptr;
264         }
265     }
266 };
267 
disp(register_id_t base,register_id_t index,s64 scale,T displacement)268 template<typename T> Instruction& Instruction::disp(register_id_t base, register_id_t index, s64 scale, T displacement)
269 {
270     Operand op;
271     op.index = operands.size();
272 
273     if((base == REGISTER_INVALID) && (index == REGISTER_INVALID))
274     {
275         op.type = OperandType::Memory;
276         op.u_value = scale * displacement;
277     }
278     else
279     {
280         op.type = OperandType::Displacement;
281         op.disp = DisplacementOperand(RegisterOperand(base), RegisterOperand(index), scale, displacement);
282     }
283 
284     operands.emplace_back(op);
285     return *this;
286 }
287 
local(s64 locindex,register_id_t base,register_id_t index,T displacement,OperandType type)288 template<typename T> Instruction& Instruction::local(s64 locindex, register_id_t base, register_id_t index, T displacement, OperandType type)
289 {
290     Operand op;
291     op.index = operands.size();
292     op.loc_index = locindex;
293     op.type = OperandType::Displacement | type;
294     op.disp = DisplacementOperand(RegisterOperand(base), RegisterOperand(index), 1, displacement);
295 
296     operands.emplace_back(op);
297     return *this;
298 }
299 
300 typedef std::shared_ptr<Instruction> InstructionPtr;
301 typedef std::deque<Operand> OperandList;
302 typedef std::deque<Segment> SegmentList;
303 
304 } // namespace REDasm
305