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//
6
7#include "stdafx.h"
8#include "unwinder_amd64.h"
9
10typedef DPTR(M128A) PTR_M128A;
11
12//---------------------------------------------------------------------------------------
13//
14// Read 64 bit unsigned value from the specified address. When the unwinder is built
15// for jitted code unwinding on non-Windows systems, this is just a plain memory read.
16// When the unwinder is built for DAC though, this reads data from the target debugged
17// process.
18//
19// Arguments:
20// addr - address to read from
21//
22// Return Value:
23// The value that was read
24//
25// Notes:
26// If the memory read fails in the DAC mode, the failure is reported as an exception
27// via the DacError function.
28//
29static ULONG64 MemoryRead64(PULONG64 addr)
30{
31 return *dac_cast<PTR_ULONG64>((TADDR)addr);
32}
33
34//---------------------------------------------------------------------------------------
35//
36// Read 128 bit value from the specified address. When the unwinder is built
37// for jitted code unwinding on non-Windows systems, this is just a plain memory read.
38// When the unwinder is built for DAC though, this reads data from the target debugged
39// process.
40//
41// Arguments:
42// addr - address to read from
43//
44// Return Value:
45// The value that was read
46//
47// Notes:
48// If the memory read fails in the DAC mode, the failure is reported as an exception
49// via the DacError function.
50//
51static M128A MemoryRead128(PM128A addr)
52{
53 return *dac_cast<PTR_M128A>((TADDR)addr);
54}
55
56#ifdef DACCESS_COMPILE
57
58// Report failure in the unwinder if the condition is FALSE
59#define UNWINDER_ASSERT(Condition) if (!(Condition)) DacError(CORDBG_E_TARGET_INCONSISTENT)
60
61//---------------------------------------------------------------------------------------
62//
63// The InstructionBuffer class abstracts accessing assembler instructions in the function
64// being unwound. It behaves as a memory byte pointer, but it reads the instruction codes
65// from the target process being debugged and removes all changes that the debugger
66// may have made to the code, e.g. breakpoint instructions.
67//
68class InstructionBuffer
69{
70 UINT m_offset;
71 SIZE_T m_address;
72 UCHAR m_buffer[32];
73
74 // Load the instructions from the target process being debugged
75 HRESULT Load()
76 {
77 HRESULT hr = DacReadAll(TO_TADDR(m_address), m_buffer, sizeof(m_buffer), false);
78 if (SUCCEEDED(hr))
79 {
80 // On X64, we need to replace any patches which are within the requested memory range.
81 // This is because the X64 unwinder needs to disassemble the native instructions in order to determine
82 // whether the IP is in an epilog.
83 MemoryRange range(dac_cast<PTR_VOID>((TADDR)m_address), sizeof(m_buffer));
84 hr = DacReplacePatchesInHostMemory(range, m_buffer);
85 }
86
87 return hr;
88 }
89
90public:
91
92 // Construct the InstructionBuffer for the given address in the target process
93 InstructionBuffer(SIZE_T address)
94 : m_offset(0),
95 m_address(address)
96 {
97 HRESULT hr = Load();
98 if (FAILED(hr))
99 {
100 // If we have failed to read from the target process, just pretend
101 // we've read zeros.
102 // The InstructionBuffer is used in code driven epilogue unwinding
103 // when we read processor instructions and simulate them.
104 // It's very rare to be stopped in an epilogue when
105 // getting a stack trace, so if we can't read the
106 // code just assume we aren't in an epilogue instead of failing
107 // the unwind.
108 memset(m_buffer, 0, sizeof(m_buffer));
109 }
110 }
111
112 // Move to the next byte in the buffer
113 InstructionBuffer& operator++()
114 {
115 m_offset++;
116 return *this;
117 }
118
119 // Skip delta bytes in the buffer
120 InstructionBuffer& operator+=(INT delta)
121 {
122 m_offset += delta;
123 return *this;
124 }
125
126 // Return address of the current byte in the buffer
127 explicit operator ULONG64()
128 {
129 return m_address + m_offset;
130 }
131
132 // Get the byte at the given index from the current position
133 // Invoke DacError if the index is out of the buffer
134 UCHAR operator[](int index)
135 {
136 int realIndex = m_offset + index;
137 UNWINDER_ASSERT(realIndex < sizeof(m_buffer));
138 return m_buffer[realIndex];
139 }
140};
141
142//---------------------------------------------------------------------------------------
143//
144// Given the target address of an UNWIND_INFO structure, this function retrieves all the memory used for
145// the UNWIND_INFO, including the variable size array of UNWIND_CODE. The function returns a host copy
146// of the UNWIND_INFO.
147//
148// Arguments:
149// taUnwindInfo - the target address of an UNWIND_INFO
150//
151// Return Value:
152// Return a host copy of the UNWIND_INFO, including the array of UNWIND_CODE.
153//
154// Notes:
155// The host copy of UNWIND_INFO is created from DAC memory, which will be flushed when the DAC cache
156// is flushed (i.e. when the debugee is continued). Thus, the caller doesn't need to worry about freeing
157// this memory.
158//
159UNWIND_INFO * DacGetUnwindInfo(TADDR taUnwindInfo)
160{
161 PTR_UNWIND_INFO pUnwindInfo = PTR_UNWIND_INFO(taUnwindInfo);
162 DWORD cbUnwindInfo = offsetof(UNWIND_INFO, UnwindCode) +
163 pUnwindInfo->CountOfUnwindCodes * sizeof(UNWIND_CODE);
164
165 // Check if there is a chained unwind info. If so, it has an extra RUNTIME_FUNCTION tagged to the end.
166 if ((pUnwindInfo->Flags & UNW_FLAG_CHAININFO) != 0)
167 {
168 // If there is an odd number of UNWIND_CODE, we need to adjust for alignment.
169 if ((pUnwindInfo->CountOfUnwindCodes & 1) != 0)
170 {
171 cbUnwindInfo += sizeof(UNWIND_CODE);
172 }
173 cbUnwindInfo += sizeof(T_RUNTIME_FUNCTION);
174 }
175 return reinterpret_cast<UNWIND_INFO *>(DacInstantiateTypeByAddress(taUnwindInfo, cbUnwindInfo, true));
176}
177
178//---------------------------------------------------------------------------------------
179//
180// This function just wraps the DacGetUnwindInfo.
181// The DacGetUnwindInfo is called from other places outside of the unwinder, so it
182// cannot be merged into the body of this method.
183//
184UNWIND_INFO * OOPStackUnwinderAMD64::GetUnwindInfo(TADDR taUnwindInfo)
185{
186 return DacGetUnwindInfo(taUnwindInfo);
187}
188
189
190//---------------------------------------------------------------------------------------
191//
192// This function is just a wrapper over OOPStackUnwinder. The runtime can call this function to
193// virtually unwind a CONTEXT out-of-process.
194//
195// Arguments:
196// pContext - This is an in-out parameter. On entry, this is the CONTEXT to be unwound.
197// On exit, this is the caller CONTEXT.
198//
199// Return Value:
200// TRUE if the unwinding is successful
201//
202// Notes:
203// This function overwrites the specified CONTEXT to store the caller CONTEXT.
204//
205
206BOOL DacUnwindStackFrame(CONTEXT * pContext, KNONVOLATILE_CONTEXT_POINTERS* pContextPointers)
207{
208 BOOL res = OOPStackUnwinderAMD64::Unwind(pContext);
209
210 if (res && pContextPointers)
211 {
212 for (int i = 0; i < 16; i++)
213 {
214 *(&pContextPointers->Rax + i) = &pContext->Rax + i;
215 }
216 }
217
218 return res;
219}
220
221//---------------------------------------------------------------------------------------
222//
223// Unwind the given CONTEXT to the caller CONTEXT. The given CONTEXT will be overwritten.
224//
225// Arguments:
226// pContext - in-out parameter storing the specified CONTEXT on entry and the unwound CONTEXT on exit
227//
228// Return Value:
229// TRUE if the unwinding is successful
230//
231
232BOOL OOPStackUnwinderAMD64::Unwind(CONTEXT * pContext)
233{
234 HRESULT hr = E_FAIL;
235
236 ULONG64 uControlPC = (DWORD64)dac_cast<PCODE>(::GetIP(pContext));
237
238 // get the module base
239 ULONG64 uImageBase;
240 hr = GetModuleBase(uControlPC, &uImageBase);
241 if (FAILED(hr))
242 {
243 return FALSE;
244 }
245
246 // get the function entry
247 IMAGE_RUNTIME_FUNCTION_ENTRY functionEntry;
248 hr = GetFunctionEntry(uControlPC, &functionEntry, sizeof(functionEntry));
249 if (FAILED(hr))
250 {
251 return FALSE;
252 }
253
254 // call VirtualUnwind() to do the real work
255 ULONG64 EstablisherFrame;
256 hr = VirtualUnwind(0, uImageBase, uControlPC, &functionEntry, pContext, NULL, &EstablisherFrame, NULL, NULL);
257
258 return (hr == S_OK);
259}
260
261#else // DACCESS_COMPILE
262
263// Report failure in the unwinder if the condition is FALSE
264#define UNWINDER_ASSERT _ASSERTE
265
266// For unwinding of the jitted code on non-Windows platforms, the Instruction buffer is
267// just a plain pointer to the instruction data.
268typedef UCHAR * InstructionBuffer;
269
270//---------------------------------------------------------------------------------------
271//
272// Return UNWIND_INFO pointer for the given address.
273//
274UNWIND_INFO * OOPStackUnwinderAMD64::GetUnwindInfo(TADDR taUnwindInfo)
275{
276 return (UNWIND_INFO *)taUnwindInfo;
277}
278
279//---------------------------------------------------------------------------------------
280//
281// This function behaves like the RtlVirtualUnwind in Windows.
282// It virtually unwinds the specified function by executing its
283// prologue code backward or its epilogue code forward.
284//
285// If a context pointers record is specified, then the address where each
286// nonvolatile registers is restored from is recorded in the appropriate
287// element of the context pointers record.
288//
289// Arguments:
290//
291// HandlerType - Supplies the handler type expected for the virtual unwind.
292// This may be either an exception or an unwind handler. A flag may
293// optionally be supplied to avoid epilogue detection if it is known
294// the specified control PC is not located inside a function epilogue.
295//
296// ImageBase - Supplies the base address of the image that contains the
297// function being unwound.
298//
299// ControlPc - Supplies the address where control left the specified
300// function.
301//
302// FunctionEntry - Supplies the address of the function table entry for the
303// specified function.
304//
305// ContextRecord - Supplies the address of a context record.
306//
307// HandlerData - Supplies a pointer to a variable that receives a pointer
308// the the language handler data.
309//
310// EstablisherFrame - Supplies a pointer to a variable that receives the
311// the establisher frame pointer value.
312//
313// ContextPointers - Supplies an optional pointer to a context pointers
314// record.
315//
316// Return value:
317//
318// The handler routine address. If control did not leave the specified
319// function in either the prologue or an epilogue and a handler of the
320// proper type is associated with the function, then the address of the
321// language specific exception handler is returned. Otherwise, NULL is
322// returned.
323//
324PEXCEPTION_ROUTINE RtlVirtualUnwind_Unsafe(
325 __in ULONG HandlerType,
326 __in ULONG64 ImageBase,
327 __in ULONG64 ControlPc,
328 __in PT_RUNTIME_FUNCTION FunctionEntry,
329 __in OUT PCONTEXT ContextRecord,
330 __out PVOID *HandlerData,
331 __out PULONG64 EstablisherFrame,
332 __inout_opt PKNONVOLATILE_CONTEXT_POINTERS ContextPointers
333 )
334{
335 PEXCEPTION_ROUTINE handlerRoutine;
336
337 HRESULT res = OOPStackUnwinderAMD64::VirtualUnwind(
338 HandlerType,
339 ImageBase,
340 ControlPc,
341 (_PIMAGE_RUNTIME_FUNCTION_ENTRY)FunctionEntry,
342 ContextRecord,
343 HandlerData,
344 EstablisherFrame,
345 ContextPointers,
346 &handlerRoutine);
347
348 _ASSERTE(SUCCEEDED(res));
349
350 return handlerRoutine;
351}
352
353
354#endif // DACCESS_COMPILE
355
356//
357//
358// <NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE>
359//
360// Everything below is borrowed from minkernel\ntos\rtl\amd64\exdsptch.c file from Windows
361//
362// <NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE>
363//
364//
365
366
367//----------------------------------------------------------------------------
368//
369// Copied OS code.
370//
371// This must be kept in sync with the system unwinder.
372// minkernel\ntos\rtl\amd64\exdsptch.c
373//
374//----------------------------------------------------------------------------
375
376//
377// ****** temp - defin elsewhere ******
378//
379
380#define SIZE64_PREFIX 0x48
381#define ADD_IMM8_OP 0x83
382#define ADD_IMM32_OP 0x81
383#define JMP_IMM8_OP 0xeb
384#define JMP_IMM32_OP 0xe9
385#define JMP_IND_OP 0xff
386#define LEA_OP 0x8d
387#define REPNE_PREFIX 0xf2
388#define REP_PREFIX 0xf3
389#define POP_OP 0x58
390#define RET_OP 0xc3
391#define RET_OP_2 0xc2
392
393#define IS_REX_PREFIX(x) (((x) & 0xf0) == 0x40)
394
395#define UNWIND_CHAIN_LIMIT 32
396
397HRESULT
398OOPStackUnwinderAMD64::UnwindEpilogue(
399 __in ULONG64 ImageBase,
400 __in ULONG64 ControlPc,
401 __in ULONG EpilogueOffset,
402 __in _PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionEntry,
403 __inout PCONTEXT ContextRecord,
404 __inout_opt PKNONVOLATILE_CONTEXT_POINTERS ContextPointers
405)
406
407/*++
408
409Routine Description:
410
411 This function emulates the state change associated with a function
412 epilogue by using the corresponding prologue unwind codes of the
413 primary function entry corresponding to the specified function.
414
415 The prologue unwind codes can be used to reverse the epilogue since
416 the epilogue operations are structured as a mirror-image of the initial
417 prologue instructions prior to the establishment of the frame.
418
419Arguments:
420
421 ImageBase - Supplies the base address of the image that contains the
422 function being unwound.
423
424 ControlPc - Supplies the address where control left the specified function.
425
426 EpilogueOffset - Supplies the offset within an epilogue of the specified
427 instruction pointer address.
428
429 FunctionEntry - Supplies a pointer to the function table entry for the
430 specified function. If appropriate, this has already been probed.
431
432 ContextRecord - Supplies a pointer to a context record.
433
434 ContextPointers - Supplies an optional pointer to a context pointers record.
435
436
437Return Value:
438
439HRESULT.
440
441--*/
442
443{
444
445 ULONG ChainCount;
446 ULONG CountOfCodes;
447 ULONG CurrentOffset;
448 ULONG FirstPushIndex;
449 ULONG Index;
450 PULONG64 IntegerAddress;
451 PULONG64 IntegerRegister;
452 ULONG OpInfo;
453 PULONG64 ReturnAddress;
454 PULONG64 StackAddress;
455 PUNWIND_INFO UnwindInfo;
456 UNWIND_CODE UnwindOp;
457
458 //
459 // A canonical epilogue sequence consists of the following operations:
460 //
461 // 1. Optional cleanup of fixed and dynamic stack allocations, which is
462 // considered to be outside of the epilogue region.
463 //
464 // add rsp, imm
465 // or
466 // lea rsp, disp[fp]
467 //
468 // 2. Zero or more pop nonvolatile-integer-register[0..15] instructions,
469 // which are unwound using the corresponding UWOP_PUSH_NONVOL opcodes.
470 //
471 // pop r64
472 // or
473 // REX.R pop r64
474 //
475 // 3. An optional one-byte pop r64 to a volatile register to clean up an
476 // RFLAGS register pushed with pushfq. This is marked with a
477 // UWOP_ALLOC_SMALL 8 opcode.
478 //
479 // pop rcx
480 //
481 // 4. A control transfer instruction (ret or jump). In both cases, there
482 // will be no prologue unwind codes remaining after the previous set of
483 // recognized operations are emulated.
484 //
485 // ret 0
486 // or
487 // jmp imm
488 // or
489 // jmp [target]
490 // or
491 // iretq
492 //
493 // N.B. The correctness of these assumptions is based on the ordering
494 // of unwind codes and the mirroring of epilogue and prologue
495 // regions.
496 //
497 // Find the function's primary entry, which contains the relevant frame
498 // adjustment unwind codes.
499 //
500 // Locate the first push unwind code. This code requires that all pushes
501 // occur within a single function entry, though not necessarily within the
502 // root function entry of a chained function.
503 //
504
505 ChainCount = 0;
506 for (;;) {
507 UnwindInfo = GetUnwindInfo(FunctionEntry->UnwindInfoAddress + ImageBase);
508 if (UnwindInfo == NULL)
509 {
510 return HRESULT_FROM_WIN32(ERROR_READ_FAULT);
511 }
512 CountOfCodes = UnwindInfo->CountOfUnwindCodes;
513 FirstPushIndex = 0;
514 while (FirstPushIndex < CountOfCodes) {
515 UnwindOp = UnwindInfo->UnwindCode[FirstPushIndex];
516 if ((UnwindOp.UnwindOp == UWOP_PUSH_NONVOL) ||
517 (UnwindOp.UnwindOp == UWOP_PUSH_MACHFRAME)) {
518
519 break;
520 }
521
522 FirstPushIndex += UnwindOpSlots(UnwindOp);
523 }
524
525 if (FirstPushIndex < CountOfCodes) {
526 break;
527 }
528
529 //
530 // If a chained parent function entry exists, continue looking for
531 // push opcodes in the parent.
532 //
533
534 if ((UnwindInfo->Flags & UNW_FLAG_CHAININFO) == 0) {
535 break;
536 }
537
538 ChainCount += 1;
539 if (ChainCount > UNWIND_CHAIN_LIMIT) {
540 return E_FAIL;
541 }
542
543 Index = CountOfCodes;
544 if (Index % 2 != 0) {
545 Index += 1;
546 }
547
548 FunctionEntry = (_PIMAGE_RUNTIME_FUNCTION_ENTRY)&UnwindInfo->UnwindCode[Index];
549 }
550
551 //
552 // Unwind any push codes that have not already been reversed by the
553 // epilogue.
554 //
555
556 CurrentOffset = 0;
557 IntegerRegister = &ContextRecord->Rax;
558 for (Index = FirstPushIndex; Index < CountOfCodes; Index += 1) {
559 UnwindOp = UnwindInfo->UnwindCode[Index];
560 OpInfo = UnwindOp.OpInfo;
561
562 if (UnwindOp.UnwindOp != UWOP_PUSH_NONVOL) {
563 break;
564 }
565
566 if (CurrentOffset >= EpilogueOffset) {
567 IntegerAddress = (PULONG64)(ContextRecord->Rsp);
568
569 ContextRecord->Rsp += 8;
570 IntegerRegister[OpInfo] = MemoryRead64(IntegerAddress);
571 if (ARGUMENT_PRESENT(ContextPointers)) {
572 ContextPointers->IntegerContext[OpInfo] = IntegerAddress;
573 }
574 }
575
576 //
577 // POP r64 is encoded as (58h + r64) for the lower 8 general-purpose
578 // registers and REX.R, (58h + r64) for r8 - r15.
579 //
580
581 CurrentOffset += 1;
582 if (OpInfo >= 8) {
583 CurrentOffset += 1;
584 }
585 }
586
587 //
588 // Check for an UWOP_ALLOC_SMALL 8 directive, which corresponds to a push
589 // of the FLAGS register.
590 //
591
592 if ((Index < CountOfCodes) &&
593 (UnwindOp.UnwindOp == UWOP_ALLOC_SMALL) && (OpInfo == 0)) {
594
595 if (CurrentOffset >= EpilogueOffset) {
596 ContextRecord->Rsp += 8;
597 }
598
599 CurrentOffset += 1;
600 Index += 1;
601 }
602
603 //
604 // Check for a machine frame.
605 //
606
607 if (Index < CountOfCodes) {
608 UnwindOp = UnwindInfo->UnwindCode[Index];
609 if (UnwindOp.UnwindOp == UWOP_PUSH_MACHFRAME) {
610 ReturnAddress = (PULONG64)(ContextRecord->Rsp);
611 StackAddress = (PULONG64)(ContextRecord->Rsp + (3 * 8));
612
613 ContextRecord->Rip = MemoryRead64(ReturnAddress);
614 ContextRecord->Rsp = MemoryRead64(StackAddress);
615 return S_OK;
616 }
617
618 //
619 // Any remaining operation must be a machine frame.
620 //
621
622 UNWINDER_ASSERT(FALSE);
623 }
624
625 //
626 // Emulate a return operation.
627 //
628
629 IntegerAddress = (PULONG64)(ContextRecord->Rsp);
630
631 ContextRecord->Rip = MemoryRead64(IntegerAddress);
632 ContextRecord->Rsp += 8;
633 return S_OK;
634}
635
636HRESULT
637OOPStackUnwinderAMD64::UnwindPrologue(
638 __in ULONG64 ImageBase,
639 __in ULONG64 ControlPc,
640 __in ULONG64 FrameBase,
641 __in _PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionEntry,
642 __inout PCONTEXT ContextRecord,
643 __inout_opt PKNONVOLATILE_CONTEXT_POINTERS ContextPointers,
644 __deref_out _PIMAGE_RUNTIME_FUNCTION_ENTRY *FinalFunctionEntry
645 )
646
647/*++
648
649Routine Description:
650
651 This function processes unwind codes and reverses the state change
652 effects of a prologue. If the specified unwind information contains
653 chained unwind information, then that prologue is unwound recursively.
654 As the prologue is unwound state changes are recorded in the specified
655 context structure and optionally in the specified context pointers
656 structures.
657
658Arguments:
659
660 ImageBase - Supplies the base address of the image that contains the
661 function being unwound.
662
663 ControlPc - Supplies the address where control left the specified
664 function.
665
666 FrameBase - Supplies the base of the stack frame subject function stack
667 frame.
668
669 FunctionEntry - Supplies the address of the function table entry for the
670 specified function.
671
672 ContextRecord - Supplies the address of a context record.
673
674 ContextPointers - Supplies an optional pointer to a context pointers
675 record.
676
677 FinalFunctionEntry - Supplies a pointer to a variable that receives the
678 final function entry after the specified function entry and all
679 descendent chained entries have been unwound. This will have been
680 probed as appropriate.
681
682Return Value:
683
684 HRESULT.
685
686--*/
687
688{
689
690 ULONG ChainCount;
691 PM128A FloatingAddress;
692 PM128A FloatingRegister;
693 ULONG FrameOffset;
694 ULONG Index;
695 PULONG64 IntegerAddress;
696 PULONG64 IntegerRegister;
697 BOOLEAN MachineFrame;
698 ULONG OpInfo;
699 ULONG PrologOffset;
700 PULONG64 ReturnAddress;
701 PULONG64 StackAddress;
702 PUNWIND_INFO UnwindInfo;
703 ULONG UnwindOp;
704
705 //
706 // Process the unwind codes for the specified function entry and all its
707 // descendent chained function entries.
708 //
709
710 ChainCount = 0;
711 FloatingRegister = &ContextRecord->Xmm0;
712 IntegerRegister = &ContextRecord->Rax;
713 do {
714 Index = 0;
715 MachineFrame = FALSE;
716 PrologOffset = (ULONG)(ControlPc - (FunctionEntry->BeginAddress + ImageBase));
717
718 UnwindInfo = GetUnwindInfo(ImageBase + FunctionEntry->UnwindInfoAddress);
719 if (UnwindInfo == NULL)
720 {
721 return HRESULT_FROM_WIN32(ERROR_READ_FAULT);
722 }
723
724 while (Index < UnwindInfo->CountOfUnwindCodes) {
725
726 //
727 // If the prologue offset is greater than the next unwind code
728 // offset, then simulate the effect of the unwind code.
729 //
730
731 UnwindOp = UnwindInfo->UnwindCode[Index].UnwindOp;
732#ifdef PLATFORM_UNIX
733 if (UnwindOp > UWOP_SET_FPREG_LARGE) {
734 return E_UNEXPECTED;
735 }
736#else // !PLATFORM_UNIX
737 if (UnwindOp > UWOP_PUSH_MACHFRAME) {
738 return E_UNEXPECTED;
739 }
740#endif // !PLATFORM_UNIX
741
742 OpInfo = UnwindInfo->UnwindCode[Index].OpInfo;
743 if (PrologOffset >= UnwindInfo->UnwindCode[Index].CodeOffset) {
744 switch (UnwindOp) {
745
746 //
747 // Push nonvolatile integer register.
748 //
749 // The operation information is the register number of
750 // the register than was pushed.
751 //
752
753 case UWOP_PUSH_NONVOL:
754 IntegerAddress = (PULONG64)ContextRecord->Rsp;
755 IntegerRegister[OpInfo] = MemoryRead64(IntegerAddress);
756
757 if (ARGUMENT_PRESENT(ContextPointers)) {
758 ContextPointers->IntegerContext[OpInfo] = IntegerAddress;
759 }
760
761 ContextRecord->Rsp += 8;
762 break;
763
764 //
765 // Allocate a large sized area on the stack.
766 //
767 // The operation information determines if the size is
768 // 16- or 32-bits.
769 //
770
771 case UWOP_ALLOC_LARGE:
772 Index += 1;
773 FrameOffset = UnwindInfo->UnwindCode[Index].FrameOffset;
774 if (OpInfo != 0) {
775 Index += 1;
776 FrameOffset += (UnwindInfo->UnwindCode[Index].FrameOffset << 16);
777
778 } else {
779 // The 16-bit form is scaled.
780 FrameOffset *= 8;
781 }
782
783 ContextRecord->Rsp += FrameOffset;
784 break;
785
786 //
787 // Allocate a small sized area on the stack.
788 //
789 // The operation information is the size of the unscaled
790 // allocation size (8 is the scale factor) minus 8.
791 //
792
793 case UWOP_ALLOC_SMALL:
794 ContextRecord->Rsp += (OpInfo * 8) + 8;
795 break;
796
797 //
798 // Establish the the frame pointer register.
799 //
800 // The operation information is not used.
801 //
802
803 case UWOP_SET_FPREG:
804 ContextRecord->Rsp = IntegerRegister[UnwindInfo->FrameRegister];
805 ContextRecord->Rsp -= UnwindInfo->FrameOffset * 16;
806 break;
807
808#ifdef PLATFORM_UNIX
809
810 //
811 // Establish the the frame pointer register using a large size displacement.
812 // UNWIND_INFO.FrameOffset must be 15 (the maximum value, corresponding to a scaled
813 // offset of 15 * 16 == 240). The next two codes contain a 32-bit offset, which
814 // is also scaled by 16, since the stack must remain 16-bit aligned.
815 //
816
817 case UWOP_SET_FPREG_LARGE:
818 UNWINDER_ASSERT(UnwindInfo->FrameOffset == 15);
819 Index += 2;
820 FrameOffset = UnwindInfo->UnwindCode[Index - 1].FrameOffset;
821 FrameOffset += UnwindInfo->UnwindCode[Index].FrameOffset << 16;
822 UNWINDER_ASSERT((FrameOffset & 0xF0000000) == 0);
823 ContextRecord->Rsp = IntegerRegister[UnwindInfo->FrameRegister];
824 ContextRecord->Rsp -= FrameOffset * 16;
825 break;
826
827#endif // PLATFORM_UNIX
828
829 //
830 // Save nonvolatile integer register on the stack using a
831 // 16-bit displacment.
832 //
833 // The operation information is the register number.
834 //
835
836 case UWOP_SAVE_NONVOL:
837 Index += 1;
838 FrameOffset = UnwindInfo->UnwindCode[Index].FrameOffset * 8;
839 IntegerAddress = (PULONG64)(FrameBase + FrameOffset);
840 IntegerRegister[OpInfo] = MemoryRead64(IntegerAddress);
841
842 if (ARGUMENT_PRESENT(ContextPointers)) {
843 ContextPointers->IntegerContext[OpInfo] = IntegerAddress;
844 }
845
846 break;
847
848 //
849 // Save nonvolatile integer register on the stack using a
850 // 32-bit displacment.
851 //
852 // The operation information is the register number.
853 //
854
855 case UWOP_SAVE_NONVOL_FAR:
856 Index += 2;
857 FrameOffset = UnwindInfo->UnwindCode[Index - 1].FrameOffset;
858 FrameOffset += UnwindInfo->UnwindCode[Index].FrameOffset << 16;
859 IntegerAddress = (PULONG64)(FrameBase + FrameOffset);
860 IntegerRegister[OpInfo] = MemoryRead64(IntegerAddress);
861
862 if (ARGUMENT_PRESENT(ContextPointers)) {
863 ContextPointers->IntegerContext[OpInfo] = IntegerAddress;
864 }
865
866 break;
867
868 //
869 // Function epilog marker (ignored for prologue unwind).
870 //
871
872 case UWOP_EPILOG:
873 Index += 1;
874 break;
875
876 //
877 // Spare unused codes.
878 //
879
880
881 case UWOP_SPARE_CODE:
882
883 UNWINDER_ASSERT(FALSE);
884
885 Index += 2;
886 break;
887
888 //
889 // Save a nonvolatile XMM(128) register on the stack using a
890 // 16-bit displacement.
891 //
892 // The operation information is the register number.
893 //
894
895 case UWOP_SAVE_XMM128:
896 Index += 1;
897 FrameOffset = UnwindInfo->UnwindCode[Index].FrameOffset * 16;
898 FloatingAddress = (PM128A)(FrameBase + FrameOffset);
899 FloatingRegister[OpInfo] = MemoryRead128(FloatingAddress);
900
901 if (ARGUMENT_PRESENT(ContextPointers)) {
902 ContextPointers->FloatingContext[OpInfo] = FloatingAddress;
903 }
904
905 break;
906
907 //
908 // Save a nonvolatile XMM(128) register on the stack using
909 // a 32-bit displacement.
910 //
911 // The operation information is the register number.
912 //
913
914 case UWOP_SAVE_XMM128_FAR:
915 Index += 2;
916 FrameOffset = UnwindInfo->UnwindCode[Index - 1].FrameOffset;
917 FrameOffset += UnwindInfo->UnwindCode[Index].FrameOffset << 16;
918 FloatingAddress = (PM128A)(FrameBase + FrameOffset);
919 FloatingRegister[OpInfo] = MemoryRead128(FloatingAddress);
920
921 if (ARGUMENT_PRESENT(ContextPointers)) {
922 ContextPointers->FloatingContext[OpInfo] = FloatingAddress;
923 }
924
925 break;
926
927 //
928 // Push a machine frame on the stack.
929 //
930 // The operation information determines whether the
931 // machine frame contains an error code or not.
932 //
933
934 case UWOP_PUSH_MACHFRAME:
935 MachineFrame = TRUE;
936 ReturnAddress = (PULONG64)ContextRecord->Rsp;
937 StackAddress = (PULONG64)(ContextRecord->Rsp + (3 * 8));
938 if (OpInfo != 0) {
939 ReturnAddress += 1;
940 StackAddress += 1;
941 }
942
943 ContextRecord->Rip = MemoryRead64(ReturnAddress);
944 ContextRecord->Rsp = MemoryRead64(StackAddress);
945
946 break;
947
948 //
949 // Unused codes.
950 //
951
952 default:
953 //RtlRaiseStatus(STATUS_BAD_FUNCTION_TABLE);
954 break;
955 }
956
957 Index += 1;
958
959 } else {
960
961 //
962 // Skip this unwind operation by advancing the slot index
963 // by the number of slots consumed by this operation.
964 //
965
966 Index += UnwindOpSlots(UnwindInfo->UnwindCode[Index]);
967 }
968 }
969
970 //
971 // If chained unwind information is specified, then set the function
972 // entry address to the chained function entry and continue the scan.
973 // Otherwise, determine the return address if a machine frame was not
974 // encountered during the scan of the unwind codes and terminate the
975 // scan.
976 //
977
978 if ((UnwindInfo->Flags & UNW_FLAG_CHAININFO) != 0) {
979
980 Index = UnwindInfo->CountOfUnwindCodes;
981 if ((Index & 1) != 0) {
982 Index += 1;
983 }
984
985 // GetUnwindInfo looks for CHAININFO and reads
986 // the trailing RUNTIME_FUNCTION so we can just
987 // directly use the data sitting in UnwindInfo.
988 FunctionEntry = (_PIMAGE_RUNTIME_FUNCTION_ENTRY)
989 &UnwindInfo->UnwindCode[Index];
990 } else {
991
992 if (MachineFrame == FALSE) {
993 ContextRecord->Rip = MemoryRead64((PULONG64)ContextRecord->Rsp);
994 ContextRecord->Rsp += 8;
995 }
996
997 break;
998 }
999
1000 //
1001 // Limit the number of iterations possible for chained function table
1002 // entries.
1003 //
1004
1005 ChainCount += 1;
1006 UNWINDER_ASSERT(ChainCount <= UNWIND_CHAIN_LIMIT);
1007
1008 } while (TRUE);
1009
1010 *FinalFunctionEntry = FunctionEntry;
1011 return S_OK;
1012}
1013
1014HRESULT
1015OOPStackUnwinderAMD64::VirtualUnwind(
1016 __in DWORD HandlerType,
1017 __in ULONG64 ImageBase,
1018 __in ULONG64 ControlPc,
1019 __in _PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionEntry,
1020 __inout PCONTEXT ContextRecord,
1021 __out PVOID *HandlerData,
1022 __out PULONG64 EstablisherFrame,
1023 __inout_opt PKNONVOLATILE_CONTEXT_POINTERS ContextPointers,
1024 __deref_opt_out_opt PEXCEPTION_ROUTINE *HandlerRoutine
1025 )
1026
1027/*++
1028
1029Routine Description:
1030
1031 This function virtually unwinds the specified function by executing its
1032 prologue code backward or its epilogue code forward.
1033
1034 If a context pointers record is specified, then the address where each
1035 nonvolatile registers is restored from is recorded in the appropriate
1036 element of the context pointers record.
1037
1038Arguments:
1039
1040 HandlerType - Supplies the handler type expected for the virtual unwind.
1041 This may be either an exception or an unwind handler. A flag may
1042 optionally be supplied to avoid epilogue detection if it is known
1043 the specified control PC is not located inside a function epilogue.
1044
1045 ImageBase - Supplies the base address of the image that contains the
1046 function being unwound.
1047
1048 ControlPc - Supplies the address where control left the specified
1049 function.
1050
1051 FunctionEntry - Supplies the address of the function table entry for the
1052 specified function.
1053
1054 ContextRecord - Supplies the address of a context record.
1055
1056
1057 HandlerData - Supplies a pointer to a variable that receives a pointer
1058 the the language handler data.
1059
1060 EstablisherFrame - Supplies a pointer to a variable that receives the
1061 the establisher frame pointer value.
1062
1063 ContextPointers - Supplies an optional pointer to a context pointers
1064 record.
1065
1066 HandlerRoutine - Supplies an optional pointer to a variable that receives
1067 the handler routine address. If control did not leave the specified
1068 function in either the prologue or an epilogue and a handler of the
1069 proper type is associated with the function, then the address of the
1070 language specific exception handler is returned. Otherwise, NULL is
1071 returned.
1072--*/
1073
1074{
1075
1076 ULONG64 BranchTarget;
1077 LONG Displacement;
1078 ULONG EpilogueOffset;
1079 ULONG EpilogueSize;
1080 PEXCEPTION_ROUTINE FoundHandler;
1081 ULONG FrameRegister;
1082 ULONG FrameOffset;
1083 ULONG Index;
1084 BOOL InEpilogue;
1085 PULONG64 IntegerAddress;
1086 PULONG64 IntegerRegister;
1087 _PIMAGE_RUNTIME_FUNCTION_ENTRY PrimaryFunctionEntry;
1088 ULONG PrologOffset;
1089 ULONG RegisterNumber;
1090 ULONG RelativePc;
1091 HRESULT Status;
1092 PUNWIND_INFO UnwindInfo;
1093 ULONG UnwindVersion;
1094 UNWIND_CODE UnwindOp;
1095
1096 FoundHandler = NULL;
1097 UnwindInfo = GetUnwindInfo(ImageBase + FunctionEntry->UnwindInfoAddress);
1098 if (UnwindInfo == NULL)
1099 {
1100 return HRESULT_FROM_WIN32(ERROR_READ_FAULT);
1101 }
1102
1103 UnwindVersion = UnwindInfo->Version;
1104
1105 //
1106 // If the specified function does not use a frame pointer, then the
1107 // establisher frame is the contents of the stack pointer. This may
1108 // not actually be the real establisher frame if control left the
1109 // function from within the prologue. In this case the establisher
1110 // frame may be not required since control has not actually entered
1111 // the function and prologue entries cannot refer to the establisher
1112 // frame before it has been established, i.e., if it has not been
1113 // established, then no save unwind codes should be encountered during
1114 // the unwind operation.
1115 //
1116 // If the specified function uses a frame pointer and control left the
1117 // function outside of the prologue or the unwind information contains
1118 // a chained information structure, then the establisher frame is the
1119 // contents of the frame pointer.
1120 //
1121 // If the specified function uses a frame pointer and control left the
1122 // function from within the prologue, then the set frame pointer unwind
1123 // code must be looked up in the unwind codes to determine if the
1124 // contents of the stack pointer or the contents of the frame pointer
1125 // should be used for the establisher frame. This may not actually be
1126 // the real establisher frame. In this case the establisher frame may
1127 // not be required since control has not actually entered the function
1128 // and prologue entries cannot refer to the establisher frame before it
1129 // has been established, i.e., if it has not been established, then no
1130 // save unwind codes should be encountered during the unwind operation.
1131 //
1132 // N.B. The correctness of these assumptions is based on the ordering of
1133 // unwind codes.
1134 //
1135
1136 PrologOffset = (ULONG)(ControlPc - (FunctionEntry->BeginAddress + ImageBase));
1137 if (UnwindInfo->FrameRegister == 0) {
1138 *EstablisherFrame = ContextRecord->Rsp;
1139
1140 } else if ((PrologOffset >= UnwindInfo->SizeOfProlog) ||
1141 ((UnwindInfo->Flags & UNW_FLAG_CHAININFO) != 0)) {
1142
1143 FrameOffset = UnwindInfo->FrameOffset;
1144
1145#ifdef PLATFORM_UNIX
1146 // If UnwindInfo->FrameOffset == 15 (the maximum value), then there might be a UWOP_SET_FPREG_LARGE.
1147 // However, it is still legal for a UWOP_SET_FPREG to set UnwindInfo->FrameOffset == 15 (since this
1148 // was always part of the specification), so we need to look through the UnwindCode array to determine
1149 // if there is indeed a UWOP_SET_FPREG_LARGE. If we don't find UWOP_SET_FPREG_LARGE, then just use
1150 // (scaled) FrameOffset of 240, as before. (We don't verify there is a UWOP_SET_FPREG code, but we could.)
1151 if (FrameOffset == 15) {
1152 Index = 0;
1153 while (Index < UnwindInfo->CountOfUnwindCodes) {
1154 UnwindOp = UnwindInfo->UnwindCode[Index];
1155 if (UnwindOp.UnwindOp == UWOP_SET_FPREG_LARGE) {
1156 FrameOffset = UnwindInfo->UnwindCode[Index + 1].FrameOffset;
1157 FrameOffset += UnwindInfo->UnwindCode[Index + 2].FrameOffset << 16;
1158 break;
1159 }
1160
1161 Index += UnwindOpSlots(UnwindOp);
1162 }
1163 }
1164#endif // PLATFORM_UNIX
1165
1166 *EstablisherFrame = (&ContextRecord->Rax)[UnwindInfo->FrameRegister];
1167 *EstablisherFrame -= FrameOffset * 16;
1168
1169 } else {
1170 FrameOffset = UnwindInfo->FrameOffset;
1171 Index = 0;
1172 while (Index < UnwindInfo->CountOfUnwindCodes) {
1173 UnwindOp = UnwindInfo->UnwindCode[Index];
1174 if (UnwindOp.UnwindOp == UWOP_SET_FPREG) {
1175 break;
1176 }
1177#ifdef PLATFORM_UNIX
1178 else if (UnwindOp.UnwindOp == UWOP_SET_FPREG_LARGE) {
1179 UNWINDER_ASSERT(UnwindInfo->FrameOffset == 15);
1180 FrameOffset = UnwindInfo->UnwindCode[Index + 1].FrameOffset;
1181 FrameOffset += UnwindInfo->UnwindCode[Index + 2].FrameOffset << 16;
1182 break;
1183 }
1184#endif // PLATFORM_UNIX
1185
1186 Index += UnwindOpSlots(UnwindOp);
1187 }
1188
1189 if (PrologOffset >= UnwindInfo->UnwindCode[Index].CodeOffset) {
1190 *EstablisherFrame = (&ContextRecord->Rax)[UnwindInfo->FrameRegister];
1191 *EstablisherFrame -= FrameOffset * 16;
1192
1193 } else {
1194 *EstablisherFrame = ContextRecord->Rsp;
1195 }
1196 }
1197
1198 //
1199 // Check if control left the specified function during an epilogue
1200 // sequence and emulate the execution of the epilogue forward and
1201 // return no exception handler.
1202 //
1203 // If the unwind version indicates the absence of epilogue unwind codes
1204 // this is done by emulating the instruction stream. Otherwise, epilogue
1205 // detection and emulation is performed using the function unwind codes.
1206 //
1207
1208 InEpilogue = FALSE;
1209 if (UnwindVersion < 2) {
1210 InstructionBuffer InstrBuffer = (InstructionBuffer)ControlPc;
1211 InstructionBuffer NextByte = InstrBuffer;
1212
1213 //
1214 // Check for one of:
1215 //
1216 // add rsp, imm8
1217 // or
1218 // add rsp, imm32
1219 // or
1220 // lea rsp, -disp8[fp]
1221 // or
1222 // lea rsp, -disp32[fp]
1223 //
1224
1225 if ((NextByte[0] == SIZE64_PREFIX) &&
1226 (NextByte[1] == ADD_IMM8_OP) &&
1227 (NextByte[2] == 0xc4)) {
1228
1229 //
1230 // add rsp, imm8.
1231 //
1232
1233 NextByte += 4;
1234
1235 } else if ((NextByte[0] == SIZE64_PREFIX) &&
1236 (NextByte[1] == ADD_IMM32_OP) &&
1237 (NextByte[2] == 0xc4)) {
1238
1239 //
1240 // add rsp, imm32.
1241 //
1242
1243 NextByte += 7;
1244
1245 } else if (((NextByte[0] & 0xfe) == SIZE64_PREFIX) &&
1246 (NextByte[1] == LEA_OP)) {
1247
1248 FrameRegister = ((NextByte[0] & 0x1) << 3) | (NextByte[2] & 0x7);
1249 if ((FrameRegister != 0) &&
1250 (FrameRegister == UnwindInfo->FrameRegister)) {
1251
1252 if ((NextByte[2] & 0xf8) == 0x60) {
1253
1254 //
1255 // lea rsp, disp8[fp].
1256 //
1257
1258 NextByte += 4;
1259
1260 } else if ((NextByte[2] &0xf8) == 0xa0) {
1261
1262 //
1263 // lea rsp, disp32[fp].
1264 //
1265
1266 NextByte += 7;
1267 }
1268 }
1269 }
1270
1271 //
1272 // Check for any number of:
1273 //
1274 // pop nonvolatile-integer-register[0..15].
1275 //
1276
1277 while (TRUE) {
1278 if ((NextByte[0] & 0xf8) == POP_OP) {
1279 NextByte += 1;
1280
1281 } else if (IS_REX_PREFIX(NextByte[0]) &&
1282 ((NextByte[1] & 0xf8) == POP_OP)) {
1283
1284 NextByte += 2;
1285
1286 } else {
1287 break;
1288 }
1289 }
1290
1291 //
1292 // A REPNE prefix may optionally precede a control transfer
1293 // instruction with no effect on unwinding.
1294 //
1295
1296 if (NextByte[0] == REPNE_PREFIX) {
1297 NextByte += 1;
1298 }
1299
1300 //
1301 // If the next instruction is a return or an appropriate jump, then
1302 // control is currently in an epilogue and execution of the epilogue
1303 // should be emulated. Otherwise, execution is not in an epilogue and
1304 // the prologue should be unwound.
1305 //
1306
1307 InEpilogue = FALSE;
1308 if ( ((NextByte[0] == RET_OP) ||
1309 (NextByte[0] == RET_OP_2)) ||
1310 (((NextByte[0] == REP_PREFIX) && (NextByte[1] == RET_OP)))) {
1311
1312 //
1313 // A return is an unambiguous indication of an epilogue.
1314 //
1315
1316 InEpilogue = TRUE;
1317
1318 } else if ((NextByte[0] == JMP_IMM8_OP) ||
1319 (NextByte[0] == JMP_IMM32_OP)) {
1320
1321 //
1322 // An unconditional branch to a target that is equal to the start of
1323 // or outside of this routine is logically a call to another function.
1324 //
1325
1326 BranchTarget = (ULONG64)NextByte - ImageBase;
1327 if (NextByte[0] == JMP_IMM8_OP) {
1328 BranchTarget += 2 + (CHAR)NextByte[1];
1329
1330 } else {
1331 LONG32 delta = NextByte[1] | (NextByte[2] << 8) |
1332 (NextByte[3] << 16) | (NextByte[4] << 24);
1333 BranchTarget += 5 + delta;
1334
1335 }
1336
1337 //
1338 // Determine whether the branch target refers to code within this
1339 // function. If not, then it is an epilogue indicator.
1340 //
1341 // A branch to the start of self implies a recursive call, so
1342 // is treated as an epilogue.
1343 //
1344
1345 if (BranchTarget < FunctionEntry->BeginAddress ||
1346 BranchTarget >= FunctionEntry->EndAddress) {
1347
1348 //
1349 // The branch target is outside of the region described by
1350 // this function entry. See whether it is contained within
1351 // an indirect function entry associated with this same
1352 // function.
1353 //
1354 // If not, then the branch target really is outside of
1355 // this function.
1356 //
1357
1358 PrimaryFunctionEntry =
1359 SameFunction(FunctionEntry,
1360 ImageBase,
1361 BranchTarget + ImageBase);
1362
1363 if ((PrimaryFunctionEntry == NULL) ||
1364 (BranchTarget == PrimaryFunctionEntry->BeginAddress)) {
1365
1366 InEpilogue = TRUE;
1367 }
1368
1369 } else if ((BranchTarget == FunctionEntry->BeginAddress) &&
1370 ((UnwindInfo->Flags & UNW_FLAG_CHAININFO) == 0)) {
1371
1372 InEpilogue = TRUE;
1373 }
1374
1375 } else if ((NextByte[0] == JMP_IND_OP) && (NextByte[1] == 0x25)) {
1376
1377 //
1378 // An unconditional jump indirect.
1379 //
1380 // This is a jmp outside of the function, probably a tail call
1381 // to an import function.
1382 //
1383
1384 InEpilogue = TRUE;
1385
1386 } else if (((NextByte[0] & 0xf8) == SIZE64_PREFIX) &&
1387 (NextByte[1] == 0xff) &&
1388 (NextByte[2] & 0x38) == 0x20) {
1389
1390 //
1391 // This is an indirect jump opcode: 0x48 0xff /4. The 64-bit
1392 // flag (REX.W) is always redundant here, so its presence is
1393 // overloaded to indicate a branch out of the function - a tail
1394 // call.
1395 //
1396 // Such an opcode is an unambiguous epilogue indication.
1397 //
1398
1399 InEpilogue = TRUE;
1400 }
1401
1402 if (InEpilogue != FALSE) {
1403 IntegerRegister = &ContextRecord->Rax;
1404 NextByte = InstrBuffer;
1405
1406 //
1407 // Emulate one of (if any):
1408 //
1409 // add rsp, imm8
1410 // or
1411 // add rsp, imm32
1412 // or
1413 // lea rsp, disp8[frame-register]
1414 // or
1415 // lea rsp, disp32[frame-register]
1416 //
1417
1418 if ((NextByte[0] & 0xf8) == SIZE64_PREFIX) {
1419
1420 if (NextByte[1] == ADD_IMM8_OP) {
1421
1422 //
1423 // add rsp, imm8.
1424 //
1425
1426 ContextRecord->Rsp += (CHAR)NextByte[3];
1427 NextByte += 4;
1428
1429 }
1430 else if (NextByte[1] == ADD_IMM32_OP) {
1431
1432 //
1433 // add rsp, imm32.
1434 //
1435
1436 Displacement = NextByte[3] | (NextByte[4] << 8);
1437 Displacement |= (NextByte[5] << 16) | (NextByte[6] << 24);
1438 ContextRecord->Rsp += Displacement;
1439 NextByte += 7;
1440
1441 }
1442 else if (NextByte[1] == LEA_OP) {
1443 if ((NextByte[2] & 0xf8) == 0x60) {
1444
1445 //
1446 // lea rsp, disp8[frame-register].
1447 //
1448
1449 ContextRecord->Rsp = IntegerRegister[FrameRegister];
1450 ContextRecord->Rsp += (CHAR)NextByte[3];
1451 NextByte += 4;
1452
1453 }
1454 else if ((NextByte[2] & 0xf8) == 0xa0) {
1455
1456 //
1457 // lea rsp, disp32[frame-register].
1458 //
1459
1460 Displacement = NextByte[3] | (NextByte[4] << 8);
1461 Displacement |= (NextByte[5] << 16) | (NextByte[6] << 24);
1462 ContextRecord->Rsp = IntegerRegister[FrameRegister];
1463 ContextRecord->Rsp += Displacement;
1464 NextByte += 7;
1465 }
1466 }
1467 }
1468
1469 //
1470 // Emulate any number of (if any):
1471 //
1472 // pop nonvolatile-integer-register.
1473 //
1474
1475 while (TRUE) {
1476 if ((NextByte[0] & 0xf8) == POP_OP) {
1477
1478 //
1479 // pop nonvolatile-integer-register[0..7]
1480 //
1481
1482 RegisterNumber = NextByte[0] & 0x7;
1483 IntegerAddress = (PULONG64)ContextRecord->Rsp;
1484 IntegerRegister[RegisterNumber] = MemoryRead64(IntegerAddress);
1485
1486 if (ARGUMENT_PRESENT(ContextPointers)) {
1487 ContextPointers->IntegerContext[RegisterNumber] = IntegerAddress;
1488 }
1489
1490 ContextRecord->Rsp += 8;
1491 NextByte += 1;
1492
1493 }
1494 else if (IS_REX_PREFIX(NextByte[0]) &&
1495 (NextByte[1] & 0xf8) == POP_OP) {
1496
1497 //
1498 // pop nonvolatile-integer-register[8..15]
1499 //
1500
1501 RegisterNumber = ((NextByte[0] & 1) << 3) | (NextByte[1] & 0x7);
1502 IntegerAddress = (PULONG64)ContextRecord->Rsp;
1503 IntegerRegister[RegisterNumber] = MemoryRead64(IntegerAddress);
1504
1505 if (ARGUMENT_PRESENT(ContextPointers)) {
1506 ContextPointers->IntegerContext[RegisterNumber] = IntegerAddress;
1507 }
1508
1509 ContextRecord->Rsp += 8;
1510 NextByte += 2;
1511
1512 }
1513 else {
1514 break;
1515 }
1516 }
1517
1518 //
1519 // Emulate return and return null exception handler.
1520 //
1521 // Note: This instruction might in fact be a jmp, however
1522 // we want to emulate a return regardless.
1523 //
1524
1525 ContextRecord->Rip = MemoryRead64((PULONG64)ContextRecord->Rsp);
1526 ContextRecord->Rsp += 8;
1527 goto ExitSetHandler;
1528 }
1529
1530 } else if (UnwindInfo->CountOfUnwindCodes != 0) {
1531
1532 UNWINDER_ASSERT(UnwindVersion >= 2);
1533
1534 //
1535 // Capture the first unwind code and check if it is an epilogue code.
1536 // If it is not an epilogue code, the current function entry does not
1537 // contain any epilogues (it could represent a body region of a
1538 // separated function or it could represent a function which never
1539 // returns).
1540 //
1541
1542 UnwindOp = UnwindInfo->UnwindCode[0];
1543 if (UnwindOp.UnwindOp == UWOP_EPILOG) {
1544 EpilogueSize = UnwindOp.CodeOffset;
1545
1546 UNWINDER_ASSERT(EpilogueSize != 0);
1547 //
1548 // If the low bit of the OpInfo field of the first epilogue code
1549 // is set, the function has a single epilogue at the end of the
1550 // function. Otherwise, subsequent epilogue unwind codes indicate
1551 // the offset of the epilogue(s) from the function end and the
1552 // relative PC must be compared against each epilogue record.
1553 //
1554 // N.B. The relative instruction pointer may not be within the
1555 // bounds of the runtime function entry if control left the
1556 // function in a region described by an indirect function
1557 // entry. Such a region cannot contain any epilogues.
1558 //
1559
1560 RelativePc = (ULONG)(ControlPc - ImageBase);
1561 if ((UnwindOp.OpInfo & 1) != 0) {
1562 EpilogueOffset = FunctionEntry->EndAddress - EpilogueSize;
1563 if (RelativePc - EpilogueOffset < EpilogueSize) {
1564 InEpilogue = TRUE;
1565 }
1566 }
1567
1568 if (InEpilogue == FALSE) {
1569 for (Index = 1; Index < UnwindInfo->CountOfUnwindCodes; Index += 1) {
1570 UnwindOp = UnwindInfo->UnwindCode[Index];
1571
1572 if (UnwindOp.UnwindOp == UWOP_EPILOG) {
1573 EpilogueOffset = UnwindOp.EpilogueCode.OffsetLow +
1574 UnwindOp.EpilogueCode.OffsetHigh * 256;
1575
1576 //
1577 // An epilogue offset of 0 indicates that this is
1578 // a padding entry (the number of epilogue codes
1579 // is a multiple of 2).
1580 //
1581
1582 if (EpilogueOffset == 0) {
1583 break;
1584 }
1585
1586 EpilogueOffset = FunctionEntry->EndAddress - EpilogueOffset;
1587 if (RelativePc - EpilogueOffset < EpilogueSize) {
1588
1589 UNWINDER_ASSERT(EpilogueOffset != FunctionEntry->EndAddress);
1590 InEpilogue = TRUE;
1591 break;
1592 }
1593
1594 } else {
1595 break;
1596 }
1597 }
1598 }
1599
1600 if (InEpilogue != FALSE) {
1601 Status = UnwindEpilogue(ImageBase,
1602 ControlPc,
1603 RelativePc - EpilogueOffset,
1604 FunctionEntry,
1605 ContextRecord,
1606 ContextPointers);
1607
1608 goto ExitSetHandler;
1609 }
1610 }
1611 }
1612
1613 //
1614 // Control left the specified function outside an epilogue. Unwind the
1615 // subject function and any chained unwind information.
1616 //
1617
1618 Status = UnwindPrologue(ImageBase,
1619 ControlPc,
1620 *EstablisherFrame,
1621 FunctionEntry,
1622 ContextRecord,
1623 ContextPointers,
1624 &FunctionEntry);
1625
1626 if (Status != S_OK) {
1627 return Status;
1628 }
1629
1630 //
1631 // If control left the specified function outside of the prologue and
1632 // the function has a handler that matches the specified type, then
1633 // return the address of the language specific exception handler.
1634 // Otherwise, return NULL.
1635 //
1636
1637 if (HandlerType != 0) {
1638 PrologOffset = (ULONG)(ControlPc - (FunctionEntry->BeginAddress + ImageBase));
1639 UnwindInfo = GetUnwindInfo(FunctionEntry->UnwindInfoAddress + ImageBase);
1640 if (UnwindInfo == NULL)
1641 {
1642 return HRESULT_FROM_WIN32(ERROR_READ_FAULT);
1643 }
1644 if ((PrologOffset >= UnwindInfo->SizeOfProlog) &&
1645 ((UnwindInfo->Flags & HandlerType) != 0)) {
1646
1647 Index = UnwindInfo->CountOfUnwindCodes;
1648 if ((Index & 1) != 0) {
1649 Index += 1;
1650 }
1651
1652 *HandlerData = &UnwindInfo->UnwindCode[Index + 2];
1653 FoundHandler = (PEXCEPTION_ROUTINE)(*((PULONG)&UnwindInfo->UnwindCode[Index]) + ImageBase);
1654 }
1655 }
1656
1657ExitSetHandler:
1658 if (ARGUMENT_PRESENT(HandlerRoutine)) {
1659 *HandlerRoutine = FoundHandler;
1660 }
1661
1662 return S_OK;
1663}
1664
1665_PIMAGE_RUNTIME_FUNCTION_ENTRY
1666OOPStackUnwinderAMD64::LookupPrimaryFunctionEntry(
1667 __in _PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionEntry,
1668 __in ULONG64 ImageBase
1669
1670 )
1671
1672/*++
1673
1674Routine Description:
1675
1676 This function determines whether the supplied function entry is a primary
1677 function entry or a chained function entry. If it is a chained function
1678 entry, then the primary function entry is returned.
1679
1680Arguments:
1681
1682 FunctionEntry - Supplies a pointer to the function entry for which the
1683 associated primary function entry will be located.
1684
1685 ImageBase - Supplies the base address of the image containing the
1686 supplied function entry.
1687
1688Return Value:
1689
1690 A pointer to the primary function entry is returned as the function value.
1691
1692--*/
1693
1694{
1695
1696 ULONG ChainCount;
1697 ULONG Index;
1698 PUNWIND_INFO UnwindInfo;
1699
1700 //
1701 // Locate the unwind information and determine whether it is chained.
1702 // If the unwind information is chained, then locate the parent function
1703 // entry and loop again.
1704 //
1705
1706 ChainCount = 0;
1707 do {
1708 UnwindInfo = GetUnwindInfo(FunctionEntry->UnwindInfoAddress + ImageBase);
1709 if ((UnwindInfo == NULL) || ((UnwindInfo->Flags & UNW_FLAG_CHAININFO) == 0))
1710 {
1711 break;
1712 }
1713
1714 Index = UnwindInfo->CountOfUnwindCodes;
1715 if ((Index & 1) != 0) {
1716 Index += 1;
1717 }
1718
1719 FunctionEntry = (_PIMAGE_RUNTIME_FUNCTION_ENTRY)&UnwindInfo->UnwindCode[Index];
1720
1721 //
1722 // Limit the number of iterations possible for chained function table
1723 // entries.
1724 //
1725
1726 ChainCount += 1;
1727 UNWINDER_ASSERT(ChainCount <= UNWIND_CHAIN_LIMIT);
1728
1729 } while (TRUE);
1730
1731 return FunctionEntry;
1732}
1733
1734_PIMAGE_RUNTIME_FUNCTION_ENTRY
1735OOPStackUnwinderAMD64::SameFunction(
1736 __in _PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionEntry,
1737 __in ULONG64 ImageBase,
1738 __in ULONG64 ControlPc
1739 )
1740
1741/*++
1742
1743Routine Description:
1744
1745 This function determines whether the address supplied by ControlPc lies
1746 anywhere within the function associated with FunctionEntry.
1747
1748Arguments:
1749
1750 FunctionEntry - Supplies a pointer to a function entry (primary or chained)
1751 associated with the function.
1752
1753 ImageBase - Supplies the base address of the image containing the supplied
1754 function entry.
1755
1756 ControlPc - Supplies the address that will be tested for inclusion within
1757 the function associated with FunctionEntry.
1758
1759Return Value:
1760
1761 If the address of the unwind information for the specified function is
1762 equal to the address of the unwind information for the control PC, then
1763 a pointer to a function table entry that describes the primary function
1764 table entry is returned as the function value. Otherwise, NULL is returned.
1765
1766--*/
1767
1768{
1769 _PIMAGE_RUNTIME_FUNCTION_ENTRY PrimaryFunctionEntry;
1770 _IMAGE_RUNTIME_FUNCTION_ENTRY TargetFunctionEntry;
1771 ULONG64 TargetImageBase;
1772
1773 //
1774 // Find the unwind information referenced by the primary function entry
1775 // associated with the specified function entry.
1776 //
1777
1778 PrimaryFunctionEntry = LookupPrimaryFunctionEntry(FunctionEntry,
1779 ImageBase);
1780
1781 //
1782 // Determine the function entry containing the control Pc and similarly
1783 // resolve its primary function entry. If no function entry can be
1784 // found then the control pc resides in a different function.
1785 //
1786
1787 if (GetModuleBase(ControlPc, &TargetImageBase) != S_OK ||
1788 GetFunctionEntry(ControlPc,
1789 &TargetFunctionEntry,
1790 sizeof(TargetFunctionEntry)) != S_OK) {
1791 return NULL;
1792 }
1793
1794 //
1795 // Lookup the primary function entry associated with the target function
1796 // entry.
1797 //
1798
1799 TargetFunctionEntry = *LookupPrimaryFunctionEntry(&TargetFunctionEntry,
1800 TargetImageBase);
1801
1802 //
1803 // If the beginning offset of the two function entries are equal, then
1804 // return the address of the primary function entry. Otherwise, return
1805 // NULL.
1806 //
1807
1808 if (PrimaryFunctionEntry->BeginAddress == TargetFunctionEntry.BeginAddress) {
1809 return PrimaryFunctionEntry;
1810
1811 } else {
1812 return NULL;
1813 }
1814}
1815
1816ULONG OOPStackUnwinderAMD64::UnwindOpSlots(__in UNWIND_CODE UnwindCode)
1817/*++
1818
1819Routine Description:
1820
1821 This routine determines the number of unwind code slots ultimately
1822 consumed by an unwind code sequence.
1823
1824Arguments:
1825
1826 UnwindCode - Supplies the first unwind code in the sequence.
1827
1828Return Value:
1829
1830 Returns the total count of the number of slots consumed by the unwind
1831 code sequence.
1832
1833--*/
1834{
1835
1836 ULONG Slots;
1837 ULONG UnwindOp;
1838
1839 //
1840 // UWOP_SPARE_CODE may be found in very old x64 images.
1841 //
1842
1843 UnwindOp = UnwindCode.UnwindOp;
1844
1845 UNWINDER_ASSERT(UnwindOp != UWOP_SPARE_CODE);
1846 UNWINDER_ASSERT(UnwindOp < sizeof(UnwindOpExtraSlotTable));
1847
1848 Slots = UnwindOpExtraSlotTable[UnwindOp] + 1;
1849 if ((UnwindOp == UWOP_ALLOC_LARGE) && (UnwindCode.OpInfo != 0)) {
1850 Slots += 1;
1851 }
1852
1853 return Slots;
1854}
1855
1856