brintos

brintos / llvm-project-archived public Read only

0
0
Text · 21.2 KiB · b303639 Raw
573 lines · cpp
1//===----------------------------------------------------------------------===//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-exception6//7//8//  Implements unw_* functions from <libunwind.h>9//10//===----------------------------------------------------------------------===//11 12#include <libunwind.h>13 14#include "config.h"15#include "libunwind_ext.h"16 17#include <stdlib.h>18 19// Define the __has_feature extension for compilers that do not support it so20// that we can later check for the presence of ASan in a compiler-neutral way.21#if !defined(__has_feature)22#define __has_feature(feature) 023#endif24 25#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)26#include <sanitizer/asan_interface.h>27#endif28 29#if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__wasm__)30#include "AddressSpace.hpp"31#include "UnwindCursor.hpp"32 33using namespace libunwind;34 35/// internal object to represent this processes address space36LocalAddressSpace LocalAddressSpace::sThisAddressSpace;37 38_LIBUNWIND_EXPORT unw_addr_space_t unw_local_addr_space =39    (unw_addr_space_t)&LocalAddressSpace::sThisAddressSpace;40 41/// Create a cursor of a thread in this process given 'context' recorded by42/// __unw_getcontext().43_LIBUNWIND_HIDDEN int __unw_init_local(unw_cursor_t *cursor,44                                       unw_context_t *context) {45  _LIBUNWIND_TRACE_API("__unw_init_local(cursor=%p, context=%p)",46                       static_cast<void *>(cursor),47                       static_cast<void *>(context));48#if defined(__i386__)49# define REGISTER_KIND Registers_x8650#elif defined(__x86_64__)51# define REGISTER_KIND Registers_x86_6452#elif defined(__powerpc64__)53# define REGISTER_KIND Registers_ppc6454#elif defined(__powerpc__)55# define REGISTER_KIND Registers_ppc56#elif defined(__aarch64__)57# define REGISTER_KIND Registers_arm6458#elif defined(__arm__)59# define REGISTER_KIND Registers_arm60#elif defined(__or1k__)61# define REGISTER_KIND Registers_or1k62#elif defined(__hexagon__)63# define REGISTER_KIND Registers_hexagon64#elif defined(__mips__) && defined(_ABIO32) && _MIPS_SIM == _ABIO3265# define REGISTER_KIND Registers_mips_o3266#elif defined(__mips64)67# define REGISTER_KIND Registers_mips_newabi68#elif defined(__mips__)69# warning The MIPS architecture is not supported with this ABI and environment!70#elif defined(__sparc__) && defined(__arch64__)71#define REGISTER_KIND Registers_sparc6472#elif defined(__sparc__)73# define REGISTER_KIND Registers_sparc74#elif defined(__riscv)75# define REGISTER_KIND Registers_riscv76#elif defined(__ve__)77# define REGISTER_KIND Registers_ve78#elif defined(__s390x__)79# define REGISTER_KIND Registers_s390x80#elif defined(__loongarch__) && __loongarch_grlen == 6481#define REGISTER_KIND Registers_loongarch82#else83# error Architecture not supported84#endif85  // Use "placement new" to allocate UnwindCursor in the cursor buffer.86  new (reinterpret_cast<UnwindCursor<LocalAddressSpace, REGISTER_KIND> *>(cursor))87      UnwindCursor<LocalAddressSpace, REGISTER_KIND>(88          context, LocalAddressSpace::sThisAddressSpace);89#undef REGISTER_KIND90  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;91  co->setInfoBasedOnIPRegister();92 93  return UNW_ESUCCESS;94}95_LIBUNWIND_WEAK_ALIAS(__unw_init_local, unw_init_local)96 97/// Get value of specified register at cursor position in stack frame.98_LIBUNWIND_HIDDEN int __unw_get_reg(unw_cursor_t *cursor, unw_regnum_t regNum,99                                    unw_word_t *value) {100  _LIBUNWIND_TRACE_API("__unw_get_reg(cursor=%p, regNum=%d, &value=%p)",101                       static_cast<void *>(cursor), regNum,102                       static_cast<void *>(value));103  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;104  if (co->validReg(regNum)) {105    *value = co->getReg(regNum);106    return UNW_ESUCCESS;107  }108  return UNW_EBADREG;109}110_LIBUNWIND_WEAK_ALIAS(__unw_get_reg, unw_get_reg)111 112/// Set value of specified register at cursor position in stack frame.113_LIBUNWIND_HIDDEN int __unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum,114                                    unw_word_t value) {115  _LIBUNWIND_TRACE_API("__unw_set_reg(cursor=%p, regNum=%d, value=0x%" PRIxPTR116                       ")",117                       static_cast<void *>(cursor), regNum, value);118  typedef LocalAddressSpace::pint_t pint_t;119  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;120  if (co->validReg(regNum)) {121    // special case altering IP to re-find info (being called by personality122    // function)123    if (regNum == UNW_REG_IP) {124      unw_proc_info_t info;125      // First, get the FDE for the old location and then update it.126      co->getInfo(&info);127 128      pint_t sp = (pint_t)co->getReg(UNW_REG_SP);129 130#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)131      {132        // It is only valid to set the IP within the current function. This is133        // important for ptrauth, otherwise the IP cannot be correctly signed.134        // The current signature of `value` is via the schema:135        //   __ptrauth(ptrauth_key_return_address, <<sp>>, 0)136        // For this to be generally usable we manually re-sign it to the137        // directly supported schema:138        //   __ptrauth(ptrauth_key_return_address, 1, 0)139        unw_word_t140              __unwind_ptrauth_restricted_intptr(ptrauth_key_return_address, 1,141                                                 0) authenticated_value;142        unw_word_t opaque_value = (uint64_t)ptrauth_auth_and_resign(143            (void *)value, ptrauth_key_return_address, sp,144            ptrauth_key_return_address, &authenticated_value);145        memmove(reinterpret_cast<void *>(&authenticated_value),146                reinterpret_cast<void *>(&opaque_value),147                sizeof(authenticated_value));148        if (authenticated_value < info.start_ip ||149            authenticated_value > info.end_ip)150          _LIBUNWIND_ABORT("PC vs frame info mismatch");151 152        // PC should have been signed with the sp, so we verify that153        // roundtripping does not fail.154        pint_t pc = (pint_t)co->getReg(UNW_REG_IP);155        if (ptrauth_auth_and_resign((void *)pc, ptrauth_key_return_address, sp,156                                    ptrauth_key_return_address,157                                    sp) != (void *)pc) {158          _LIBUNWIND_LOG("Bad unwind through arm64e (0x%zX, 0x%zX)->0x%zX\n",159                         pc, sp,160                         (pint_t)ptrauth_auth_data(161                             (void *)pc, ptrauth_key_return_address, sp));162          _LIBUNWIND_ABORT("Bad unwind through arm64e");163        }164      }165#endif166 167      // If the original call expects stack adjustment, perform this now.168      // Normal frame unwinding would have included the offset already in the169      // CFA computation.170      // Note: for PA-RISC and other platforms where the stack grows up,171      // this should actually be - info.gp. LLVM doesn't currently support172      // any such platforms and Clang doesn't export a macro for them.173      if (info.gp)174        co->setReg(UNW_REG_SP, sp + info.gp);175      co->setReg(UNW_REG_IP, value);176      co->setInfoBasedOnIPRegister(false);177    } else {178      co->setReg(regNum, (pint_t)value);179    }180    return UNW_ESUCCESS;181  }182  return UNW_EBADREG;183}184_LIBUNWIND_WEAK_ALIAS(__unw_set_reg, unw_set_reg)185 186/// Get value of specified float register at cursor position in stack frame.187_LIBUNWIND_HIDDEN int __unw_get_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum,188                                      unw_fpreg_t *value) {189  _LIBUNWIND_TRACE_API("__unw_get_fpreg(cursor=%p, regNum=%d, &value=%p)",190                       static_cast<void *>(cursor), regNum,191                       static_cast<void *>(value));192  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;193  if (co->validFloatReg(regNum)) {194    *value = co->getFloatReg(regNum);195    return UNW_ESUCCESS;196  }197  return UNW_EBADREG;198}199_LIBUNWIND_WEAK_ALIAS(__unw_get_fpreg, unw_get_fpreg)200 201/// Set value of specified float register at cursor position in stack frame.202_LIBUNWIND_HIDDEN int __unw_set_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum,203                                      unw_fpreg_t value) {204#if defined(_LIBUNWIND_ARM_EHABI)205  _LIBUNWIND_TRACE_API("__unw_set_fpreg(cursor=%p, regNum=%d, value=%llX)",206                       static_cast<void *>(cursor), regNum, value);207#else208  _LIBUNWIND_TRACE_API("__unw_set_fpreg(cursor=%p, regNum=%d, value=%g)",209                       static_cast<void *>(cursor), regNum, value);210#endif211  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;212  if (co->validFloatReg(regNum)) {213    co->setFloatReg(regNum, value);214    return UNW_ESUCCESS;215  }216  return UNW_EBADREG;217}218_LIBUNWIND_WEAK_ALIAS(__unw_set_fpreg, unw_set_fpreg)219 220/// Move cursor to next frame.221_LIBUNWIND_HIDDEN int __unw_step(unw_cursor_t *cursor) {222  _LIBUNWIND_TRACE_API("__unw_step(cursor=%p)", static_cast<void *>(cursor));223  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;224  return co->step();225}226_LIBUNWIND_WEAK_ALIAS(__unw_step, unw_step)227 228// Move cursor to next frame and for stage2 of unwinding.229// This resets MTE tags of tagged frames to zero.230extern "C" _LIBUNWIND_HIDDEN int __unw_step_stage2(unw_cursor_t *cursor) {231  _LIBUNWIND_TRACE_API("__unw_step_stage2(cursor=%p)",232                       static_cast<void *>(cursor));233  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;234  return co->step(true);235}236 237/// Get unwind info at cursor position in stack frame.238_LIBUNWIND_HIDDEN int __unw_get_proc_info(unw_cursor_t *cursor,239                                          unw_proc_info_t *info) {240  _LIBUNWIND_TRACE_API("__unw_get_proc_info(cursor=%p, &info=%p)",241                       static_cast<void *>(cursor), static_cast<void *>(info));242  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;243  co->getInfo(info);244  if (info->end_ip == 0)245    return UNW_ENOINFO;246  return UNW_ESUCCESS;247}248_LIBUNWIND_WEAK_ALIAS(__unw_get_proc_info, unw_get_proc_info)249 250/// Rebalance the execution flow by injecting the right amount of `ret`251/// instruction relatively to the amount of `walkedFrames` then resume execution252/// at cursor position (aka longjump).253_LIBUNWIND_HIDDEN int __unw_resume_with_frames_walked(unw_cursor_t *cursor,254                                                      unsigned walkedFrames) {255  _LIBUNWIND_TRACE_API("__unw_resume(cursor=%p, walkedFrames=%u)",256                       static_cast<void *>(cursor), walkedFrames);257#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)258  // Inform the ASan runtime that now might be a good time to clean stuff up.259  __asan_handle_no_return();260#endif261#ifdef _LIBUNWIND_TRACE_RET_INJECT262  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;263  co->setWalkedFrames(walkedFrames);264#endif265  return __unw_resume(cursor);266}267_LIBUNWIND_WEAK_ALIAS(__unw_resume_with_frames_walked,268                      unw_resume_with_frames_walked)269 270/// Legacy function. Resume execution at cursor position (aka longjump).271_LIBUNWIND_HIDDEN int __unw_resume(unw_cursor_t *cursor) {272  _LIBUNWIND_TRACE_API("__unw_resume(cursor=%p)", static_cast<void *>(cursor));273#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)274  // Inform the ASan runtime that now might be a good time to clean stuff up.275  __asan_handle_no_return();276#endif277  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;278  co->jumpto();279  return UNW_EUNSPEC;280}281_LIBUNWIND_WEAK_ALIAS(__unw_resume, unw_resume)282 283/// Get name of function at cursor position in stack frame.284_LIBUNWIND_HIDDEN int __unw_get_proc_name(unw_cursor_t *cursor, char *buf,285                                          size_t bufLen, unw_word_t *offset) {286  _LIBUNWIND_TRACE_API("__unw_get_proc_name(cursor=%p, &buf=%p, bufLen=%lu)",287                       static_cast<void *>(cursor), static_cast<void *>(buf),288                       static_cast<unsigned long>(bufLen));289  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;290  if (co->getFunctionName(buf, bufLen, offset))291    return UNW_ESUCCESS;292  return UNW_EUNSPEC;293}294_LIBUNWIND_WEAK_ALIAS(__unw_get_proc_name, unw_get_proc_name)295 296/// Checks if a register is a floating-point register.297_LIBUNWIND_HIDDEN int __unw_is_fpreg(unw_cursor_t *cursor,298                                     unw_regnum_t regNum) {299  _LIBUNWIND_TRACE_API("__unw_is_fpreg(cursor=%p, regNum=%d)",300                       static_cast<void *>(cursor), regNum);301  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;302  return co->validFloatReg(regNum);303}304_LIBUNWIND_WEAK_ALIAS(__unw_is_fpreg, unw_is_fpreg)305 306/// Checks if a register is a floating-point register.307_LIBUNWIND_HIDDEN const char *__unw_regname(unw_cursor_t *cursor,308                                            unw_regnum_t regNum) {309  _LIBUNWIND_TRACE_API("__unw_regname(cursor=%p, regNum=%d)",310                       static_cast<void *>(cursor), regNum);311  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;312  return co->getRegisterName(regNum);313}314_LIBUNWIND_WEAK_ALIAS(__unw_regname, unw_regname)315 316/// Checks if current frame is signal trampoline.317_LIBUNWIND_HIDDEN int __unw_is_signal_frame(unw_cursor_t *cursor) {318  _LIBUNWIND_TRACE_API("__unw_is_signal_frame(cursor=%p)",319                       static_cast<void *>(cursor));320  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;321  return co->isSignalFrame();322}323_LIBUNWIND_WEAK_ALIAS(__unw_is_signal_frame, unw_is_signal_frame)324 325#ifdef _AIX326_LIBUNWIND_EXPORT uintptr_t __unw_get_data_rel_base(unw_cursor_t *cursor) {327  _LIBUNWIND_TRACE_API("unw_get_data_rel_base(cursor=%p)",328                       static_cast<void *>(cursor));329  AbstractUnwindCursor *co = reinterpret_cast<AbstractUnwindCursor *>(cursor);330  return co->getDataRelBase();331}332_LIBUNWIND_WEAK_ALIAS(__unw_get_data_rel_base, unw_get_data_rel_base)333#endif334 335#ifdef __arm__336// Save VFP registers d0-d15 using FSTMIADX instead of FSTMIADD337_LIBUNWIND_HIDDEN void __unw_save_vfp_as_X(unw_cursor_t *cursor) {338  _LIBUNWIND_TRACE_API("__unw_get_fpreg_save_vfp_as_X(cursor=%p)",339                       static_cast<void *>(cursor));340  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;341  return co->saveVFPAsX();342}343_LIBUNWIND_WEAK_ALIAS(__unw_save_vfp_as_X, unw_save_vfp_as_X)344#endif345 346 347#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)348/// SPI: walks cached DWARF entries349_LIBUNWIND_HIDDEN void __unw_iterate_dwarf_unwind_cache(void (*func)(350    unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) {351  _LIBUNWIND_TRACE_API("__unw_iterate_dwarf_unwind_cache(func=%p)",352                       reinterpret_cast<void *>(func));353  DwarfFDECache<LocalAddressSpace>::iterateCacheEntries(func);354}355_LIBUNWIND_WEAK_ALIAS(__unw_iterate_dwarf_unwind_cache,356                      unw_iterate_dwarf_unwind_cache)357 358/// IPI: for __register_frame()359void __unw_add_dynamic_fde(unw_word_t fde) {360  CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo;361  CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo;362  const char *message = CFI_Parser<LocalAddressSpace>::decodeFDE(363                           LocalAddressSpace::sThisAddressSpace,364                          (LocalAddressSpace::pint_t) fde, &fdeInfo, &cieInfo);365  if (message == NULL) {366    // dynamically registered FDEs don't have a mach_header group they are in.367    // Use fde as mh_group368    unw_word_t mh_group = fdeInfo.fdeStart;369    DwarfFDECache<LocalAddressSpace>::add((LocalAddressSpace::pint_t)mh_group,370                                          fdeInfo.pcStart, fdeInfo.pcEnd,371                                          fdeInfo.fdeStart);372  } else {373    _LIBUNWIND_DEBUG_LOG("__unw_add_dynamic_fde: bad fde: %s", message);374  }375}376 377/// IPI: for __deregister_frame()378void __unw_remove_dynamic_fde(unw_word_t fde) {379  // fde is own mh_group380  DwarfFDECache<LocalAddressSpace>::removeAllIn((LocalAddressSpace::pint_t)fde);381}382 383void __unw_add_dynamic_eh_frame_section(unw_word_t eh_frame_start) {384  // The eh_frame section start serves as the mh_group385  unw_word_t mh_group = eh_frame_start;386  CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo;387  CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo;388  auto p = (LocalAddressSpace::pint_t)eh_frame_start;389  while (LocalAddressSpace::sThisAddressSpace.get32(p)) {390    if (CFI_Parser<LocalAddressSpace>::decodeFDE(391            LocalAddressSpace::sThisAddressSpace, p, &fdeInfo, &cieInfo,392            true) == NULL) {393      DwarfFDECache<LocalAddressSpace>::add((LocalAddressSpace::pint_t)mh_group,394                                            fdeInfo.pcStart, fdeInfo.pcEnd,395                                            fdeInfo.fdeStart);396      p += fdeInfo.fdeLength;397    } else if (CFI_Parser<LocalAddressSpace>::parseCIE(398                   LocalAddressSpace::sThisAddressSpace, p, &cieInfo) == NULL) {399      p += cieInfo.cieLength;400    } else401      return;402  }403}404 405void __unw_remove_dynamic_eh_frame_section(unw_word_t eh_frame_start) {406  // The eh_frame section start serves as the mh_group407  DwarfFDECache<LocalAddressSpace>::removeAllIn(408      (LocalAddressSpace::pint_t)eh_frame_start);409}410 411#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)412 413/// Maps the UNW_* error code to a textual representation414_LIBUNWIND_HIDDEN const char *__unw_strerror(int error_code) {415  switch (error_code) {416  case UNW_ESUCCESS:417    return "no error";418  case UNW_EUNSPEC:419    return "unspecified (general) error";420  case UNW_ENOMEM:421    return "out of memory";422  case UNW_EBADREG:423    return "bad register number";424  case UNW_EREADONLYREG:425    return "attempt to write read-only register";426  case UNW_ESTOPUNWIND:427    return "stop unwinding";428  case UNW_EINVALIDIP:429    return "invalid IP";430  case UNW_EBADFRAME:431    return "bad frame";432  case UNW_EINVAL:433    return "unsupported operation or bad value";434  case UNW_EBADVERSION:435    return "unwind info has unsupported version";436  case UNW_ENOINFO:437    return "no unwind info found";438#if defined(_LIBUNWIND_TARGET_AARCH64) && !defined(_LIBUNWIND_IS_NATIVE_ONLY)439  case UNW_ECROSSRASIGNING:440    return "cross unwind with return address signing";441#endif442  }443  return "invalid error code";444}445_LIBUNWIND_WEAK_ALIAS(__unw_strerror, unw_strerror)446 447#endif // !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__wasm__)448 449#ifdef __APPLE__450 451namespace libunwind {452 453static constexpr size_t MAX_DYNAMIC_UNWIND_SECTIONS_FINDERS = 8;454 455static RWMutex findDynamicUnwindSectionsLock;456static size_t numDynamicUnwindSectionsFinders = 0;457static unw_find_dynamic_unwind_sections458    dynamicUnwindSectionsFinders[MAX_DYNAMIC_UNWIND_SECTIONS_FINDERS] = {0};459 460bool findDynamicUnwindSections(void *addr, unw_dynamic_unwind_sections *info) {461  bool found = false;462  findDynamicUnwindSectionsLock.lock_shared();463  for (size_t i = 0; i != numDynamicUnwindSectionsFinders; ++i) {464    if (dynamicUnwindSectionsFinders[i]((unw_word_t)addr, info)) {465      found = true;466      break;467    }468  }469  findDynamicUnwindSectionsLock.unlock_shared();470  return found;471}472 473} // namespace libunwind474 475int __unw_add_find_dynamic_unwind_sections(476    unw_find_dynamic_unwind_sections find_dynamic_unwind_sections) {477  findDynamicUnwindSectionsLock.lock();478 479  // Check that we have enough space...480  if (numDynamicUnwindSectionsFinders == MAX_DYNAMIC_UNWIND_SECTIONS_FINDERS) {481    findDynamicUnwindSectionsLock.unlock();482    return UNW_ENOMEM;483  }484 485  // Check for value already present...486  for (size_t i = 0; i != numDynamicUnwindSectionsFinders; ++i) {487    if (dynamicUnwindSectionsFinders[i] == find_dynamic_unwind_sections) {488      findDynamicUnwindSectionsLock.unlock();489      return UNW_EINVAL;490    }491  }492 493  // Success -- add callback entry.494  dynamicUnwindSectionsFinders[numDynamicUnwindSectionsFinders++] =495    find_dynamic_unwind_sections;496  findDynamicUnwindSectionsLock.unlock();497 498  return UNW_ESUCCESS;499}500 501int __unw_remove_find_dynamic_unwind_sections(502    unw_find_dynamic_unwind_sections find_dynamic_unwind_sections) {503  findDynamicUnwindSectionsLock.lock();504 505  // Find index to remove.506  size_t finderIdx = numDynamicUnwindSectionsFinders;507  for (size_t i = 0; i != numDynamicUnwindSectionsFinders; ++i) {508    if (dynamicUnwindSectionsFinders[i] == find_dynamic_unwind_sections) {509      finderIdx = i;510      break;511    }512  }513 514  // If no such registration is present then error out.515  if (finderIdx == numDynamicUnwindSectionsFinders) {516    findDynamicUnwindSectionsLock.unlock();517    return UNW_EINVAL;518  }519 520  // Remove entry.521  for (size_t i = finderIdx; i != numDynamicUnwindSectionsFinders - 1; ++i)522    dynamicUnwindSectionsFinders[i] = dynamicUnwindSectionsFinders[i + 1];523  dynamicUnwindSectionsFinders[--numDynamicUnwindSectionsFinders] = nullptr;524 525  findDynamicUnwindSectionsLock.unlock();526  return UNW_ESUCCESS;527}528 529#endif // __APPLE__530 531// Add logging hooks in Debug builds only532#ifndef NDEBUG533#include <stdlib.h>534 535_LIBUNWIND_HIDDEN536bool logAPIs() {537  // do manual lock to avoid use of _cxa_guard_acquire or initializers538  static bool checked = false;539  static bool log = false;540  if (!checked) {541    log = (getenv("LIBUNWIND_PRINT_APIS") != NULL);542    checked = true;543  }544  return log;545}546 547_LIBUNWIND_HIDDEN548bool logUnwinding() {549  // do manual lock to avoid use of _cxa_guard_acquire or initializers550  static bool checked = false;551  static bool log = false;552  if (!checked) {553    log = (getenv("LIBUNWIND_PRINT_UNWINDING") != NULL);554    checked = true;555  }556  return log;557}558 559_LIBUNWIND_HIDDEN560bool logDWARF() {561  // do manual lock to avoid use of _cxa_guard_acquire or initializers562  static bool checked = false;563  static bool log = false;564  if (!checked) {565    log = (getenv("LIBUNWIND_PRINT_DWARF") != NULL);566    checked = true;567  }568  return log;569}570 571#endif // NDEBUG572 573