OLD | NEW |
---|---|
1 // Copyright 2012 Google Inc. All Rights Reserved. | 1 // Copyright 2012 Google Inc. All Rights Reserved. |
2 // | 2 // |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
4 // you may not use this file except in compliance with 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 | 5 // You may obtain a copy of the License at |
6 // | 6 // |
7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
8 // | 8 // |
9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 // See the License for the specific language governing permissions and | 12 // See the License for the specific language governing permissions and |
13 // limitations under the License. | 13 // limitations under the License. |
14 | 14 |
15 #include "syzygy/core/disassembler_util.h" | 15 #include "syzygy/core/disassembler_util.h" |
16 | 16 |
17 #include <algorithm> | 17 #include <algorithm> |
18 | 18 |
19 #include "base/logging.h" | 19 #include "base/logging.h" |
20 #include "base/strings/stringprintf.h" | 20 #include "base/strings/stringprintf.h" |
21 #include "mnemonics.h" // NOLINT | 21 #include "mnemonics.h" // NOLINT |
22 | 22 |
23 namespace core { | 23 namespace core { |
24 | 24 |
25 namespace { | 25 namespace { |
26 | 26 |
27 // Return the size of a 3-byte VEX encoded instruction. | 27 // Opcode of the 3-byte VEX instructions. |
28 const uint8_t kThreeByteVexOpcode = 0xC4; | |
29 | |
30 // Structure representing a Mod R/M byte, it has the following format: | |
31 // +---+---+---+---+---+---+---+---+ | |
32 // | mod |reg/opcode | r/m | | |
33 // +---+---+---+---+---+---+---+---+ | |
34 // | |
35 // Here's a description of the different fields (from | |
36 // https://en.wikipedia.org/wiki/VEX_prefix): | |
37 // - mod: combined with the r/m field, encodes either 8 registers or 2 | |
huangs
2017/05/01 18:54:13
3 addressing modes, not 2?
Sébastien Marchand
2017/05/01 21:19:27
It should be "24" addressing modes (according to W
| |
38 // addressing modes. Also encodes opcode information for some | |
39 // instructions. | |
40 // - reg/opcode: specifies either a register or three more bits of | |
41 // opcode information, as specified in the primary opcode byte. | |
42 // - r/m: can specify a register as an operand, or combine with the mod | |
43 // field to encode an addressing mode. | |
44 // | |
45 // The |mod| field can have the following values: | |
46 // - 0b00: Register indirect addressing mode or SIB with no displacement | |
47 // (if R/M = 0b100) or displacement only addressing mode (if R/M = 0b101). | |
huangs
2017/05/01 18:54:13
NIT: "R/M" here should be "r/m"?
Sébastien Marchand
2017/05/01 21:19:27
Done.
| |
48 // - 0b01: One-byte signed displacement follows addressing mode byte(s). | |
49 // - 0b10: Four-byte signed displacement follows addressing mode byte(s). | |
50 // - 0b11: Register addressing mode. | |
51 struct ModRMByte { | |
52 // Constructor. | |
53 // @param value The Value used to initialize this Mod R/M byte. | |
54 explicit ModRMByte(uint8_t value) : raw_value(value) {} | |
55 | |
56 union { | |
57 uint8_t raw_value; | |
58 struct { | |
59 uint8_t r_m : 3; | |
60 uint8_t reg_or_opcode : 3; | |
61 uint8_t mod : 2; | |
62 }; | |
63 }; | |
64 }; | |
65 | |
66 // Calculates the number of bytes used to encode a Mod R/M operand. | |
67 // @param ci The code information for this instruction. | |
68 // @param no_register_addressing_mode Indicates if the instruction supports | |
huangs
2017/05/01 18:54:13
NIT: Style-wise it's better to avoid negatives, i.
Sébastien Marchand
2017/05/01 21:19:27
Done, you're right it's cleaner like this (and not
| |
69 // the register addressing mode (value of |mod| of 0b11). | |
70 // @returns the total size of this Mod R/M operand (in bytes), 0 on failure. | |
71 size_t GetModRMOperandBytesSize(const _CodeInfo* ci, | |
72 bool no_register_addressing_mode) { | |
73 DCHECK_GE(ci->codeLen, 5); | |
74 | |
75 // If SIB (Scale*Index+Base) is specified then the operand uses an | |
76 // additional SIB byte. | |
77 const uint8_t kSIBValue = 0b100; | |
78 ModRMByte modRM_byte(ci->code[4]); | |
79 | |
80 switch (modRM_byte.mod) { | |
81 case 0b00: { | |
82 if (modRM_byte.r_m == kSIBValue) { | |
83 CHECK_GE(ci->codeLen, 6); | |
84 // The SIB byte has the following layout: | |
85 // +---+---+---+---+---+---+---+---+ | |
86 // | scale | index | base | | |
87 // +---+---+---+---+---+---+---+---+ | |
88 // | |
89 // If |base| = 5 then there's an additional 4-byte used to encode the | |
90 // displacement, e.g.: | |
91 // vpbroadcastd ymm0, DWORD PTR [ebp+eax*8+0x76543210] | |
92 const uint8_t kSIBImm32Mask = 0b111; | |
huangs
2017/05/01 18:54:14
NIT: kSIBBaseMask?
Sébastien Marchand
2017/05/01 21:19:27
Done.
| |
93 if ((ci->code[5] & kSIBImm32Mask) == 5) | |
94 return 6; | |
95 // If |base| != 5 then there's just the SIB byte, e.g.: | |
96 // vpbroadcastd ymm0, DWORD PTR [ecx+edx*1] | |
97 return 2; | |
98 } | |
99 if (modRM_byte.r_m == 0b101) { | |
100 // Displacement only addressing mode, e.g.: | |
101 // vpbroadcastb xmm2, BYTE PTR ds:0x12345678 | |
102 return 5; | |
103 } | |
104 // Register indirect addressing mode, e.g.: | |
105 // vpbroadcastb xmm2, BYTE PTR [eax] | |
106 return 1; | |
107 } | |
108 case 0b01: { | |
109 // One-byte displacement. | |
110 if (modRM_byte.r_m == kSIBValue) { | |
111 // Additional SIB byte, e.g.: | |
112 // vpbroadcastb xmm2, BYTE PTR [eax+edx*1+0x42] | |
113 return 3; | |
114 } | |
115 // No SIB byte, e.g.: | |
116 // vpbroadcastb xmm2, BYTE PTR [eax+0x42] | |
117 return 2; | |
118 } | |
119 case 0b10: { | |
120 // One-byte displacement. | |
121 if (modRM_byte.r_m == kSIBValue) { | |
122 // Additional SIB byte, e.g.: | |
123 // vpbroadcastb xmm0, BYTE PTR [edx+edx*1+0x12345678] | |
124 return 6; | |
125 } | |
126 // No SIB byte, e.g.: | |
127 // vpbroadcastb xmm0, BYTE PTR [eax+0x34567812] | |
128 return 5; | |
129 } | |
130 case 0b11: | |
131 // Register addressing mode, e.g.: | |
132 // vpbroadcastb xmm2, BYTE PTR [eax] | |
133 if (no_register_addressing_mode) { | |
134 LOG(ERROR) << "Unexpected |mod| value of 0b11 for an instruction that " | |
135 << "doesn't support it."; | |
136 return 0; | |
137 } | |
138 return 1; | |
139 default: | |
140 NOTREACHED(); | |
141 } | |
142 | |
143 return 0; | |
144 } | |
145 | |
146 // Structure representing a 3-byte VEX encoded instruction. | |
28 // | 147 // |
29 // The layout of these instructions is as follows, starting with a byte with | 148 // The layout of these instructions is as follows, starting with a byte with |
30 // value 0xC4: | 149 // value 0xC4: |
150 // - Opcode indicating that this is a 3-byte VEX instruction: | |
151 // +---+---+---+---+---+---+---+---+ | |
152 // | 1 1 0 0 0 1 0 0 | | |
153 // +---+---+---+---+---+---+---+---+ | |
31 // - First byte: | 154 // - First byte: |
32 // +---+---+---+---+---+---+---+---+ | 155 // +---+---+---+---+---+---+---+---+ |
33 // | 1 1 0 0 0 1 0 0 | | 156 // |~R |~X |~B | map_select | |
34 // +---+---+---+---+---+---+---+---+ | 157 // +---+---+---+---+---+---+---+---+ |
35 // - Second byte: | 158 // - Second byte: |
36 // +---+---+---+---+---+---+---+---+ | 159 // +---+---+---+---+---+---+---+---+ |
37 // |~R |~X |~B | map_select | | |
38 // +---+---+---+---+---+---+---+---+ | |
39 // - Third byte: | |
40 // +---+---+---+---+---+---+---+---+ | |
41 // |W/E| ~vvvv | L | pp | | 160 // |W/E| ~vvvv | L | pp | |
42 // +---+---+---+---+---+---+---+---+ | 161 // +---+---+---+---+---+---+---+---+ |
43 // - Fourth byte: The opcode for this instruction. | 162 // - Third byte: The opcode for this instruction. |
44 // | 163 // |
45 // |map_select| Indicates the opcode map that should be used for this | 164 // If this instructions takes some operands then it's followed by a ModR/M byte |
46 // instruction. | 165 // and some optional bytes to represent the operand. We don't represent these |
47 // | 166 // optional bytes here. |
48 // See http://wiki.osdev.org/X86-64_Instruction_Encoding#Three_byte_VEX_escape_p refix | 167 // |
168 // See | |
169 // http://wiki.osdev.org/X86-64_Instruction_Encoding#Three_byte_VEX_escape_prefi x | |
49 // for more details. | 170 // for more details. |
171 struct ThreeBytesVexInstruction { | |
172 explicit ThreeBytesVexInstruction(const uint8_t* data) { | |
173 DCHECK_NE(nullptr, data); | |
174 CHECK_EQ(kThreeByteVexOpcode, data[0]); | |
175 first_byte = data[1]; | |
176 second_byte = data[2]; | |
177 opcode = data[3]; | |
178 } | |
179 | |
180 // Check if this instruction match the expectations that we have for it. | |
huangs
2017/05/01 18:54:14
NIT: Checks
Sébastien Marchand
2017/05/01 21:19:27
Thanks.
| |
181 // | |
182 // It compares the value of several fields that can have an impact on the | |
183 // instruction size and make sure that they have the expected value. | |
184 // | |
185 // @param expected_inv_rxb The expected value for |inv_rxb|. | |
186 // @param expected_we The expected value for |we|. | |
187 // @param expected_l The expected value for |l|. | |
188 // @param expected_pp The expected value for |pp|. | |
189 // @returns true if all the expectations are met, false otherwise. | |
190 bool MatchExpectations(uint8_t expected_inv_rxb, | |
191 uint8_t expected_we, | |
192 uint8_t expected_l, | |
193 uint8_t expected_pp, | |
194 const char* instruction); | |
195 | |
196 // First byte, contains the RXB value and map_select. | |
197 union { | |
198 uint8_t first_byte; | |
199 struct { | |
200 uint8_t map_select : 5; | |
201 uint8_t inv_rxb : 3; | |
202 }; | |
203 }; | |
204 // Second byte, contains the W/E, ~vvvv, L and pp values. | |
205 union { | |
206 uint8_t second_byte; | |
207 struct { | |
208 uint8_t pp : 2; | |
209 uint8_t l : 1; | |
210 uint8_t inv_vvvv : 4; | |
211 uint8_t w_e : 1; | |
212 }; | |
213 }; | |
214 | |
215 // Opcode of this instruction. | |
216 uint8_t opcode; | |
217 }; | |
218 | |
219 // Check if |value| is equal to |expected| value and log verbosely if it's not | |
huangs
2017/05/01 18:54:13
NIT: Checks
Sébastien Marchand
2017/05/01 21:19:27
Thanks again :)
| |
220 // the case. | |
221 bool CheckField(uint8_t expected_value, | |
222 uint8_t value, | |
223 const char* field_name, | |
224 const char* instruction) { | |
225 if (expected_value != value) { | |
226 LOG(ERROR) << "Unexpected " << field_name << " value for the " | |
227 << instruction << " instruction, expecting 0x" << std::hex | |
228 << static_cast<size_t>(expected_value) << " but got 0x" | |
229 << static_cast<size_t>(value) << "." << std::dec; | |
230 return false; | |
231 } | |
232 return true; | |
233 } | |
234 | |
235 bool ThreeBytesVexInstruction::MatchExpectations(uint8_t expected_inv_rxb, | |
236 uint8_t expected_we, | |
237 uint8_t expected_l, | |
238 uint8_t expected_pp, | |
239 const char* instruction) { | |
240 if (!CheckField(expected_inv_rxb, inv_rxb, "inv_rxb", instruction)) | |
241 return false; | |
242 if (!CheckField(expected_we, w_e, "we", instruction)) | |
243 return false; | |
244 if (!CheckField(expected_l, l, "l", instruction)) | |
245 return false; | |
246 if (!CheckField(expected_pp, pp, "pp", instruction)) | |
247 return false; | |
248 return true; | |
249 } | |
250 | |
251 // Return the size of a 3-byte VEX encoded instruction. | |
huangs
2017/05/01 18:54:13
NIT: Returns
Sébastien Marchand
2017/05/01 21:19:27
... And again :)
| |
252 // | |
253 // NOTE: We only support the instructions that have been encountered in Chrome | |
254 // and there's some restrictions on which variants of these instructions are | |
255 // supported. | |
50 size_t Get3ByteVexEncodedInstructionSize(_CodeInfo* ci) { | 256 size_t Get3ByteVexEncodedInstructionSize(_CodeInfo* ci) { |
51 DCHECK_EQ(0xC4, ci->code[0]); | 257 // A 3-byte VEX instructions has always a size of 5 bytes or more (the C4 |
52 // Switch case based on the opcode map used by this instruction. | 258 // constant, the 3 VEX bytes and the opcode). |
huangs
2017/05/01 18:54:13
The 3 VEX bytes already includes the opcode. You m
Sébastien Marchand
2017/05/01 21:19:27
Yep, thanks for spotting this.
| |
53 switch (ci->code[1] & 0x1F) { | 259 DCHECK_GE(ci->codeLen, 5); |
260 | |
261 ThreeBytesVexInstruction instruction(ci->code); | |
262 | |
263 const size_t kBaseSize = 4; | |
264 size_t operand_size = 0; | |
265 size_t constants_size = 0; | |
266 | |
267 // Switch case based on the opcode mp used by this instruction. | |
huangs
2017/05/01 18:54:14
Typo: mp?
Sébastien Marchand
2017/05/01 21:19:27
Oops
| |
268 switch (instruction.map_select) { | |
54 case 0x02: { | 269 case 0x02: { |
55 switch (ci->code[3]) { | 270 switch (instruction.opcode) { |
56 case 0x13: return 5; // vcvtps2ps | 271 case 0x13: // vcvtph2ps |
57 case 0x18: return 5; // vbroadcastss | 272 if (instruction.MatchExpectations(0b111, 0, 0, 1, "vcvtph2ps")) |
58 case 0x36: return 5; // vpermd | 273 operand_size = GetModRMOperandBytesSize(ci, false); |
59 case 0x58: return 6; // vpbroadcastd | 274 break; |
60 case 0x5A: return 6; // vbroadcasti128 | 275 case 0x18: // vbroadcastss |
61 case 0x78: return 5; // vpbroadcastb | 276 if (instruction.MatchExpectations(0b111, 0, 1, 1, "vbroadcastss")) |
62 case 0x8C: return 5; // vpmaskmovd | 277 operand_size = GetModRMOperandBytesSize(ci, false); |
63 case 0x8E: return 5; // vpmaskmovd | 278 break; |
64 case 0x90: return 6; // vpgatherdd | 279 case 0x36: // vpermd |
280 if (instruction.MatchExpectations(0b111, 0, 1, 1, "vpermd")) | |
281 operand_size = GetModRMOperandBytesSize(ci, false); | |
282 break; | |
283 case 0x58: // vpbroadcastd | |
284 if (instruction.MatchExpectations(0b111, 0, 1, 1, "vpbroadcastd")) | |
285 operand_size = GetModRMOperandBytesSize(ci, false); | |
286 break; | |
287 case 0x5A: // vbroadcasti128 | |
288 if (instruction.MatchExpectations(0b111, 0, 1, 1, "vbroadcasti128")) | |
289 operand_size = GetModRMOperandBytesSize(ci, true); | |
290 break; | |
291 case 0x78: // vpbroadcastb | |
292 if (instruction.MatchExpectations(0b111, 0, 0, 1, "vpbroadcastb")) | |
293 operand_size = GetModRMOperandBytesSize(ci, false); | |
294 break; | |
295 case 0x8C: // vpmaskmovd | |
296 if (instruction.MatchExpectations(0b111, 0, 1, 1, "vpmaskmovd")) | |
297 operand_size = GetModRMOperandBytesSize(ci, true); | |
298 break; | |
299 case 0x90: // vpgatherdd | |
300 if (instruction.MatchExpectations(0b111, 0, 1, 1, "vpgatherdd")) | |
301 operand_size = GetModRMOperandBytesSize(ci, true); | |
302 break; | |
65 default: | 303 default: |
66 break; | 304 break; |
67 } | 305 } |
68 break; | 306 break; |
69 } | 307 } |
70 case 0x03: { | 308 case 0x03: { |
71 switch (ci->code[3]) { | 309 switch (instruction.opcode) { |
72 case 0x00: return 6; // vpermq | 310 case 0x00: // vpermq |
73 case 0x1D: return 6; // vcvtps2ph | 311 if (instruction.MatchExpectations(0b111, 1, 1, 1, "vpermq")) { |
74 case 0x38: return 7; // vinserti128 | 312 operand_size = GetModRMOperandBytesSize(ci, false); |
75 case 0x39: return 6; // vextracti128 | 313 constants_size = 1; |
314 } | |
315 break; | |
316 case 0x1D: // vcvtps2ph | |
317 if (instruction.MatchExpectations(0b111, 0, 0, 1, "vcvtps2ph")) { | |
318 operand_size = GetModRMOperandBytesSize(ci, false); | |
319 constants_size = 1; | |
320 } | |
321 break; | |
322 case 0x38: // vinserti128 | |
323 if (instruction.MatchExpectations(0b111, 0, 1, 1, "vinserti128")) { | |
324 operand_size = GetModRMOperandBytesSize(ci, false); | |
325 constants_size = 1; | |
326 } | |
327 break; | |
328 case 0x39: // vextracti128 | |
329 if (instruction.MatchExpectations(0b111, 0, 0, 1, "vextracti128")) | |
330 operand_size = GetModRMOperandBytesSize(ci, false); | |
huangs
2017/05/01 18:54:13
constants_size = 1? According to
http://www.feli
Sébastien Marchand
2017/05/01 21:19:27
You're right, the unittest for this instruction wa
| |
76 default: break; | 331 default: break; |
77 } | 332 } |
78 break; | 333 break; |
79 } | 334 } |
80 default: | 335 default: |
81 break; | 336 break; |
82 } | 337 } |
83 | 338 |
339 if (operand_size != 0) | |
340 return kBaseSize + operand_size + constants_size; | |
341 | |
84 // Print the instructions that we haven't been able to decompose in a format | 342 // Print the instructions that we haven't been able to decompose in a format |
85 // that can easily be pasted into ODA (https://onlinedisassembler.com/). | 343 // that can easily be pasted into ODA (https://onlinedisassembler.com/). |
86 const int kMaxBytes = 10; | 344 const int kMaxBytes = 10; |
87 size_t byte_count = std::min(ci->codeLen, kMaxBytes); | 345 size_t byte_count = std::min(ci->codeLen, kMaxBytes); |
88 std::string instruction_bytes; | 346 std::string instruction_bytes; |
89 for (size_t i = 0; i < byte_count; ++i) { | 347 for (size_t i = 0; i < byte_count; ++i) { |
90 base::StringAppendF(&instruction_bytes, "%02X", ci->code[i]); | 348 base::StringAppendF(&instruction_bytes, "%02X", ci->code[i]); |
91 if (i != byte_count - 1) | 349 if (i != byte_count - 1) |
92 instruction_bytes += " "; | 350 instruction_bytes += " "; |
93 } | 351 } |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
143 CHECK_EQ(O_NONE, result->ops[3].type); | 401 CHECK_EQ(O_NONE, result->ops[3].type); |
144 | 402 |
145 --result->addr; | 403 --result->addr; |
146 ++result->size; | 404 ++result->size; |
147 | 405 |
148 *used_instructions_count = 1; | 406 *used_instructions_count = 1; |
149 *ret = DECRES_SUCCESS; | 407 *ret = DECRES_SUCCESS; |
150 | 408 |
151 return true; | 409 return true; |
152 } | 410 } |
411 } else if (ci->code[0] == kThreeByteVexOpcode) { | |
412 size = Get3ByteVexEncodedInstructionSize(ci); | |
153 } | 413 } |
154 | 414 |
155 if (ci->code[0] == 0xC4) | |
156 size = Get3ByteVexEncodedInstructionSize(ci); | |
157 | |
158 if (size == 0) | 415 if (size == 0) |
159 return false; | 416 return false; |
160 | 417 |
161 // We set the bare minimum properties that are required for any | 418 // We set the bare minimum properties that are required for any |
162 // subsequent processing that we perform. | 419 // subsequent processing that we perform. |
163 | 420 |
164 *used_instructions_count = 1; | 421 *used_instructions_count = 1; |
165 | 422 |
166 ::memset(result, 0, sizeof(result[0])); | 423 ::memset(result, 0, sizeof(result[0])); |
167 result[0].addr = ci->codeOffset; | 424 result[0].addr = ci->codeOffset; |
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
444 | 701 |
445 default: return assm::kRegisterNone; | 702 default: return assm::kRegisterNone; |
446 } | 703 } |
447 } | 704 } |
448 | 705 |
449 const Register& GetRegister(uint32_t distorm_reg_type) { | 706 const Register& GetRegister(uint32_t distorm_reg_type) { |
450 return Register::Get(GetRegisterId(distorm_reg_type)); | 707 return Register::Get(GetRegisterId(distorm_reg_type)); |
451 } | 708 } |
452 | 709 |
453 } // namespace core | 710 } // namespace core |
OLD | NEW |