summaryrefslogtreecommitdiff
path: root/src/inc/stackframe.h
blob: 940951de313dde9b6c1cf3fb141f52dc68a099c2 (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
// 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)
    {
    }

#ifdef WIN64EXCEPTIONS
    static inline CallerStackFrame FromRegDisplay(REGDISPLAY* pRD)
    {
        _ASSERTE(pRD->IsCallerSPValid || pRD->IsCallerContextValid);
        return CallerStackFrame(GetSP(pRD->pCallerContext));
    }
#endif // WIN64EXCEPTIONS
};

#endif  // __STACKFRAME_H