1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | //***************************************************************************** |
5 | // File: Amd64walker.cpp |
6 | // |
7 | |
8 | // |
9 | // AMD64 instruction decoding/stepping logic |
10 | // |
11 | //***************************************************************************** |
12 | |
13 | #include "stdafx.h" |
14 | |
15 | #include "walker.h" |
16 | |
17 | #include "frames.h" |
18 | #include "openum.h" |
19 | |
20 | #ifdef _TARGET_AMD64_ |
21 | |
22 | // |
23 | // The AMD64 walker is currently pretty minimal. It only recognizes call and return opcodes, plus a few jumps. The rest |
24 | // is treated as unknown. |
25 | // |
26 | void NativeWalker::Decode() |
27 | { |
28 | const BYTE *ip = m_ip; |
29 | |
30 | m_type = WALK_UNKNOWN; |
31 | m_skipIP = NULL; |
32 | m_nextIP = NULL; |
33 | |
34 | BYTE rex = NULL; |
35 | |
36 | LOG((LF_CORDB, LL_INFO100000, "NW:Decode: m_ip 0x%x\n" , m_ip)); |
37 | |
38 | BYTE prefix = *ip; |
39 | if (prefix == 0xcc) |
40 | { |
41 | prefix = (BYTE)DebuggerController::GetPatchedOpcode(m_ip); |
42 | LOG((LF_CORDB, LL_INFO100000, "NW:Decode 1st byte was patched, might have been prefix\n" )); |
43 | } |
44 | |
45 | // |
46 | // Skip instruction prefixes |
47 | // |
48 | do |
49 | { |
50 | switch (prefix) |
51 | { |
52 | // Segment overrides |
53 | case 0x26: // ES |
54 | case 0x2E: // CS |
55 | case 0x36: // SS |
56 | case 0x3E: // DS |
57 | case 0x64: // FS |
58 | case 0x65: // GS |
59 | |
60 | // Size overrides |
61 | case 0x66: // Operand-Size |
62 | case 0x67: // Address-Size |
63 | |
64 | // Lock |
65 | case 0xf0: |
66 | |
67 | // String REP prefixes |
68 | case 0xf2: // REPNE/REPNZ |
69 | case 0xf3: |
70 | LOG((LF_CORDB, LL_INFO10000, "NW:Decode: prefix:%0.2x " , prefix)); |
71 | ip++; |
72 | continue; |
73 | |
74 | // REX register extension prefixes |
75 | case 0x40: |
76 | case 0x41: |
77 | case 0x42: |
78 | case 0x43: |
79 | case 0x44: |
80 | case 0x45: |
81 | case 0x46: |
82 | case 0x47: |
83 | case 0x48: |
84 | case 0x49: |
85 | case 0x4a: |
86 | case 0x4b: |
87 | case 0x4c: |
88 | case 0x4d: |
89 | case 0x4e: |
90 | case 0x4f: |
91 | LOG((LF_CORDB, LL_INFO10000, "NW:Decode: REX prefix:%0.2x " , prefix)); |
92 | // make sure to set rex to prefix, not *ip because *ip still represents the |
93 | // codestream which has a 0xcc in it. |
94 | rex = prefix; |
95 | ip++; |
96 | continue; |
97 | |
98 | default: |
99 | break; |
100 | } |
101 | } while (0); |
102 | |
103 | // Read the opcode |
104 | m_opcode = *ip++; |
105 | |
106 | LOG((LF_CORDB, LL_INFO100000, "NW:Decode: ip 0x%x, m_opcode:%0.2x\n" , ip, m_opcode)); |
107 | |
108 | // Don't remove this, when we did the check above for the prefix we didn't modify the codestream |
109 | // and since m_opcode was just taken directly from the code stream it will be patched if we |
110 | // didn't have a prefix |
111 | if (m_opcode == 0xcc) |
112 | { |
113 | m_opcode = (BYTE)DebuggerController::GetPatchedOpcode(m_ip); |
114 | LOG((LF_CORDB, LL_INFO100000, "NW:Decode after patch look up: m_opcode:%0.2x\n" , m_opcode)); |
115 | } |
116 | |
117 | // Setup rex bits if needed |
118 | BYTE rex_b = 0; |
119 | BYTE rex_x = 0; |
120 | BYTE rex_r = 0; |
121 | |
122 | if (rex != NULL) |
123 | { |
124 | rex_b = (rex & 0x1); // high bit to modrm r/m field or SIB base field or OPCODE reg field -- Hmm, when which? |
125 | rex_x = (rex & 0x2) >> 1; // high bit to sib index field |
126 | rex_r = (rex & 0x4) >> 2; // high bit to modrm reg field |
127 | } |
128 | |
129 | // Analyze what we can of the opcode |
130 | switch (m_opcode) |
131 | { |
132 | case 0xff: |
133 | { |
134 | BYTE modrm = *ip++; |
135 | |
136 | // Ignore "inc dword ptr [reg]" instructions |
137 | if (modrm == 0) |
138 | break; |
139 | |
140 | BYTE mod = (modrm & 0xC0) >> 6; |
141 | BYTE reg = (modrm & 0x38) >> 3; |
142 | BYTE rm = (modrm & 0x07); |
143 | |
144 | reg |= (rex_r << 3); |
145 | rm |= (rex_b << 3); |
146 | |
147 | if ((reg < 2) || (reg > 5 && reg < 8) || (reg > 15)) { |
148 | // not a valid register for a CALL or BRANCH |
149 | return; |
150 | } |
151 | |
152 | BYTE *result; |
153 | WORD displace; |
154 | |
155 | // See: Tables A-15,16,17 in AMD Dev Manual 3 for information |
156 | // about how the ModRM/SIB/REX bytes interact. |
157 | |
158 | switch (mod) |
159 | { |
160 | case 0: |
161 | case 1: |
162 | case 2: |
163 | if ((rm & 0x07) == 4) // we have an SIB byte following |
164 | { |
165 | // |
166 | // Get values from the SIB byte |
167 | // |
168 | BYTE sib = *ip; |
169 | |
170 | _ASSERT(sib != NULL); |
171 | |
172 | BYTE ss = (sib & 0xC0) >> 6; |
173 | BYTE index = (sib & 0x38) >> 3; |
174 | BYTE base = (sib & 0x07); |
175 | |
176 | index |= (rex_x << 3); |
177 | base |= (rex_b << 3); |
178 | |
179 | ip++; |
180 | |
181 | // |
182 | // Get starting value |
183 | // |
184 | if ((mod == 0) && ((base & 0x07) == 5)) |
185 | { |
186 | result = 0; |
187 | } |
188 | else |
189 | { |
190 | result = (BYTE *)(size_t)GetRegisterValue(base); |
191 | } |
192 | |
193 | // |
194 | // Add in the [index] |
195 | // |
196 | if (index != 0x4) |
197 | { |
198 | result = result + (GetRegisterValue(index) << ss); |
199 | } |
200 | |
201 | // |
202 | // Finally add in the offset |
203 | // |
204 | if (mod == 0) |
205 | { |
206 | if ((base & 0x07) == 5) |
207 | { |
208 | result = result + *((INT32*)ip); |
209 | displace = 7; |
210 | } |
211 | else |
212 | { |
213 | displace = 3; |
214 | } |
215 | } |
216 | else if (mod == 1) |
217 | { |
218 | result = result + *((INT8*)ip); |
219 | displace = 4; |
220 | } |
221 | else // mod == 2 |
222 | { |
223 | result = result + *((INT32*)ip); |
224 | displace = 7; |
225 | } |
226 | |
227 | } |
228 | else |
229 | { |
230 | // |
231 | // Get the value we need from the register. |
232 | // |
233 | |
234 | // Check for RIP-relative addressing mode. |
235 | if ((mod == 0) && ((rm & 0x07) == 5)) |
236 | { |
237 | displace = 6; // 1 byte opcode + 1 byte modrm + 4 byte displacement (signed) |
238 | result = const_cast<BYTE *>(m_ip) + displace + *(reinterpret_cast<const INT32*>(ip)); |
239 | } |
240 | else |
241 | { |
242 | result = (BYTE *)GetRegisterValue(rm); |
243 | |
244 | if (mod == 0) |
245 | { |
246 | displace = 2; |
247 | } |
248 | else if (mod == 1) |
249 | { |
250 | result = result + *((INT8*)ip); |
251 | displace = 3; |
252 | } |
253 | else // mod == 2 |
254 | { |
255 | result = result + *((INT32*)ip); |
256 | displace = 6; |
257 | } |
258 | } |
259 | } |
260 | |
261 | // |
262 | // Now dereference thru the result to get the resulting IP. |
263 | // |
264 | result = (BYTE *)(*((UINT64*)result)); |
265 | |
266 | break; |
267 | |
268 | case 3: |
269 | default: |
270 | // The operand is stored in a register. |
271 | result = (BYTE *)GetRegisterValue(rm); |
272 | displace = 2; |
273 | |
274 | break; |
275 | |
276 | } |
277 | |
278 | // the instruction uses r8-r15, add in the extra byte to the displacement |
279 | // for the REX prefix which was used to specify the extended register |
280 | if (rex != NULL) |
281 | { |
282 | displace++; |
283 | } |
284 | |
285 | // because we already checked register validity for CALL/BRANCH |
286 | // instructions above we can assume that there is no other option |
287 | if ((reg == 4) || (reg == 5)) |
288 | { |
289 | m_type = WALK_BRANCH; |
290 | } |
291 | else |
292 | { |
293 | m_type = WALK_CALL; |
294 | } |
295 | m_nextIP = result; |
296 | m_skipIP = m_ip + displace; |
297 | break; |
298 | } |
299 | case 0xe8: |
300 | { |
301 | m_type = WALK_CALL; |
302 | |
303 | // Sign-extend the displacement is necessary. |
304 | INT32 disp = *((INT32*)ip); |
305 | m_nextIP = ip + 4 + (disp < 0 ? (disp | 0xffffffff00000000) : disp); |
306 | m_skipIP = ip + 4; |
307 | |
308 | break; |
309 | } |
310 | case 0xe9: |
311 | { |
312 | m_type = WALK_BRANCH; |
313 | |
314 | // Sign-extend the displacement is necessary. |
315 | INT32 disp = *((INT32*)ip); |
316 | m_nextIP = ip + 4 + (disp < 0 ? (disp | 0xffffffff00000000) : disp); |
317 | m_skipIP = ip + 4; |
318 | |
319 | break; |
320 | } |
321 | case 0xc2: |
322 | case 0xc3: |
323 | case 0xca: |
324 | case 0xcb: |
325 | { |
326 | m_type = WALK_RETURN; |
327 | break; |
328 | } |
329 | default: |
330 | break; |
331 | } |
332 | } |
333 | |
334 | |
335 | // |
336 | // Given a regdisplay and a register number, return the value of the register. |
337 | // |
338 | |
339 | UINT64 NativeWalker::GetRegisterValue(int registerNumber) |
340 | { |
341 | if (m_registers == NULL) { |
342 | return 0; |
343 | } |
344 | |
345 | switch (registerNumber) |
346 | { |
347 | case 0: |
348 | return m_registers->pCurrentContext->Rax; |
349 | break; |
350 | case 1: |
351 | return m_registers->pCurrentContext->Rcx; |
352 | break; |
353 | case 2: |
354 | return m_registers->pCurrentContext->Rdx; |
355 | break; |
356 | case 3: |
357 | return m_registers->pCurrentContext->Rbx; |
358 | break; |
359 | case 4: |
360 | return m_registers->pCurrentContext->Rsp; |
361 | break; |
362 | case 5: |
363 | return m_registers->pCurrentContext->Rbp; |
364 | break; |
365 | case 6: |
366 | return m_registers->pCurrentContext->Rsi; |
367 | break; |
368 | case 7: |
369 | return m_registers->pCurrentContext->Rdi; |
370 | break; |
371 | case 8: |
372 | return m_registers->pCurrentContext->R8; |
373 | break; |
374 | case 9: |
375 | return m_registers->pCurrentContext->R9; |
376 | break; |
377 | case 10: |
378 | return m_registers->pCurrentContext->R10; |
379 | break; |
380 | case 11: |
381 | return m_registers->pCurrentContext->R11; |
382 | break; |
383 | case 12: |
384 | return m_registers->pCurrentContext->R12; |
385 | break; |
386 | case 13: |
387 | return m_registers->pCurrentContext->R13; |
388 | break; |
389 | case 14: |
390 | return m_registers->pCurrentContext->R14; |
391 | break; |
392 | case 15: |
393 | return m_registers->pCurrentContext->R15; |
394 | break; |
395 | default: |
396 | _ASSERTE(!"Invalid register number!" ); |
397 | } |
398 | |
399 | return 0; |
400 | } |
401 | |
402 | |
403 | // mod reg r/m |
404 | // bits 7-6 5-3 2-0 |
405 | struct ModRMByte |
406 | { |
407 | BYTE rm :3; |
408 | BYTE reg:3; |
409 | BYTE mod:2; |
410 | }; |
411 | |
412 | // fixed W R X B |
413 | // bits 7-4 3 2 1 0 |
414 | struct RexByte |
415 | { |
416 | BYTE b:1; |
417 | BYTE x:1; |
418 | BYTE r:1; |
419 | BYTE w:1; |
420 | BYTE fixed:4; |
421 | }; |
422 | |
423 | // static |
424 | void NativeWalker::DecodeInstructionForPatchSkip(const BYTE *address, InstructionAttribute * pInstrAttrib) |
425 | { |
426 | // |
427 | // Skip instruction prefixes |
428 | // |
429 | |
430 | LOG((LF_CORDB, LL_INFO10000, "Patch decode: " )); |
431 | |
432 | // for reads and writes where the destination is a RIP-relative address pInstrAttrib->m_cOperandSize will contain the size in bytes of the pointee; in all other |
433 | // cases it will be zero. if the RIP-relative address is being written to then pInstrAttrib->m_fIsWrite will be true; in all other cases it will be false. |
434 | // similar to cbImmedSize in some cases we'll set pInstrAttrib->m_cOperandSize to 0x3 meaning that the prefix will determine the size if one is specified. |
435 | pInstrAttrib->m_cOperandSize = 0; |
436 | pInstrAttrib->m_fIsWrite = false; |
437 | |
438 | if (pInstrAttrib == NULL) |
439 | { |
440 | return; |
441 | } |
442 | |
443 | // These three legacy prefixes are used to modify some of the two-byte opcodes. |
444 | bool fPrefix66 = false; |
445 | bool fPrefixF2 = false; |
446 | bool fPrefixF3 = false; |
447 | |
448 | bool fRex = false; |
449 | bool fModRM = false; |
450 | |
451 | RexByte rex = {0}; |
452 | ModRMByte modrm = {0}; |
453 | |
454 | // We use 0x3 to indicate that we need to look at the operand-size override and the rex byte |
455 | // to determine whether the immediate size is 2 bytes or 4 bytes. |
456 | BYTE cbImmedSize = 0; |
457 | |
458 | const BYTE* originalAddr = address; |
459 | |
460 | do |
461 | { |
462 | switch (*address) |
463 | { |
464 | // Operand-Size override |
465 | case 0x66: |
466 | fPrefix66 = true; |
467 | goto LLegacyPrefix; |
468 | |
469 | // Repeat (REP/REPE/REPZ) |
470 | case 0xf2: |
471 | fPrefixF2 = true; |
472 | goto LLegacyPrefix; |
473 | |
474 | // Repeat (REPNE/REPNZ) |
475 | case 0xf3: |
476 | fPrefixF3 = true; |
477 | goto LLegacyPrefix; |
478 | |
479 | // Address-Size override |
480 | case 0x67: // fall through |
481 | |
482 | // Segment overrides |
483 | case 0x26: // ES |
484 | case 0x2E: // CS |
485 | case 0x36: // SS |
486 | case 0x3E: // DS |
487 | case 0x64: // FS |
488 | case 0x65: // GS // fall through |
489 | |
490 | // Lock |
491 | case 0xf0: |
492 | LLegacyPrefix: |
493 | LOG((LF_CORDB, LL_INFO10000, "prefix:%0.2x " , *address)); |
494 | address++; |
495 | continue; |
496 | |
497 | // REX register extension prefixes |
498 | case 0x40: |
499 | case 0x41: |
500 | case 0x42: |
501 | case 0x43: |
502 | case 0x44: |
503 | case 0x45: |
504 | case 0x46: |
505 | case 0x47: |
506 | case 0x48: |
507 | case 0x49: |
508 | case 0x4a: |
509 | case 0x4b: |
510 | case 0x4c: |
511 | case 0x4d: |
512 | case 0x4e: |
513 | case 0x4f: |
514 | LOG((LF_CORDB, LL_INFO10000, "prefix:%0.2x " , *address)); |
515 | fRex = true; |
516 | rex = *(RexByte*)address; |
517 | address++; |
518 | continue; |
519 | |
520 | default: |
521 | break; |
522 | } |
523 | } while (0); |
524 | |
525 | pInstrAttrib->Reset(); |
526 | |
527 | BYTE opcode0 = *address; |
528 | BYTE opcode1 = *(address + 1); // this is only valid if the first opcode byte is 0x0F |
529 | |
530 | // Handle AVX encodings. Note that these can mostly be handled as if they are aliases |
531 | // for a corresponding SSE encoding. |
532 | // See Figure 2-9 in "Intel 64 and IA-32 Architectures Software Developer's Manual". |
533 | |
534 | if (opcode0 == 0xC4 || opcode0 == 0xC5) |
535 | { |
536 | BYTE pp; |
537 | if (opcode0 == 0xC4) |
538 | { |
539 | BYTE opcode2 = *(address + 2); |
540 | address++; |
541 | |
542 | // REX bits are encoded in inverted form. |
543 | // R,X, and B are the top bits (in that order) of opcode1. |
544 | // W is the top bit of opcode2. |
545 | if ((opcode1 & 0x80) != 0) |
546 | { |
547 | rex.b = 1; |
548 | fRex = true; |
549 | } |
550 | if ((opcode1 & 0x40) == 0) |
551 | { |
552 | rex.x = 1; |
553 | fRex = true; |
554 | } |
555 | if ((opcode1 & 0x20) == 0) |
556 | { |
557 | rex.b = 1; |
558 | fRex = true; |
559 | } |
560 | if ((opcode2 & 0x80) != 0) |
561 | { |
562 | rex.w = 1; |
563 | fRex = true; |
564 | } |
565 | |
566 | pp = opcode2 & 0x3; |
567 | |
568 | BYTE mmBits = opcode1 & 0x1f; |
569 | BYTE impliedOpcode1 = 0; |
570 | switch(mmBits) |
571 | { |
572 | case 1: break; // No implied leading byte. |
573 | case 2: impliedOpcode1 = 0x38; break; |
574 | case 3: impliedOpcode1 = 0x3A; break; |
575 | default: _ASSERTE(!"NW::DIFPS - invalid opcode" ); break; |
576 | } |
577 | |
578 | if (impliedOpcode1 != 0) |
579 | { |
580 | opcode1 = impliedOpcode1; |
581 | } |
582 | else |
583 | { |
584 | opcode1 = *address; |
585 | address++; |
586 | } |
587 | } |
588 | else |
589 | { |
590 | pp = opcode1 & 0x3; |
591 | if ((opcode1 & 0x80) == 0) |
592 | { |
593 | // The two-byte VEX encoding only encodes the 'R' bit. |
594 | fRex = true; |
595 | rex.r = 1; |
596 | } |
597 | opcode1 = *address; |
598 | address++; |
599 | } |
600 | opcode0 = 0x0f; |
601 | switch (pp) |
602 | { |
603 | case 1: fPrefix66 = true; break; |
604 | case 2: fPrefixF3 = true; break; |
605 | case 3: fPrefixF2 = true; break; |
606 | } |
607 | } |
608 | |
609 | // The following opcode decoding follows the tables in "Appendix A Opcode and Operand Encodings" of |
610 | // "AMD64 Architecture Programmer's Manual Volume 3" |
611 | |
612 | // one-byte opcodes |
613 | if (opcode0 != 0x0F) |
614 | { |
615 | BYTE highNibble = (opcode0 & 0xF0) >> 4; |
616 | BYTE lowNibble = (opcode0 & 0x0F); |
617 | |
618 | switch (highNibble) |
619 | { |
620 | case 0x0: |
621 | case 0x1: |
622 | case 0x2: |
623 | case 0x3: |
624 | if ((lowNibble == 0x6) || (lowNibble == 0x7) || (lowNibble == 0xE) || (lowNibble == 0xF)) |
625 | { |
626 | _ASSERTE(!"NW::DIFPS - invalid opcode" ); |
627 | } |
628 | |
629 | // CMP |
630 | if ( (lowNibble <= 0x3) || |
631 | ((lowNibble >= 0x8) && (lowNibble <= 0xB)) ) |
632 | { |
633 | fModRM = true; |
634 | } |
635 | |
636 | // ADD/XOR reg/mem, reg |
637 | if (lowNibble == 0x0) |
638 | { |
639 | pInstrAttrib->m_cOperandSize = 0x1; |
640 | pInstrAttrib->m_fIsWrite = true; |
641 | } |
642 | else if (lowNibble == 0x1) |
643 | { |
644 | pInstrAttrib->m_cOperandSize = 0x3; |
645 | pInstrAttrib->m_fIsWrite = true; |
646 | } |
647 | // XOR reg, reg/mem |
648 | else if (lowNibble == 0x2) |
649 | { |
650 | pInstrAttrib->m_cOperandSize = 0x1; |
651 | } |
652 | else if (lowNibble == 0x3) |
653 | { |
654 | pInstrAttrib->m_cOperandSize = 0x3; |
655 | } |
656 | |
657 | break; |
658 | |
659 | case 0x4: |
660 | case 0x5: |
661 | break; |
662 | |
663 | case 0x6: |
664 | // IMUL |
665 | if (lowNibble == 0x9) |
666 | { |
667 | fModRM = true; |
668 | cbImmedSize = 0x3; |
669 | } |
670 | else if (lowNibble == 0xB) |
671 | { |
672 | fModRM = true; |
673 | cbImmedSize = 0x1; |
674 | } |
675 | else if (lowNibble == 0x3) |
676 | { |
677 | if (fRex) |
678 | { |
679 | // MOVSXD |
680 | fModRM = true; |
681 | } |
682 | } |
683 | break; |
684 | |
685 | case 0x7: |
686 | break; |
687 | |
688 | case 0x8: |
689 | fModRM = true; |
690 | |
691 | // Group 1: lowNibble in [0x0, 0x3] |
692 | _ASSERTE(lowNibble != 0x2); |
693 | |
694 | // ADD/XOR reg/mem, imm |
695 | if (lowNibble == 0x0) |
696 | { |
697 | cbImmedSize = 1; |
698 | pInstrAttrib->m_cOperandSize = 1; |
699 | pInstrAttrib->m_fIsWrite = true; |
700 | } |
701 | else if (lowNibble == 0x1) |
702 | { |
703 | cbImmedSize = 3; |
704 | pInstrAttrib->m_cOperandSize = 3; |
705 | pInstrAttrib->m_fIsWrite = true; |
706 | } |
707 | else if (lowNibble == 0x3) |
708 | { |
709 | cbImmedSize = 1; |
710 | pInstrAttrib->m_cOperandSize = 3; |
711 | pInstrAttrib->m_fIsWrite = true; |
712 | } |
713 | // MOV reg/mem, reg |
714 | else if (lowNibble == 0x8) |
715 | { |
716 | pInstrAttrib->m_cOperandSize = 0x1; |
717 | pInstrAttrib->m_fIsWrite = true; |
718 | } |
719 | else if (lowNibble == 0x9) |
720 | { |
721 | pInstrAttrib->m_cOperandSize = 0x3; |
722 | pInstrAttrib->m_fIsWrite = true; |
723 | } |
724 | // MOV reg, reg/mem |
725 | else if (lowNibble == 0xA) |
726 | { |
727 | pInstrAttrib->m_cOperandSize = 0x1; |
728 | } |
729 | else if (lowNibble == 0xB) |
730 | { |
731 | pInstrAttrib->m_cOperandSize = 0x3; |
732 | } |
733 | |
734 | break; |
735 | |
736 | case 0x9: |
737 | case 0xA: |
738 | case 0xB: |
739 | break; |
740 | |
741 | case 0xC: |
742 | if ((lowNibble == 0x4) || (lowNibble == 0x5) || (lowNibble == 0xE)) |
743 | { |
744 | _ASSERTE(!"NW::DIFPS - invalid opcode" ); |
745 | } |
746 | |
747 | // RET |
748 | if ((lowNibble == 0x2) || (lowNibble == 0x3)) |
749 | { |
750 | break; |
751 | } |
752 | |
753 | // Group 2 (part 1): lowNibble in [0x0, 0x1] |
754 | // RCL reg/mem, imm |
755 | if (lowNibble == 0x0) |
756 | { |
757 | fModRM = true; |
758 | cbImmedSize = 0x1; |
759 | pInstrAttrib->m_cOperandSize = 0x1; |
760 | pInstrAttrib->m_fIsWrite = true; |
761 | } |
762 | else if (lowNibble == 0x1) |
763 | { |
764 | fModRM = true; |
765 | cbImmedSize = 0x1; |
766 | pInstrAttrib->m_cOperandSize = 0x3; |
767 | pInstrAttrib->m_fIsWrite = true; |
768 | } |
769 | // Group 11: lowNibble in [0x6, 0x7] |
770 | // MOV reg/mem, imm |
771 | else if (lowNibble == 0x6) |
772 | { |
773 | fModRM = true; |
774 | cbImmedSize = 1; |
775 | pInstrAttrib->m_cOperandSize = 1; |
776 | pInstrAttrib->m_fIsWrite = true; |
777 | } |
778 | else if (lowNibble == 0x7) |
779 | { |
780 | fModRM = true; |
781 | cbImmedSize = 3; |
782 | pInstrAttrib->m_cOperandSize = 3; |
783 | pInstrAttrib->m_fIsWrite = true; |
784 | } |
785 | break; |
786 | |
787 | case 0xD: |
788 | // Group 2 (part 2): lowNibble in [0x0, 0x3] |
789 | // RCL reg/mem, 1/reg |
790 | if (lowNibble == 0x0 || lowNibble == 0x2) |
791 | { |
792 | fModRM = true; |
793 | pInstrAttrib->m_cOperandSize = 0x1; |
794 | pInstrAttrib->m_fIsWrite = true; |
795 | } |
796 | else if (lowNibble == 0x1 || lowNibble == 0x3) |
797 | { |
798 | fModRM = true; |
799 | pInstrAttrib->m_cOperandSize = 0x3; |
800 | pInstrAttrib->m_fIsWrite = true; |
801 | } |
802 | |
803 | // x87 instructions: lowNibble in [0x8, 0xF] |
804 | // - the entire ModRM byte is used to modify the opcode, |
805 | // so the ModRM byte cannot be used in RIP-relative addressing |
806 | break; |
807 | |
808 | case 0xE: |
809 | break; |
810 | |
811 | case 0xF: |
812 | // Group 3: lowNibble in [0x6, 0x7] |
813 | // TEST |
814 | if ((lowNibble == 0x6) || (lowNibble == 0x7)) |
815 | { |
816 | fModRM = true; |
817 | |
818 | modrm = *(ModRMByte*)(address + 1); |
819 | if ((modrm.reg == 0x0) || (modrm.reg == 0x1)) |
820 | { |
821 | if (lowNibble == 0x6) |
822 | { |
823 | cbImmedSize = 0x1; |
824 | } |
825 | else |
826 | { |
827 | cbImmedSize = 0x3; |
828 | } |
829 | } |
830 | } |
831 | // Group 4: lowNibble == 0xE |
832 | // INC reg/mem |
833 | else if (lowNibble == 0xE) |
834 | { |
835 | fModRM = true; |
836 | pInstrAttrib->m_cOperandSize = 1; |
837 | pInstrAttrib->m_fIsWrite = true; |
838 | } |
839 | // Group 5: lowNibble == 0xF |
840 | else if (lowNibble == 0xF) |
841 | { |
842 | fModRM = true; |
843 | pInstrAttrib->m_cOperandSize = 3; |
844 | pInstrAttrib->m_fIsWrite = true; |
845 | } |
846 | break; |
847 | } |
848 | |
849 | address += 1; |
850 | if (fModRM) |
851 | { |
852 | modrm = *(ModRMByte*)address; |
853 | address += 1; |
854 | } |
855 | } |
856 | // two-byte opcodes |
857 | else |
858 | { |
859 | BYTE highNibble = (opcode1 & 0xF0) >> 4; |
860 | BYTE lowNibble = (opcode1 & 0x0F); |
861 | |
862 | switch (highNibble) |
863 | { |
864 | case 0x0: |
865 | // Group 6: lowNibble == 0x0 |
866 | if (lowNibble == 0x0) |
867 | { |
868 | fModRM = true; |
869 | } |
870 | // Group 7: lowNibble == 0x1 |
871 | else if (lowNibble == 0x1) |
872 | { |
873 | fModRM = true; |
874 | } |
875 | else if ((lowNibble == 0x2) || (lowNibble == 0x3)) |
876 | { |
877 | fModRM = true; |
878 | } |
879 | // Group p: lowNibble == 0xD |
880 | else if (lowNibble == 0xD) |
881 | { |
882 | fModRM = true; |
883 | } |
884 | // 3DNow! instructions: lowNibble == 0xF |
885 | // - all 3DNow! instructions use the ModRM byte |
886 | else if (lowNibble == 0xF) |
887 | { |
888 | fModRM = true; |
889 | cbImmedSize = 0x1; |
890 | } |
891 | break; |
892 | |
893 | case 0x1: // Group 16: lowNibble == 0x8 |
894 | // MOVSS xmm, xmm/mem (low nibble 0x0) |
895 | // MOVSS xmm/mem, xmm (low nibble 0x1) |
896 | if (lowNibble <= 0x1) |
897 | { |
898 | fModRM = true; |
899 | if (fPrefixF2 || fPrefixF3) |
900 | pInstrAttrib->m_cOperandSize = 0x8; |
901 | else |
902 | pInstrAttrib->m_cOperandSize = 0x10; |
903 | |
904 | if (lowNibble == 0x1) |
905 | pInstrAttrib->m_fIsWrite = true; |
906 | |
907 | break; |
908 | } |
909 | case 0x2: // fall through |
910 | fModRM = true; |
911 | if (lowNibble == 0x8 || lowNibble == 0x9) |
912 | { |
913 | pInstrAttrib->m_cOperandSize = 0x10; |
914 | |
915 | if (lowNibble == 0x9) |
916 | pInstrAttrib->m_fIsWrite = true; |
917 | } |
918 | break; |
919 | |
920 | case 0x3: |
921 | break; |
922 | |
923 | case 0x4: |
924 | case 0x5: |
925 | case 0x6: // fall through |
926 | fModRM = true; |
927 | break; |
928 | |
929 | case 0x7: |
930 | if (lowNibble == 0x0) |
931 | { |
932 | fModRM = true; |
933 | cbImmedSize = 0x1; |
934 | } |
935 | else if ((lowNibble >= 0x1) && (lowNibble <= 0x3)) |
936 | { |
937 | _ASSERTE(!fPrefixF2 && !fPrefixF3); |
938 | |
939 | // Group 12: lowNibble == 0x1 |
940 | // Group 13: lowNibble == 0x2 |
941 | // Group 14: lowNibble == 0x3 |
942 | fModRM = true; |
943 | cbImmedSize = 0x1; |
944 | } |
945 | else if ((lowNibble >= 0x4) && (lowNibble <= 0x6)) |
946 | { |
947 | fModRM = true; |
948 | } |
949 | // MOVD reg/mem, mmx for 0F 7E |
950 | else if ((lowNibble == 0xE) || (lowNibble == 0xF)) |
951 | { |
952 | _ASSERTE(!fPrefixF2); |
953 | |
954 | fModRM = true; |
955 | } |
956 | break; |
957 | |
958 | case 0x8: |
959 | break; |
960 | |
961 | case 0x9: |
962 | fModRM = true; |
963 | break; |
964 | |
965 | case 0xA: |
966 | if ((lowNibble >= 0x3) && (lowNibble <= 0x5)) |
967 | { |
968 | // BT reg/mem, reg |
969 | fModRM = true; |
970 | if (lowNibble == 0x3) |
971 | { |
972 | pInstrAttrib->m_cOperandSize = 0x3; |
973 | pInstrAttrib->m_fIsWrite = true; |
974 | } |
975 | // SHLD reg/mem, imm |
976 | else if (lowNibble == 0x4) |
977 | { |
978 | cbImmedSize = 0x1; |
979 | } |
980 | } |
981 | else if (lowNibble >= 0xB) |
982 | { |
983 | fModRM = true; |
984 | // BTS reg/mem, reg |
985 | if (lowNibble == 0xB) |
986 | { |
987 | pInstrAttrib->m_cOperandSize = 0x3; |
988 | pInstrAttrib->m_fIsWrite = true; |
989 | } |
990 | // SHRD reg/mem, imm |
991 | else if (lowNibble == 0xC) |
992 | { |
993 | cbImmedSize = 0x1; |
994 | } |
995 | // Group 15: lowNibble == 0xE |
996 | } |
997 | break; |
998 | |
999 | case 0xB: |
1000 | // Group 10: lowNibble == 0x9 |
1001 | // - this entire group is invalid |
1002 | _ASSERTE((lowNibble != 0x8) && (lowNibble != 0x9)); |
1003 | |
1004 | fModRM = true; |
1005 | // CMPXCHG reg/mem, reg |
1006 | if (lowNibble == 0x0) |
1007 | { |
1008 | pInstrAttrib->m_cOperandSize = 0x1; |
1009 | pInstrAttrib->m_fIsWrite = true; |
1010 | } |
1011 | else if (lowNibble == 0x1) |
1012 | { |
1013 | pInstrAttrib->m_cOperandSize = 0x3; |
1014 | pInstrAttrib->m_fIsWrite = true; |
1015 | } |
1016 | // Group 8: lowNibble == 0xA |
1017 | // BTS reg/mem, imm |
1018 | else if (lowNibble == 0xA) |
1019 | { |
1020 | cbImmedSize = 0x1; |
1021 | pInstrAttrib->m_cOperandSize = 0x3; |
1022 | pInstrAttrib->m_fIsWrite = true; |
1023 | } |
1024 | // MOVSX reg, reg/mem |
1025 | else if (lowNibble == 0xE) |
1026 | { |
1027 | pInstrAttrib->m_cOperandSize = 1; |
1028 | } |
1029 | else if (lowNibble == 0xF) |
1030 | { |
1031 | pInstrAttrib->m_cOperandSize = 2; |
1032 | } |
1033 | break; |
1034 | |
1035 | case 0xC: |
1036 | if (lowNibble <= 0x7) |
1037 | { |
1038 | fModRM = true; |
1039 | // XADD reg/mem, reg |
1040 | if (lowNibble == 0x0) |
1041 | { |
1042 | pInstrAttrib->m_cOperandSize = 0x1; |
1043 | pInstrAttrib->m_fIsWrite = true; |
1044 | } |
1045 | else if (lowNibble == 0x1) |
1046 | { |
1047 | pInstrAttrib->m_cOperandSize = 0x3; |
1048 | pInstrAttrib->m_fIsWrite = true; |
1049 | } |
1050 | else if ( (lowNibble == 0x2) || |
1051 | ((lowNibble >= 0x4) && (lowNibble <= 0x6)) ) |
1052 | { |
1053 | cbImmedSize = 0x1; |
1054 | } |
1055 | } |
1056 | break; |
1057 | |
1058 | case 0xD: |
1059 | case 0xE: |
1060 | case 0xF: // fall through |
1061 | fModRM = true; |
1062 | break; |
1063 | } |
1064 | |
1065 | address += 2; |
1066 | if (fModRM) |
1067 | { |
1068 | modrm = *(ModRMByte*)address; |
1069 | address += 1; |
1070 | } |
1071 | } |
1072 | |
1073 | // Check for RIP-relative addressing |
1074 | if (fModRM && (modrm.mod == 0x0) && (modrm.rm == 0x5)) |
1075 | { |
1076 | // SIB byte cannot be present with RIP-relative addressing. |
1077 | |
1078 | pInstrAttrib->m_dwOffsetToDisp = (DWORD)(address - originalAddr); |
1079 | _ASSERTE(pInstrAttrib->m_dwOffsetToDisp <= MAX_INSTRUCTION_LENGTH); |
1080 | |
1081 | // Add 4 to the address for the displacement. |
1082 | address += 4; |
1083 | |
1084 | // Further adjust the address by the size of the cbImmedSize (if any). |
1085 | if (cbImmedSize == 0x3) |
1086 | { |
1087 | // The size of the cbImmedSizeiate depends on the effective operand size: |
1088 | // 2 bytes if the effective operand size is 16-bit, or |
1089 | // 4 bytes if the effective operand size is 32- or 64-bit. |
1090 | if (fPrefix66) |
1091 | { |
1092 | cbImmedSize = 0x2; |
1093 | } |
1094 | else |
1095 | { |
1096 | cbImmedSize = 0x4; |
1097 | } |
1098 | } |
1099 | address += cbImmedSize; |
1100 | |
1101 | // if this is a read or write to a RIP-relative address then update pInstrAttrib->m_cOperandSize with the size of the pointee. |
1102 | if (pInstrAttrib->m_cOperandSize == 0x3) |
1103 | { |
1104 | if (fPrefix66) |
1105 | pInstrAttrib->m_cOperandSize = 0x2; // WORD* |
1106 | else |
1107 | pInstrAttrib->m_cOperandSize = 0x4; // DWORD* |
1108 | |
1109 | if (fRex && rex.w == 0x1) |
1110 | { |
1111 | _ASSERTE(pInstrAttrib->m_cOperandSize == 0x4); |
1112 | pInstrAttrib->m_cOperandSize = 0x8; // QWORD* |
1113 | } |
1114 | } |
1115 | |
1116 | pInstrAttrib->m_cbInstr = (DWORD)(address - originalAddr); |
1117 | _ASSERTE(pInstrAttrib->m_cbInstr <= MAX_INSTRUCTION_LENGTH); |
1118 | } |
1119 | else |
1120 | { |
1121 | // not a RIP-relative address so set to default values |
1122 | pInstrAttrib->m_cOperandSize = 0; |
1123 | pInstrAttrib->m_fIsWrite = false; |
1124 | } |
1125 | |
1126 | // |
1127 | // Look at opcode to tell if it's a call or an |
1128 | // absolute branch. |
1129 | // |
1130 | switch (opcode0) |
1131 | { |
1132 | case 0xC2: // RET |
1133 | case 0xC3: // RET N |
1134 | pInstrAttrib->m_fIsAbsBranch = true; |
1135 | LOG((LF_CORDB, LL_INFO10000, "ABS:%0.2x\n" , opcode0)); |
1136 | break; |
1137 | |
1138 | case 0xE8: // CALL relative |
1139 | pInstrAttrib->m_fIsCall = true; |
1140 | LOG((LF_CORDB, LL_INFO10000, "CALL REL:%0.2x\n" , opcode0)); |
1141 | break; |
1142 | |
1143 | case 0xC8: // ENTER |
1144 | pInstrAttrib->m_fIsCall = true; |
1145 | pInstrAttrib->m_fIsAbsBranch = true; |
1146 | LOG((LF_CORDB, LL_INFO10000, "CALL ABS:%0.2x\n" , opcode0)); |
1147 | break; |
1148 | |
1149 | case 0xFF: // CALL/JMP modr/m |
1150 | // |
1151 | // Read opcode modifier from modr/m |
1152 | // |
1153 | |
1154 | _ASSERTE(fModRM); |
1155 | switch (modrm.reg) |
1156 | { |
1157 | case 2: |
1158 | case 3: |
1159 | pInstrAttrib->m_fIsCall = true; |
1160 | // fall through |
1161 | case 4: |
1162 | case 5: |
1163 | pInstrAttrib->m_fIsAbsBranch = true; |
1164 | } |
1165 | LOG((LF_CORDB, LL_INFO10000, "CALL/JMP modr/m:%0.2x\n" , opcode0)); |
1166 | break; |
1167 | |
1168 | default: |
1169 | LOG((LF_CORDB, LL_INFO10000, "NORMAL:%0.2x\n" , opcode0)); |
1170 | } |
1171 | |
1172 | if (pInstrAttrib->m_cOperandSize == 0x0) |
1173 | { |
1174 | // if an operand size wasn't computed (likely because the decoder didn't understand the instruction) then set |
1175 | // the size to the max buffer size. this is a fall-back to the dev10 behavior and is applicable for reads only. |
1176 | _ASSERTE(!pInstrAttrib->m_fIsWrite); |
1177 | pInstrAttrib->m_cOperandSize = SharedPatchBypassBuffer::cbBufferBypass; |
1178 | } |
1179 | } |
1180 | |
1181 | |
1182 | #endif |
1183 | |