Arcane  v4.1.2.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-2025 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 }
87
88 ~DWHandler()
89 {
90 if (m_session)
91 dwfl_end(m_session);
92 }
93
99 DebugSourceInfo getInfo(unw_word_t func_address)
100 {
101 std::scoped_lock<std::mutex> lock(m_mutex);
102 DebugSourceInfo source_info;
103
104 _init();
105
106 auto dw_address = reinterpret_cast<Dwarf_Addr>(func_address);
107
108 Dwfl_Module* module = dwfl_addrmodule(m_session, dw_address);
109 if (!module)
110 return source_info;
111 Dwarf_Addr bias = 0;
112 Dwarf_Die* dw_die = dwfl_module_addrdie(module, dw_address, &bias);
113 if (dw_die)
114 return source_info;
115
116 Dwarf_Line* dw_source_info = dwarf_getsrc_die(dw_die, dw_address - bias);
117
118 if (dw_source_info) {
119 int line = 0;
120 int column = 0;
121 // ATTENTION : le pointeur retourné n'est plus valide si m_session est détruit.
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 };
126 }
127
128 return source_info;
129 }
130
131 public:
132
133 bool m_is_init = false;
134 Dwfl_Callbacks m_callback;
135 Dwfl* m_session = nullptr;
136 std::mutex m_mutex;
137
138 private:
139
140 void _init()
141 {
142 if (m_is_init)
143 return;
144 m_is_init = true;
145
146 m_session = dwfl_begin(&m_callback);
147 // TODO: faire dwfl_end()
148 if (!m_session)
149 return;
150
151 dwfl_report_begin(m_session);
152 dwfl_linux_proc_report(m_session, getpid());
153 dwfl_report_end(m_session, nullptr, nullptr);
154 }
155};
156
157#else
158
159// Implémentation vide si libdw n'est pas trouvé.
161{
162 public:
163
164 DebugSourceInfo getInfo(unw_word_t func_address)
165 {
166 return {};
167 }
168};
169
170#endif
171
172/*---------------------------------------------------------------------------*/
173/*---------------------------------------------------------------------------*/
177class LibUnwindStackTraceService
178: public TraceAccessor
179, public IStackTraceService
180{
181 private:
182
184 struct ProcInfo
185 {
186 public:
187
188 ProcInfo() = default;
189 explicit ProcInfo(const String& aname)
190 : m_name(aname)
191 {}
192
193 public:
194
196 const String& name() const { return m_name; }
198 const char* libraryFileName() const { return m_library_file_name; }
199
200 public:
201
205 const char* m_library_file_name = nullptr;
207 //TODO: ne pas stocker cela pour chaque fonction.
208 unw_word_t m_file_loaded_address = 0;
209 unw_word_t m_base_ip = 0;
210 DebugSourceInfo m_source_info;
211 };
212
213 public:
214
215 explicit LibUnwindStackTraceService(const ServiceBuildInfo& sbi)
216 : TraceAccessor(sbi.application()->traceMng())
217 {
218 }
220 : TraceAccessor(tm)
221 {
222 }
223
224 public:
225
226 void build() override
227 {
228 if (!platform::getEnvironmentVariable("ARCANE_GDB_STACK").null())
229 m_want_gdb_info = true;
230 if (!platform::getEnvironmentVariable("ARCANE_USE_BACKTRACE").null())
231 m_use_backtrace = true;
232 }
233
234 public:
235
237 StackTrace stackTrace(int first_function) override;
238 StackTrace stackTraceFunction(int function_index) override;
239
240 private:
241
242 using ProcInfoMap = std::map<unw_word_t,ProcInfo>;
243 ProcInfoMap m_proc_name_map;
244 std::mutex m_proc_name_map_mutex;
245
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();
252 StackTrace _backtraceStackTrace(const FixedStackFrameArray& stack_frames);
253 String _generateFileAndOffset(const FixedStackFrameArray& stack_frames);
254 FixedStackFrameArray _backtraceStackFrame(int first_function);
255};
256
257/*---------------------------------------------------------------------------*/
258/*---------------------------------------------------------------------------*/
259
260LibUnwindStackTraceService::ProcInfo LibUnwindStackTraceService::
261_getFuncInfo(unw_word_t ip,unw_cursor_t* cursor)
262{
263 {
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())
267 return v->second;
268 }
269
270 unw_word_t offset;
271 char func_name_buf[10000];
272 char demangled_func_name_buf[10000];
273 unw_get_proc_name(cursor,func_name_buf,10000,&offset);
274 int dstatus = 0;
275 size_t len = 10000;
276 char* buf = abi::__cxa_demangle (func_name_buf,demangled_func_name_buf,&len,&dstatus);
277 ProcInfo pi;
278 pi.m_base_ip = offset;
279 {
280 Dl_info dl_info;
281 void* addr = (void*)ip;
282 int r2 = dladdr(addr,&dl_info);
283 if (r2!=0){
284 const char* dli_fname = dl_info.dli_fname;
285 // Adresse de base de chargement du fichier.
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;
289 }
290 }
291
292 if (buf)
293 pi.m_name = std::string_view(buf);
294 else
295 pi.m_name = std::string_view(func_name_buf);
296
297 // Il faut faire 'ip-1' car l'adresse retournée par libunwind est celle
298 // de l'instruction de retour.
299 pi.m_source_info = m_dw_handler.getInfo(ip - 1);
300
301 {
302 std::lock_guard<std::mutex> lk(m_proc_name_map_mutex);
303 m_proc_name_map.insert(ProcInfoMap::value_type(ip, pi));
304 }
305
306 return pi;
307}
308
309/*---------------------------------------------------------------------------*/
310/*---------------------------------------------------------------------------*/
315LibUnwindStackTraceService::ProcInfo LibUnwindStackTraceService::
316_getFuncInfo(const void* addr)
317{
318 {
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()){
322 return v->second;
323 }
324 }
325 const size_t buf_size = 10000;
326 char demangled_func_name_buf[buf_size];
327 Dl_info dl_info;
328 int r = dladdr(addr, &dl_info);
329 if (r==0){
330 // Erreur dans dladdr.
331 std::cout << "ERROR in dladdr\n";
332 return ProcInfo("Unknown");
333 }
334 const char* dli_sname = dl_info.dli_sname;
335 if (!dli_sname)
336 dli_sname = "";
337 int dstatus = 0;
338 size_t len = buf_size;
339 char* buf = abi::__cxa_demangle (dli_sname,demangled_func_name_buf,&len,&dstatus);
340 //char* buf = (char*)dli_sname;
341 ProcInfo pi;
342 if (buf)
343 pi.m_name = std::string_view(buf);
344 else
345 pi.m_name = std::string_view(dli_sname);
346 {
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));
349 }
350 return pi;
351}
352
353/*---------------------------------------------------------------------------*/
354/*---------------------------------------------------------------------------*/
355
356String LibUnwindStackTraceService::
357_getGDBStack()
358{
359 void *array [256];
360 char **names;
361 int i, size;
362
363 fprintf (stderr, "\nNative stacktrace:\n\n");
364
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]);
369 }
370
371 fflush (stderr);
372 return platform::getGDBStack();
373}
374
375/*---------------------------------------------------------------------------*/
376/*---------------------------------------------------------------------------*/
377
380stackTrace(int first_function)
381{
382 unw_cursor_t cursor;
383 unw_context_t uc;
384
385 String last_str;
386 if (m_want_gdb_info)
387 last_str = _getGDBStack();
388 FixedStackFrameArray backtrace_stack_frames = _backtraceStackFrame(first_function);
389 if (m_use_backtrace)
390 return _backtraceStackTrace(backtrace_stack_frames);
391
392 const size_t hexa_buf_size = 100;
393 char hexa[hexa_buf_size+1];
394
395 unw_getcontext(&uc);
396 unw_init_local(&cursor, &uc);
397 int current_func = 0;
398 StringBuilder message;
399
400 FixedStackFrameArray stack_frames;
401 while (unw_step(&cursor) > 0) {
402 unw_word_t ip;
403 unw_get_reg(&cursor, UNW_REG_IP, &ip);
404 if (current_func>=first_function){
405 ProcInfo pi = _getFuncInfo(ip,&cursor);
406 String func_name = pi.m_name;
407 message += " ";
408 snprintf(hexa,hexa_buf_size,"%14llx",(long long)ip);
409 message += hexa;
410 message += " ";
411 message += func_name;
412 if (pi.m_source_info.m_source_file) {
413 message += " \"";
414 message += pi.m_source_info.m_source_file;
415 if (pi.m_source_info.m_line > 0) {
416 message += ":";
417 message += pi.m_source_info.m_line;
418 }
419 message += "\"";
420 }
421 message += "\n";
422
423 stack_frames.addFrame(StackFrame((intptr_t)ip));
424 }
425 ++current_func;
426 }
428
429 if (ss){
430 // Il faut mieux lire la pile d'appel de _backtrace() car
431 // la libunwind retourne l'adresse de retour pour chaque fonction
432 // ce qui provoque un décalage dans les infos des lignes du code
433 // source (on pointe vers la ligne après celle qu'on est en train d'exécuter).
434 last_str = ss->stackTrace(backtrace_stack_frames.view());
435 }
436 else{
437 message += "\nFileAndOffsetStack:{{\n";
438 message += _generateFileAndOffset(backtrace_stack_frames);
439 message += "}}\n";
440 }
441 message += last_str;
442 return StackTrace(stack_frames,message);
443}
444
445/*---------------------------------------------------------------------------*/
446/*---------------------------------------------------------------------------*/
453stackTraceFunction(int function_index)
454{
455 unw_cursor_t cursor;
456 unw_context_t uc;
457 unw_word_t ip;
458 //unw_word_t offset;
459
460 String last_str;
461 if (m_want_gdb_info)
462 last_str = _getGDBStack();
463
464 unw_getcontext(&uc);
465 unw_init_local(&cursor, &uc);
466 int current_func = 0;
467 StringBuilder message;
468
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);
473 String func_name = pi.m_name;
474 message += func_name;
475 break;
476 }
477 ++current_func;
478 }
479 return StackTrace(message.toString()+last_str);
480}
481
482/*---------------------------------------------------------------------------*/
483/*---------------------------------------------------------------------------*/
484
487_backtraceStackFrame(int first_function)
488{
489 void *ips [256];
490 Integer size = backtrace (ips, 256);
491
492 FixedStackFrameArray stack_frames;
493 for( Integer i=first_function; i<size; ++i ){
494 stack_frames.addFrame(StackFrame((intptr_t)ips[i]));
495 }
496 return stack_frames;
497}
498
499/*---------------------------------------------------------------------------*/
500/*---------------------------------------------------------------------------*/
501
505{
506 const size_t buf_size = 100;
507 char hexa[buf_size+1];
508
509 StringBuilder message;
510 ConstArrayView<StackFrame> frames_view = stack_frames.view();
511 for( StackFrame f : frames_view ){
512 intptr_t ip = f.address();
513 ProcInfo pinfo = _getFuncInfo((void*)ip);
514 String func_name = pinfo.name();
515 message += " ";
516 snprintf(hexa,buf_size,"%10llx",(long long)ip);
517 message += hexa;
518 message += " ";
519 message += func_name;
520 message += "\n";
521 }
522 return StackTrace(stack_frames,message);
523}
524
525/*---------------------------------------------------------------------------*/
526/*---------------------------------------------------------------------------*/
539{
540 const size_t buf_size = 100;
541 char hexa[buf_size+1];
542
543 StringBuilder message;
544 ConstArrayView<StackFrame> frames_view = stack_frames.view();
545 for( StackFrame f : frames_view ){
546 intptr_t ip = f.address();
547 ProcInfo pinfo = _getFuncInfo(reinterpret_cast<const void*>(ip));
548 message += (pinfo.libraryFileName() ? pinfo.libraryFileName() : "()");
549 message += " ";
550 auto file_base_address = pinfo.m_file_loaded_address;
551 // Sous Linux (CentOS 6 et 7), l'adresse 0x400000 correspond à celle
552 // de chargement de l'exécutable mais si on retranche cette adresse de celle
553 // de la fonction alors le symboliser ne fonctionne pas (que ce soit
554 // llvm-symbolize ou addr2line)
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);
559 message += "0x";
560 message += hexa;
561 message += "\n";
562 }
563 return message;
564}
565
566/*---------------------------------------------------------------------------*/
567/*---------------------------------------------------------------------------*/
568
569/*---------------------------------------------------------------------------*/
570/*---------------------------------------------------------------------------*/
571
572class LLVMSymbolizerService
573: public TraceAccessor
574, public ISymbolizerService
575{
576 public:
577
578 explicit LLVMSymbolizerService(const ServiceBuildInfo& sbi)
580 {
581 _init();
582 }
583 explicit LLVMSymbolizerService(ITraceMng* tm)
584 : TraceAccessor(tm)
585 {
586 _init();
587 }
588
589 public:
590
591 void build() {}
592
593 public:
594
596
597 private:
598
599 String m_llvm_symbolizer_path;
600 bool m_is_check_done = false;
601 bool m_is_valid = false;
602
603 private:
604
607 {
608 if (m_is_check_done)
609 return;
610 // Avant appel à cette méthode, m_llvm_symbolizer_path doit contenir
611 // le nom du répertoire dans lequel se trouve llvm-symbolizer.
612 Directory dir(m_llvm_symbolizer_path);
613 String fullpath = dir.file("llvm-symbolizer");
614 Int64 length = platform::getFileLength(fullpath);
615 m_llvm_symbolizer_path = fullpath;
616 if (length>0)
617 m_is_valid = true;
618 m_is_check_done = true;
619 }
620 void _init()
621 {
622 m_llvm_symbolizer_path = platform::getEnvironmentVariable("ARCANE_LLVMSYMBOLIZER_PATH");
623 }
624};
625
626/*---------------------------------------------------------------------------*/
627/*---------------------------------------------------------------------------*/
628
631{
632 _checkValid();
633 if (!m_is_valid)
634 return String();
635 std::stringstream ostr;
636 // NOTE: le code ci dessous est similaire à
637 // LibUnwindStackTraceService::_generateFileAndOffset(). Il faudrait
638 // fusionner les deux.
639 for( Integer i=0, n=frames.size(); i<n; ++i ){
640 Dl_info dl_info;
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;
645 if (r2!=0){
646 dli_fname = dl_info.dli_fname;
647 // Adresse de base de chargement du fichier.
648 void* dli_fbase = dl_info.dli_fbase;
649 intptr_t true_base = reinterpret_cast<intptr_t>(dli_fbase);
650 // Sous Linux (CentOS 6 et 7), l'adresse 0x400000 correspond à celle
651 // de chargement de l'exécutable, mais si on retranche cette adresse de celle
652 // de la fonction alors le symboliser ne fonctionne pas (que ce soit
653 // llvm-symbolize ou addr2line)
654 if (true_base==0x400000)
655 true_base = 0;
656 base_address = addr - true_base;
657 }
658 // TODO: écrire base_address en hexa pour pouvoir le relire avec addr2line
659 ostr << (dli_fname ? dli_fname : "??") << " " << base_address << '\n';
660 }
661
662 std::string input_str(ostr.str());
663 String output_str;
664 ProcessExecArgs args;
665 args.setCommand(m_llvm_symbolizer_path);
666 Integer input_size = arcaneCheckArraySize(input_str.length());
667 ByteConstArrayView input_bytes(input_size, reinterpret_cast<const Byte*>(input_str.c_str()));
668 args.setInputBytes(input_bytes);
669 args.addArguments("--demangle");
670 args.addArguments("--pretty-print");
671 //args.addArguments("--print-source-context-lines=5");
672 Process::execute(args);
673 return String(args.outputBytes());
674}
675
676/*---------------------------------------------------------------------------*/
677/*---------------------------------------------------------------------------*/
678
680 ServiceProperty("LibUnwind",ST_Application),
682
684 ServiceProperty("LLVMSymbolizer",ST_Application),
686
687ARCANE_DI_REGISTER_PROVIDER(LibUnwindStackTraceService,
688 DependencyInjection::ProviderProperty("LibUnwind"),
689 ARCANE_DI_INTERFACES(IStackTraceService),
690 ARCANE_DI_CONSTRUCTOR(ITraceMng*));
691
692ARCANE_DI_REGISTER_PROVIDER(LLVMSymbolizerService,
693 DependencyInjection::ProviderProperty("LLVMSymbolizer"),
694 ARCANE_DI_INTERFACES(ISymbolizerService),
695 ARCANE_DI_CONSTRUCTOR(ITraceMng*));
696
697/*---------------------------------------------------------------------------*/
698/*---------------------------------------------------------------------------*/
699
700} // End namespace Arcane
701
702/*---------------------------------------------------------------------------*/
703/*---------------------------------------------------------------------------*/
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.
Definition Directory.h:35
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:40
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.
ISymbolizerService * getSymbolizerService()
Service utilisé pour obtenir des informations sur les symboles du code source.
ARCCORE_BASE_EXPORT long unsigned int getFileLength(const String &filename)
Longueur du fichier filename. Si le fichier n'est pas lisible ou n'existe pas, retourne 0.
ARCCORE_BASE_EXPORT String getEnvironmentVariable(const String &name)
Variable d'environnement du nom name.
String getGDBStack()
Récupère la pile d'appel via gdb.
-*- 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:476
unsigned char Byte
Type d'un octet.
Definition BaseTypes.h:43
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.