Tristan Gingold | bf1431e | 2012-07-19 07:29:24 +0000 | [diff] [blame] | 1 | /* Structured Exception Handling (SEH) runtime interface routines. |
Jakub Jelinek | 85ec4fe | 2018-01-03 11:03:58 +0100 | [diff] [blame] | 2 | Copyright (C) 2010-2018 Free Software Foundation, Inc. |
Tristan Gingold | bf1431e | 2012-07-19 07:29:24 +0000 | [diff] [blame] | 3 | |
| 4 | This file is part of GCC. |
| 5 | |
| 6 | GCC is free software; you can redistribute it and/or modify it |
| 7 | under the terms of the GNU General Public License as published by |
| 8 | the Free Software Foundation; either version 3, or (at your option) |
| 9 | any later version. |
| 10 | |
| 11 | GCC is distributed in the hope that it will be useful, but WITHOUT |
| 12 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
| 13 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public |
| 14 | License for more details. |
| 15 | |
| 16 | Under Section 7 of GPL version 3, you are granted additional |
| 17 | permissions described in the GCC Runtime Library Exception, version |
| 18 | 3.1, as published by the Free Software Foundation. |
| 19 | |
| 20 | You should have received a copy of the GNU General Public License and |
| 21 | a copy of the GCC Runtime Library Exception along with this program; |
| 22 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
| 23 | <http://www.gnu.org/licenses/>. */ |
| 24 | |
| 25 | #include "tconfig.h" |
| 26 | #include "tsystem.h" |
| 27 | #include "coretypes.h" |
| 28 | #include "tm.h" |
| 29 | #include "unwind.h" |
| 30 | |
Kai Tietz | e5a81c8 | 2012-11-29 10:36:41 +0100 | [diff] [blame] | 31 | #if defined (__SEH__) && !defined (__USING_SJLJ_EXCEPTIONS__) |
Tristan Gingold | bf1431e | 2012-07-19 07:29:24 +0000 | [diff] [blame] | 32 | |
| 33 | /* At the moment everything is written for x64, but in theory this could |
| 34 | also be used for i386, arm, mips and other extant embedded Windows. */ |
| 35 | #ifndef __x86_64__ |
| 36 | #error "Unsupported architecture." |
| 37 | #endif |
| 38 | |
| 39 | /* Define GCC's exception codes. See |
| 40 | http://msdn.microsoft.com/en-us/library/het71c37(v=VS.80).aspx |
| 41 | In particular, MS defines bits: |
| 42 | [31:30] = 3 (error), 2 (warning), 1 (info), 0 (success) |
| 43 | [29] = 1 (user-defined) |
| 44 | [28] = 0 (reserved) |
| 45 | We define bits: |
| 46 | [24:27] = type |
| 47 | [0:23] = magic |
| 48 | We set "magic" to "GCC", which is similar to MVC++ which uses "msc" |
| 49 | as the low 3 bytes of its user-defined codes for C++ exceptions. |
| 50 | |
| 51 | We define the ExceptionInformation entries as follows: |
| 52 | [0] = _Unwind_Exception pointer |
| 53 | [1] = target frame |
| 54 | [2] = target ip |
| 55 | [3] = target rdx |
| 56 | */ |
| 57 | |
| 58 | #define STATUS_USER_DEFINED (1U << 29) |
| 59 | |
| 60 | #define GCC_MAGIC (('G' << 16) | ('C' << 8) | 'C') |
| 61 | #define GCC_EXCEPTION(TYPE) \ |
| 62 | (STATUS_USER_DEFINED | ((TYPE) << 24) | GCC_MAGIC) |
| 63 | |
| 64 | #define STATUS_GCC_THROW GCC_EXCEPTION (0) |
| 65 | #define STATUS_GCC_UNWIND GCC_EXCEPTION (1) |
| 66 | #define STATUS_GCC_FORCED GCC_EXCEPTION (2) |
| 67 | |
| 68 | |
| 69 | struct _Unwind_Context |
| 70 | { |
| 71 | _Unwind_Word cfa; |
| 72 | _Unwind_Word ra; |
| 73 | _Unwind_Word reg[2]; |
| 74 | PDISPATCHER_CONTEXT disp; |
| 75 | }; |
| 76 | |
| 77 | /* Get the value of register INDEX as saved in CONTEXT. */ |
| 78 | |
| 79 | _Unwind_Word |
| 80 | _Unwind_GetGR (struct _Unwind_Context *c, int index) |
| 81 | { |
Kai Tietz | 5c7dac8 | 2014-06-23 18:20:31 +0200 | [diff] [blame] | 82 | if (index < 0 || index >= 2) |
Tristan Gingold | bf1431e | 2012-07-19 07:29:24 +0000 | [diff] [blame] | 83 | abort (); |
| 84 | return c->reg[index]; |
| 85 | } |
| 86 | |
| 87 | /* Overwrite the saved value for register INDEX in CONTEXT with VAL. */ |
| 88 | |
| 89 | void |
| 90 | _Unwind_SetGR (struct _Unwind_Context *c, int index, _Unwind_Word val) |
| 91 | { |
Kai Tietz | 5c7dac8 | 2014-06-23 18:20:31 +0200 | [diff] [blame] | 92 | if (index < 0 || index >= 2) |
Tristan Gingold | bf1431e | 2012-07-19 07:29:24 +0000 | [diff] [blame] | 93 | abort (); |
| 94 | c->reg[index] = val; |
| 95 | } |
| 96 | |
| 97 | /* Get the value of the CFA as saved in CONTEXT. */ |
| 98 | |
| 99 | _Unwind_Word |
| 100 | _Unwind_GetCFA (struct _Unwind_Context *c) |
| 101 | { |
| 102 | return c->cfa; |
| 103 | } |
| 104 | |
| 105 | /* Retrieve the return address for CONTEXT. */ |
| 106 | |
| 107 | _Unwind_Ptr |
| 108 | _Unwind_GetIP (struct _Unwind_Context *c) |
| 109 | { |
| 110 | return c->ra; |
| 111 | } |
| 112 | |
| 113 | /* Retrieve the return address and flag whether that IP is before |
| 114 | or after first not yet fully executed instruction. */ |
| 115 | |
| 116 | _Unwind_Ptr |
| 117 | _Unwind_GetIPInfo (struct _Unwind_Context *c, int *ip_before_insn) |
| 118 | { |
| 119 | /* ??? Is there a concept of a signal context properly? There's |
| 120 | obviously an UNWP_PUSH_MACHFRAME opcode, but the runtime might |
| 121 | have arranged for that not to matter, really. */ |
| 122 | *ip_before_insn = 0; |
| 123 | return c->ra; |
| 124 | } |
| 125 | |
| 126 | /* Overwrite the return address for CONTEXT with VAL. */ |
| 127 | |
| 128 | void |
| 129 | _Unwind_SetIP (struct _Unwind_Context *c, _Unwind_Ptr val) |
| 130 | { |
| 131 | c->ra = val; |
| 132 | } |
| 133 | |
| 134 | void * |
| 135 | _Unwind_GetLanguageSpecificData (struct _Unwind_Context *c) |
| 136 | { |
| 137 | return c->disp->HandlerData; |
| 138 | } |
| 139 | |
| 140 | _Unwind_Ptr |
| 141 | _Unwind_GetRegionStart (struct _Unwind_Context *c) |
| 142 | { |
| 143 | return c->disp->FunctionEntry->BeginAddress + c->disp->ImageBase; |
| 144 | } |
| 145 | |
| 146 | void * |
| 147 | _Unwind_FindEnclosingFunction (void *pc) |
| 148 | { |
| 149 | PRUNTIME_FUNCTION entry; |
| 150 | ULONG64 ImageBase; |
| 151 | |
| 152 | entry = RtlLookupFunctionEntry ((ULONG64)pc, &ImageBase, NULL); |
| 153 | |
| 154 | return (entry ? (void *)(entry->BeginAddress + ImageBase) : NULL); |
| 155 | } |
| 156 | |
| 157 | _Unwind_Ptr |
| 158 | _Unwind_GetDataRelBase (struct _Unwind_Context *c ATTRIBUTE_UNUSED) |
| 159 | { |
| 160 | return 0; |
| 161 | } |
| 162 | |
| 163 | _Unwind_Ptr |
| 164 | _Unwind_GetTextRelBase (struct _Unwind_Context *c) |
| 165 | { |
| 166 | return c->disp->ImageBase; |
| 167 | } |
| 168 | |
| 169 | |
| 170 | /* The two-phase unwind process that GCC uses is ordered differently |
| 171 | from the two-phase unwind process that SEH uses. The mechansism |
| 172 | that GCC uses is to have the filter return _URC_HANDER_FOUND; the |
| 173 | mechanism that SEH uses is for the filter function call back into |
| 174 | the unwinder. |
| 175 | |
| 176 | An Ideal port to SEH would have GCC emit handler functions that |
| 177 | can be called, given a pointer to the "EstablisherFrame" (i.e. |
| 178 | the frame pointer base of the user-level function) can manipulate |
| 179 | the user-level variables within the user-level function's stack |
| 180 | frame. Once done manipulating the variables, it would return |
| 181 | a ExceptionContinueSearch, and the unwind process would continue. |
| 182 | |
| 183 | GCC has always done things a bit differently. We continue to |
| 184 | transfer control back into the user-level function which, once |
| 185 | done manipulating the user-level variables, re-throws the exception. */ |
| 186 | |
| 187 | /* The "real" language-specific personality handler forwards to here |
| 188 | where we handle the MS SEH state and transforms it into the GCC |
| 189 | unwind state as per GCC's <unwind.h>, at which point we defer to |
| 190 | the regular language-specfic exception handler, which is passed in. */ |
| 191 | |
| 192 | EXCEPTION_DISPOSITION |
| 193 | _GCC_specific_handler (PEXCEPTION_RECORD ms_exc, void *this_frame, |
| 194 | PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp, |
| 195 | _Unwind_Personality_Fn gcc_per) |
| 196 | { |
| 197 | DWORD ms_flags = ms_exc->ExceptionFlags; |
| 198 | DWORD ms_code = ms_exc->ExceptionCode; |
| 199 | |
| 200 | struct _Unwind_Exception *gcc_exc |
| 201 | = (struct _Unwind_Exception *) ms_exc->ExceptionInformation[0]; |
| 202 | struct _Unwind_Context gcc_context; |
| 203 | _Unwind_Action gcc_action; |
| 204 | _Unwind_Reason_Code gcc_reason; |
| 205 | |
| 206 | if (ms_flags & EXCEPTION_TARGET_UNWIND) |
| 207 | { |
| 208 | /* This frame is known to be the target frame. We've already |
| 209 | "installed" the target_ip and RAX value via the arguments |
| 210 | to RtlUnwindEx. All that's left is to set the RDX value |
| 211 | and "continue" to have the context installed. */ |
| 212 | ms_disp->ContextRecord->Rdx = ms_exc->ExceptionInformation[3]; |
| 213 | return ExceptionContinueSearch; |
| 214 | } |
| 215 | |
| 216 | if (ms_code == STATUS_GCC_UNWIND) |
| 217 | { |
| 218 | /* This is a colliding exception that we threw so that we could |
| 219 | cancel the already in-flight exception and stop in a frame |
| 220 | that wanted to perform some unwind action. The only relevant |
| 221 | test is that we're the target frame. */ |
| 222 | if (ms_exc->ExceptionInformation[1] == (_Unwind_Ptr) this_frame) |
| 223 | { |
Jonathan Yong | 126437c | 2017-03-02 11:00:28 +0000 | [diff] [blame] | 224 | RtlUnwindEx (this_frame, (PVOID) ms_exc->ExceptionInformation[2], |
Tristan Gingold | bf1431e | 2012-07-19 07:29:24 +0000 | [diff] [blame] | 225 | ms_exc, gcc_exc, ms_orig_context, |
| 226 | ms_disp->HistoryTable); |
| 227 | abort (); |
| 228 | } |
| 229 | return ExceptionContinueSearch; |
| 230 | } |
| 231 | |
| 232 | gcc_context.cfa = ms_disp->ContextRecord->Rsp; |
| 233 | gcc_context.ra = ms_disp->ControlPc; |
| 234 | gcc_context.reg[0] = 0xdeadbeef; /* These are write-only. */ |
| 235 | gcc_context.reg[1] = 0xdeadbeef; |
| 236 | gcc_context.disp = ms_disp; |
| 237 | |
| 238 | if (ms_code == STATUS_GCC_FORCED) |
| 239 | { |
| 240 | _Unwind_Stop_Fn stop = (_Unwind_Stop_Fn) gcc_exc->private_[0]; |
| 241 | void *stop_argument = (void *) gcc_exc->private_[4]; |
| 242 | |
| 243 | gcc_action = _UA_FORCE_UNWIND | _UA_CLEANUP_PHASE; |
| 244 | |
| 245 | stop (1, gcc_action, gcc_exc->exception_class, gcc_exc, |
| 246 | &gcc_context, stop_argument); |
| 247 | |
| 248 | goto phase2; |
| 249 | } |
| 250 | |
| 251 | /* ??? TODO: handling non-gcc user-defined exceptions as foreign. */ |
| 252 | if (ms_code != STATUS_GCC_THROW) |
| 253 | return ExceptionContinueSearch; |
| 254 | |
| 255 | if (ms_flags & (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND)) |
| 256 | { |
| 257 | /* This is Phase 2. */ |
| 258 | /* We know this isn't the target frame because we've already tested |
| 259 | EXCEPTION_TARGET_UNWIND. The remaining possibility is that the |
| 260 | gcc personality has unwind code to run. */ |
| 261 | |
| 262 | gcc_action = _UA_CLEANUP_PHASE; |
| 263 | phase2: |
| 264 | gcc_reason = gcc_per (1, gcc_action, gcc_exc->exception_class, |
| 265 | gcc_exc, &gcc_context); |
| 266 | |
| 267 | if (gcc_reason == _URC_CONTINUE_UNWIND) |
| 268 | return ExceptionContinueSearch; |
| 269 | |
| 270 | if (gcc_reason == _URC_INSTALL_CONTEXT) |
| 271 | { |
| 272 | /* Scratch space for the bits for the unwind catch. */ |
| 273 | ms_exc->ExceptionInformation[1] = (_Unwind_Ptr) this_frame; |
| 274 | ms_exc->ExceptionInformation[2] = gcc_context.ra; |
| 275 | ms_exc->ExceptionInformation[3] = gcc_context.reg[1]; |
| 276 | |
| 277 | /* Cancel the current exception by raising another. */ |
| 278 | RaiseException (STATUS_GCC_UNWIND, EXCEPTION_NONCONTINUABLE, |
| 279 | 4, ms_exc->ExceptionInformation); |
| 280 | |
| 281 | /* Is RaiseException declared noreturn? */ |
| 282 | } |
| 283 | |
| 284 | /* In _Unwind_RaiseException_Phase2 we return _URC_FATAL_PHASE2_ERROR. */ |
| 285 | } |
| 286 | else |
| 287 | { |
| 288 | /* This is Phase 1. */ |
| 289 | gcc_reason = gcc_per (1, _UA_SEARCH_PHASE, gcc_exc->exception_class, |
| 290 | gcc_exc, &gcc_context); |
| 291 | |
| 292 | if (gcc_reason == _URC_CONTINUE_UNWIND) |
| 293 | return ExceptionContinueSearch; |
| 294 | |
| 295 | if (gcc_reason == _URC_HANDLER_FOUND) |
| 296 | { |
| 297 | /* We really need some of the information that GCC's personality |
| 298 | routines compute during phase 2 right now, like the target IP. |
| 299 | Go ahead and ask for it now, and cache it. */ |
| 300 | gcc_reason = gcc_per (1, _UA_CLEANUP_PHASE | _UA_HANDLER_FRAME, |
| 301 | gcc_exc->exception_class, gcc_exc, |
| 302 | &gcc_context); |
| 303 | if (gcc_reason != _URC_INSTALL_CONTEXT) |
| 304 | abort (); |
| 305 | |
| 306 | gcc_exc->private_[1] = (_Unwind_Ptr) this_frame; |
| 307 | gcc_exc->private_[2] = gcc_context.ra; |
| 308 | gcc_exc->private_[3] = gcc_context.reg[1]; |
| 309 | |
| 310 | ms_exc->NumberParameters = 4; |
| 311 | ms_exc->ExceptionInformation[1] = (_Unwind_Ptr) this_frame; |
| 312 | ms_exc->ExceptionInformation[2] = gcc_context.ra; |
| 313 | ms_exc->ExceptionInformation[3] = gcc_context.reg[1]; |
| 314 | |
| 315 | /* Begin phase 2. Perform the unwinding. */ |
Jonathan Yong | 126437c | 2017-03-02 11:00:28 +0000 | [diff] [blame] | 316 | RtlUnwindEx (this_frame, (PVOID)gcc_context.ra, ms_exc, |
Kai Tietz | 0bb4fc0 | 2014-02-18 18:02:54 +0100 | [diff] [blame] | 317 | (PVOID)gcc_context.reg[0], ms_orig_context, |
| 318 | ms_disp->HistoryTable); |
Tristan Gingold | bf1431e | 2012-07-19 07:29:24 +0000 | [diff] [blame] | 319 | } |
| 320 | |
| 321 | /* In _Unwind_RaiseException we return _URC_FATAL_PHASE1_ERROR. */ |
| 322 | } |
| 323 | abort (); |
| 324 | } |
| 325 | |
| 326 | /* Raise an exception, passing along the given exception object. */ |
| 327 | |
| 328 | _Unwind_Reason_Code |
| 329 | _Unwind_RaiseException (struct _Unwind_Exception *exc) |
| 330 | { |
| 331 | memset (exc->private_, 0, sizeof (exc->private_)); |
| 332 | |
| 333 | /* The ExceptionInformation array will have only 1 element, EXC. */ |
| 334 | RaiseException (STATUS_GCC_THROW, 0, 1, (ULONG_PTR *)&exc); |
| 335 | |
| 336 | /* The exception handler installed in crt0 will continue any GCC |
| 337 | exception that reaches there (and isn't marked non-continuable). |
| 338 | Returning allows the C++ runtime to call std::terminate. */ |
| 339 | return _URC_END_OF_STACK; |
| 340 | } |
| 341 | |
| 342 | /* Resume propagation of an existing exception. This is used after |
| 343 | e.g. executing cleanup code, and not to implement rethrowing. */ |
| 344 | |
| 345 | void |
| 346 | _Unwind_Resume (struct _Unwind_Exception *gcc_exc) |
| 347 | { |
| 348 | UNWIND_HISTORY_TABLE ms_history; |
| 349 | EXCEPTION_RECORD ms_exc; |
| 350 | CONTEXT ms_context; |
| 351 | |
| 352 | memset (&ms_exc, 0, sizeof(ms_exc)); |
| 353 | memset (&ms_history, 0, sizeof(ms_history)); |
| 354 | |
| 355 | /* ??? Not 100% perfect, since we aren't passing on the *original* |
| 356 | exception context, but should be good enough. */ |
| 357 | ms_exc.ExceptionCode = STATUS_GCC_THROW; |
| 358 | ms_exc.ExceptionFlags = EXCEPTION_NONCONTINUABLE; |
| 359 | ms_exc.NumberParameters = 4; |
| 360 | ms_exc.ExceptionInformation[0] = (ULONG_PTR) gcc_exc; |
| 361 | ms_exc.ExceptionInformation[1] = gcc_exc->private_[1]; |
| 362 | ms_exc.ExceptionInformation[2] = gcc_exc->private_[2]; |
| 363 | ms_exc.ExceptionInformation[3] = gcc_exc->private_[3]; |
| 364 | |
| 365 | ms_context.ContextFlags = CONTEXT_ALL; |
| 366 | RtlCaptureContext (&ms_context); |
| 367 | |
Jonathan Yong | 126437c | 2017-03-02 11:00:28 +0000 | [diff] [blame] | 368 | RtlUnwindEx ((void *) gcc_exc->private_[1], (PVOID)gcc_exc->private_[2], |
Tristan Gingold | bf1431e | 2012-07-19 07:29:24 +0000 | [diff] [blame] | 369 | &ms_exc, gcc_exc, &ms_context, &ms_history); |
| 370 | |
| 371 | /* Is RtlUnwindEx declared noreturn? */ |
| 372 | abort (); |
| 373 | } |
| 374 | |
| 375 | static _Unwind_Reason_Code |
| 376 | _Unwind_ForcedUnwind_Phase2 (struct _Unwind_Exception *exc) |
| 377 | { |
| 378 | _Unwind_Stop_Fn stop; |
| 379 | void * stop_argument; |
| 380 | |
| 381 | RaiseException (STATUS_GCC_FORCED, 0, 1, (ULONG_PTR *)&exc); |
| 382 | |
| 383 | /* If we get here, we got to top-of-stack. */ |
| 384 | /* ??? We no longer have a context pointer to pass in. */ |
| 385 | |
| 386 | stop = (_Unwind_Stop_Fn) exc->private_[0]; |
| 387 | stop_argument = (void *) exc->private_[4]; |
| 388 | stop (1, _UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK, |
| 389 | exc->exception_class, exc, NULL, stop_argument); |
| 390 | |
| 391 | return _UA_END_OF_STACK; |
| 392 | } |
| 393 | |
| 394 | _Unwind_Reason_Code |
| 395 | _Unwind_Resume_or_Rethrow (struct _Unwind_Exception *exc) |
| 396 | { |
| 397 | if (exc->private_[0] == 0) |
| 398 | _Unwind_RaiseException (exc); |
| 399 | else |
| 400 | _Unwind_ForcedUnwind_Phase2 (exc); |
| 401 | abort (); |
| 402 | } |
| 403 | |
| 404 | /* Raise an exception for forced unwinding. */ |
| 405 | |
| 406 | _Unwind_Reason_Code |
| 407 | _Unwind_ForcedUnwind (struct _Unwind_Exception *exc, |
| 408 | _Unwind_Stop_Fn stop, void * stop_argument) |
| 409 | { |
| 410 | /* ??? This is a hack that only works with _GCC_specific_handler. |
| 411 | There's no way to invoke STOP within frames that use a different |
| 412 | exception handler. This is essentially just good enough to run |
| 413 | the code within the gcc testsuite. */ |
| 414 | |
| 415 | memset (exc->private_, 0, sizeof (exc->private_)); |
| 416 | exc->private_[0] = (_Unwind_Ptr) stop; |
| 417 | exc->private_[4] = (_Unwind_Ptr) stop_argument; |
| 418 | |
| 419 | return _Unwind_ForcedUnwind_Phase2 (exc); |
| 420 | } |
| 421 | |
| 422 | /* A convenience function that calls the exception_cleanup field. */ |
| 423 | |
| 424 | void |
| 425 | _Unwind_DeleteException (struct _Unwind_Exception *exc) |
| 426 | { |
| 427 | if (exc->exception_cleanup) |
| 428 | (*exc->exception_cleanup) (_URC_FOREIGN_EXCEPTION_CAUGHT, exc); |
| 429 | } |
| 430 | |
| 431 | /* Perform stack backtrace through unwind data. */ |
| 432 | |
| 433 | _Unwind_Reason_Code |
Bernd Edlinger | 54fde02 | 2014-05-13 16:23:11 +0000 | [diff] [blame] | 434 | _Unwind_Backtrace(_Unwind_Trace_Fn trace, |
| 435 | void *trace_argument) |
Tristan Gingold | bf1431e | 2012-07-19 07:29:24 +0000 | [diff] [blame] | 436 | { |
Tristan Gingold | bf1431e | 2012-07-19 07:29:24 +0000 | [diff] [blame] | 437 | UNWIND_HISTORY_TABLE ms_history; |
| 438 | CONTEXT ms_context; |
| 439 | struct _Unwind_Context gcc_context; |
Bernd Edlinger | 54fde02 | 2014-05-13 16:23:11 +0000 | [diff] [blame] | 440 | DISPATCHER_CONTEXT disp_context; |
Tristan Gingold | bf1431e | 2012-07-19 07:29:24 +0000 | [diff] [blame] | 441 | |
| 442 | memset (&ms_history, 0, sizeof(ms_history)); |
| 443 | memset (&gcc_context, 0, sizeof(gcc_context)); |
Bernd Edlinger | 54fde02 | 2014-05-13 16:23:11 +0000 | [diff] [blame] | 444 | memset (&disp_context, 0, sizeof(disp_context)); |
Tristan Gingold | bf1431e | 2012-07-19 07:29:24 +0000 | [diff] [blame] | 445 | |
| 446 | ms_context.ContextFlags = CONTEXT_ALL; |
| 447 | RtlCaptureContext (&ms_context); |
| 448 | |
Bernd Edlinger | 54fde02 | 2014-05-13 16:23:11 +0000 | [diff] [blame] | 449 | gcc_context.disp = &disp_context; |
| 450 | gcc_context.disp->ContextRecord = &ms_context; |
| 451 | gcc_context.disp->HistoryTable = &ms_history; |
Tristan Gingold | bf1431e | 2012-07-19 07:29:24 +0000 | [diff] [blame] | 452 | |
| 453 | while (1) |
| 454 | { |
Bernd Edlinger | 54fde02 | 2014-05-13 16:23:11 +0000 | [diff] [blame] | 455 | gcc_context.disp->ControlPc = ms_context.Rip; |
| 456 | gcc_context.disp->FunctionEntry |
| 457 | = RtlLookupFunctionEntry (ms_context.Rip, &gcc_context.disp->ImageBase, |
Tristan Gingold | bf1431e | 2012-07-19 07:29:24 +0000 | [diff] [blame] | 458 | &ms_history); |
| 459 | |
Bernd Edlinger | 54fde02 | 2014-05-13 16:23:11 +0000 | [diff] [blame] | 460 | if (!gcc_context.disp->FunctionEntry) |
| 461 | return _URC_END_OF_STACK; |
| 462 | |
| 463 | gcc_context.disp->LanguageHandler |
| 464 | = RtlVirtualUnwind (0, gcc_context.disp->ImageBase, ms_context.Rip, |
| 465 | gcc_context.disp->FunctionEntry, &ms_context, |
| 466 | &gcc_context.disp->HandlerData, |
| 467 | &gcc_context.disp->EstablisherFrame, NULL); |
Tristan Gingold | bf1431e | 2012-07-19 07:29:24 +0000 | [diff] [blame] | 468 | |
| 469 | /* Call trace function. */ |
| 470 | if (trace (&gcc_context, trace_argument) != _URC_NO_REASON) |
| 471 | return _URC_FATAL_PHASE1_ERROR; |
| 472 | |
| 473 | /* ??? Check for invalid stack pointer. */ |
| 474 | if (ms_context.Rip == 0) |
| 475 | return _URC_END_OF_STACK; |
| 476 | } |
Tristan Gingold | bf1431e | 2012-07-19 07:29:24 +0000 | [diff] [blame] | 477 | } |
Kai Tietz | e5a81c8 | 2012-11-29 10:36:41 +0100 | [diff] [blame] | 478 | #endif /* __SEH__ && !defined (__USING_SJLJ_EXCEPTIONS__) */ |