14#include "arcane/utils/PlatformUtils.h"
15#include "arcane/utils/IStackTraceService.h"
16#include "arcane/utils/StackTrace.h"
17#include "arcane/utils/StringBuilder.h"
18#include "arcane/utils/Array.h"
19#include "arcane/utils/ISymbolizerService.h"
21#include "arccore/base/internal/DependencyInjection.h"
22#include "arccore/common/internal/Process.h"
24#include "arcane/core/ServiceBuilder.h"
25#include "arcane/core/Directory.h"
28#include "arcane/core/AbstractService.h"
30#include "arcane_packages.h"
46#if defined(ARCANE_HAS_PACKAGE_DW)
47#include <elfutils/libdwfl.h>
60 const char* m_source_file =
nullptr;
63#if defined(ARCANE_HAS_PACKAGE_DW)
82 m_callback.find_elf = &dwfl_linux_proc_find_elf;
83 m_callback.find_debuginfo = &dwfl_standard_find_debuginfo;
84 m_callback.section_address =
nullptr;
85 m_callback.debuginfo_path =
nullptr;
88 setenv(
"DEBUGINFOD_URLS",
"", 1);
102 DebugSourceInfo getInfo(unw_word_t func_address)
104 DebugSourceInfo source_info;
109 ScopedTryLock tried_lock(m_mutex);
110 if (!tried_lock.isLock())
115 auto dw_address =
reinterpret_cast<Dwarf_Addr
>(func_address);
117 Dwfl_Module* module = dwfl_addrmodule(m_session, dw_address);
121 Dwarf_Die* dw_die = dwfl_module_addrdie(module, dw_address, &bias);
125 Dwarf_Line* dw_source_info = dwarf_getsrc_die(dw_die, dw_address - bias);
127 if (dw_source_info) {
131 const char* source_file = dwarf_linesrc(dw_source_info,
nullptr,
nullptr);
132 dwarf_lineno(dw_source_info, &line);
133 dwarf_linecol(dw_source_info, &column);
134 source_info = { line, column, source_file };
142 bool m_is_init =
false;
143 Dwfl_Callbacks m_callback;
144 Dwfl* m_session =
nullptr;
154 ScopedTryLock(std::mutex& mutex)
157 m_is_lock = m_mutex.try_lock();
165 constexpr bool isLock()
const {
return m_is_lock; }
170 bool m_is_lock =
false;
179 m_session = dwfl_begin(&m_callback);
184 dwfl_report_begin(m_session);
185 dwfl_linux_proc_report(m_session, getpid());
186 dwfl_report_end(m_session,
nullptr,
nullptr);
211class LibUnwindStackTraceService
222 ProcInfo() =
default;
223 explicit ProcInfo(
const String& aname)
243 unw_word_t m_base_ip = 0;
260 void build()
override
263 m_want_gdb_info =
true;
265 m_use_backtrace =
true;
271 StackTrace
stackTrace(
int first_function)
override;
276 using ProcInfoMap = std::map<unw_word_t, ProcInfo>;
277 ProcInfoMap m_proc_name_map;
278 std::mutex m_proc_name_map_mutex;
280 bool m_want_gdb_info =
false;
281 bool m_use_backtrace =
false;
282 DWHandler m_dw_handler;
283 ProcInfo _getFuncInfo(unw_word_t ip, unw_cursor_t* cursor);
284 ProcInfo _getFuncInfo(
const void* ip);
285 String _getGDBStack();
295_getFuncInfo(unw_word_t ip, unw_cursor_t* cursor)
298 std::lock_guard<std::mutex> lk(m_proc_name_map_mutex);
299 auto v = m_proc_name_map.find(ip);
300 if (v != m_proc_name_map.end())
305 char func_name_buf[10000];
306 char demangled_func_name_buf[10000];
307 unw_get_proc_name(cursor, func_name_buf, 10000, &offset);
310 char* buf = abi::__cxa_demangle(func_name_buf, demangled_func_name_buf, &len, &dstatus);
312 pi.m_base_ip = offset;
315 void* addr = (
void*)ip;
316 int r2 = dladdr(addr, &dl_info);
318 const char* dli_fname = dl_info.dli_fname;
320 void* dli_fbase = dl_info.dli_fbase;
321 pi.m_library_file_name = dli_fname;
322 pi.m_file_loaded_address = (unw_word_t)dli_fbase;
327 pi.m_name = std::string_view(buf);
329 pi.m_name = std::string_view(func_name_buf);
333 pi.m_source_info = m_dw_handler.getInfo(ip - 1);
336 std::lock_guard<std::mutex> lk(m_proc_name_map_mutex);
337 m_proc_name_map.insert(ProcInfoMap::value_type(ip, pi));
351_getFuncInfo(
const void* addr)
354 std::lock_guard<std::mutex> lk(m_proc_name_map_mutex);
355 auto v = m_proc_name_map.find((unw_word_t)addr);
356 if (v != m_proc_name_map.end()) {
360 const size_t buf_size = 10000;
361 char demangled_func_name_buf[buf_size];
363 int r = dladdr(addr, &dl_info);
366 std::cout <<
"ERROR in dladdr\n";
369 const char* dli_sname = dl_info.dli_sname;
373 size_t len = buf_size;
374 char* buf = abi::__cxa_demangle(dli_sname, demangled_func_name_buf, &len, &dstatus);
378 pi.
m_name = std::string_view(buf);
380 pi.
m_name = std::string_view(dli_sname);
382 std::lock_guard<std::mutex> lk(m_proc_name_map_mutex);
383 m_proc_name_map.insert(ProcInfoMap::value_type((unw_word_t)addr, pi));
391String LibUnwindStackTraceService::
398 fprintf(stderr,
"\nNative stacktrace:\n\n");
400 size = backtrace(array, 256);
401 names = backtrace_symbols(array, size);
402 for (i = 0; i < size; ++i) {
403 fprintf(stderr,
"\t%s\n", names[i]);
422 last_str = _getGDBStack();
427 const size_t hexa_buf_size = 100;
428 char hexa[hexa_buf_size + 1];
431 unw_init_local(&cursor, &uc);
432 int current_func = 0;
436 while (unw_step(&cursor) > 0) {
438 unw_get_reg(&cursor, UNW_REG_IP, &ip);
439 if (current_func >= first_function) {
440 ProcInfo pi = _getFuncInfo(ip, &cursor);
443 snprintf(hexa, hexa_buf_size,
"%14llx", (
long long)ip);
446 message += func_name;
447 if (pi.m_source_info.m_source_file) {
449 message += pi.m_source_info.m_source_file;
450 if (pi.m_source_info.m_line > 0) {
452 message += pi.m_source_info.m_line;
469 last_str = ss->
stackTrace(backtrace_stack_frames.view());
472 message +=
"\nFileAndOffsetStack:{{\n";
498 last_str = _getGDBStack();
501 unw_init_local(&cursor, &uc);
502 int current_func = 0;
505 while (unw_step(&cursor) > 0) {
506 unw_get_reg(&cursor, UNW_REG_IP, &ip);
507 if (current_func == function_index) {
508 ProcInfo pi = _getFuncInfo(ip, &cursor);
510 message += func_name;
526 Integer size = backtrace(ips, 256);
529 for (
Integer i = first_function; i < size; ++i) {
542 const size_t buf_size = 100;
543 char hexa[buf_size + 1];
548 intptr_t ip = f.address();
552 snprintf(hexa, buf_size,
"%10llx", (
long long)ip);
555 message += func_name;
577 const size_t buf_size = 100;
578 char hexa[buf_size + 1];
583 intptr_t ip = f.address();
584 ProcInfo pinfo = _getFuncInfo(
reinterpret_cast<const void*
>(ip));
585 message += (
pinfo.libraryFileName() ?
pinfo.libraryFileName() :
"()");
587 auto file_base_address =
pinfo.m_file_loaded_address;
592 if (file_base_address == 0x400000)
593 file_base_address = 0;
594 intptr_t offset_ip = (ip - file_base_address);
595 snprintf(hexa, buf_size,
"%llx", (
long long)offset_ip);
609class LLVMSymbolizerService
620 explicit LLVMSymbolizerService(
ITraceMng* tm)
636 String m_llvm_symbolizer_path;
637 bool m_is_check_done =
false;
638 bool m_is_valid =
false;
650 String fullpath = dir.
file(
"llvm-symbolizer");
652 m_llvm_symbolizer_path = fullpath;
655 m_is_check_done =
true;
672 std::stringstream ostr;
676 for (
Integer i = 0, n = frames.
size(); i < n; ++i) {
678 intptr_t addr = frames[i].address();
679 int r2 = dladdr((
void*)addr, &dl_info);
680 const char* dli_fname =
nullptr;
681 intptr_t base_address = 0;
683 dli_fname = dl_info.dli_fname;
685 void* dli_fbase = dl_info.dli_fbase;
686 intptr_t true_base =
reinterpret_cast<intptr_t
>(dli_fbase);
691 if (true_base == 0x400000)
693 base_address = addr - true_base;
696 ostr << (dli_fname ? dli_fname :
"??") <<
" " << base_address <<
'\n';
699 std::string input_str(ostr.str());
702 args.setCommand(m_llvm_symbolizer_path);
705 args.setInputBytes(input_bytes);
706 args.addArguments(
"--demangle");
707 args.addArguments(
"--pretty-print");
725 DependencyInjection::ProviderProperty(
"LibUnwind"),
730 DependencyInjection::ProviderProperty(
"LLVMSymbolizer"),
This file contains the various service factories and macros for registering services.
#define ARCANE_SERVICE_INTERFACE(ainterface)
Macro to declare an interface when registering a service.
Constant view of an array of type T.
constexpr Integer size() const noexcept
Number of elements in the array.
Class managing a directory.
String file(const String &file_name) const override
Returns the full path of the file file_name in the directory.
Stores a fixed maximum size list of StackFrame.
void addFrame(const StackFrame &frame)
Adds a frame to the list of frames. If nbFrame() is greater than or equal to MAX_FRAME,...
virtual ITraceMng * traceMng() const =0
Trace manager.
Interface of a function call tracing service.
Interface of a source code symbol retrieval service.
virtual String stackTrace(ConstArrayView< StackFrame > frames)=0
Information for the call stack frames.
String stackTrace(ConstArrayView< StackFrame > frames) override
Information for the call stack frames.
void _checkValid()
Checks that the specified path is valid.
Function call trace service using libunwind.
StackTrace _backtraceStackTrace(const FixedStackFrameArray &stack_frames)
Call stack via the backtrace function.
FixedStackFrameArray _backtraceStackFrame(int first_function)
Call stack via the backtrace function.
String _generateFileAndOffset(const FixedStackFrameArray &stack_frames)
Generates a list of file names and offsets for a call stack.
StackTrace stackTrace(int first_function) override
Character string indicating the call stack.
StackTrace stackTraceFunction(int function_index) override
Returns the current call stack.
ConstArrayView< Byte > outputBytes() const
Contains the result of the process's standard output (STDOUT).
static ProcessExecArgs::ExecStatus execute(ProcessExecArgs &args)
Executes a process whose information is contained in args.
IApplication * application() const
Access to the associated IApplication.
Structure containing the information to create a service.
Service creation properties.
Stores the addresses corresponding to a call stack. This class is internal and should not be used out...
Information about function call stacks.
Unicode character string constructor.
String toString() const
Returns the constructed character string.
Unicode character string.
TraceAccessor(ITraceMng *m)
Constructs an accessor via the trace manager m.
TraceMessage pinfo() const
Flow for a parallel information message.
ITraceMng * traceMng() const
Trace manager.
#define ARCANE_REGISTER_SERVICE(aclass, a_service_property,...)
Macro for registering a service.
Integer len(const char *s)
Returns the length of the string s.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Integer arcaneCheckArraySize(unsigned long long size)
Checks that size can be converted into an 'Integer' to serve as the size of an array....
std::int64_t Int64
Signed integer type of 64 bits.
Int32 Integer
Type representing an integer.
@ ST_Application
The service is used at the application level.
ConstArrayView< Byte > ByteConstArrayView
C equivalent of a 1D array of characters.
unsigned char Byte
Type of a byte.
Information about a memory address.
const char * m_library_file_name
Name of the library (.so or .exe) where the method is located.
unw_word_t m_file_loaded_address
Library load address.
String m_name
Demangled procedure name.
const char * libraryFileName() const
Name of the library containing the function. May be null.
const String & name() const
Function name.