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);
177class LibUnwindStackTraceService
188 ProcInfo() =
default;
189 explicit ProcInfo(
const String& aname)
209 unw_word_t m_base_ip = 0;
226 void build()
override
229 m_want_gdb_info =
true;
231 m_use_backtrace =
true;
237 StackTrace
stackTrace(
int first_function)
override;
242 using ProcInfoMap = std::map<unw_word_t,ProcInfo>;
243 ProcInfoMap m_proc_name_map;
244 std::mutex m_proc_name_map_mutex;
246 bool m_want_gdb_info =
false;
247 bool m_use_backtrace =
false;
248 DWHandler m_dw_handler;
249 ProcInfo _getFuncInfo(unw_word_t ip,unw_cursor_t* cursor);
250 ProcInfo _getFuncInfo(
const void* ip);
251 String _getGDBStack();
261_getFuncInfo(unw_word_t ip,unw_cursor_t* cursor)
264 std::lock_guard<std::mutex> lk(m_proc_name_map_mutex);
265 auto v = m_proc_name_map.find(ip);
266 if (v!=m_proc_name_map.end())
271 char func_name_buf[10000];
272 char demangled_func_name_buf[10000];
273 unw_get_proc_name(cursor,func_name_buf,10000,&offset);
276 char* buf = abi::__cxa_demangle (func_name_buf,demangled_func_name_buf,&len,&dstatus);
278 pi.m_base_ip = offset;
281 void* addr = (
void*)ip;
282 int r2 = dladdr(addr,&dl_info);
284 const char* dli_fname = dl_info.dli_fname;
286 void* dli_fbase = dl_info.dli_fbase;
287 pi.m_library_file_name = dli_fname;
288 pi.m_file_loaded_address = (unw_word_t)dli_fbase;
293 pi.m_name = std::string_view(buf);
295 pi.m_name = std::string_view(func_name_buf);
299 pi.m_source_info = m_dw_handler.getInfo(ip - 1);
302 std::lock_guard<std::mutex> lk(m_proc_name_map_mutex);
303 m_proc_name_map.insert(ProcInfoMap::value_type(ip, pi));
316_getFuncInfo(
const void* addr)
319 std::lock_guard<std::mutex> lk(m_proc_name_map_mutex);
320 auto v = m_proc_name_map.find((unw_word_t)addr);
321 if (v!=m_proc_name_map.end()){
325 const size_t buf_size = 10000;
326 char demangled_func_name_buf[buf_size];
328 int r = dladdr(addr, &dl_info);
331 std::cout <<
"ERROR in dladdr\n";
334 const char* dli_sname = dl_info.dli_sname;
338 size_t len = buf_size;
339 char* buf = abi::__cxa_demangle (dli_sname,demangled_func_name_buf,&len,&dstatus);
343 pi.
m_name = std::string_view(buf);
345 pi.
m_name = std::string_view(dli_sname);
347 std::lock_guard<std::mutex> lk(m_proc_name_map_mutex);
348 m_proc_name_map.insert(ProcInfoMap::value_type((unw_word_t)addr,pi));
356String LibUnwindStackTraceService::
363 fprintf (stderr,
"\nNative stacktrace:\n\n");
365 size = backtrace (array, 256);
366 names = backtrace_symbols (array, size);
367 for (i =0; i < size; ++i) {
368 fprintf (stderr,
"\t%s\n", names [i]);
387 last_str = _getGDBStack();
392 const size_t hexa_buf_size = 100;
393 char hexa[hexa_buf_size+1];
396 unw_init_local(&cursor, &uc);
397 int current_func = 0;
401 while (unw_step(&cursor) > 0) {
403 unw_get_reg(&cursor, UNW_REG_IP, &ip);
404 if (current_func>=first_function){
405 ProcInfo pi = _getFuncInfo(ip,&cursor);
408 snprintf(hexa,hexa_buf_size,
"%14llx",(
long long)ip);
411 message += func_name;
412 if (pi.m_source_info.m_source_file) {
414 message += pi.m_source_info.m_source_file;
415 if (pi.m_source_info.m_line > 0) {
417 message += pi.m_source_info.m_line;
434 last_str = ss->
stackTrace(backtrace_stack_frames.view());
437 message +=
"\nFileAndOffsetStack:{{\n";
462 last_str = _getGDBStack();
465 unw_init_local(&cursor, &uc);
466 int current_func = 0;
469 while (unw_step(&cursor) > 0) {
470 unw_get_reg(&cursor, UNW_REG_IP, &ip);
471 if (current_func==function_index){
472 ProcInfo pi = _getFuncInfo(ip,&cursor);
474 message += func_name;
490 Integer size = backtrace (ips, 256);
493 for(
Integer i=first_function; i<size; ++i ){
506 const size_t buf_size = 100;
507 char hexa[buf_size+1];
512 intptr_t ip = f.address();
516 snprintf(hexa,buf_size,
"%10llx",(
long long)ip);
519 message += func_name;
540 const size_t buf_size = 100;
541 char hexa[buf_size+1];
546 intptr_t ip = f.address();
547 ProcInfo pinfo = _getFuncInfo(
reinterpret_cast<const void*
>(ip));
548 message += (
pinfo.libraryFileName() ?
pinfo.libraryFileName() :
"()");
550 auto file_base_address =
pinfo.m_file_loaded_address;
555 if (file_base_address==0x400000)
556 file_base_address = 0;
557 intptr_t offset_ip = (ip - file_base_address);
558 snprintf(hexa,buf_size,
"%llx",(
long long)offset_ip);
572class LLVMSymbolizerService
583 explicit LLVMSymbolizerService(
ITraceMng* tm)
599 String m_llvm_symbolizer_path;
600 bool m_is_check_done =
false;
601 bool m_is_valid =
false;
613 String fullpath = dir.
file(
"llvm-symbolizer");
615 m_llvm_symbolizer_path = fullpath;
618 m_is_check_done =
true;
635 std::stringstream ostr;
641 intptr_t addr = frames[i].address();
642 int r2 = dladdr((
void*)addr,&dl_info);
643 const char* dli_fname =
nullptr;
644 intptr_t base_address = 0;
646 dli_fname = dl_info.dli_fname;
648 void* dli_fbase = dl_info.dli_fbase;
649 intptr_t true_base =
reinterpret_cast<intptr_t
>(dli_fbase);
654 if (true_base==0x400000)
656 base_address = addr - true_base;
659 ostr << (dli_fname ? dli_fname :
"??") <<
" " << base_address <<
'\n';
662 std::string input_str(ostr.str());
665 args.setCommand(m_llvm_symbolizer_path);
668 args.setInputBytes(input_bytes);
669 args.addArguments(
"--demangle");
670 args.addArguments(
"--pretty-print");
688 DependencyInjection::ProviderProperty(
"LibUnwind"),
693 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.