11cb0ef41Sopenharmony_ci#include "debug_utils-inl.h"  // NOLINT(build/include)
21cb0ef41Sopenharmony_ci#include "env-inl.h"
31cb0ef41Sopenharmony_ci#include "node_internals.h"
41cb0ef41Sopenharmony_ci#include "util.h"
51cb0ef41Sopenharmony_ci
61cb0ef41Sopenharmony_ci#ifdef __POSIX__
71cb0ef41Sopenharmony_ci#if defined(__linux__)
81cb0ef41Sopenharmony_ci#include <features.h>
91cb0ef41Sopenharmony_ci#endif
101cb0ef41Sopenharmony_ci
111cb0ef41Sopenharmony_ci#ifdef __ANDROID__
121cb0ef41Sopenharmony_ci#include <android/log.h>
131cb0ef41Sopenharmony_ci#endif
141cb0ef41Sopenharmony_ci
151cb0ef41Sopenharmony_ci#if defined(__linux__) && !defined(__GLIBC__) || \
161cb0ef41Sopenharmony_ci    defined(__UCLIBC__) || \
171cb0ef41Sopenharmony_ci    defined(_AIX)
181cb0ef41Sopenharmony_ci#define HAVE_EXECINFO_H 0
191cb0ef41Sopenharmony_ci#else
201cb0ef41Sopenharmony_ci#define HAVE_EXECINFO_H 1
211cb0ef41Sopenharmony_ci#endif
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_ci#if HAVE_EXECINFO_H
241cb0ef41Sopenharmony_ci#include <cxxabi.h>
251cb0ef41Sopenharmony_ci#include <dlfcn.h>
261cb0ef41Sopenharmony_ci#include <execinfo.h>
271cb0ef41Sopenharmony_ci#include <unistd.h>
281cb0ef41Sopenharmony_ci#include <sys/mman.h>
291cb0ef41Sopenharmony_ci#include <cstdio>
301cb0ef41Sopenharmony_ci#endif
311cb0ef41Sopenharmony_ci
321cb0ef41Sopenharmony_ci#endif  // __POSIX__
331cb0ef41Sopenharmony_ci
341cb0ef41Sopenharmony_ci#if defined(__linux__) || defined(__sun) || \
351cb0ef41Sopenharmony_ci    defined(__FreeBSD__) || defined(__OpenBSD__) || \
361cb0ef41Sopenharmony_ci    defined(__DragonFly__)
371cb0ef41Sopenharmony_ci#include <link.h>
381cb0ef41Sopenharmony_ci#endif
391cb0ef41Sopenharmony_ci
401cb0ef41Sopenharmony_ci#ifdef __APPLE__
411cb0ef41Sopenharmony_ci#include <mach-o/dyld.h>  // _dyld_get_image_name()
421cb0ef41Sopenharmony_ci#endif                    // __APPLE__
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_ci#ifdef _AIX
451cb0ef41Sopenharmony_ci#include <sys/ldr.h>  // ld_info structure
461cb0ef41Sopenharmony_ci#endif                // _AIX
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_ci#ifdef _WIN32
491cb0ef41Sopenharmony_ci#include <Lm.h>
501cb0ef41Sopenharmony_ci#include <Windows.h>
511cb0ef41Sopenharmony_ci#include <dbghelp.h>
521cb0ef41Sopenharmony_ci#include <process.h>
531cb0ef41Sopenharmony_ci#include <psapi.h>
541cb0ef41Sopenharmony_ci#include <tchar.h>
551cb0ef41Sopenharmony_ci#endif  // _WIN32
561cb0ef41Sopenharmony_ci
571cb0ef41Sopenharmony_cinamespace node {
581cb0ef41Sopenharmony_cinamespace per_process {
591cb0ef41Sopenharmony_ciEnabledDebugList enabled_debug_list;
601cb0ef41Sopenharmony_ci}
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_civoid EnabledDebugList::Parse(std::shared_ptr<KVStore> env_vars,
631cb0ef41Sopenharmony_ci                             v8::Isolate* isolate) {
641cb0ef41Sopenharmony_ci  std::string cats;
651cb0ef41Sopenharmony_ci  credentials::SafeGetenv("NODE_DEBUG_NATIVE", &cats, env_vars, isolate);
661cb0ef41Sopenharmony_ci  Parse(cats);
671cb0ef41Sopenharmony_ci}
681cb0ef41Sopenharmony_ci
691cb0ef41Sopenharmony_civoid EnabledDebugList::Parse(const std::string& cats) {
701cb0ef41Sopenharmony_ci  std::string debug_categories = cats;
711cb0ef41Sopenharmony_ci  while (!debug_categories.empty()) {
721cb0ef41Sopenharmony_ci    std::string::size_type comma_pos = debug_categories.find(',');
731cb0ef41Sopenharmony_ci    std::string wanted = ToLower(debug_categories.substr(0, comma_pos));
741cb0ef41Sopenharmony_ci
751cb0ef41Sopenharmony_ci#define V(name)                                                                \
761cb0ef41Sopenharmony_ci  {                                                                            \
771cb0ef41Sopenharmony_ci    static const std::string available_category = ToLower(#name);              \
781cb0ef41Sopenharmony_ci    if (available_category.find(wanted) != std::string::npos)                  \
791cb0ef41Sopenharmony_ci      set_enabled(DebugCategory::name);                                        \
801cb0ef41Sopenharmony_ci  }
811cb0ef41Sopenharmony_ci
821cb0ef41Sopenharmony_ci    DEBUG_CATEGORY_NAMES(V)
831cb0ef41Sopenharmony_ci#undef V
841cb0ef41Sopenharmony_ci
851cb0ef41Sopenharmony_ci    if (comma_pos == std::string::npos) break;
861cb0ef41Sopenharmony_ci    // Use everything after the `,` as the list for the next iteration.
871cb0ef41Sopenharmony_ci    debug_categories = debug_categories.substr(comma_pos + 1);
881cb0ef41Sopenharmony_ci  }
891cb0ef41Sopenharmony_ci}
901cb0ef41Sopenharmony_ci
911cb0ef41Sopenharmony_ci#ifdef __POSIX__
921cb0ef41Sopenharmony_ci#if HAVE_EXECINFO_H
931cb0ef41Sopenharmony_ciclass PosixSymbolDebuggingContext final : public NativeSymbolDebuggingContext {
941cb0ef41Sopenharmony_ci public:
951cb0ef41Sopenharmony_ci  PosixSymbolDebuggingContext() : pagesize_(getpagesize()) { }
961cb0ef41Sopenharmony_ci
971cb0ef41Sopenharmony_ci  SymbolInfo LookupSymbol(void* address) override {
981cb0ef41Sopenharmony_ci    Dl_info info;
991cb0ef41Sopenharmony_ci    const bool have_info = dladdr(address, &info);
1001cb0ef41Sopenharmony_ci    SymbolInfo ret;
1011cb0ef41Sopenharmony_ci    if (!have_info)
1021cb0ef41Sopenharmony_ci      return ret;
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_ci    if (info.dli_sname != nullptr) {
1051cb0ef41Sopenharmony_ci      if (char* demangled =
1061cb0ef41Sopenharmony_ci              abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, nullptr)) {
1071cb0ef41Sopenharmony_ci        ret.name = demangled;
1081cb0ef41Sopenharmony_ci        free(demangled);
1091cb0ef41Sopenharmony_ci      } else {
1101cb0ef41Sopenharmony_ci        ret.name = info.dli_sname;
1111cb0ef41Sopenharmony_ci      }
1121cb0ef41Sopenharmony_ci    }
1131cb0ef41Sopenharmony_ci
1141cb0ef41Sopenharmony_ci    if (info.dli_fname != nullptr) {
1151cb0ef41Sopenharmony_ci      ret.filename = info.dli_fname;
1161cb0ef41Sopenharmony_ci    }
1171cb0ef41Sopenharmony_ci
1181cb0ef41Sopenharmony_ci    return ret;
1191cb0ef41Sopenharmony_ci  }
1201cb0ef41Sopenharmony_ci
1211cb0ef41Sopenharmony_ci  bool IsMapped(void* address) override {
1221cb0ef41Sopenharmony_ci    void* page_aligned = reinterpret_cast<void*>(
1231cb0ef41Sopenharmony_ci        reinterpret_cast<uintptr_t>(address) & ~(pagesize_ - 1));
1241cb0ef41Sopenharmony_ci    return msync(page_aligned, pagesize_, MS_ASYNC) == 0;
1251cb0ef41Sopenharmony_ci  }
1261cb0ef41Sopenharmony_ci
1271cb0ef41Sopenharmony_ci  int GetStackTrace(void** frames, int count) override {
1281cb0ef41Sopenharmony_ci    return backtrace(frames, count);
1291cb0ef41Sopenharmony_ci  }
1301cb0ef41Sopenharmony_ci
1311cb0ef41Sopenharmony_ci private:
1321cb0ef41Sopenharmony_ci  uintptr_t pagesize_;
1331cb0ef41Sopenharmony_ci};
1341cb0ef41Sopenharmony_ci
1351cb0ef41Sopenharmony_cistd::unique_ptr<NativeSymbolDebuggingContext>
1361cb0ef41Sopenharmony_ciNativeSymbolDebuggingContext::New() {
1371cb0ef41Sopenharmony_ci  return std::make_unique<PosixSymbolDebuggingContext>();
1381cb0ef41Sopenharmony_ci}
1391cb0ef41Sopenharmony_ci
1401cb0ef41Sopenharmony_ci#else  // HAVE_EXECINFO_H
1411cb0ef41Sopenharmony_ci
1421cb0ef41Sopenharmony_cistd::unique_ptr<NativeSymbolDebuggingContext>
1431cb0ef41Sopenharmony_ciNativeSymbolDebuggingContext::New() {
1441cb0ef41Sopenharmony_ci  return std::make_unique<NativeSymbolDebuggingContext>();
1451cb0ef41Sopenharmony_ci}
1461cb0ef41Sopenharmony_ci
1471cb0ef41Sopenharmony_ci#endif  // HAVE_EXECINFO_H
1481cb0ef41Sopenharmony_ci
1491cb0ef41Sopenharmony_ci#else  // __POSIX__
1501cb0ef41Sopenharmony_ci
1511cb0ef41Sopenharmony_ciclass Win32SymbolDebuggingContext final : public NativeSymbolDebuggingContext {
1521cb0ef41Sopenharmony_ci public:
1531cb0ef41Sopenharmony_ci  Win32SymbolDebuggingContext() {
1541cb0ef41Sopenharmony_ci    current_process_ = GetCurrentProcess();
1551cb0ef41Sopenharmony_ci    USE(SymInitialize(current_process_, nullptr, true));
1561cb0ef41Sopenharmony_ci  }
1571cb0ef41Sopenharmony_ci
1581cb0ef41Sopenharmony_ci  ~Win32SymbolDebuggingContext() override {
1591cb0ef41Sopenharmony_ci    USE(SymCleanup(current_process_));
1601cb0ef41Sopenharmony_ci  }
1611cb0ef41Sopenharmony_ci
1621cb0ef41Sopenharmony_ci  using NameAndDisplacement = std::pair<std::string, DWORD64>;
1631cb0ef41Sopenharmony_ci  NameAndDisplacement WrappedSymFromAddr(DWORD64 dwAddress) const {
1641cb0ef41Sopenharmony_ci    // Refs: https://docs.microsoft.com/en-us/windows/desktop/Debug/retrieving-symbol-information-by-address
1651cb0ef41Sopenharmony_ci    // Patches:
1661cb0ef41Sopenharmony_ci    // Use `fprintf(stderr, ` instead of `printf`
1671cb0ef41Sopenharmony_ci    // `sym.filename = pSymbol->Name` on success
1681cb0ef41Sopenharmony_ci    // `current_process_` instead of `hProcess.
1691cb0ef41Sopenharmony_ci    DWORD64 dwDisplacement = 0;
1701cb0ef41Sopenharmony_ci    // Patch: made into arg - DWORD64  dwAddress = SOME_ADDRESS;
1711cb0ef41Sopenharmony_ci
1721cb0ef41Sopenharmony_ci    char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
1731cb0ef41Sopenharmony_ci    const auto pSymbol = reinterpret_cast<PSYMBOL_INFO>(buffer);
1741cb0ef41Sopenharmony_ci
1751cb0ef41Sopenharmony_ci    pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
1761cb0ef41Sopenharmony_ci    pSymbol->MaxNameLen = MAX_SYM_NAME;
1771cb0ef41Sopenharmony_ci
1781cb0ef41Sopenharmony_ci    if (SymFromAddr(current_process_, dwAddress, &dwDisplacement, pSymbol)) {
1791cb0ef41Sopenharmony_ci      // SymFromAddr returned success
1801cb0ef41Sopenharmony_ci      return NameAndDisplacement(pSymbol->Name, dwDisplacement);
1811cb0ef41Sopenharmony_ci    } else {
1821cb0ef41Sopenharmony_ci      // SymFromAddr failed
1831cb0ef41Sopenharmony_ci      const DWORD error = GetLastError();  // "eat" the error anyway
1841cb0ef41Sopenharmony_ci#ifdef DEBUG
1851cb0ef41Sopenharmony_ci      fprintf(stderr, "SymFromAddr returned error : %lu\n", error);
1861cb0ef41Sopenharmony_ci#endif
1871cb0ef41Sopenharmony_ci    }
1881cb0ef41Sopenharmony_ci    // End MSDN code
1891cb0ef41Sopenharmony_ci
1901cb0ef41Sopenharmony_ci    return NameAndDisplacement();
1911cb0ef41Sopenharmony_ci  }
1921cb0ef41Sopenharmony_ci
1931cb0ef41Sopenharmony_ci  SymbolInfo WrappedGetLine(DWORD64 dwAddress) const {
1941cb0ef41Sopenharmony_ci    SymbolInfo sym{};
1951cb0ef41Sopenharmony_ci
1961cb0ef41Sopenharmony_ci    // Refs: https://docs.microsoft.com/en-us/windows/desktop/Debug/retrieving-symbol-information-by-address
1971cb0ef41Sopenharmony_ci    // Patches:
1981cb0ef41Sopenharmony_ci    // Use `fprintf(stderr, ` instead of `printf`.
1991cb0ef41Sopenharmony_ci    // Assign values to `sym` on success.
2001cb0ef41Sopenharmony_ci    // `current_process_` instead of `hProcess.
2011cb0ef41Sopenharmony_ci
2021cb0ef41Sopenharmony_ci    // Patch: made into arg - DWORD64  dwAddress;
2031cb0ef41Sopenharmony_ci    DWORD dwDisplacement;
2041cb0ef41Sopenharmony_ci    IMAGEHLP_LINE64 line;
2051cb0ef41Sopenharmony_ci
2061cb0ef41Sopenharmony_ci    SymSetOptions(SYMOPT_LOAD_LINES);
2071cb0ef41Sopenharmony_ci
2081cb0ef41Sopenharmony_ci    line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
2091cb0ef41Sopenharmony_ci    // Patch: made into arg - dwAddress = 0x1000000;
2101cb0ef41Sopenharmony_ci
2111cb0ef41Sopenharmony_ci    if (SymGetLineFromAddr64(current_process_, dwAddress,
2121cb0ef41Sopenharmony_ci                             &dwDisplacement, &line)) {
2131cb0ef41Sopenharmony_ci      // SymGetLineFromAddr64 returned success
2141cb0ef41Sopenharmony_ci      sym.filename = line.FileName;
2151cb0ef41Sopenharmony_ci      sym.line = line.LineNumber;
2161cb0ef41Sopenharmony_ci    } else {
2171cb0ef41Sopenharmony_ci      // SymGetLineFromAddr64 failed
2181cb0ef41Sopenharmony_ci      const DWORD error = GetLastError();  // "eat" the error anyway
2191cb0ef41Sopenharmony_ci#ifdef DEBUG
2201cb0ef41Sopenharmony_ci      fprintf(stderr, "SymGetLineFromAddr64 returned error : %lu\n", error);
2211cb0ef41Sopenharmony_ci#endif
2221cb0ef41Sopenharmony_ci    }
2231cb0ef41Sopenharmony_ci    // End MSDN code
2241cb0ef41Sopenharmony_ci
2251cb0ef41Sopenharmony_ci    return sym;
2261cb0ef41Sopenharmony_ci  }
2271cb0ef41Sopenharmony_ci
2281cb0ef41Sopenharmony_ci  // Fills the SymbolInfo::name of the io/out argument `sym`
2291cb0ef41Sopenharmony_ci  std::string WrappedUnDecorateSymbolName(const char* name) const {
2301cb0ef41Sopenharmony_ci    // Refs: https://docs.microsoft.com/en-us/windows/desktop/Debug/retrieving-undecorated-symbol-names
2311cb0ef41Sopenharmony_ci    // Patches:
2321cb0ef41Sopenharmony_ci    // Use `fprintf(stderr, ` instead of `printf`.
2331cb0ef41Sopenharmony_ci    // return `szUndName` instead of `printf` on success
2341cb0ef41Sopenharmony_ci    char szUndName[MAX_SYM_NAME];
2351cb0ef41Sopenharmony_ci    if (UnDecorateSymbolName(name, szUndName, sizeof(szUndName),
2361cb0ef41Sopenharmony_ci                             UNDNAME_COMPLETE)) {
2371cb0ef41Sopenharmony_ci      // UnDecorateSymbolName returned success
2381cb0ef41Sopenharmony_ci      return szUndName;
2391cb0ef41Sopenharmony_ci    } else {
2401cb0ef41Sopenharmony_ci      // UnDecorateSymbolName failed
2411cb0ef41Sopenharmony_ci      const DWORD error = GetLastError();  // "eat" the error anyway
2421cb0ef41Sopenharmony_ci#ifdef DEBUG
2431cb0ef41Sopenharmony_ci      fprintf(stderr, "UnDecorateSymbolName returned error %lu\n", error);
2441cb0ef41Sopenharmony_ci#endif
2451cb0ef41Sopenharmony_ci    }
2461cb0ef41Sopenharmony_ci    return nullptr;
2471cb0ef41Sopenharmony_ci  }
2481cb0ef41Sopenharmony_ci
2491cb0ef41Sopenharmony_ci  SymbolInfo LookupSymbol(void* address) override {
2501cb0ef41Sopenharmony_ci    const DWORD64 dw_address = reinterpret_cast<DWORD64>(address);
2511cb0ef41Sopenharmony_ci    SymbolInfo ret = WrappedGetLine(dw_address);
2521cb0ef41Sopenharmony_ci    std::tie(ret.name, ret.dis) = WrappedSymFromAddr(dw_address);
2531cb0ef41Sopenharmony_ci    if (!ret.name.empty()) {
2541cb0ef41Sopenharmony_ci      ret.name = WrappedUnDecorateSymbolName(ret.name.c_str());
2551cb0ef41Sopenharmony_ci    }
2561cb0ef41Sopenharmony_ci    return ret;
2571cb0ef41Sopenharmony_ci  }
2581cb0ef41Sopenharmony_ci
2591cb0ef41Sopenharmony_ci  bool IsMapped(void* address) override {
2601cb0ef41Sopenharmony_ci    MEMORY_BASIC_INFORMATION info;
2611cb0ef41Sopenharmony_ci
2621cb0ef41Sopenharmony_ci    if (VirtualQuery(address, &info, sizeof(info)) != sizeof(info))
2631cb0ef41Sopenharmony_ci      return false;
2641cb0ef41Sopenharmony_ci
2651cb0ef41Sopenharmony_ci    return info.State == MEM_COMMIT && info.Protect != 0;
2661cb0ef41Sopenharmony_ci  }
2671cb0ef41Sopenharmony_ci
2681cb0ef41Sopenharmony_ci  int GetStackTrace(void** frames, int count) override {
2691cb0ef41Sopenharmony_ci    return CaptureStackBackTrace(0, count, frames, nullptr);
2701cb0ef41Sopenharmony_ci  }
2711cb0ef41Sopenharmony_ci
2721cb0ef41Sopenharmony_ci  Win32SymbolDebuggingContext(const Win32SymbolDebuggingContext&) = delete;
2731cb0ef41Sopenharmony_ci  Win32SymbolDebuggingContext(Win32SymbolDebuggingContext&&) = delete;
2741cb0ef41Sopenharmony_ci  Win32SymbolDebuggingContext operator=(const Win32SymbolDebuggingContext&)
2751cb0ef41Sopenharmony_ci    = delete;
2761cb0ef41Sopenharmony_ci  Win32SymbolDebuggingContext operator=(Win32SymbolDebuggingContext&&)
2771cb0ef41Sopenharmony_ci    = delete;
2781cb0ef41Sopenharmony_ci
2791cb0ef41Sopenharmony_ci private:
2801cb0ef41Sopenharmony_ci  HANDLE current_process_;
2811cb0ef41Sopenharmony_ci};
2821cb0ef41Sopenharmony_ci
2831cb0ef41Sopenharmony_cistd::unique_ptr<NativeSymbolDebuggingContext>
2841cb0ef41Sopenharmony_ciNativeSymbolDebuggingContext::New() {
2851cb0ef41Sopenharmony_ci  return std::unique_ptr<NativeSymbolDebuggingContext>(
2861cb0ef41Sopenharmony_ci      new Win32SymbolDebuggingContext());
2871cb0ef41Sopenharmony_ci}
2881cb0ef41Sopenharmony_ci
2891cb0ef41Sopenharmony_ci#endif  // __POSIX__
2901cb0ef41Sopenharmony_ci
2911cb0ef41Sopenharmony_cistd::string NativeSymbolDebuggingContext::SymbolInfo::Display() const {
2921cb0ef41Sopenharmony_ci  std::ostringstream oss;
2931cb0ef41Sopenharmony_ci  oss << name;
2941cb0ef41Sopenharmony_ci  if (dis != 0) {
2951cb0ef41Sopenharmony_ci    oss << "+" << dis;
2961cb0ef41Sopenharmony_ci  }
2971cb0ef41Sopenharmony_ci  if (!filename.empty()) {
2981cb0ef41Sopenharmony_ci    oss << " [" << filename << ']';
2991cb0ef41Sopenharmony_ci  }
3001cb0ef41Sopenharmony_ci  if (line != 0) {
3011cb0ef41Sopenharmony_ci    oss << ":L" << line;
3021cb0ef41Sopenharmony_ci  }
3031cb0ef41Sopenharmony_ci  return oss.str();
3041cb0ef41Sopenharmony_ci}
3051cb0ef41Sopenharmony_ci
3061cb0ef41Sopenharmony_civoid DumpBacktrace(FILE* fp) {
3071cb0ef41Sopenharmony_ci  auto sym_ctx = NativeSymbolDebuggingContext::New();
3081cb0ef41Sopenharmony_ci  void* frames[256];
3091cb0ef41Sopenharmony_ci  const int size = sym_ctx->GetStackTrace(frames, arraysize(frames));
3101cb0ef41Sopenharmony_ci  for (int i = 1; i < size; i += 1) {
3111cb0ef41Sopenharmony_ci    void* frame = frames[i];
3121cb0ef41Sopenharmony_ci    NativeSymbolDebuggingContext::SymbolInfo s = sym_ctx->LookupSymbol(frame);
3131cb0ef41Sopenharmony_ci    fprintf(fp, "%2d: %p %s\n", i, frame, s.Display().c_str());
3141cb0ef41Sopenharmony_ci  }
3151cb0ef41Sopenharmony_ci}
3161cb0ef41Sopenharmony_ci
3171cb0ef41Sopenharmony_civoid CheckedUvLoopClose(uv_loop_t* loop) {
3181cb0ef41Sopenharmony_ci  if (uv_loop_close(loop) == 0) return;
3191cb0ef41Sopenharmony_ci
3201cb0ef41Sopenharmony_ci  PrintLibuvHandleInformation(loop, stderr);
3211cb0ef41Sopenharmony_ci
3221cb0ef41Sopenharmony_ci  fflush(stderr);
3231cb0ef41Sopenharmony_ci  // Finally, abort.
3241cb0ef41Sopenharmony_ci  UNREACHABLE("uv_loop_close() while having open handles");
3251cb0ef41Sopenharmony_ci}
3261cb0ef41Sopenharmony_ci
3271cb0ef41Sopenharmony_civoid PrintLibuvHandleInformation(uv_loop_t* loop, FILE* stream) {
3281cb0ef41Sopenharmony_ci  struct Info {
3291cb0ef41Sopenharmony_ci    std::unique_ptr<NativeSymbolDebuggingContext> ctx;
3301cb0ef41Sopenharmony_ci    FILE* stream;
3311cb0ef41Sopenharmony_ci    size_t num_handles;
3321cb0ef41Sopenharmony_ci  };
3331cb0ef41Sopenharmony_ci
3341cb0ef41Sopenharmony_ci  Info info { NativeSymbolDebuggingContext::New(), stream, 0 };
3351cb0ef41Sopenharmony_ci
3361cb0ef41Sopenharmony_ci  fprintf(stream, "uv loop at [%p] has open handles:\n", loop);
3371cb0ef41Sopenharmony_ci
3381cb0ef41Sopenharmony_ci  uv_walk(loop, [](uv_handle_t* handle, void* arg) {
3391cb0ef41Sopenharmony_ci    Info* info = static_cast<Info*>(arg);
3401cb0ef41Sopenharmony_ci    NativeSymbolDebuggingContext* sym_ctx = info->ctx.get();
3411cb0ef41Sopenharmony_ci    FILE* stream = info->stream;
3421cb0ef41Sopenharmony_ci    info->num_handles++;
3431cb0ef41Sopenharmony_ci
3441cb0ef41Sopenharmony_ci    fprintf(stream, "[%p] %s%s\n", handle, uv_handle_type_name(handle->type),
3451cb0ef41Sopenharmony_ci            uv_is_active(handle) ? " (active)" : "");
3461cb0ef41Sopenharmony_ci
3471cb0ef41Sopenharmony_ci    void* close_cb = reinterpret_cast<void*>(handle->close_cb);
3481cb0ef41Sopenharmony_ci    fprintf(stream, "\tClose callback: %p %s\n",
3491cb0ef41Sopenharmony_ci        close_cb, sym_ctx->LookupSymbol(close_cb).Display().c_str());
3501cb0ef41Sopenharmony_ci
3511cb0ef41Sopenharmony_ci    fprintf(stream, "\tData: %p %s\n",
3521cb0ef41Sopenharmony_ci        handle->data, sym_ctx->LookupSymbol(handle->data).Display().c_str());
3531cb0ef41Sopenharmony_ci
3541cb0ef41Sopenharmony_ci    // We are also interested in the first field of what `handle->data`
3551cb0ef41Sopenharmony_ci    // points to, because for C++ code that is usually the virtual table pointer
3561cb0ef41Sopenharmony_ci    // and gives us information about the exact kind of object we're looking at.
3571cb0ef41Sopenharmony_ci    void* first_field = nullptr;
3581cb0ef41Sopenharmony_ci    // `handle->data` might be any value, including `nullptr`, or something
3591cb0ef41Sopenharmony_ci    // cast from a completely different type; therefore, check that it’s
3601cb0ef41Sopenharmony_ci    // dereferenceable first.
3611cb0ef41Sopenharmony_ci    if (sym_ctx->IsMapped(handle->data))
3621cb0ef41Sopenharmony_ci      first_field = *reinterpret_cast<void**>(handle->data);
3631cb0ef41Sopenharmony_ci
3641cb0ef41Sopenharmony_ci    if (first_field != nullptr) {
3651cb0ef41Sopenharmony_ci      fprintf(stream, "\t(First field): %p %s\n",
3661cb0ef41Sopenharmony_ci          first_field, sym_ctx->LookupSymbol(first_field).Display().c_str());
3671cb0ef41Sopenharmony_ci    }
3681cb0ef41Sopenharmony_ci  }, &info);
3691cb0ef41Sopenharmony_ci
3701cb0ef41Sopenharmony_ci  fprintf(stream, "uv loop at [%p] has %zu open handles in total\n",
3711cb0ef41Sopenharmony_ci          loop, info.num_handles);
3721cb0ef41Sopenharmony_ci}
3731cb0ef41Sopenharmony_ci
3741cb0ef41Sopenharmony_cistd::vector<std::string> NativeSymbolDebuggingContext::GetLoadedLibraries() {
3751cb0ef41Sopenharmony_ci  std::vector<std::string> list;
3761cb0ef41Sopenharmony_ci#if defined(__linux__) || defined(__FreeBSD__) || \
3771cb0ef41Sopenharmony_ci    defined(__OpenBSD__) || defined(__DragonFly__)
3781cb0ef41Sopenharmony_ci  dl_iterate_phdr(
3791cb0ef41Sopenharmony_ci      [](struct dl_phdr_info* info, size_t size, void* data) {
3801cb0ef41Sopenharmony_ci        auto list = static_cast<std::vector<std::string>*>(data);
3811cb0ef41Sopenharmony_ci        if (*info->dlpi_name != '\0') {
3821cb0ef41Sopenharmony_ci          list->emplace_back(info->dlpi_name);
3831cb0ef41Sopenharmony_ci        }
3841cb0ef41Sopenharmony_ci        return 0;
3851cb0ef41Sopenharmony_ci      },
3861cb0ef41Sopenharmony_ci      &list);
3871cb0ef41Sopenharmony_ci#elif __APPLE__
3881cb0ef41Sopenharmony_ci  uint32_t i = 0;
3891cb0ef41Sopenharmony_ci  for (const char* name = _dyld_get_image_name(i); name != nullptr;
3901cb0ef41Sopenharmony_ci       name = _dyld_get_image_name(++i)) {
3911cb0ef41Sopenharmony_ci    list.emplace_back(name);
3921cb0ef41Sopenharmony_ci  }
3931cb0ef41Sopenharmony_ci
3941cb0ef41Sopenharmony_ci#elif _AIX
3951cb0ef41Sopenharmony_ci  // We can't tell in advance how large the buffer needs to be.
3961cb0ef41Sopenharmony_ci  // Retry until we reach too large a size (1Mb).
3971cb0ef41Sopenharmony_ci  const unsigned int kBufferGrowStep = 4096;
3981cb0ef41Sopenharmony_ci  MallocedBuffer<char> buffer(kBufferGrowStep);
3991cb0ef41Sopenharmony_ci  int rc = -1;
4001cb0ef41Sopenharmony_ci  do {
4011cb0ef41Sopenharmony_ci    rc = loadquery(L_GETINFO, buffer.data, buffer.size);
4021cb0ef41Sopenharmony_ci    if (rc == 0) break;
4031cb0ef41Sopenharmony_ci    buffer = MallocedBuffer<char>(buffer.size + kBufferGrowStep);
4041cb0ef41Sopenharmony_ci  } while (buffer.size < 1024 * 1024);
4051cb0ef41Sopenharmony_ci
4061cb0ef41Sopenharmony_ci  if (rc == 0) {
4071cb0ef41Sopenharmony_ci    char* buf = buffer.data;
4081cb0ef41Sopenharmony_ci    ld_info* cur_info = nullptr;
4091cb0ef41Sopenharmony_ci    do {
4101cb0ef41Sopenharmony_ci      std::ostringstream str;
4111cb0ef41Sopenharmony_ci      cur_info = reinterpret_cast<ld_info*>(buf);
4121cb0ef41Sopenharmony_ci      char* member_name = cur_info->ldinfo_filename +
4131cb0ef41Sopenharmony_ci          strlen(cur_info->ldinfo_filename) + 1;
4141cb0ef41Sopenharmony_ci      if (*member_name != '\0') {
4151cb0ef41Sopenharmony_ci        str << cur_info->ldinfo_filename << "(" << member_name << ")";
4161cb0ef41Sopenharmony_ci        list.emplace_back(str.str());
4171cb0ef41Sopenharmony_ci        str.str("");
4181cb0ef41Sopenharmony_ci      } else {
4191cb0ef41Sopenharmony_ci        list.emplace_back(cur_info->ldinfo_filename);
4201cb0ef41Sopenharmony_ci      }
4211cb0ef41Sopenharmony_ci      buf += cur_info->ldinfo_next;
4221cb0ef41Sopenharmony_ci    } while (cur_info->ldinfo_next != 0);
4231cb0ef41Sopenharmony_ci  }
4241cb0ef41Sopenharmony_ci#elif __sun
4251cb0ef41Sopenharmony_ci  Link_map* p;
4261cb0ef41Sopenharmony_ci
4271cb0ef41Sopenharmony_ci  if (dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &p) != -1) {
4281cb0ef41Sopenharmony_ci    for (Link_map* l = p; l != nullptr; l = l->l_next) {
4291cb0ef41Sopenharmony_ci      list.emplace_back(l->l_name);
4301cb0ef41Sopenharmony_ci    }
4311cb0ef41Sopenharmony_ci  }
4321cb0ef41Sopenharmony_ci
4331cb0ef41Sopenharmony_ci#elif _WIN32
4341cb0ef41Sopenharmony_ci  // Windows implementation - get a handle to the process.
4351cb0ef41Sopenharmony_ci  HANDLE process_handle = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,
4361cb0ef41Sopenharmony_ci                                      FALSE, GetCurrentProcessId());
4371cb0ef41Sopenharmony_ci  if (process_handle == nullptr) {
4381cb0ef41Sopenharmony_ci    // Cannot proceed, return an empty list.
4391cb0ef41Sopenharmony_ci    return list;
4401cb0ef41Sopenharmony_ci  }
4411cb0ef41Sopenharmony_ci  // Get a list of all the modules in this process
4421cb0ef41Sopenharmony_ci  DWORD size_1 = 0;
4431cb0ef41Sopenharmony_ci  DWORD size_2 = 0;
4441cb0ef41Sopenharmony_ci  // First call to get the size of module array needed
4451cb0ef41Sopenharmony_ci  if (EnumProcessModules(process_handle, nullptr, 0, &size_1)) {
4461cb0ef41Sopenharmony_ci    MallocedBuffer<HMODULE> modules(size_1);
4471cb0ef41Sopenharmony_ci
4481cb0ef41Sopenharmony_ci    // Second call to populate the module array
4491cb0ef41Sopenharmony_ci    if (EnumProcessModules(process_handle, modules.data, size_1, &size_2)) {
4501cb0ef41Sopenharmony_ci      for (DWORD i = 0;
4511cb0ef41Sopenharmony_ci           i < (size_1 / sizeof(HMODULE)) && i < (size_2 / sizeof(HMODULE));
4521cb0ef41Sopenharmony_ci           i++) {
4531cb0ef41Sopenharmony_ci        WCHAR module_name[MAX_PATH];
4541cb0ef41Sopenharmony_ci        // Obtain and report the full pathname for each module
4551cb0ef41Sopenharmony_ci        if (GetModuleFileNameExW(process_handle,
4561cb0ef41Sopenharmony_ci                                 modules.data[i],
4571cb0ef41Sopenharmony_ci                                 module_name,
4581cb0ef41Sopenharmony_ci                                 arraysize(module_name) / sizeof(WCHAR))) {
4591cb0ef41Sopenharmony_ci          DWORD size = WideCharToMultiByte(
4601cb0ef41Sopenharmony_ci              CP_UTF8, 0, module_name, -1, nullptr, 0, nullptr, nullptr);
4611cb0ef41Sopenharmony_ci          char* str = new char[size];
4621cb0ef41Sopenharmony_ci          WideCharToMultiByte(
4631cb0ef41Sopenharmony_ci              CP_UTF8, 0, module_name, -1, str, size, nullptr, nullptr);
4641cb0ef41Sopenharmony_ci          list.emplace_back(str);
4651cb0ef41Sopenharmony_ci        }
4661cb0ef41Sopenharmony_ci      }
4671cb0ef41Sopenharmony_ci    }
4681cb0ef41Sopenharmony_ci  }
4691cb0ef41Sopenharmony_ci
4701cb0ef41Sopenharmony_ci  // Release the handle to the process.
4711cb0ef41Sopenharmony_ci  CloseHandle(process_handle);
4721cb0ef41Sopenharmony_ci#endif
4731cb0ef41Sopenharmony_ci  return list;
4741cb0ef41Sopenharmony_ci}
4751cb0ef41Sopenharmony_ci
4761cb0ef41Sopenharmony_civoid FWrite(FILE* file, const std::string& str) {
4771cb0ef41Sopenharmony_ci  auto simple_fwrite = [&]() {
4781cb0ef41Sopenharmony_ci    // The return value is ignored because there's no good way to handle it.
4791cb0ef41Sopenharmony_ci    fwrite(str.data(), str.size(), 1, file);
4801cb0ef41Sopenharmony_ci  };
4811cb0ef41Sopenharmony_ci
4821cb0ef41Sopenharmony_ci  if (file != stderr && file != stdout) {
4831cb0ef41Sopenharmony_ci    simple_fwrite();
4841cb0ef41Sopenharmony_ci    return;
4851cb0ef41Sopenharmony_ci  }
4861cb0ef41Sopenharmony_ci#ifdef _WIN32
4871cb0ef41Sopenharmony_ci  HANDLE handle =
4881cb0ef41Sopenharmony_ci      GetStdHandle(file == stdout ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE);
4891cb0ef41Sopenharmony_ci
4901cb0ef41Sopenharmony_ci  // Check if stderr is something other than a tty/console
4911cb0ef41Sopenharmony_ci  if (handle == INVALID_HANDLE_VALUE || handle == nullptr ||
4921cb0ef41Sopenharmony_ci      uv_guess_handle(_fileno(file)) != UV_TTY) {
4931cb0ef41Sopenharmony_ci    simple_fwrite();
4941cb0ef41Sopenharmony_ci    return;
4951cb0ef41Sopenharmony_ci  }
4961cb0ef41Sopenharmony_ci
4971cb0ef41Sopenharmony_ci  // Get required wide buffer size
4981cb0ef41Sopenharmony_ci  int n = MultiByteToWideChar(CP_UTF8, 0, str.data(), str.size(), nullptr, 0);
4991cb0ef41Sopenharmony_ci
5001cb0ef41Sopenharmony_ci  std::vector<wchar_t> wbuf(n);
5011cb0ef41Sopenharmony_ci  MultiByteToWideChar(CP_UTF8, 0, str.data(), str.size(), wbuf.data(), n);
5021cb0ef41Sopenharmony_ci
5031cb0ef41Sopenharmony_ci  WriteConsoleW(handle, wbuf.data(), n, nullptr, nullptr);
5041cb0ef41Sopenharmony_ci  return;
5051cb0ef41Sopenharmony_ci#elif defined(__ANDROID__)
5061cb0ef41Sopenharmony_ci  if (file == stderr) {
5071cb0ef41Sopenharmony_ci    __android_log_print(ANDROID_LOG_ERROR, "nodejs", "%s", str.data());
5081cb0ef41Sopenharmony_ci    return;
5091cb0ef41Sopenharmony_ci  }
5101cb0ef41Sopenharmony_ci#endif
5111cb0ef41Sopenharmony_ci  simple_fwrite();
5121cb0ef41Sopenharmony_ci}
5131cb0ef41Sopenharmony_ci
5141cb0ef41Sopenharmony_ci}  // namespace node
5151cb0ef41Sopenharmony_ci
5161cb0ef41Sopenharmony_ciextern "C" void __DumpBacktrace(FILE* fp) {
5171cb0ef41Sopenharmony_ci  node::DumpBacktrace(fp);
5181cb0ef41Sopenharmony_ci}
519