diff --git a/contrib/epee/include/misc_os_dependent.h b/contrib/epee/include/misc_os_dependent.h index c06e5d94..2c11460d 100644 --- a/contrib/epee/include/misc_os_dependent.h +++ b/contrib/epee/include/misc_os_dependent.h @@ -114,26 +114,33 @@ namespace misc_utils #include #include #endif - inline std::string print_trace_default() + inline std::string print_trace_default() noexcept { - std::stringstream ss; + try + { + std::stringstream ss; #if defined(__GNUC__) && !defined(__ANDROID__) - ss << std::endl << "STACK" << std::endl; - const size_t max_depth = 100; - size_t stack_depth; - void *stack_addrs[max_depth]; - char **stack_strings; + ss << std::endl << "STACK" << std::endl; + const size_t max_depth = 100; + size_t stack_depth; + void *stack_addrs[max_depth]; + char **stack_strings; - stack_depth = backtrace(stack_addrs, max_depth); - stack_strings = backtrace_symbols(stack_addrs, stack_depth); + stack_depth = backtrace(stack_addrs, max_depth); + stack_strings = backtrace_symbols(stack_addrs, stack_depth); - for (size_t i = 1; i < stack_depth; i++) - { - ss << boost::core::demangle(stack_strings[i]) << std::endl; - } - free(stack_strings); // malloc()ed by backtrace_symbols + for (size_t i = 1; i < stack_depth; i++) + { + ss << boost::core::demangle(stack_strings[i]) << std::endl; + } + free(stack_strings); // malloc()ed by backtrace_symbols #endif - return ss.str(); + return ss.str(); + } + catch(...) + { + return std::string("(no callstack due to an exception)"); + } } typedef std::string (stack_retrieving_function_t)(); @@ -141,27 +148,35 @@ namespace misc_utils // // To get stack trace call it with the defaults. // - inline std::string get_callstack(stack_retrieving_function_t* p_stack_retrieving_function_to_be_added = nullptr, bool remove_func = false) + inline std::string get_callstack(stack_retrieving_function_t* p_stack_retrieving_function_to_be_added = nullptr, bool remove_func = false) noexcept { static stack_retrieving_function_t* p_srf = nullptr; - - if (remove_func) - { - p_srf = nullptr; - return ""; - } - - if (p_stack_retrieving_function_to_be_added != nullptr) - { - p_srf = p_stack_retrieving_function_to_be_added; - return ""; - } - if (p_srf != nullptr) - return p_srf(); + try + { + + if (remove_func) + { + p_srf = nullptr; + return ""; + } + + if (p_stack_retrieving_function_to_be_added != nullptr) + { + p_srf = p_stack_retrieving_function_to_be_added; + return ""; + } - return print_trace_default(); + if (p_srf != nullptr) + return p_srf(); + + return print_trace_default(); + } + catch(...) + { + return std::string("(no callstack due to an exception)"); + } } -} -} +} // namespace misc_utils +} // namespace epee diff --git a/src/common/callstack_helper.cpp b/src/common/callstack_helper.cpp index b84fe5a8..865817e0 100644 --- a/src/common/callstack_helper.cpp +++ b/src/common/callstack_helper.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Zano Project +// Copyright (c) 2019-2025 Zano Project // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -38,64 +38,84 @@ namespace public: get_mod_info(HANDLE h) : process(h) {} - module_data operator()(HMODULE module) + module_data operator()(HMODULE module) noexcept { - module_data ret; - char temp[buffer_length]; - MODULEINFO mi; + module_data ret{}; + try + { + char temp[buffer_length]; + MODULEINFO mi; - GetModuleInformation(process, module, &mi, sizeof(mi)); - ret.base_address = mi.lpBaseOfDll; - ret.load_size = mi.SizeOfImage; + GetModuleInformation(process, module, &mi, sizeof(mi)); + ret.base_address = mi.lpBaseOfDll; + ret.load_size = mi.SizeOfImage; - GetModuleFileNameEx(process, module, temp, sizeof(temp)); - ret.image_name = temp; - GetModuleBaseName(process, module, temp, sizeof(temp)); - ret.module_name = temp; - std::vector img(ret.image_name.begin(), ret.image_name.end()); - std::vector mod(ret.module_name.begin(), ret.module_name.end()); - SymLoadModule64(process, 0, &img[0], &mod[0], (DWORD64)ret.base_address, ret.load_size); + GetModuleFileNameEx(process, module, temp, sizeof(temp)); + ret.image_name = temp; + GetModuleBaseName(process, module, temp, sizeof(temp)); + ret.module_name = temp; + std::vector img(ret.image_name.begin(), ret.image_name.end()); + std::vector mod(ret.module_name.begin(), ret.module_name.end()); + SymLoadModule64(process, 0, &img[0], &mod[0], (DWORD64)ret.base_address, ret.load_size); + } + catch(std::exception& e) + { + ret = module_data{}; + ret.module_name = std::string("!!std::exception ") + e.what(); + } + catch(...) + { + ret = module_data{}; + ret.module_name = std::string("!!exception"); + } return ret; } }; - std::string get_symbol_undecorated_name(HANDLE process, DWORD64 address, std::stringstream& ss) + std::string get_symbol_undecorated_name(HANDLE process, DWORD64 address, std::stringstream& ss) noexcept { - SYMBOL_INFO* sym; - static const int max_name_len = 1024; - std::vector sym_buffer(sizeof(SYMBOL_INFO) + max_name_len, '\0'); - sym = (SYMBOL_INFO *)sym_buffer.data(); - sym->SizeOfStruct = sizeof(SYMBOL_INFO); - sym->MaxNameLen = max_name_len; + try + { + SYMBOL_INFO* sym; + static const int max_name_len = 1024; + std::vector sym_buffer(sizeof(SYMBOL_INFO) + max_name_len, '\0'); + sym = (SYMBOL_INFO *)sym_buffer.data(); + sym->SizeOfStruct = sizeof(SYMBOL_INFO); + sym->MaxNameLen = max_name_len; - DWORD64 displacement; - if (!SymFromAddr(process, address, &displacement, sym)) - return std::string("SymFromAddr failed1: ") + epee::string_tools::num_to_string_fast(GetLastError()); + DWORD64 displacement; + if (!SymFromAddr(process, address, &displacement, sym)) + return std::string("SymFromAddr failed1: ") + epee::string_tools::num_to_string_fast(GetLastError()); - if (*sym->Name == '\0') - return std::string("SymFromAddr failed2: ") + epee::string_tools::num_to_string_fast(GetLastError()); + if (*sym->Name == '\0') + return std::string("SymFromAddr failed2: ") + epee::string_tools::num_to_string_fast(GetLastError()); - /* - ss << " SizeOfStruct : " << sym->SizeOfStruct << ENDL; - ss << " TypeIndex : " << sym->TypeIndex << ENDL; // Type Index of symbol - ss << " Index : " << sym->Index << ENDL; - ss << " Size : " << sym->Size << ENDL; - ss << " ModBase : " << sym->ModBase << ENDL; // Base Address of module comtaining this symbol - ss << " Flags : " << sym->Flags << ENDL; - ss << " Value : " << sym->Value << ENDL; // Value of symbol, ValuePresent should be 1 - ss << " Address : " << sym->Address << ENDL; // Address of symbol including base address of module - ss << " Register : " << sym->Register << ENDL; // register holding value or pointer to value - ss << " Scope : " << sym->Scope << ENDL; // scope of the symbol - ss << " Tag : " << sym->Tag << ENDL; // pdb classification - ss << " NameLen : " << sym->NameLen << ENDL; // Actual length of name - ss << " MaxNameLen : " << sym->MaxNameLen << ENDL; - ss << " Name[1] : " << &sym->Name << ENDL; // Name of symbol - */ + /* + ss << " SizeOfStruct : " << sym->SizeOfStruct << ENDL; + ss << " TypeIndex : " << sym->TypeIndex << ENDL; // Type Index of symbol + ss << " Index : " << sym->Index << ENDL; + ss << " Size : " << sym->Size << ENDL; + ss << " ModBase : " << sym->ModBase << ENDL; // Base Address of module comtaining this symbol + ss << " Flags : " << sym->Flags << ENDL; + ss << " Value : " << sym->Value << ENDL; // Value of symbol, ValuePresent should be 1 + ss << " Address : " << sym->Address << ENDL; // Address of symbol including base address of module + ss << " Register : " << sym->Register << ENDL; // register holding value or pointer to value + ss << " Scope : " << sym->Scope << ENDL; // scope of the symbol + ss << " Tag : " << sym->Tag << ENDL; // pdb classification + ss << " NameLen : " << sym->NameLen << ENDL; // Actual length of name + ss << " MaxNameLen : " << sym->MaxNameLen << ENDL; + ss << " Name[1] : " << &sym->Name << ENDL; // Name of symbol + */ - std::string und_name(max_name_len, '\0'); - DWORD chars_written = UnDecorateSymbolName(sym->Name, &und_name.front(), max_name_len, UNDNAME_COMPLETE); - und_name.resize(chars_written); - return und_name; + std::string und_name(max_name_len, '\0'); + DWORD chars_written = UnDecorateSymbolName(sym->Name, &und_name.front(), max_name_len, UNDNAME_COMPLETE); + und_name.resize(chars_written); + return und_name; + } + catch(...) + { + return std::string("!!exception"); + } } } // namespace @@ -103,86 +123,93 @@ namespace namespace tools { - std::string get_callstack_win_x64() + std::string get_callstack_win_x64() noexcept { - // @TODO@ - // static epee::static_helpers::wrapper cs; - static std::recursive_mutex cs; - std::lock_guard lock(cs); - - HANDLE h_process = GetCurrentProcess(); - HANDLE h_thread = GetCurrentThread(); - - PCSTR user_search_path = NULL; // may be path to a pdb? - if (!SymInitialize(h_process, user_search_path, false)) - return ""; - - DWORD sym_options = SymGetOptions(); - sym_options |= SYMOPT_LOAD_LINES | SYMOPT_UNDNAME; - SymSetOptions(sym_options); - - DWORD cb_needed; - std::vector module_handles(1); - EnumProcessModules(h_process, &module_handles[0], static_cast(module_handles.size() * sizeof(HMODULE)), &cb_needed); - module_handles.resize(cb_needed / sizeof(HMODULE)); - EnumProcessModules(h_process, &module_handles[0], static_cast(module_handles.size() * sizeof(HMODULE)), &cb_needed); - - std::vector modules; - std::transform(module_handles.begin(), module_handles.end(), std::back_inserter(modules), get_mod_info(h_process)); - void *base = modules[0].base_address; - - CONTEXT context; - memset(&context, 0, sizeof context); - RtlCaptureContext( &context ); - - STACKFRAME64 frame; - memset(&frame, 0, sizeof frame); -#ifndef _M_ARM64 - frame.AddrPC.Offset = context.Rip; -#endif - frame.AddrPC.Mode = AddrModeFlat; -#ifndef _M_ARM64 - frame.AddrStack.Offset = context.Rsp; -#endif - frame.AddrStack.Mode = AddrModeFlat; -#ifndef _M_ARM64 - frame.AddrFrame.Offset = context.Rbp; -#endif - frame.AddrFrame.Mode = AddrModeFlat; - - IMAGEHLP_LINE64 line = { 0 }; - line.SizeOfStruct = sizeof line; - IMAGE_NT_HEADERS *image_nt_header = ImageNtHeader(base); - - std::stringstream ss; - ss << ENDL; - // ss << "main module loaded at 0x" << std::hex << std::setw(16) << std::setfill('0') << base << std::dec << " from " << modules[0].image_name << ENDL; - for (size_t n = 0; n < 250; ++n) + try { - if (!StackWalk64(image_nt_header->FileHeader.Machine, h_process, h_thread, &frame, &context, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) - break; - if (frame.AddrReturn.Offset == 0) - break; + // @TODO@ + // static epee::static_helpers::wrapper cs; + static std::recursive_mutex cs; + std::lock_guard lock(cs); - std::string fnName = get_symbol_undecorated_name(h_process, frame.AddrPC.Offset, ss); - ss << "0x" << std::setw(16) << std::setfill('0') << std::hex << frame.AddrPC.Offset << " " << std::dec << fnName; - DWORD offset_from_line = 0; - if (SymGetLineFromAddr64(h_process, frame.AddrPC.Offset, &offset_from_line, &line)) - ss << "+" << offset_from_line << " " << line.FileName << "(" << line.LineNumber << ")"; + HANDLE h_process = GetCurrentProcess(); + HANDLE h_thread = GetCurrentThread(); - for (auto el : modules) + PCSTR user_search_path = NULL; // may be path to a pdb? + if (!SymInitialize(h_process, user_search_path, false)) + return ""; + + DWORD sym_options = SymGetOptions(); + sym_options |= SYMOPT_LOAD_LINES | SYMOPT_UNDNAME; + SymSetOptions(sym_options); + + DWORD cb_needed; + std::vector module_handles(1); + EnumProcessModules(h_process, &module_handles[0], static_cast(module_handles.size() * sizeof(HMODULE)), &cb_needed); + module_handles.resize(cb_needed / sizeof(HMODULE)); + EnumProcessModules(h_process, &module_handles[0], static_cast(module_handles.size() * sizeof(HMODULE)), &cb_needed); + + std::vector modules; + std::transform(module_handles.begin(), module_handles.end(), std::back_inserter(modules), get_mod_info(h_process)); + void *base = modules[0].base_address; + + CONTEXT context; + memset(&context, 0, sizeof context); + RtlCaptureContext( &context ); + + STACKFRAME64 frame; + memset(&frame, 0, sizeof frame); +#ifndef _M_ARM64 + frame.AddrPC.Offset = context.Rip; +#endif + frame.AddrPC.Mode = AddrModeFlat; +#ifndef _M_ARM64 + frame.AddrStack.Offset = context.Rsp; +#endif + frame.AddrStack.Mode = AddrModeFlat; +#ifndef _M_ARM64 + frame.AddrFrame.Offset = context.Rbp; +#endif + frame.AddrFrame.Mode = AddrModeFlat; + + IMAGEHLP_LINE64 line = { 0 }; + line.SizeOfStruct = sizeof line; + IMAGE_NT_HEADERS *image_nt_header = ImageNtHeader(base); + + std::stringstream ss; + ss << ENDL; + // ss << "main module loaded at 0x" << std::hex << std::setw(16) << std::setfill('0') << base << std::dec << " from " << modules[0].image_name << ENDL; + for (size_t n = 0; n < 250; ++n) { - if ((DWORD64)el.base_address <= frame.AddrPC.Offset && frame.AddrPC.Offset < (DWORD64)el.base_address + (DWORD64)el.load_size) - { - ss << " : " << el.module_name << " @ 0x" << std::setw(0) << std::hex << (DWORD64)el.base_address << ENDL; + if (!StackWalk64(image_nt_header->FileHeader.Machine, h_process, h_thread, &frame, &context, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) break; + if (frame.AddrReturn.Offset == 0) + break; + + std::string fnName = get_symbol_undecorated_name(h_process, frame.AddrPC.Offset, ss); + ss << "0x" << std::setw(16) << std::setfill('0') << std::hex << frame.AddrPC.Offset << " " << std::dec << fnName; + DWORD offset_from_line = 0; + if (SymGetLineFromAddr64(h_process, frame.AddrPC.Offset, &offset_from_line, &line)) + ss << "+" << offset_from_line << " " << line.FileName << "(" << line.LineNumber << ")"; + + for (auto el : modules) + { + if ((DWORD64)el.base_address <= frame.AddrPC.Offset && frame.AddrPC.Offset < (DWORD64)el.base_address + (DWORD64)el.load_size) + { + ss << " : " << el.module_name << " @ 0x" << std::setw(0) << std::hex << (DWORD64)el.base_address << ENDL; + break; + } } + } + SymCleanup(h_process); + return ss.str(); + } + catch(...) + { + return std::string("(no callstack due to an exception)"); } - SymCleanup(h_process); - - return ss.str(); } } // namespace tools diff --git a/src/common/callstack_helper.h b/src/common/callstack_helper.h index 3853d148..439ddcd8 100644 --- a/src/common/callstack_helper.h +++ b/src/common/callstack_helper.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Zano Project +// Copyright (c) 2019-2025 Zano Project // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #pragma once @@ -7,10 +7,10 @@ namespace tools { #if defined(WIN32) - extern std::string get_callstack_win_x64(); + extern std::string get_callstack_win_x64() noexcept; #endif - inline std::string get_callstack() + inline std::string get_callstack() noexcept { #if defined(__GNUC__) return epee::misc_utils::print_trace_default();