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