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;
99 DebugSourceInfo getInfo(unw_word_t func_address)
101 std::scoped_lock<std::mutex> lock(m_mutex);
102 DebugSourceInfo source_info;
106 auto dw_address =
reinterpret_cast<Dwarf_Addr
>(func_address);
108 Dwfl_Module* module = dwfl_addrmodule(m_session, dw_address);
112 Dwarf_Die* dw_die = dwfl_module_addrdie(module, dw_address, &bias);
116 Dwarf_Line* dw_source_info = dwarf_getsrc_die(dw_die, dw_address - bias);
118 if (dw_source_info) {
122 const char* source_file = dwarf_linesrc(dw_source_info,
nullptr,
nullptr);
123 dwarf_lineno(dw_source_info, &line);
124 dwarf_linecol(dw_source_info, &column);
125 source_info = { line, column, source_file };
133 bool m_is_init =
false;
134 Dwfl_Callbacks m_callback;
135 Dwfl* m_session =
nullptr;
146 m_session = dwfl_begin(&m_callback);
151 dwfl_report_begin(m_session);
152 dwfl_linux_proc_report(m_session, getpid());
153 dwfl_report_end(m_session,
nullptr,
nullptr);
178class LibUnwindStackTraceService
189 ProcInfo() =
default;
190 explicit ProcInfo(
const String& aname)
210 unw_word_t m_base_ip = 0;
227 void build()
override
230 m_want_gdb_info =
true;
232 m_use_backtrace =
true;
238 StackTrace
stackTrace(
int first_function)
override;
243 using ProcInfoMap = std::map<unw_word_t, ProcInfo>;
244 ProcInfoMap m_proc_name_map;
245 std::mutex m_proc_name_map_mutex;
247 bool m_want_gdb_info =
false;
248 bool m_use_backtrace =
false;
249 DWHandler m_dw_handler;
250 ProcInfo _getFuncInfo(unw_word_t ip, unw_cursor_t* cursor);
251 ProcInfo _getFuncInfo(
const void* ip);
252 String _getGDBStack();
262_getFuncInfo(unw_word_t ip, unw_cursor_t* cursor)
265 std::lock_guard<std::mutex> lk(m_proc_name_map_mutex);
266 auto v = m_proc_name_map.find(ip);
267 if (v != m_proc_name_map.end())
272 char func_name_buf[10000];
273 char demangled_func_name_buf[10000];
274 unw_get_proc_name(cursor, func_name_buf, 10000, &offset);
277 char* buf = abi::__cxa_demangle(func_name_buf, demangled_func_name_buf, &len, &dstatus);
279 pi.m_base_ip = offset;
282 void* addr = (
void*)ip;
283 int r2 = dladdr(addr, &dl_info);
285 const char* dli_fname = dl_info.dli_fname;
287 void* dli_fbase = dl_info.dli_fbase;
288 pi.m_library_file_name = dli_fname;
289 pi.m_file_loaded_address = (unw_word_t)dli_fbase;
294 pi.m_name = std::string_view(buf);
296 pi.m_name = std::string_view(func_name_buf);
300 pi.m_source_info = m_dw_handler.getInfo(ip - 1);
303 std::lock_guard<std::mutex> lk(m_proc_name_map_mutex);
304 m_proc_name_map.insert(ProcInfoMap::value_type(ip, pi));
318_getFuncInfo(
const void* addr)
321 std::lock_guard<std::mutex> lk(m_proc_name_map_mutex);
322 auto v = m_proc_name_map.find((unw_word_t)addr);
323 if (v != m_proc_name_map.end()) {
327 const size_t buf_size = 10000;
328 char demangled_func_name_buf[buf_size];
330 int r = dladdr(addr, &dl_info);
333 std::cout <<
"ERROR in dladdr\n";
336 const char* dli_sname = dl_info.dli_sname;
340 size_t len = buf_size;
341 char* buf = abi::__cxa_demangle(dli_sname, demangled_func_name_buf, &len, &dstatus);
345 pi.
m_name = std::string_view(buf);
347 pi.
m_name = std::string_view(dli_sname);
349 std::lock_guard<std::mutex> lk(m_proc_name_map_mutex);
350 m_proc_name_map.insert(ProcInfoMap::value_type((unw_word_t)addr, pi));
358String LibUnwindStackTraceService::
365 fprintf(stderr,
"\nNative stacktrace:\n\n");
367 size = backtrace(array, 256);
368 names = backtrace_symbols(array, size);
369 for (i = 0; i < size; ++i) {
370 fprintf(stderr,
"\t%s\n", names[i]);
389 last_str = _getGDBStack();
394 const size_t hexa_buf_size = 100;
395 char hexa[hexa_buf_size + 1];
398 unw_init_local(&cursor, &uc);
399 int current_func = 0;
403 while (unw_step(&cursor) > 0) {
405 unw_get_reg(&cursor, UNW_REG_IP, &ip);
406 if (current_func >= first_function) {
407 ProcInfo pi = _getFuncInfo(ip, &cursor);
410 snprintf(hexa, hexa_buf_size,
"%14llx", (
long long)ip);
413 message += func_name;
414 if (pi.m_source_info.m_source_file) {
416 message += pi.m_source_info.m_source_file;
417 if (pi.m_source_info.m_line > 0) {
419 message += pi.m_source_info.m_line;
436 last_str = ss->
stackTrace(backtrace_stack_frames.view());
439 message +=
"\nFileAndOffsetStack:{{\n";
465 last_str = _getGDBStack();
468 unw_init_local(&cursor, &uc);
469 int current_func = 0;
472 while (unw_step(&cursor) > 0) {
473 unw_get_reg(&cursor, UNW_REG_IP, &ip);
474 if (current_func == function_index) {
475 ProcInfo pi = _getFuncInfo(ip, &cursor);
477 message += func_name;
493 Integer size = backtrace(ips, 256);
496 for (
Integer i = first_function; i < size; ++i) {
509 const size_t buf_size = 100;
510 char hexa[buf_size + 1];
515 intptr_t ip = f.address();
519 snprintf(hexa, buf_size,
"%10llx", (
long long)ip);
522 message += func_name;
544 const size_t buf_size = 100;
545 char hexa[buf_size + 1];
550 intptr_t ip = f.address();
551 ProcInfo pinfo = _getFuncInfo(
reinterpret_cast<const void*
>(ip));
552 message += (
pinfo.libraryFileName() ?
pinfo.libraryFileName() :
"()");
554 auto file_base_address =
pinfo.m_file_loaded_address;
559 if (file_base_address == 0x400000)
560 file_base_address = 0;
561 intptr_t offset_ip = (ip - file_base_address);
562 snprintf(hexa, buf_size,
"%llx", (
long long)offset_ip);
576class LLVMSymbolizerService
587 explicit LLVMSymbolizerService(
ITraceMng* tm)
603 String m_llvm_symbolizer_path;
604 bool m_is_check_done =
false;
605 bool m_is_valid =
false;
617 String fullpath = dir.
file(
"llvm-symbolizer");
619 m_llvm_symbolizer_path = fullpath;
622 m_is_check_done =
true;
639 std::stringstream ostr;
643 for (
Integer i = 0, n = frames.
size(); i < n; ++i) {
645 intptr_t addr = frames[i].address();
646 int r2 = dladdr((
void*)addr, &dl_info);
647 const char* dli_fname =
nullptr;
648 intptr_t base_address = 0;
650 dli_fname = dl_info.dli_fname;
652 void* dli_fbase = dl_info.dli_fbase;
653 intptr_t true_base =
reinterpret_cast<intptr_t
>(dli_fbase);
658 if (true_base == 0x400000)
660 base_address = addr - true_base;
663 ostr << (dli_fname ? dli_fname :
"??") <<
" " << base_address <<
'\n';
666 std::string input_str(ostr.str());
669 args.setCommand(m_llvm_symbolizer_path);
672 args.setInputBytes(input_bytes);
673 args.addArguments(
"--demangle");
674 args.addArguments(
"--pretty-print");
692 DependencyInjection::ProviderProperty(
"LibUnwind"),
697 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.