diff options
Diffstat (limited to 'gcc/ada/tracebak.c')
-rw-r--r-- | gcc/ada/tracebak.c | 72 |
1 files changed, 71 insertions, 1 deletions
diff --git a/gcc/ada/tracebak.c b/gcc/ada/tracebak.c index ff2a3b6..b65dbc7 100644 --- a/gcc/ada/tracebak.c +++ b/gcc/ada/tracebak.c @@ -6,7 +6,7 @@ * * * C Implementation File * * * - * Copyright (C) 2000-2011, Free Software Foundation, Inc. * + * Copyright (C) 2000-2012, Free Software Foundation, Inc. * * * * GNAT is free software; you can redistribute it and/or modify it under * * terms of the GNU General Public License as published by the Free Soft- * @@ -106,6 +106,76 @@ extern void (*Unlock_Task) (void); #include "tb-ivms.c" +#elif defined (_WIN64) && defined (__SEH__) + +#include <windows.h> + +int +__gnat_backtrace (void **array, + int size, + void *exclude_min, + void *exclude_max, + int skip_frames) +{ + CONTEXT context; + UNWIND_HISTORY_TABLE history; + int i; + + /* Get the context. */ + RtlCaptureContext (&context); + + /* Setup unwind history table (a cached to speed-up unwinding). */ + memset (&history, 0, sizeof (history)); + + i = 0; + while (1) + { + PRUNTIME_FUNCTION RuntimeFunction; + KNONVOLATILE_CONTEXT_POINTERS NvContext; + ULONG64 ImageBase; + VOID *HandlerData; + ULONG64 EstablisherFrame; + + /* Get function metadata. */ + RuntimeFunction = RtlLookupFunctionEntry + (context.Rip, &ImageBase, &history); + + if (!RuntimeFunction) + { + /* In case of failure, assume this is a leaf function. */ + context.Rip = *(ULONG64 **) context.Rsp; + context.Rsp += 8; + } + else + { + /* Unwind. */ + memset (&NvContext, 0, sizeof (KNONVOLATILE_CONTEXT_POINTERS)); + RtlVirtualUnwind (0, ImageBase, context.Rip, RuntimeFunction, + &context, &HandlerData, &EstablisherFrame, + &NvContext); + } + + /* 0 means bottom of the stack. */ + if (context.Rip == 0) + break; + + /* Skip frames. */ + if (skip_frames) + { + skip_frames--; + continue; + } + /* Excluded frames. */ + if ((void *)context.Rip >= exclude_min + && (void *)context.Rip <= exclude_max) + continue; + + array[i++] = context.Rip - 2; + if (i >= size) + break; + } + return i; +} #else /* No target specific implementation. */ |