VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/compiler/vcc/except-x86-vcc.cpp@ 97863

Last change on this file since 97863 was 97863, checked in by vboxsync, 2 years ago

IPRT/nocrt: Some _except_handler4 cleanups. bugref:10261 ticketref:21303

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.6 KB
Line 
1/* $Id: except-x86-vcc.cpp 97863 2022-12-23 17:01:49Z vboxsync $ */
2/** @file
3 * IPRT - Visual C++ Compiler - x86 Exception Handler Filter.
4 */
5
6/*
7 * Copyright (C) 2006-2022 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include <iprt/win/windows.h>
42
43#include "except-vcc.h"
44
45
46/*********************************************************************************************************************************
47* Global Variables *
48*********************************************************************************************************************************/
49extern "C" uintptr_t __security_cookie;
50
51
52/*********************************************************************************************************************************
53* Internal Functions *
54*********************************************************************************************************************************/
55DECLASM(LONG) rtVccEh4DoFiltering(PFN_EH4_XCPT_FILTER_T pfnFilter, uint8_t const *pbFrame);
56DECLASM(DECL_NO_RETURN(void)) rtVccEh4JumpToHandler(PFN_EH4_XCPT_HANDLER_T pfnHandler, uint8_t const *pbFrame);
57DECLASM(void) rtVccEh4DoGlobalUnwind(PEXCEPTION_RECORD pXcptRec, PEXCEPTION_REGISTRATION_RECORD pXcptRegRec);
58DECLASM(void) rtVccEh4DoFinally(PFN_EH4_FINALLY_T pfnFinally, bool fAbend, uint8_t const *pbFrame);
59
60
61/**
62 * Calls the __finally blocks up to @a uTargetTryLevel is reached, starting with
63 * @a pEh4XcptRegRec->uTryLevel.
64 *
65 * @param pEh4XcptRegRec The EH4 exception registration record.
66 * @param uTargetTryLevel The target __try level to stop unwinding at.
67 * @param pbFrame The frame pointer (EBP).
68 */
69static void rtVccEh4DoLocalUnwind(PEH4_XCPT_REG_REC_T pEh4XcptRegRec, uint32_t uTargetTryLevel, uint8_t const *pbFrame)
70{
71 /*
72 * Manually set up exception handler.
73 */
74 /** @todo */
75
76 /*
77 * Do the unwinding.
78 */
79 uint32_t uCurTryLevel = pEh4XcptRegRec->uTryLevel;
80 while ( uCurTryLevel != EH4_TOPMOST_TRY_LEVEL
81 && ( uCurTryLevel > uTargetTryLevel
82 || uTargetTryLevel == EH4_TOPMOST_TRY_LEVEL /* if we knew what 0xffffffff meant, this could probably be omitted */ ))
83 {
84 PCEH4_SCOPE_TAB_T const pScopeTable = (PCEH4_SCOPE_TAB_T)(pEh4XcptRegRec->uEncodedScopeTable ^ __security_cookie);
85 PCEH4_SCOPE_TAB_REC_T const pEntry = &pScopeTable->aScopeRecords[uCurTryLevel];
86
87 pEh4XcptRegRec->uTryLevel = uCurTryLevel = pEntry->uEnclosingLevel;
88
89 /* __finally scope table entries have no filter sub-function. */
90 if (!pEntry->pfnFilter)
91 {
92 //RTAssertMsg2("rtVccEh4DoLocalUnwind: Calling %p (level %#x)\n", pEntry->pfnFinally, uCurTryLevel);
93 rtVccEh4DoFinally(pEntry->pfnFinally, true /*fAbend*/, pbFrame);
94
95 /* Read the try level again in case it changed... */
96 uCurTryLevel = pEh4XcptRegRec->uTryLevel;
97 }
98 }
99
100 /*
101 * Deregister exception handler.
102 */
103 /** @todo */
104}
105
106
107DECLINLINE(void) rtVccValidateExceptionContextRecord(PCONTEXT pCpuCtx)
108{
109 RT_NOREF(pCpuCtx);
110 /** @todo Implement __exception_validate_context_record .*/
111}
112
113
114/**
115 * Helper that validates stack cookies.
116 */
117DECLINLINE(void) rtVccEh4ValidateCookies(PCEH4_SCOPE_TAB_T pScopeTable, uint8_t const *pbFrame)
118{
119 if (pScopeTable->offGSCookie != EH4_NO_GS_COOKIE)
120 {
121 uintptr_t uGsCookie = *(uintptr_t const *)&pbFrame[pScopeTable->offGSCookie];
122 uGsCookie ^= (uintptr_t)&pbFrame[pScopeTable->offGSCookieXor];
123 __security_check_cookie(uGsCookie);
124 }
125
126 uintptr_t uEhCookie = *(uintptr_t const *)&pbFrame[pScopeTable->offEHCookie];
127 uEhCookie ^= (uintptr_t)&pbFrame[pScopeTable->offEHCookieXor];
128 __security_check_cookie(uEhCookie);
129}
130
131
132/**
133 * Call exception filters, handlers and unwind code for x86 code.
134 *
135 * This is called for windows' structured exception handling (SEH) in x86 32-bit
136 * code, i.e. the __try/__except/__finally stuff in Visual C++. The compiler
137 * generate scope records for the __try/__except blocks as well as unwind
138 * records for __finally and probably C++ stack object destructors.
139 *
140 * @returns Exception disposition.
141 * @param pXcptRec The exception record.
142 * @param pXcptRegRec The exception registration record, taken to be the frame
143 * address.
144 * @param pCpuCtx The CPU context for the exception.
145 * @param pDispCtx Dispatcher context.
146 */
147extern "C" __declspec(guard(suppress))
148DWORD _except_handler4(PEXCEPTION_RECORD pXcptRec, PEXCEPTION_REGISTRATION_RECORD pXcptRegRec, PCONTEXT pCpuCtx, PVOID pvCtx)
149{
150 /*
151 * The registration record (probably chained on FS:[0] like in the OS/2 days)
152 * points to a larger structure specific to _except_handler4. The structure
153 * is planted right after the saved caller EBP value when establishing the
154 * stack frame, so EBP = pXcptRegRec + 1;
155 */
156 PEH4_XCPT_REG_REC_T const pEh4XcptRegRec = RT_FROM_MEMBER(pXcptRegRec, EH4_XCPT_REG_REC_T, XcptRec);
157 uint8_t * const pbFrame = (uint8_t *)&pEh4XcptRegRec[1];
158 PCEH4_SCOPE_TAB_T const pScopeTable = (PCEH4_SCOPE_TAB_T)(pEh4XcptRegRec->uEncodedScopeTable ^ __security_cookie);
159
160 /*
161 * Validate the stack cookie and exception context.
162 */
163 rtVccEh4ValidateCookies(pScopeTable, pbFrame);
164 rtVccValidateExceptionContextRecord(pCpuCtx);
165
166 /*
167 * If dispatching an exception, call the exception filter functions and jump
168 * to the __except blocks if so directed.
169 */
170 if (IS_DISPATCHING(pXcptRec->ExceptionFlags))
171 {
172 uint32_t uTryLevel = pEh4XcptRegRec->uTryLevel;
173 //RTAssertMsg2("_except_handler4: dispatch: uTryLevel=%#x\n", uTryLevel);
174 while (uTryLevel != EH4_TOPMOST_TRY_LEVEL)
175 {
176 PCEH4_SCOPE_TAB_REC_T const pEntry = &pScopeTable->aScopeRecords[uTryLevel];
177 PFN_EH4_XCPT_FILTER_T const pfnFilter = pEntry->pfnFilter;
178 if (pfnFilter)
179 {
180 /* Call the __except filtering expression: */
181 //RTAssertMsg2("_except_handler4: Calling pfnFilter=%p\n", pfnFilter);
182 EXCEPTION_POINTERS XcptPtrs = { pXcptRec, pCpuCtx };
183 pEh4XcptRegRec->pXctpPtrs = &XcptPtrs;
184 LONG lRet = rtVccEh4DoFiltering(pfnFilter, pbFrame);
185 pEh4XcptRegRec->pXctpPtrs = NULL;
186 //RTAssertMsg2("_except_handler4: pfnFilter=%p -> %ld\n", pfnFilter, lRet);
187 rtVccEh4ValidateCookies(pScopeTable, pbFrame);
188
189 /* Return if we're supposed to continue execution (the convention
190 it to match negative values rather than the exact defined value): */
191 AssertCompile(EXCEPTION_CONTINUE_EXECUTION == -1);
192 if (lRet <= EXCEPTION_CONTINUE_EXECUTION)
193 return ExceptionContinueExecution;
194
195 /* Similarly, the handler is executed for any positive value. */
196 AssertCompile(EXCEPTION_CONTINUE_SEARCH == 0);
197 AssertCompile(EXCEPTION_EXECUTE_HANDLER == 1);
198 if (lRet >= EXCEPTION_EXECUTE_HANDLER)
199 {
200 /* We're about to resume execution in the __except block, so unwind
201 up to it first. */
202 //RTAssertMsg2("_except_handler4: global unwind\n");
203 rtVccEh4DoGlobalUnwind(pXcptRec, &pEh4XcptRegRec->XcptRec);
204 if (pEh4XcptRegRec->uTryLevel != EH4_TOPMOST_TRY_LEVEL)
205 {
206 //RTAssertMsg2("_except_handler4: local unwind\n");
207 rtVccEh4DoLocalUnwind(pEh4XcptRegRec, uTryLevel, pbFrame);
208 }
209 rtVccEh4ValidateCookies(pScopeTable, pbFrame);
210
211 /* Now jump to the __except block. This will _not_ return. */
212 //RTAssertMsg2("_except_handler4: jumping to __except block %p (level %#x)\n", pEntry->pfnHandler, pEntry->uEnclosingLevel);
213 pEh4XcptRegRec->uTryLevel = pEntry->uEnclosingLevel;
214 rtVccEh4ValidateCookies(pScopeTable, pbFrame); /* paranoia^2 */
215
216 rtVccEh4JumpToHandler(pEntry->pfnHandler, pbFrame);
217 /* (not reached) */
218 }
219 }
220
221 /*
222 * Next try level.
223 */
224 uTryLevel = pEntry->uEnclosingLevel;
225 }
226 }
227 /*
228 * If not dispatching we're unwinding, so we call any __finally blocks.
229 */
230 else
231 {
232 //RTAssertMsg2("_except_handler4: unwind: uTryLevel=%#x\n", pEh4XcptRegRec->uTryLevel);
233 if (pEh4XcptRegRec->uTryLevel != EH4_TOPMOST_TRY_LEVEL)
234 {
235 rtVccEh4DoLocalUnwind(pEh4XcptRegRec, EH4_TOPMOST_TRY_LEVEL, pbFrame);
236 rtVccEh4ValidateCookies(pScopeTable, pbFrame);
237 }
238 }
239
240 RT_NOREF(pvCtx);
241 return ExceptionContinueSearch;
242}
243
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette