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);
210class LibUnwindStackTraceService
221 ProcInfo() =
default;
222 explicit ProcInfo(
const String& aname)
242 unw_word_t m_base_ip = 0;
259 void build()
override
262 m_want_gdb_info =
true;
264 m_use_backtrace =
true;
270 StackTrace
stackTrace(
int first_function)
override;
275 using ProcInfoMap = std::map<unw_word_t,ProcInfo>;
276 ProcInfoMap m_proc_name_map;
277 std::mutex m_proc_name_map_mutex;
279 bool m_want_gdb_info =
false;
280 bool m_use_backtrace =
false;
281 DWHandler m_dw_handler;
282 ProcInfo _getFuncInfo(unw_word_t ip,unw_cursor_t* cursor);
283 ProcInfo _getFuncInfo(
const void* ip);
284 String _getGDBStack();
294_getFuncInfo(unw_word_t ip,unw_cursor_t* cursor)
297 std::lock_guard<std::mutex> lk(m_proc_name_map_mutex);
298 auto v = m_proc_name_map.find(ip);
299 if (v!=m_proc_name_map.end())
304 char func_name_buf[10000];
305 char demangled_func_name_buf[10000];
306 unw_get_proc_name(cursor,func_name_buf,10000,&offset);
309 char* buf = abi::__cxa_demangle (func_name_buf,demangled_func_name_buf,&len,&dstatus);
311 pi.m_base_ip = offset;
314 void* addr = (
void*)ip;
315 int r2 = dladdr(addr,&dl_info);
317 const char* dli_fname = dl_info.dli_fname;
319 void* dli_fbase = dl_info.dli_fbase;
320 pi.m_library_file_name = dli_fname;
321 pi.m_file_loaded_address = (unw_word_t)dli_fbase;
326 pi.m_name = std::string_view(buf);
328 pi.m_name = std::string_view(func_name_buf);
332 pi.m_source_info = m_dw_handler.getInfo(ip - 1);
335 std::lock_guard<std::mutex> lk(m_proc_name_map_mutex);
336 m_proc_name_map.insert(ProcInfoMap::value_type(ip, pi));
349_getFuncInfo(
const void* addr)
352 std::lock_guard<std::mutex> lk(m_proc_name_map_mutex);
353 auto v = m_proc_name_map.find((unw_word_t)addr);
354 if (v!=m_proc_name_map.end()){
358 const size_t buf_size = 10000;
359 char demangled_func_name_buf[buf_size];
361 int r = dladdr(addr, &dl_info);
364 std::cout <<
"ERROR in dladdr\n";
367 const char* dli_sname = dl_info.dli_sname;
371 size_t len = buf_size;
372 char* buf = abi::__cxa_demangle (dli_sname,demangled_func_name_buf,&len,&dstatus);
376 pi.
m_name = std::string_view(buf);
378 pi.
m_name = std::string_view(dli_sname);
380 std::lock_guard<std::mutex> lk(m_proc_name_map_mutex);
381 m_proc_name_map.insert(ProcInfoMap::value_type((unw_word_t)addr,pi));
389String LibUnwindStackTraceService::
396 fprintf (stderr,
"\nNative stacktrace:\n\n");
398 size = backtrace (array, 256);
399 names = backtrace_symbols (array, size);
400 for (i =0; i < size; ++i) {
401 fprintf (stderr,
"\t%s\n", names [i]);
420 last_str = _getGDBStack();
425 const size_t hexa_buf_size = 100;
426 char hexa[hexa_buf_size+1];
429 unw_init_local(&cursor, &uc);
430 int current_func = 0;
434 while (unw_step(&cursor) > 0) {
436 unw_get_reg(&cursor, UNW_REG_IP, &ip);
437 if (current_func>=first_function){
438 ProcInfo pi = _getFuncInfo(ip,&cursor);
441 snprintf(hexa,hexa_buf_size,
"%14llx",(
long long)ip);
444 message += func_name;
445 if (pi.m_source_info.m_source_file) {
447 message += pi.m_source_info.m_source_file;
448 if (pi.m_source_info.m_line > 0) {
450 message += pi.m_source_info.m_line;
467 last_str = ss->
stackTrace(backtrace_stack_frames.view());
470 message +=
"\nFileAndOffsetStack:{{\n";
495 last_str = _getGDBStack();
498 unw_init_local(&cursor, &uc);
499 int current_func = 0;
502 while (unw_step(&cursor) > 0) {
503 unw_get_reg(&cursor, UNW_REG_IP, &ip);
504 if (current_func==function_index){
505 ProcInfo pi = _getFuncInfo(ip,&cursor);
507 message += func_name;
523 Integer size = backtrace (ips, 256);
526 for(
Integer i=first_function; i<size; ++i ){
539 const size_t buf_size = 100;
540 char hexa[buf_size+1];
545 intptr_t ip = f.address();
549 snprintf(hexa,buf_size,
"%10llx",(
long long)ip);
552 message += func_name;
573 const size_t buf_size = 100;
574 char hexa[buf_size+1];
579 intptr_t ip = f.address();
580 ProcInfo pinfo = _getFuncInfo(
reinterpret_cast<const void*
>(ip));
581 message += (
pinfo.libraryFileName() ?
pinfo.libraryFileName() :
"()");
583 auto file_base_address =
pinfo.m_file_loaded_address;
588 if (file_base_address==0x400000)
589 file_base_address = 0;
590 intptr_t offset_ip = (ip - file_base_address);
591 snprintf(hexa,buf_size,
"%llx",(
long long)offset_ip);
605class LLVMSymbolizerService
616 explicit LLVMSymbolizerService(
ITraceMng* tm)
632 String m_llvm_symbolizer_path;
633 bool m_is_check_done =
false;
634 bool m_is_valid =
false;
646 String fullpath = dir.
file(
"llvm-symbolizer");
648 m_llvm_symbolizer_path = fullpath;
651 m_is_check_done =
true;
668 std::stringstream ostr;
674 intptr_t addr = frames[i].address();
675 int r2 = dladdr((
void*)addr,&dl_info);
676 const char* dli_fname =
nullptr;
677 intptr_t base_address = 0;
679 dli_fname = dl_info.dli_fname;
681 void* dli_fbase = dl_info.dli_fbase;
682 intptr_t true_base =
reinterpret_cast<intptr_t
>(dli_fbase);
687 if (true_base==0x400000)
689 base_address = addr - true_base;
692 ostr << (dli_fname ? dli_fname :
"??") <<
" " << base_address <<
'\n';
695 std::string input_str(ostr.str());
698 args.setCommand(m_llvm_symbolizer_path);
701 args.setInputBytes(input_bytes);
702 args.addArguments(
"--demangle");
703 args.addArguments(
"--pretty-print");
721 DependencyInjection::ProviderProperty(
"LibUnwind"),
726 DependencyInjection::ProviderProperty(
"LLVMSymbolizer"),
Ce fichier contient les différentes fabriques de services et macro pour enregistrer les services.
#define ARCANE_SERVICE_INTERFACE(ainterface)
Macro pour déclarer une interface lors de l'enregistrement d'un service.
Vue constante d'un tableau de type T.
constexpr Integer size() const noexcept
Nombre d'éléments du tableau.
Classe gérant un répertoire.
String file(const String &file_name) const override
Retourne le chemin complet du fichier file_name dans le répertoire.
Conserve une liste de taille fixe maximale de StackFrame.
void addFrame(const StackFrame &frame)
Ajoute frame à la liste des frames. Si nbFrame() est supérieur ou égal à MAX_FRAME,...
virtual ITraceMng * traceMng() const =0
Gestionnaire de traces.
Interface d'un service de trace des appels de fonctions.
Interface d'un service de récupération des symboles du code source.
virtual String stackTrace(ConstArrayView< StackFrame > frames)=0
Informations pour la pile d'appel frames.
Interface du gestionnaire de traces.
String stackTrace(ConstArrayView< StackFrame > frames) override
Informations pour la pile d'appel frames.
void _checkValid()
Vérifie que le chemin spécifié est valid.
Service de trace des appels de fonctions utilisant la libunwind.
StackTrace _backtraceStackTrace(const FixedStackFrameArray &stack_frames)
Pile d'appel via la fonction backtrace.
FixedStackFrameArray _backtraceStackFrame(int first_function)
Pile d'appel via la fonction backtrace.
String _generateFileAndOffset(const FixedStackFrameArray &stack_frames)
Génère liste des noms de fichier et offset d'une pile d'appel.
StackTrace stackTrace(int first_function) override
Chaîne de caractère indiquant la pile d'appel.
StackTrace stackTraceFunction(int function_index) override
Retourne la pile à d'appel actuelle.
ConstArrayView< Byte > outputBytes() const
Contient le résultat de la sortie standard (STDOUT) du processus.
static ProcessExecArgs::ExecStatus execute(ProcessExecArgs &args)
Exécute un processus dont les infos sont contenues dans args.
IApplication * application() const
Accès à l'application IApplication associé.
Structure contenant les informations pour créer un service.
Propriétés de création d'un service.
Conserve les adresses correspondantes à une pile d'appel. Cette classe est interne et ne dois pas êtr...
Informations sur la pile d'appel des fonctions.
Constructeur de chaîne de caractère unicode.
String toString() const
Retourne la chaîne de caractères construite.
Chaîne de caractères unicode.
Classe d'accès aux traces.
TraceAccessor(ITraceMng *m)
Construit un accesseur via le gestionnaire de trace m.
TraceMessage pinfo() const
Flot pour un message d'information en parallèle.
ITraceMng * traceMng() const
Gestionnaire de trace.
#define ARCANE_REGISTER_SERVICE(aclass, a_service_property,...)
Macro pour enregistrer un service.
Integer len(const char *s)
Retourne la longueur de la chaîne s.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Integer arcaneCheckArraySize(unsigned long long size)
Vérifie que size peut être converti dans un 'Integer' pour servir de taille à un tableau....
std::int64_t Int64
Type entier signé sur 64 bits.
Int32 Integer
Type représentant un entier.
@ ST_Application
Le service s'utilise au niveau de l'application.
ConstArrayView< Byte > ByteConstArrayView
Equivalent C d'un tableau à une dimension de caractères.
unsigned char Byte
Type d'un octet.
Information sur une adresse mémoire.
const char * m_library_file_name
Nom de la bibliothèque (.so ou .exe) dans laquelle se trouve la méthode.
unw_word_t m_file_loaded_address
Adresse de chargement de la bibliothèque.
String m_name
Nom (démanglé) de la procédure.
const char * libraryFileName() const
Nom de la bibliothèque contenant la fonction. Peut-être nul.
const String & name() const
Nom de la fonction.