Arcane  v4.1.1.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
BackwardCppStackTraceService.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/* BackwardCppStackTraceService.cc (C) 2000-2025 */
9/* */
10/* Service de trace des appels de fonctions utilisant 'backward-cpp'. */
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/Convert.h"
19
21#include "arcane/core/AbstractService.h"
22
23#include "arcane_packages.h"
24
25//TODO : Ajouter les autres packages.
26#define BACKWARD_HAS_DW 1
27
28#if defined(ARCANE_HAS_PACKAGE_LIBUNWIND)
29#define BACKWARD_HAS_LIBUNWIND 1
30#endif
31
32#include "arcane/std/internal/backwardcpp/backward.hpp"
33
34/*---------------------------------------------------------------------------*/
35/*---------------------------------------------------------------------------*/
36
37namespace Arcane
38{
39
40/*---------------------------------------------------------------------------*/
41/*---------------------------------------------------------------------------*/
42
43class BackwardCppStackTraceService
44: public AbstractService
45, public IStackTraceService
46{
47
48 public:
49
50 explicit BackwardCppStackTraceService(const ServiceBuildInfo& sbi)
51 : AbstractService(sbi)
52 , m_verbose_level(2)
53 , m_human_readable(true)
54 {}
55
56 public:
57
58 void build() override
59 {
60 // 0 : CallStack classique (nom de fonction uniquement)
61 // 1 : CallStack classique avec numéro de ligne et fichier pour les classes/fonctions hors du namespace Arcane
62 // 2 : (default) CallStack classique avec numéro de ligne et fichier pour toutes les classes/fonctions
63 // 3 : CallStack classique avec numéro de ligne, fichier pour toutes les classes/fonctions et snippet pour les classes/fonctions hors du namespace Arcane
64 // 4 : CallStack classique avec numéro de ligne, fichier et snippet pour toutes les classes/fonctions
65 if (const auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_CALLSTACK_VERBOSE", true)) {
66 if (v.value() < 0 || v.value() > 4) {
67 return;
68 }
69 m_verbose_level = v.value();
70 }
71
72 // Permet d'ajouter les espaces entre les appels dans la pile d'appel et
73 // d'afficher le numéro de ligne avant le chemin du fichier source.
74 // Sinon, on affiche le chemin du fichier et le numéro de ligne de manière
75 // lisible par les debuggers/IDE (path:line).
76 // Défaut = true.
77 if (const auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_CALLSTACK_HUMAN_READABLE", true)) {
78 m_human_readable = (v.value() != 0);
79 }
80 }
81
82 public:
83
84 StackTrace stackTrace(int first_function) override;
85 StackTrace stackTraceFunction(int function_index) override;
86
87 private:
88
89 Int32 m_verbose_level;
90 bool m_human_readable;
91};
92
93/*---------------------------------------------------------------------------*/
94/*---------------------------------------------------------------------------*/
95
97stackTrace(int first_function)
98{
99 StringBuilder message;
100 FixedStackFrameArray stack_frames;
101 constexpr size_t hexa_buf_size = 100;
102 char hexa[hexa_buf_size + 1];
103
104 backward::StackTrace st;
105 st.skip_n_firsts(first_function);
106 st.load_here(64);
107
108 backward::TraceResolver tr;
109 tr.load_stacktrace(st);
110
111 backward::SnippetFactory sf;
112
113 for (size_t i = 0; i < st.size(); ++i) {
114 backward::ResolvedTrace trace = tr.resolve(st[i]);
115 message += " ";
116 snprintf(hexa, hexa_buf_size, "%14p", trace.addr);
117 message += hexa;
118 message += " ";
119 message += trace.object_function;
120
121 UInt32 src_line = trace.source.line;
122
123 if (m_verbose_level > 0 && src_line > 0) {
124 bool arcane_function = String(trace.object_function).startsWith("Arcane");
125 if (m_verbose_level > 1 || !arcane_function) {
126 auto lines = sf.get_snippet(trace.source.filename, src_line, 5);
127 if (m_human_readable) {
128 message += "\n Line: ";
129 message += src_line;
130 message += " -- File: ";
131 message += trace.source.filename;
132 }
133 else {
134 message += "\n ";
135 message += trace.source.filename;
136 message += ":";
137 message += src_line;
138 }
139 if (m_verbose_level > 3 || (m_verbose_level > 2 && !arcane_function)) {
140 for (const auto& [line_num, line] : lines) {
141 message += (line_num == src_line ? "\n >>> " : "\n ");
142 message += line_num;
143 message += ": ";
144 message += line;
145 }
146 }
147 }
148 }
149
150 if (m_human_readable)
151 message += "\n\n";
152 else
153 message += "\n";
154
155 stack_frames.addFrame(StackFrame(reinterpret_cast<intptr_t>(trace.addr)));
156 }
157
158 return { stack_frames, message };
159}
160
161/*---------------------------------------------------------------------------*/
162/*---------------------------------------------------------------------------*/
163
165stackTraceFunction(int function_index)
166{
167 backward::StackTrace st;
168 st.skip_n_firsts(function_index);
169 st.load_here(1);
170
171 if (st.size() < 1) {
172 return {};
173 }
174 backward::TraceResolver tr;
175 tr.load_stacktrace(st);
176
177 backward::ResolvedTrace trace = tr.resolve(st[0]);
178
179 return { trace.object_function };
180}
181
182/*---------------------------------------------------------------------------*/
183/*---------------------------------------------------------------------------*/
184
186 ServiceProperty("BackwardCppStackTraceService", ST_Application),
188
189/*---------------------------------------------------------------------------*/
190/*---------------------------------------------------------------------------*/
191
192} // End namespace Arcane
193
194/*---------------------------------------------------------------------------*/
195/*---------------------------------------------------------------------------*/
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.
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
Nom d'une fonction dans la pile d'appel.
Classe template pour convertir un type.
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 d'un service de trace des appels de fonctions.
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.
Chaîne de caractères unicode.
bool startsWith(const String &s) const
Indique si la chaîne commence par les caractères de s.
Definition String.cc:1100
#define ARCANE_REGISTER_SERVICE(aclass, a_service_property,...)
Macro pour enregistrer un service.
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
std::uint32_t UInt32
Type entier non signé sur 32 bits.
@ ST_Application
Le service s'utilise au niveau de l'application.
std::int32_t Int32
Type entier signé sur 32 bits.