summaryrefslogtreecommitdiff
path: root/src/inc/stackframe.h
blob: 11977e927305d1395c82162a49fd48229a55bb8d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#ifndef __STACKFRAME_H
#define __STACKFRAME_H

#include "regdisp.h"


struct StackFrame
{
    const static UINT_PTR maxVal = (UINT_PTR)(INT_PTR)-1;
    StackFrame() : SP(NULL)
    {
    }

    StackFrame(UINT_PTR sp)
    {
        SP = sp;
    }

    void Clear()
    {
        SP = NULL;
    }

    void SetMaxVal()
    {
        SP = maxVal;
    }

    bool IsNull()
    {
        return (SP == NULL);
    }

    bool IsMaxVal()
    {
        return (SP == maxVal);
    }

    bool operator==(StackFrame sf)
    {
        return (SP == sf.SP);
    }

    bool operator!=(StackFrame sf)
    {
        return (SP != sf.SP);
    }

    bool operator<(StackFrame sf)
    {
        return (SP < sf.SP);
    }

    bool operator<=(StackFrame sf)
    {
        return (SP <= sf.SP);
    }

    bool operator>(StackFrame sf)
    {
        return (SP > sf.SP);
    }

    bool operator>=(StackFrame sf)
    {
        return (SP >= sf.SP);
    }

    static inline StackFrame FromEstablisherFrame(UINT_PTR EstablisherFrame)
    {
        return StackFrame(EstablisherFrame);
    }

    static inline StackFrame FromRegDisplay(REGDISPLAY* pRD)
    {
        return StackFrame(GetRegdisplaySP(pRD));
    }

    UINT_PTR SP;
};


//---------------------------------------------------------------------------------------
//
// On WIN64, all the stack range tracking done by the Exception Handling (EH) subsystem is based on the 
// establisher frame given by the OS.  On IA64, the establisher frame is the caller SP and the current BSP.
// On X64, it is the initial SP before any dynamic stack allocation, i.e. it is the SP when a function exits
// the prolog.  The EH subsystem uses the same format.
//
// The stackwalker needs to get information from the EH subsystem in order to skip funclets.  Unfortunately, 
// stackwalking is based on the current SP, i.e. the SP when the control flow leaves a function via a 
// function call.  Thus, for stack frames with dynamic stack allocations on X64, the SP values used by the 
// stackwalker and the EH subsystem don't match.  
//
// To work around this problem, we need to somehow bridge the different SP values.  We do so by using the
// caller SP instead of the current SP for comparisons during a stackwalk on X64.  Creating a new type 
// explicitly spells out the important distinction that this is NOT in the same format as the 
// OS establisher frame.
//
// Notes:
//    In the long term, we should look at merging the two SP formats and have one consistent abstraction.
//

struct CallerStackFrame : StackFrame
{
    CallerStackFrame() : StackFrame()
    {
    }

    CallerStackFrame(UINT_PTR sp) : StackFrame(sp)
    {
    }

    static inline CallerStackFrame FromRegDisplay(REGDISPLAY* pRD)
    {
#if defined(_TARGET_AMD64_) || defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)
        _ASSERTE(pRD->IsCallerSPValid || pRD->IsCallerContextValid);
        return CallerStackFrame(GetSP(pRD->pCallerContext));
#else  // !_TARGET_AMD64_ && !_TARGET_ARM_ && !_TARGET_ARM64_
        _ASSERTE(!"CallerStackFrame::FromRegDisplay() - NYI on this platform");
        return CallerStackFrame();
#endif // !_TARGET_AMD64_ && !_TARGET_ARM_ && !_TARGET_ARM64_
    }
};

#endif  // __STACKFRAME_H