Arcane  4.2.3.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
LibUnwindStackTraceService.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* LibUnwindStackTraceService.cc (C) 2000-2025 */
9/* */
10/* Service de trace des appels de fonctions utilisant 'libunwind'. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
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"
20
21#include "arccore/base/internal/DependencyInjection.h"
22#include "arccore/common/internal/Process.h"
23
24#include "arcane/core/ServiceBuilder.h"
25#include "arcane/core/Directory.h"
26
28#include "arcane/core/AbstractService.h"
29
30#include "arcane_packages.h"
31
32#define UNW_LOCAL_ONLY
33#include <libunwind.h>
34#include <cxxabi.h>
35
36#include <map>
37#include <mutex>
38
39#include <execinfo.h>
40#include <cstdio>
41#include <sys/types.h>
42#include <unistd.h>
43//#include <cstdlib>
44#include <dlfcn.h>
45
46#if defined(ARCANE_HAS_PACKAGE_DW)
47#include <elfutils/libdwfl.h>
48#endif
49
50/*---------------------------------------------------------------------------*/
51/*---------------------------------------------------------------------------*/
52
53namespace Arcane
54{
55
57{
58 int m_line = 0;
59 int m_column = 0;
60 const char* m_source_file = nullptr;
61};
62
63#if defined(ARCANE_HAS_PACKAGE_DW)
76class DWHandler
77{
78 public:
79
80 DWHandler()
81 {
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;
86 // S'assure qu'on n'essaie pas de se connecter à internet pour chercher des
87 // informations de debug. Cela peut provoquer des deadlocks sur certains environnements.
88 setenv("DEBUGINFOD_URLS", "", 1);
89 }
90
91 ~DWHandler()
92 {
93 if (m_session)
94 dwfl_end(m_session);
95 }
96
102 DebugSourceInfo getInfo(unw_word_t func_address)
103 {
104 DebugSourceInfo source_info;
105
106 // Cette fonction nécessite un verrou mais elle peut être appelée récursivement, ce qui
107 // peut provoquer un deadlock. Pour l'éviter, on tente de prendre le verrou
108 // et si cela ne fonctionne pas on retourne immédiatement.
109 ScopedTryLock tried_lock(m_mutex);
110 if (!tried_lock.isLock())
111 return source_info;
112
113 _init();
114
115 auto dw_address = reinterpret_cast<Dwarf_Addr>(func_address);
116
117 Dwfl_Module* module = dwfl_addrmodule(m_session, dw_address);
118 if (!module)
119 return source_info;
120 Dwarf_Addr bias = 0;
121 Dwarf_Die* dw_die = dwfl_module_addrdie(module, dw_address, &bias);
122 if (dw_die)
123 return source_info;
124
125 Dwarf_Line* dw_source_info = dwarf_getsrc_die(dw_die, dw_address - bias);
126
127 if (dw_source_info) {
128 int line = 0;
129 int column = 0;
130 // ATTENTION : le pointeur retourné n'est plus valide si m_session est détruit.
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 };
135 }
136
137 return source_info;
138 }
139
140 public:
141
142 bool m_is_init = false;
143 Dwfl_Callbacks m_callback;
144 Dwfl* m_session = nullptr;
145 std::mutex m_mutex;
146
147 private:
148
150 class ScopedTryLock
151 {
152 public:
153
154 ScopedTryLock(std::mutex& mutex)
155 : m_mutex(mutex)
156 {
157 m_is_lock = m_mutex.try_lock();
158 }
159 ~ScopedTryLock()
160 {
161 if (m_is_lock)
162 m_mutex.unlock();
163 }
164
165 constexpr bool isLock() const { return m_is_lock; }
166
167 private:
168
169 std::mutex& m_mutex;
170 bool m_is_lock = false;
171 };
172
173 void _init()
174 {
175 if (m_is_init)
176 return;
177 m_is_init = true;
178
179 m_session = dwfl_begin(&m_callback);
180 // TODO: faire dwfl_end()
181 if (!m_session)
182 return;
183
184 dwfl_report_begin(m_session);
185 dwfl_linux_proc_report(m_session, getpid());
186 dwfl_report_end(m_session, nullptr, nullptr);
187 }
188};
189
190#else
191
192// Implémentation vide si libdw n'est pas trouvé.
194{
195 public:
196
197 DebugSourceInfo getInfo(unw_word_t func_address)
198 {
199 return {};
200 }
201};
202
203#endif
204
205/*---------------------------------------------------------------------------*/
206/*---------------------------------------------------------------------------*/
210class LibUnwindStackTraceService
211: public TraceAccessor
212, public IStackTraceService
213{
214 private:
215
217 struct ProcInfo
218 {
219 public:
220
221 ProcInfo() = default;
222 explicit ProcInfo(const String& aname)
223 : m_name(aname)
224 {}
225
226 public:
227
229 const String& name() const { return m_name; }
231 const char* libraryFileName() const { return m_library_file_name; }
232
233 public:
234
238 const char* m_library_file_name = nullptr;
240 //TODO: ne pas stocker cela pour chaque fonction.
241 unw_word_t m_file_loaded_address = 0;
242 unw_word_t m_base_ip = 0;
243 DebugSourceInfo m_source_info;
244 };
245
246 public:
247
248 explicit LibUnwindStackTraceService(const ServiceBuildInfo& sbi)
249 : TraceAccessor(sbi.application()->traceMng())
250 {
251 }
253 : TraceAccessor(tm)
254 {
255 }
256
257 public:
258
259 void build() override
260 {
261 if (!platform::getEnvironmentVariable("ARCANE_GDB_STACK").null())
262 m_want_gdb_info = true;
263 if (!platform::getEnvironmentVariable("ARCANE_USE_BACKTRACE").null())
264 m_use_backtrace = true;
265 }
266
267 public:
268
270 StackTrace stackTrace(int first_function) override;
271 StackTrace stackTraceFunction(int function_index) override;
272
273 private:
274
275 using ProcInfoMap = std::map<unw_word_t,ProcInfo>;
276 ProcInfoMap m_proc_name_map;
277 std::mutex m_proc_name_map_mutex;
278
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();
285 StackTrace _backtraceStackTrace(const FixedStackFrameArray& stack_frames);
286 String _generateFileAndOffset(const FixedStackFrameArray& stack_frames);
287 FixedStackFrameArray _backtraceStackFrame(int first_function);
288};
289
290/*---------------------------------------------------------------------------*/
291/*---------------------------------------------------------------------------*/
292
293LibUnwindStackTraceService::ProcInfo LibUnwindStackTraceService::
294_getFuncInfo(unw_word_t ip,unw_cursor_t* cursor)
295{
296 {
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())
300 return v->second;
301 }
302
303 unw_word_t offset;
304 char func_name_buf[10000];
305 char demangled_func_name_buf[10000];
306 unw_get_proc_name(cursor,func_name_buf,10000,&offset);
307 int dstatus = 0;
308 size_t len = 10000;
309 char* buf = abi::__cxa_demangle (func_name_buf,demangled_func_name_buf,&len,&dstatus);
310 ProcInfo pi;
311 pi.m_base_ip = offset;
312 {
313 Dl_info dl_info;
314 void* addr = (void*)ip;
315 int r2 = dladdr(addr,&dl_info);
316 if (r2!=0){
317 const char* dli_fname = dl_info.dli_fname;
318 // Adresse de base de chargement du fichier.
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;
322 }
323 }
324
325 if (buf)
326 pi.m_name = std::string_view(buf);
327 else
328 pi.m_name = std::string_view(func_name_buf);
329
330 // Il faut faire 'ip-1' car l'adresse retournée par libunwind est celle
331 // de l'instruction de retour.
332 pi.m_source_info = m_dw_handler.getInfo(ip - 1);
333
334 {
335 std::lock_guard<std::mutex> lk(m_proc_name_map_mutex);
336 m_proc_name_map.insert(ProcInfoMap::value_type(ip, pi));
337 }
338
339 return pi;
340}
341
342/*---------------------------------------------------------------------------*/
343/*---------------------------------------------------------------------------*/
348LibUnwindStackTraceService::ProcInfo LibUnwindStackTraceService::
349_getFuncInfo(const void* addr)
350{
351 {
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()){
355 return v->second;
356 }
357 }
358 const size_t buf_size = 10000;
359 char demangled_func_name_buf[buf_size];
360 Dl_info dl_info;
361 int r = dladdr(addr, &dl_info);
362 if (r==0){
363 // Erreur dans dladdr.
364 std::cout << "ERROR in dladdr\n";
365 return ProcInfo("Unknown");
366 }
367 const char* dli_sname = dl_info.dli_sname;
368 if (!dli_sname)
369 dli_sname = "";
370 int dstatus = 0;
371 size_t len = buf_size;
372 char* buf = abi::__cxa_demangle (dli_sname,demangled_func_name_buf,&len,&dstatus);
373 //char* buf = (char*)dli_sname;
374 ProcInfo pi;
375 if (buf)
376 pi.m_name = std::string_view(buf);
377 else
378 pi.m_name = std::string_view(dli_sname);
379 {
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));
382 }
383 return pi;
384}
385
386/*---------------------------------------------------------------------------*/
387/*---------------------------------------------------------------------------*/
388
389String LibUnwindStackTraceService::
390_getGDBStack()
391{
392 void *array [256];
393 char **names;
394 int i, size;
395
396 fprintf (stderr, "\nNative stacktrace:\n\n");
397
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]);
402 }
403
404 fflush (stderr);
405 return platform::getGDBStack();
406}
407
408/*---------------------------------------------------------------------------*/
409/*---------------------------------------------------------------------------*/
410
413stackTrace(int first_function)
414{
415 unw_cursor_t cursor;
416 unw_context_t uc;
417
418 String last_str;
419 if (m_want_gdb_info)
420 last_str = _getGDBStack();
421 FixedStackFrameArray backtrace_stack_frames = _backtraceStackFrame(first_function);
422 if (m_use_backtrace)
423 return _backtraceStackTrace(backtrace_stack_frames);
424
425 const size_t hexa_buf_size = 100;
426 char hexa[hexa_buf_size+1];
427
428 unw_getcontext(&uc);
429 unw_init_local(&cursor, &uc);
430 int current_func = 0;
431 StringBuilder message;
432
433 FixedStackFrameArray stack_frames;
434 while (unw_step(&cursor) > 0) {
435 unw_word_t ip;
436 unw_get_reg(&cursor, UNW_REG_IP, &ip);
437 if (current_func>=first_function){
438 ProcInfo pi = _getFuncInfo(ip,&cursor);
439 String func_name = pi.m_name;
440 message += " ";
441 snprintf(hexa,hexa_buf_size,"%14llx",(long long)ip);
442 message += hexa;
443 message += " ";
444 message += func_name;
445 if (pi.m_source_info.m_source_file) {
446 message += " \"";
447 message += pi.m_source_info.m_source_file;
448 if (pi.m_source_info.m_line > 0) {
449 message += ":";
450 message += pi.m_source_info.m_line;
451 }
452 message += "\"";
453 }
454 message += "\n";
455
456 stack_frames.addFrame(StackFrame((intptr_t)ip));
457 }
458 ++current_func;
459 }
461
462 if (ss){
463 // Il faut mieux lire la pile d'appel de _backtrace() car
464 // la libunwind retourne l'adresse de retour pour chaque fonction
465 // ce qui provoque un décalage dans les infos des lignes du code
466 // source (on pointe vers la ligne après celle qu'on est en train d'exécuter).
467 last_str = ss->stackTrace(backtrace_stack_frames.view());
468 }
469 else{
470 message += "\nFileAndOffsetStack:{{\n";
471 message += _generateFileAndOffset(backtrace_stack_frames);
472 message += "}}\n";
473 }
474 message += last_str;
475 return StackTrace(stack_frames,message);
476}
477
478/*---------------------------------------------------------------------------*/
479/*---------------------------------------------------------------------------*/
486stackTraceFunction(int function_index)
487{
488 unw_cursor_t cursor;
489 unw_context_t uc;
490 unw_word_t ip;
491 //unw_word_t offset;
492
493 String last_str;
494 if (m_want_gdb_info)
495 last_str = _getGDBStack();
496
497 unw_getcontext(&uc);
498 unw_init_local(&cursor, &uc);
499 int current_func = 0;
500 StringBuilder message;
501
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);
506 String func_name = pi.m_name;
507 message += func_name;
508 break;
509 }
510 ++current_func;
511 }
512 return StackTrace(message.toString()+last_str);
513}
514
515/*---------------------------------------------------------------------------*/
516/*---------------------------------------------------------------------------*/
517
520_backtraceStackFrame(int first_function)
521{
522 void *ips [256];
523 Integer size = backtrace (ips, 256);
524
525 FixedStackFrameArray stack_frames;
526 for( Integer i=first_function; i<size; ++i ){
527 stack_frames.addFrame(StackFrame((intptr_t)ips[i]));
528 }
529 return stack_frames;
530}
531
532/*---------------------------------------------------------------------------*/
533/*---------------------------------------------------------------------------*/
534
538{
539 const size_t buf_size = 100;
540 char hexa[buf_size+1];
541
542 StringBuilder message;
543 ConstArrayView<StackFrame> frames_view = stack_frames.view();
544 for( StackFrame f : frames_view ){
545 intptr_t ip = f.address();
546 ProcInfo pinfo = _getFuncInfo((void*)ip);
547 String func_name = pinfo.name();
548 message += " ";
549 snprintf(hexa,buf_size,"%10llx",(long long)ip);
550 message += hexa;
551 message += " ";
552 message += func_name;
553 message += "\n";
554 }
555 return StackTrace(stack_frames,message);
556}
557
558/*---------------------------------------------------------------------------*/
559/*---------------------------------------------------------------------------*/
572{
573 const size_t buf_size = 100;
574 char hexa[buf_size+1];
575
576 StringBuilder message;
577 ConstArrayView<StackFrame> frames_view = stack_frames.view();
578 for( StackFrame f : frames_view ){
579 intptr_t ip = f.address();
580 ProcInfo pinfo = _getFuncInfo(reinterpret_cast<const void*>(ip));
581 message += (pinfo.libraryFileName() ? pinfo.libraryFileName() : "()");
582 message += " ";
583 auto file_base_address = pinfo.m_file_loaded_address;
584 // Sous Linux (CentOS 6 et 7), l'adresse 0x400000 correspond à celle
585 // de chargement de l'exécutable mais si on retranche cette adresse de celle
586 // de la fonction alors le symboliser ne fonctionne pas (que ce soit
587 // llvm-symbolize ou addr2line)
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);
592 message += "0x";
593 message += hexa;
594 message += "\n";
595 }
596 return message;
597}
598
599/*---------------------------------------------------------------------------*/
600/*---------------------------------------------------------------------------*/
601
602/*---------------------------------------------------------------------------*/
603/*---------------------------------------------------------------------------*/
604
605class LLVMSymbolizerService
606: public TraceAccessor
607, public ISymbolizerService
608{
609 public:
610
611 explicit LLVMSymbolizerService(const ServiceBuildInfo& sbi)
613 {
614 _init();
615 }
616 explicit LLVMSymbolizerService(ITraceMng* tm)
617 : TraceAccessor(tm)
618 {
619 _init();
620 }
621
622 public:
623
624 void build() {}
625
626 public:
627
629
630 private:
631
632 String m_llvm_symbolizer_path;
633 bool m_is_check_done = false;
634 bool m_is_valid = false;
635
636 private:
637
640 {
641 if (m_is_check_done)
642 return;
643 // Avant appel à cette méthode, m_llvm_symbolizer_path doit contenir
644 // le nom du répertoire dans lequel se trouve llvm-symbolizer.
645 Directory dir(m_llvm_symbolizer_path);
646 String fullpath = dir.file("llvm-symbolizer");
647 Int64 length = platform::getFileLength(fullpath);
648 m_llvm_symbolizer_path = fullpath;
649 if (length>0)
650 m_is_valid = true;
651 m_is_check_done = true;
652 }
653 void _init()
654 {
655 m_llvm_symbolizer_path = platform::getEnvironmentVariable("ARCANE_LLVMSYMBOLIZER_PATH");
656 }
657};
658
659/*---------------------------------------------------------------------------*/
660/*---------------------------------------------------------------------------*/
661
664{
665 _checkValid();
666 if (!m_is_valid)
667 return String();
668 std::stringstream ostr;
669 // NOTE: le code ci dessous est similaire à
670 // LibUnwindStackTraceService::_generateFileAndOffset(). Il faudrait
671 // fusionner les deux.
672 for( Integer i=0, n=frames.size(); i<n; ++i ){
673 Dl_info dl_info;
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;
678 if (r2!=0){
679 dli_fname = dl_info.dli_fname;
680 // Adresse de base de chargement du fichier.
681 void* dli_fbase = dl_info.dli_fbase;
682 intptr_t true_base = reinterpret_cast<intptr_t>(dli_fbase);
683 // Sous Linux (CentOS 6 et 7), l'adresse 0x400000 correspond à celle
684 // de chargement de l'exécutable, mais si on retranche cette adresse de celle
685 // de la fonction alors le symboliser ne fonctionne pas (que ce soit
686 // llvm-symbolize ou addr2line)
687 if (true_base==0x400000)
688 true_base = 0;
689 base_address = addr - true_base;
690 }
691 // TODO: écrire base_address en hexa pour pouvoir le relire avec addr2line
692 ostr << (dli_fname ? dli_fname : "??") << " " << base_address << '\n';
693 }
694
695 std::string input_str(ostr.str());
696 String output_str;
697 ProcessExecArgs args;
698 args.setCommand(m_llvm_symbolizer_path);
699 Integer input_size = arcaneCheckArraySize(input_str.length());
700 ByteConstArrayView input_bytes(input_size, reinterpret_cast<const Byte*>(input_str.c_str()));
701 args.setInputBytes(input_bytes);
702 args.addArguments("--demangle");
703 args.addArguments("--pretty-print");
704 //args.addArguments("--print-source-context-lines=5");
705 Process::execute(args);
706 return String(args.outputBytes());
707}
708
709/*---------------------------------------------------------------------------*/
710/*---------------------------------------------------------------------------*/
711
713 ServiceProperty("LibUnwind",ST_Application),
715
717 ServiceProperty("LLVMSymbolizer",ST_Application),
719
720ARCANE_DI_REGISTER_PROVIDER(LibUnwindStackTraceService,
721 DependencyInjection::ProviderProperty("LibUnwind"),
722 ARCANE_DI_INTERFACES(IStackTraceService),
723 ARCANE_DI_CONSTRUCTOR(ITraceMng*));
724
725ARCANE_DI_REGISTER_PROVIDER(LLVMSymbolizerService,
726 DependencyInjection::ProviderProperty("LLVMSymbolizer"),
727 ARCANE_DI_INTERFACES(ISymbolizerService),
728 ARCANE_DI_CONSTRUCTOR(ITraceMng*));
729
730/*---------------------------------------------------------------------------*/
731/*---------------------------------------------------------------------------*/
732
733} // End namespace Arcane
734
735/*---------------------------------------------------------------------------*/
736/*---------------------------------------------------------------------------*/
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.
Definition Directory.cc:120
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.
Definition Process.h:64
static ProcessExecArgs::ExecStatus execute(ProcessExecArgs &args)
Exécute un processus dont les infos sont contenues dans args.
Definition Process.cc:42
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.
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.
long unsigned int getFileLength(const String &filename)
Longueur du fichier filename. Si le fichier n'est pas lisible ou n'existe pas, retourne 0.
ISymbolizerService * getSymbolizerService()
Service utilisé pour obtenir des informations sur les symboles du code source.
String getGDBStack()
Récupère la pile d'appel via gdb.
String getEnvironmentVariable(const String &name)
Variable d'environnement du nom name.
-- 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.
Definition UtilsTypes.h:474
unsigned char Byte
Type d'un octet.
Definition BaseTypes.h:42
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.