xref: /freebsd/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_unwind_win.cpp (revision 6c4b055cfb6bf549e9145dde6454cc6b178c35e4)
168d75effSDimitry Andric //===-- sanitizer_unwind_win.cpp ------------------------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric /// Sanitizer unwind Windows specific functions.
1068d75effSDimitry Andric //
1168d75effSDimitry Andric //===----------------------------------------------------------------------===//
1268d75effSDimitry Andric 
1368d75effSDimitry Andric #include "sanitizer_platform.h"
1468d75effSDimitry Andric #if SANITIZER_WINDOWS
1568d75effSDimitry Andric 
1668d75effSDimitry Andric #define WIN32_LEAN_AND_MEAN
1768d75effSDimitry Andric #define NOGDI
1868d75effSDimitry Andric #include <windows.h>
1968d75effSDimitry Andric 
2068d75effSDimitry Andric #include "sanitizer_dbghelp.h"  // for StackWalk64
2168d75effSDimitry Andric #include "sanitizer_stacktrace.h"
2268d75effSDimitry Andric #include "sanitizer_symbolizer.h"  // for InitializeDbgHelpIfNeeded
2368d75effSDimitry Andric 
2468d75effSDimitry Andric using namespace __sanitizer;
2568d75effSDimitry Andric 
2668d75effSDimitry Andric #if !SANITIZER_GO
UnwindSlow(uptr pc,u32 max_depth)2768d75effSDimitry Andric void BufferedStackTrace::UnwindSlow(uptr pc, u32 max_depth) {
2868d75effSDimitry Andric   CHECK_GE(max_depth, 2);
2968d75effSDimitry Andric   // FIXME: CaptureStackBackTrace might be too slow for us.
3068d75effSDimitry Andric   // FIXME: Compare with StackWalk64.
3168d75effSDimitry Andric   // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc
3268d75effSDimitry Andric   size = CaptureStackBackTrace(1, Min(max_depth, kStackTraceMax),
3368d75effSDimitry Andric     (void **)&trace_buffer[0], 0);
3468d75effSDimitry Andric   if (size == 0)
3568d75effSDimitry Andric     return;
3668d75effSDimitry Andric 
3768d75effSDimitry Andric   // Skip the RTL frames by searching for the PC in the stacktrace.
3868d75effSDimitry Andric   uptr pc_location = LocatePcInTrace(pc);
3968d75effSDimitry Andric   PopStackFrames(pc_location);
40e8d8bef9SDimitry Andric 
41e8d8bef9SDimitry Andric   // Replace the first frame with the PC because the frame in the
42e8d8bef9SDimitry Andric   // stacktrace might be incorrect.
43e8d8bef9SDimitry Andric   trace_buffer[0] = pc;
4468d75effSDimitry Andric }
4568d75effSDimitry Andric 
46e8d8bef9SDimitry Andric #ifdef __clang__
47e8d8bef9SDimitry Andric #pragma clang diagnostic push
48e8d8bef9SDimitry Andric #pragma clang diagnostic ignored "-Wframe-larger-than="
49e8d8bef9SDimitry Andric #endif
UnwindSlow(uptr pc,void * context,u32 max_depth)5068d75effSDimitry Andric void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) {
5168d75effSDimitry Andric   CHECK(context);
5268d75effSDimitry Andric   CHECK_GE(max_depth, 2);
5368d75effSDimitry Andric   CONTEXT ctx = *(CONTEXT *)context;
5468d75effSDimitry Andric   STACKFRAME64 stack_frame;
5568d75effSDimitry Andric   memset(&stack_frame, 0, sizeof(stack_frame));
5668d75effSDimitry Andric 
5768d75effSDimitry Andric   InitializeDbgHelpIfNeeded();
5868d75effSDimitry Andric 
5968d75effSDimitry Andric   size = 0;
6004eeddc0SDimitry Andric #    if SANITIZER_WINDOWS64
6104eeddc0SDimitry Andric #      if SANITIZER_ARM64
6204eeddc0SDimitry Andric   int machine_type = IMAGE_FILE_MACHINE_ARM64;
6304eeddc0SDimitry Andric   stack_frame.AddrPC.Offset = ctx.Pc;
6404eeddc0SDimitry Andric   stack_frame.AddrFrame.Offset = ctx.Fp;
6504eeddc0SDimitry Andric   stack_frame.AddrStack.Offset = ctx.Sp;
6604eeddc0SDimitry Andric #      else
6768d75effSDimitry Andric   int machine_type = IMAGE_FILE_MACHINE_AMD64;
6868d75effSDimitry Andric   stack_frame.AddrPC.Offset = ctx.Rip;
6968d75effSDimitry Andric   stack_frame.AddrFrame.Offset = ctx.Rbp;
7068d75effSDimitry Andric   stack_frame.AddrStack.Offset = ctx.Rsp;
7104eeddc0SDimitry Andric #      endif
7268d75effSDimitry Andric #    else
73*6c4b055cSDimitry Andric #      if SANITIZER_ARM
74*6c4b055cSDimitry Andric   int machine_type = IMAGE_FILE_MACHINE_ARM;
75*6c4b055cSDimitry Andric   stack_frame.AddrPC.Offset = ctx.Pc;
76*6c4b055cSDimitry Andric   stack_frame.AddrFrame.Offset = ctx.R11;
77*6c4b055cSDimitry Andric   stack_frame.AddrStack.Offset = ctx.Sp;
78*6c4b055cSDimitry Andric #      else
7968d75effSDimitry Andric   int machine_type = IMAGE_FILE_MACHINE_I386;
8068d75effSDimitry Andric   stack_frame.AddrPC.Offset = ctx.Eip;
8168d75effSDimitry Andric   stack_frame.AddrFrame.Offset = ctx.Ebp;
8268d75effSDimitry Andric   stack_frame.AddrStack.Offset = ctx.Esp;
8368d75effSDimitry Andric #      endif
84*6c4b055cSDimitry Andric #    endif
8568d75effSDimitry Andric   stack_frame.AddrPC.Mode = AddrModeFlat;
8668d75effSDimitry Andric   stack_frame.AddrFrame.Mode = AddrModeFlat;
8768d75effSDimitry Andric   stack_frame.AddrStack.Mode = AddrModeFlat;
8868d75effSDimitry Andric   while (StackWalk64(machine_type, GetCurrentProcess(), GetCurrentThread(),
8968d75effSDimitry Andric                      &stack_frame, &ctx, NULL, SymFunctionTableAccess64,
9068d75effSDimitry Andric                      SymGetModuleBase64, NULL) &&
9168d75effSDimitry Andric          size < Min(max_depth, kStackTraceMax)) {
9268d75effSDimitry Andric     trace_buffer[size++] = (uptr)stack_frame.AddrPC.Offset;
9368d75effSDimitry Andric   }
9468d75effSDimitry Andric }
95e8d8bef9SDimitry Andric #    ifdef __clang__
96e8d8bef9SDimitry Andric #      pragma clang diagnostic pop
97e8d8bef9SDimitry Andric #    endif
9868d75effSDimitry Andric #  endif  // #if !SANITIZER_GO
9968d75effSDimitry Andric 
10068d75effSDimitry Andric #endif  // SANITIZER_WINDOWS
101