File: Seh32.cpp

package info (click to toggle)
storm-lang 0.7.4-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 52,004 kB
  • sloc: ansic: 261,462; cpp: 140,405; sh: 14,891; perl: 9,846; python: 2,525; lisp: 2,504; asm: 860; makefile: 678; pascal: 70; java: 52; xml: 37; awk: 12
file content (135 lines) | stat: -rw-r--r-- 3,778 bytes parent folder | download | duplicates (2)
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
131
132
133
134
135
#include "stdafx.h"
#include "Seh.h"

#if defined(WINDOWS) && defined(X86)

#include "SafeSeh.h"
#include "Code/Binary.h"
#include "Code/FnState.h"
#include "Utils/Memory.h"

namespace code {
	namespace eh {

		/**
		 * Stack frame on x86:
		 */
		struct OnStack {
			// SEH chain.
			OnStack *prev;
			const void *sehHandler;

			// Pointer to the running code. This is so that we are able to extract the location of
			// the Binary object during unwinding.
			void *self;

			// The topmost active block and active variables.
			Nat activePartVars;

			// Current EBP points to this.
			void *lastEbp;

			// Get ebp.
			inline void *ebp() {
				return &lastEbp;
			}

			// Create from base pointer:
			static OnStack *fromEBP(void *ebp) {
				byte *p = (byte *)ebp;
				return (OnStack *)(p - OFFSET_OF(OnStack, lastEbp));
			}

			// Get SEH address.
			inline void *seh() {
				return &prev;
			}

			// Create from SEH pointer:
			static OnStack *fromSEH(void *seh) {
				byte *p = (byte *)seh;
				return (OnStack *)(p - OFFSET_OF(OnStack, prev));
			}
		};

		SehFrame extractFrame(_EXCEPTION_RECORD *er, void *frame, _CONTEXT *ctx, void *dispatch) {
			OnStack *onStack = OnStack::fromSEH(frame);

			SehFrame result;
			result.stackPtr = onStack->ebp();
			result.frameOffset = 0;
			result.binary = codeBinary(onStack->self);
			decodeFnState(onStack->activePartVars, result.part, result.activation);
			return result;
		}

		// Called when we catch an exception. Called from a shim in assembler located in SafeSeh.asm
		extern "C"
		void *x86SEHCleanup(OnStack *onStack, storm::Nat cleanUntil, void *exception) {
			// Perform a partial cleanup of the frame:
			SehFrame frame;
			frame.stackPtr = onStack->ebp();
			frame.frameOffset = 0;
			frame.binary = codeBinary(onStack->self);
			decodeFnState(onStack->activePartVars, frame.part, frame.activation);

			Nat part = cleanupPartialFrame(frame, cleanUntil);

			// Update the state.
			onStack->activePartVars = encodeFnState(part, frame.activation);

			return exception;
		}

		void resumeFrame(SehFrame &frame, Binary::Resume &resume, storm::RootObject *object,
						_CONTEXT *ctx, _EXCEPTION_RECORD *er, void *dispatch) {
			OnStack *onStack = OnStack::fromEBP(frame.stackPtr);

			// Note: we could just let RtlUnwind return from the exception handler for us.

			// Note: In contrast to on 64-bit Windows, the RtlUnwind function does not traverse the
			// caller's frame.

			// First, we need to unwind the stack:
			er->ExceptionFlags |= EXCEPTION_UNWINDING;
			x86Unwind(er, onStack->seh());
			er->ExceptionFlags &= EXCEPTION_UNWINDING;

			// Clear the noncontinuable flag. Otherwise, we can't continue from the exception.
			er->ExceptionFlags &= ~DWORD(EXCEPTION_NONCONTINUABLE);

			// Build a stack "frame" that executes 'x86EhEntry' and returns to the resume point with Eax
			// set as intended. This approach places all data in registers, so that data on the stack is
			// not clobbered if we need it. It is also nice, as we don't have to think too carefully about
			// calling conventions and stack manipulations.
			ctx->Ebp = (UINT_PTR)frame.stackPtr;
			ctx->Esp = ctx->Ebp + resume.stackOffset;

			// Run.
			ctx->Eip = (UINT_PTR)&x86HandleException;
			// Return to.
			ctx->Edx = (UINT_PTR)resume.ip;
			// Exception.
			ctx->Eax = (UINT_PTR)object;
			// Current part.
			ctx->Ebx = (UINT_PTR)resume.cleanUntil;
			// Current frame.
			ctx->Ecx = (UINT_PTR)onStack;

			// Note: We also need to restore the EH chain (fs:[0]). The ASM shim does this for us.
		}

		void cleanupPartialFrame(SehFrame &, _EXCEPTION_RECORD *) {
			// Not used on x86.
		}

	}
}

#else

// Symbol to avoid warning when building on 64-bit systems.
// Defined in SafeSeh.h
void x86SafeSEH() {}

#endif