forked from google/binexport
-
Notifications
You must be signed in to change notification settings - Fork 0
/
instruction.h
161 lines (134 loc) · 5.74 KB
/
instruction.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// Copyright 2011-2024 Google LLC
//
// 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
//
// https://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.
#ifndef INSTRUCTION_H_
#define INSTRUCTION_H_
#include <ostream>
#include <string>
#include <vector>
#include "third_party/absl/container/node_hash_set.h"
#include "third_party/zynamics/binexport/operand.h"
#include "third_party/zynamics/binexport/util/range.h"
class FlowGraph;
class AddressSpace;
enum {
FLAG_NONE = 0,
// Used in main disassembly loop: instruction address already visited.
FLAG_VISITED = 1 << 0,
// This is a flow instruction and continues to the next (as opposed to jmps or
// calls).
// TODO(soerenme) As olonho@ pointed out, this flag is used somewhat
// inconsistently throughout the code base. We should be using the following
// definition: if the flag is set, execution is guaranteed to flow to the next
// instruction. I.e. branches and switches do not have it set. Calls may or
// may not, depending on whether they return.
FLAG_FLOW = 1 << 1,
// This instruction has already been exported (used in database writer).
FLAG_EXPORTED = 1 << 2,
// This instruction is a branch, conditional or unconditional. Currently only
// set by Bea. Intentionally the same value as FLAG_EXPORTED as they are both
// used in isolated and independent contexts and can be reset/forgotten after
// use.
FLAG_BRANCH = 1 << 2,
// The instruction was matched by the library signatures.
FLAG_LIB = 1 << 3,
// This instruction is invalid.
FLAG_INVALID = 1 << 4,
// This instruction is a call.
FLAG_CALL = 1 << 5,
// A switch table or vtable starts at this address.
FLAG_TABLE_START = 1 << 6,
// This instruction is a NOP instruction.
FLAG_NOP = 1 << 7,
// This instruction is an entry point.
FLAG_ENTRY_POINT = 1 << 8,
};
#pragma pack(push, 1)
class Instruction {
public:
using GetBytesCallback = std::function<std::string(const Instruction&)>;
using StringCache = absl::node_hash_set<std::string>;
explicit Instruction(Address address, Address next_instruction = 0,
uint16_t size = 0, const std::string& mnemonic = "",
const Operands& operands = Operands());
Instruction& operator=(const Instruction&);
Instruction(const Instruction&);
~Instruction();
static const std::string* CacheString(const std::string& value);
static void SetBitness(int bitness);
static int GetBitness();
static void SetGetBytesCallback(GetBytesCallback callback);
static void SetMemoryFlags(AddressSpace* flags);
static void SetVirtualMemory(AddressSpace* virtual_memory);
static bool IsNegativeValue(int64_t value);
uint8_t GetOperandCount() const;
Operands::iterator begin() const;
Operands::iterator end() const;
Operands::const_iterator cbegin() const;
Operands::const_iterator cend() const;
const Operand& GetOperand(int index) const;
// TODO(cblichmann): Remove these again as part of improving the overall API
// of this class.
const Operand& GetFirstOperand() const;
const Operand& GetSecondOperand() const;
const Operand& GetThirdOperand() const;
Address GetAddress() const;
int GetSize() const;
Address GetNextInstruction() const;
void SetNextInstruction(Address address);
const std::string& GetMnemonic() const;
std::string GetBytes() const;
uint16_t GetInDegree() const;
void AddInEdge();
void Render(std::ostream* stream, const FlowGraph& flow_graph) const;
bool IsFlow() const;
bool IsExported() const;
static bool IsExported(Address address);
void SetExported(bool exported);
void SetFlag(uint8_t flag, bool value);
bool HasFlag(uint8_t flag) const;
private:
static thread_local int instance_count_;
static thread_local StringCache string_cache_;
static thread_local Operands operands_;
static thread_local int bitness_;
static thread_local GetBytesCallback get_bytes_callback_;
static thread_local AddressSpace* flags_;
static thread_local AddressSpace* virtual_memory_;
const std::string* mnemonic_; // 4|8 + overhead in stringcache
Address address_; // 8
uint32_t operand_index_; // 4 + overhead in operand pointer vector
uint8_t operand_count_; // 1
uint16_t in_degree_; // 2 TODO(cblichmann): in-degree count in edges.
uint8_t size_; // 1
};
#pragma pack(pop)
// TODO(cblichmann): Remove this hack. It's here because IDA defines a global
// variable of the same name.
namespace detego {
using Instructions = std::vector<Instruction>;
} // namespace detego
using namespace detego; // NOLINT
using InstructionRange = Range<detego::Instructions>;
void SortInstructions(detego::Instructions* instructions);
Instructions::const_iterator GetInstructionFromRange(
const InstructionRange& range, Address address);
Instructions::iterator GetInstructionFromRange(InstructionRange* range,
Address address);
Instructions::iterator GetInstruction(detego::Instructions* instructions,
Address address);
Instructions::iterator GetNextInstruction(detego::Instructions* instructions,
Instructions::iterator instruction);
std::string RenderOperands(const Instruction& instruction,
const FlowGraph& flow_graph);
#endif // INSTRUCTION_H_