1 : // Copyright 2012 Google Inc.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include "syzygy/core/disassembler_util.h"
16 :
17 : #include "base/logging.h"
18 : #include "mnemonics.h" // NOLINT
19 :
20 : namespace core {
21 :
22 : bool DecodeOneInstruction(
23 E : uint32 address, const uint8* buffer, size_t length, _DInst* instruction) {
24 E : DCHECK(buffer != NULL);
25 E : DCHECK(instruction != NULL);
26 :
27 E : _CodeInfo code = {};
28 E : code.dt = Decode32Bits;
29 E : code.features = DF_NONE;
30 E : code.codeOffset = address;
31 E : code.codeLen = length;
32 E : code.code = buffer;
33 :
34 E : unsigned int decoded = 0;
35 E : ::memset(instruction, 0, sizeof(instruction));
36 E : _DecodeResult result = distorm_decompose(&code, instruction, 1, &decoded);
37 :
38 E : if (result != DECRES_MEMORYERR && result != DECRES_SUCCESS)
39 i : return false;
40 :
41 E : DCHECK_EQ(1u, decoded);
42 E : DCHECK_GE(length, instruction->size);
43 E : DCHECK_LT(0, instruction->size);
44 :
45 E : return true;
46 E : }
47 :
48 : bool DecodeOneInstruction(
49 E : const uint8* buffer, size_t length, _DInst* instruction) {
50 E : DCHECK(buffer != NULL);
51 E : DCHECK(instruction != NULL);
52 E : if (!DecodeOneInstruction(0x10000000, buffer, length, instruction))
53 i : return false;
54 E : return true;
55 E : }
56 :
57 E : bool IsNop(const _DInst& instruction) {
58 E : switch (instruction.opcode) {
59 : default:
60 : // Only the sequences recognized below qualify as NOP instructions.
61 E : return false;
62 :
63 : case I_XCHG:
64 : // This handles the 1 bytes NOP sequence.
65 : // 1-byte: xchg eax, eax.
66 : return instruction.ops[0].type == O_REG &&
67 : instruction.ops[0].index == RM_AX &&
68 : instruction.ops[1].type == O_REG &&
69 i : instruction.ops[1].index == RM_AX;
70 :
71 : case I_NOP:
72 : // This handles the 2, 4, 5, 7, 8 and 9 byte NOP sequences.
73 : // 2-byte: 66 NOP
74 : // 4-byte: NOP DWORD PTR [EAX + 0] (8-bit displacement)
75 : // 5-byte: NOP DWORD PTR [EAX + EAX*1 + 0] (8-bit displacement)
76 : // 7-byte: NOP DWORD PTR [EAX + 0] (32-bit displacement)
77 : // 8-byte: NOP DWORD PTR [EAX + EAX*1 + 0] (32-bit displacement)
78 : // 9-byte: NOP WORD PTR [EAX + EAX*1 + 0] (32-bit displacement)
79 E : return true;
80 :
81 : case I_LEA:
82 : // This handles the 3 and 6 byte NOP sequences.
83 : // 3-byte: LEA REG, 0 (REG) (8-bit displacement)
84 : // 6-byte: LEA REG, 0 (REG) (32-bit displacement)
85 : return instruction.ops[0].type == O_REG &&
86 : instruction.ops[1].type == O_SMEM &&
87 : instruction.ops[0].index == instruction.ops[1].index &&
88 E : instruction.disp == 0;
89 :
90 : case I_MOV:
91 : // Not documented in the Intel manuals, but we see "mov reg, reg" a lot.
92 : return instruction.ops[0].type == O_REG &&
93 : instruction.ops[1].type == O_REG &&
94 E : instruction.ops[0].index == instruction.ops[1].index;
95 : }
96 E : }
97 :
98 E : bool IsCall(const _DInst& instruction) {
99 E : uint8 fc = META_GET_FC(instruction.meta);
100 E : if (fc == FC_CALL)
101 E : return true;
102 E : return false;
103 E : }
104 :
105 E : bool IsControlFlow(const _DInst& instruction) {
106 E : uint8 fc = META_GET_FC(instruction.meta);
107 : if (fc == FC_CND_BRANCH || fc == FC_UNC_BRANCH ||
108 E : fc == FC_RET || fc == FC_SYS) {
109 E : return true;
110 : }
111 E : return false;
112 E : }
113 :
114 E : bool IsImplicitControlFlow(const _DInst& instruction) {
115 E : uint8 fc = META_GET_FC(instruction.meta);
116 E : if (fc == FC_RET || fc == FC_SYS) {
117 : // Control flow jumps implicitly out of the block.
118 E : return true;
119 E : } else if (fc == FC_UNC_BRANCH && instruction.ops[0].type != O_PC) {
120 : // There is an explicit branch but the target is not explicitly given as
121 : // a PC relative value (i.e., the target is computed, stored in a register,
122 : // stored in a memory location, or otherwise indirect).
123 E : return true;
124 : }
125 E : return false;
126 E : }
127 :
128 E : bool IsInterrupt(const _DInst& instruction) {
129 E : return META_GET_FC(instruction.meta) == FC_INT;
130 E : }
131 :
132 E : bool IsDebugInterrupt(const _DInst& instruction) {
133 : return IsInterrupt(instruction) && instruction.size == 1 &&
134 E : instruction.opcode == I_INT_3;
135 E : }
136 :
137 : } // namespace core
|