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