master
  1//===-- sanitizer_unwind_win.cpp ------------------------------------------===//
  2//
  3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4// See https://llvm.org/LICENSE.txt for license information.
  5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6//
  7//===----------------------------------------------------------------------===//
  8//
  9/// Sanitizer unwind Windows specific functions.
 10//
 11//===----------------------------------------------------------------------===//
 12
 13#include "sanitizer_platform.h"
 14#if SANITIZER_WINDOWS
 15
 16#define WIN32_LEAN_AND_MEAN
 17#define NOGDI
 18#include <windows.h>
 19
 20#include "sanitizer_dbghelp.h"  // for StackWalk64
 21#include "sanitizer_stacktrace.h"
 22#include "sanitizer_symbolizer.h"  // for InitializeDbgHelpIfNeeded
 23
 24using namespace __sanitizer;
 25
 26#if !SANITIZER_GO
 27void BufferedStackTrace::UnwindSlow(uptr pc, u32 max_depth) {
 28  CHECK_GE(max_depth, 2);
 29  // FIXME: CaptureStackBackTrace might be too slow for us.
 30  // FIXME: Compare with StackWalk64.
 31  // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc
 32  size = CaptureStackBackTrace(1, Min(max_depth, kStackTraceMax),
 33    (void **)&trace_buffer[0], 0);
 34  if (size == 0)
 35    return;
 36
 37  // Skip the RTL frames by searching for the PC in the stacktrace.
 38  uptr pc_location = LocatePcInTrace(pc);
 39  PopStackFrames(pc_location);
 40
 41  // Replace the first frame with the PC because the frame in the
 42  // stacktrace might be incorrect.
 43  trace_buffer[0] = pc;
 44}
 45
 46#ifdef __clang__
 47#pragma clang diagnostic push
 48#pragma clang diagnostic ignored "-Wframe-larger-than="
 49#endif
 50void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) {
 51  CHECK(context);
 52  CHECK_GE(max_depth, 2);
 53  CONTEXT ctx = *(CONTEXT *)context;
 54  STACKFRAME64 stack_frame;
 55  memset(&stack_frame, 0, sizeof(stack_frame));
 56
 57  InitializeDbgHelpIfNeeded();
 58
 59  size = 0;
 60#    if SANITIZER_WINDOWS64
 61#      if SANITIZER_ARM64
 62  int machine_type = IMAGE_FILE_MACHINE_ARM64;
 63  stack_frame.AddrPC.Offset = ctx.Pc;
 64  stack_frame.AddrFrame.Offset = ctx.Fp;
 65  stack_frame.AddrStack.Offset = ctx.Sp;
 66#      else
 67  int machine_type = IMAGE_FILE_MACHINE_AMD64;
 68  stack_frame.AddrPC.Offset = ctx.Rip;
 69  stack_frame.AddrFrame.Offset = ctx.Rbp;
 70  stack_frame.AddrStack.Offset = ctx.Rsp;
 71#      endif
 72#    else
 73#      if SANITIZER_ARM
 74  int machine_type = IMAGE_FILE_MACHINE_ARM;
 75  stack_frame.AddrPC.Offset = ctx.Pc;
 76  stack_frame.AddrFrame.Offset = ctx.R11;
 77  stack_frame.AddrStack.Offset = ctx.Sp;
 78#      elif SANITIZER_MIPS32
 79  int machine_type = IMAGE_FILE_MACHINE_R4000;
 80  stack_frame.AddrPC.Offset = ctx.Fir;
 81  stack_frame.AddrFrame.Offset = ctx.IntS8;
 82  stack_frame.AddrStack.Offset = ctx.IntSp;
 83#      else
 84  int machine_type = IMAGE_FILE_MACHINE_I386;
 85  stack_frame.AddrPC.Offset = ctx.Eip;
 86  stack_frame.AddrFrame.Offset = ctx.Ebp;
 87  stack_frame.AddrStack.Offset = ctx.Esp;
 88#      endif
 89#    endif
 90  stack_frame.AddrPC.Mode = AddrModeFlat;
 91  stack_frame.AddrFrame.Mode = AddrModeFlat;
 92  stack_frame.AddrStack.Mode = AddrModeFlat;
 93  while (StackWalk64(machine_type, GetCurrentProcess(), GetCurrentThread(),
 94                     &stack_frame, &ctx, NULL, SymFunctionTableAccess64,
 95                     SymGetModuleBase64, NULL) &&
 96         size < Min(max_depth, kStackTraceMax)) {
 97    trace_buffer[size++] = (uptr)stack_frame.AddrPC.Offset;
 98  }
 99}
100#    ifdef __clang__
101#      pragma clang diagnostic pop
102#    endif
103#  endif  // #if !SANITIZER_GO
104
105#endif  // SANITIZER_WINDOWS