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/Process.h"
20#include "arcane/utils/ISymbolizerService.h"
22#include "arcane/core/ServiceBuilder.h"
23#include "arcane/core/Directory.h"
26#include "arcane/core/AbstractService.h"
28#include "arcane_packages.h"
44#if defined(ARCANE_HAS_PACKAGE_DW)
45#include <elfutils/libdwfl.h>
58 const char* m_source_file =
nullptr;
61#if defined(ARCANE_HAS_PACKAGE_DW)
80 m_callback.find_elf = &dwfl_linux_proc_find_elf;
81 m_callback.find_debuginfo = &dwfl_standard_find_debuginfo;
82 m_callback.section_address =
nullptr;
83 m_callback.debuginfo_path =
nullptr;
97 DebugSourceInfo getInfo(unw_word_t func_address)
99 std::scoped_lock<std::mutex> lock(m_mutex);
100 DebugSourceInfo source_info;
104 auto dw_address =
reinterpret_cast<Dwarf_Addr
>(func_address);
106 Dwfl_Module* module = dwfl_addrmodule(m_session, dw_address);
110 Dwarf_Die* dw_die = dwfl_module_addrdie(module, dw_address, &bias);
114 Dwarf_Line* dw_source_info = dwarf_getsrc_die(dw_die, dw_address - bias);
116 if (dw_source_info) {
120 const char* source_file = dwarf_linesrc(dw_source_info,
nullptr,
nullptr);
121 dwarf_lineno(dw_source_info, &line);
122 dwarf_linecol(dw_source_info, &column);
123 source_info = { line, column, source_file };
131 bool m_is_init =
false;
132 Dwfl_Callbacks m_callback;
133 Dwfl* m_session =
nullptr;
144 m_session = dwfl_begin(&m_callback);
149 dwfl_report_begin(m_session);
150 dwfl_linux_proc_report(m_session, getpid());
151 dwfl_report_end(m_session,
nullptr,
nullptr);
175class LibUnwindStackTraceService
186 ProcInfo() =
default;
187 explicit ProcInfo(
const String& aname)
207 unw_word_t m_base_ip = 0;
224 m_want_gdb_info =
true;
226 m_use_backtrace =
true;
237 using ProcInfoMap = std::map<unw_word_t,ProcInfo>;
238 ProcInfoMap m_proc_name_map;
239 std::mutex m_proc_name_map_mutex;
241 bool m_want_gdb_info =
false;
242 bool m_use_backtrace =
false;
245 ProcInfo _getFuncInfo(unw_word_t ip,unw_cursor_t* cursor);
246 ProcInfo _getFuncInfo(
const void* ip);
256LibUnwindStackTraceService::ProcInfo LibUnwindStackTraceService::
257_getFuncInfo(unw_word_t ip,unw_cursor_t* cursor)
260 std::lock_guard<std::mutex> lk(m_proc_name_map_mutex);
261 auto v = m_proc_name_map.find(ip);
262 if (v!=m_proc_name_map.end())
267 char func_name_buf[10000];
268 char demangled_func_name_buf[10000];
269 unw_get_proc_name(cursor,func_name_buf,10000,&offset);
272 char* buf = abi::__cxa_demangle (func_name_buf,demangled_func_name_buf,&len,&dstatus);
274 pi.m_base_ip = offset;
277 void* addr = (
void*)ip;
278 int r2 = dladdr(addr,&dl_info);
280 const char* dli_fname = dl_info.dli_fname;
282 void* dli_fbase = dl_info.dli_fbase;
283 pi.m_library_file_name = dli_fname;
284 pi.m_file_loaded_address = (unw_word_t)dli_fbase;
289 pi.m_name = std::string_view(buf);
291 pi.m_name = std::string_view(func_name_buf);
295 pi.m_source_info = m_dw_handler.getInfo(ip - 1);
298 std::lock_guard<std::mutex> lk(m_proc_name_map_mutex);
299 m_proc_name_map.insert(ProcInfoMap::value_type(ip, pi));
312_getFuncInfo(
const void* addr)
315 std::lock_guard<std::mutex> lk(m_proc_name_map_mutex);
316 auto v = m_proc_name_map.find((unw_word_t)addr);
317 if (v!=m_proc_name_map.end()){
321 const size_t buf_size = 10000;
322 char demangled_func_name_buf[buf_size];
324 int r = dladdr(addr, &dl_info);
327 std::cout <<
"ERROR in dladdr\n";
330 const char* dli_sname = dl_info.dli_sname;
334 size_t len = buf_size;
335 char* buf = abi::__cxa_demangle (dli_sname,demangled_func_name_buf,&len,&dstatus);
339 pi.
m_name = std::string_view(buf);
341 pi.
m_name = std::string_view(dli_sname);
343 std::lock_guard<std::mutex> lk(m_proc_name_map_mutex);
344 m_proc_name_map.insert(ProcInfoMap::value_type((unw_word_t)addr,pi));
352String LibUnwindStackTraceService::
359 fprintf (stderr,
"\nNative stacktrace:\n\n");
361 size = backtrace (array, 256);
362 names = backtrace_symbols (array, size);
363 for (i =0; i < size; ++i) {
364 fprintf (stderr,
"\t%s\n", names [i]);
383 last_str = _getGDBStack();
388 const size_t hexa_buf_size = 100;
389 char hexa[hexa_buf_size+1];
392 unw_init_local(&cursor, &uc);
393 int current_func = 0;
397 while (unw_step(&cursor) > 0) {
399 unw_get_reg(&cursor, UNW_REG_IP, &ip);
400 if (current_func>=first_function){
401 ProcInfo pi = _getFuncInfo(ip,&cursor);
404 snprintf(hexa,hexa_buf_size,
"%14llx",(
long long)ip);
407 message += func_name;
408 if (pi.m_source_info.m_source_file) {
410 message += pi.m_source_info.m_source_file;
411 if (pi.m_source_info.m_line > 0) {
413 message += pi.m_source_info.m_line;
430 last_str = ss->
stackTrace(backtrace_stack_frames.view());
433 message +=
"\nFileAndOffsetStack:{{\n";
458 last_str = _getGDBStack();
461 unw_init_local(&cursor, &uc);
462 int current_func = 0;
465 while (unw_step(&cursor) > 0) {
466 unw_get_reg(&cursor, UNW_REG_IP, &ip);
467 if (current_func==function_index){
468 ProcInfo pi = _getFuncInfo(ip,&cursor);
470 message += func_name;
486 Integer size = backtrace (ips, 256);
489 for(
Integer i=first_function; i<size; ++i ){
502 const size_t buf_size = 100;
503 char hexa[buf_size+1];
508 intptr_t ip = f.address();
512 snprintf(hexa,buf_size,
"%10llx",(
long long)ip);
515 message += func_name;
536 const size_t buf_size = 100;
537 char hexa[buf_size+1];
542 intptr_t ip = f.address();
543 ProcInfo pinfo = _getFuncInfo(
reinterpret_cast<const void*
>(ip));
544 message += (
pinfo.libraryFileName() ?
pinfo.libraryFileName() :
"()");
546 auto file_base_address =
pinfo.m_file_loaded_address;
551 if (file_base_address==0x400000)
552 file_base_address = 0;
553 intptr_t offset_ip = (ip - file_base_address);
554 snprintf(hexa,buf_size,
"%llx",(
long long)offset_ip);
568class LLVMSymbolizerService
576 , m_is_check_done(
false)
593 String m_llvm_symbolizer_path;
594 bool m_is_check_done =
false;
595 bool m_is_valid =
false;
607 String fullpath = dir.
file(
"llvm-symbolizer");
609 m_llvm_symbolizer_path = fullpath;
612 m_is_check_done =
true;
625 std::stringstream ostr;
631 intptr_t addr = frames[i].address();
632 int r2 = dladdr((
void*)addr,&dl_info);
633 const char* dli_fname =
nullptr;
634 intptr_t base_address = 0;
636 dli_fname = dl_info.dli_fname;
638 void* dli_fbase = dl_info.dli_fbase;
639 intptr_t true_base =
reinterpret_cast<intptr_t
>(dli_fbase);
644 if (true_base==0x400000)
646 base_address = addr - true_base;
649 ostr << (dli_fname ? dli_fname :
"??") <<
" " << base_address <<
'\n';
652 std::string input_str(ostr.str());
655 args.setCommand(m_llvm_symbolizer_path);
658 args.setInputBytes(input_bytes);
659 args.addArguments(
"--demangle");
660 args.addArguments(
"--pretty-print");
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.
AbstractService(const ServiceBuildInfo &)
Constructeur à partir d'un ServiceBuildInfo.
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,...
Interface de l'application.
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.
String stackTrace(ConstArrayView< StackFrame > frames) override
Informations pour la pile d'appel frames.
void _checkValid()
Vérifie que le chemin spécifié est valid.
void build() override
Construction de niveau build du service.
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.
void build() override
Construction de niveau build du service.
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.
ByteConstArrayView 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.
TraceMessage pinfo() const
Flot pour un message d'information en parallèle.
#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.