folly/folly/debugging/symbolizer/StackTrace.cpp

/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <folly/debugging/symbolizer/StackTrace.h>
#include <folly/tracing/AsyncStack.h>

#include <memory>

#include <folly/CppAttributes.h>
#include <folly/Portability.h>
#include <folly/portability/Config.h>
#include <folly/tracing/AsyncStack.h>

#if FOLLY_HAVE_LIBUNWIND
// Must be first to ensure that UNW_LOCAL_ONLY is defined
#define UNW_LOCAL_ONLY
#include <folly/portability/Libunwind.h>
#endif

#if FOLLY_HAVE_BACKTRACE
#include <execinfo.h>
#endif

namespace folly {
namespace symbolizer {

namespace {
// force a getStackTrace to work around a race condition in the
// libunwind tdep_init
static uintptr_t sAddr =;
static ssize_t sInit =;
} // namespace

ssize_t getStackTrace(
    [[maybe_unused]] uintptr_t* addresses,
    [[maybe_unused]] size_t maxAddresses) {}

namespace {

// Heuristic for guessing the maximum stack frame size. This is needed to ensure
// we do not have stack corruption while walking the stack.
constexpr size_t kMaxExpectedStackFrameSizeLg2 = // 256MB
    ;
constexpr size_t kMaxExpectedStackFrameSize //
    =;

#if FOLLY_HAVE_LIBUNWIND

inline bool getFrameInfo(unw_cursor_t* cursor, uintptr_t& ip) {
  unw_word_t uip;
  if (unw_get_reg(cursor, UNW_REG_IP, &uip) < 0) {
    return false;
  }
  int r = unw_is_signal_frame(cursor);
  if (r < 0) {
    return false;
  }
  // Use previous instruction in normal (call) frames (because the
  // return address might not be in the same function for noreturn functions)
  // but not in signal frames.
  ip = uip - (r == 0);
  return true;
}

// on ppc64le, fails with
// function can never be inlined because it uses setjmp
#if FOLLY_PPC64 == 0
FOLLY_ALWAYS_INLINE
#endif
ssize_t getStackTraceInPlace(
    unw_context_t& context,
    unw_cursor_t& cursor,
    uintptr_t* addresses,
    size_t maxAddresses) {
  if (maxAddresses == 0) {
    return 0;
  }
  if (unw_getcontext(&context) < 0) {
    return -1;
  }
  if (unw_init_local(&cursor, &context) < 0) {
    return -1;
  }
  if (!getFrameInfo(&cursor, *addresses)) {
    return -1;
  }
  ++addresses;
  size_t count = 1;
  for (; count != maxAddresses; ++count, ++addresses) {
    int r = unw_step(&cursor);
    if (r < 0) {
      return -1;
    }
    if (r == 0) {
      break;
    }
    if (!getFrameInfo(&cursor, *addresses)) {
      return -1;
    }
  }
  return count;
}

#endif // FOLLY_HAVE_LIBUNWIND
} // namespace

ssize_t getStackTraceSafe(
    [[maybe_unused]] uintptr_t* addresses,
    [[maybe_unused]] size_t maxAddresses) {}

ssize_t getStackTraceHeap(
    [[maybe_unused]] uintptr_t* addresses,
    [[maybe_unused]] size_t maxAddresses) {}

namespace {
// Helper struct for manually walking the stack using stack frame pointers
struct StackFrame {};

FOLLY_DISABLE_THREAD_SANITIZER size_t walkNormalStack(
    uintptr_t* addresses,
    size_t maxAddresses,
    StackFrame* normalStackFrame,
    StackFrame* normalStackFrameStop) {}

struct WalkAsyncStackResult {};

WalkAsyncStackResult walkAsyncStack(
    uintptr_t* addresses,
    size_t maxAddresses,
    AsyncStackFrame* asyncStackFrame) {}
} // namespace

ssize_t getAsyncStackTraceSafe(uintptr_t* addresses, size_t maxAddresses) {}

} // namespace symbolizer
} // namespace folly