Arcane  4.1.12.0
Developer documentation
Loading...
Searching...
No Matches
BackwardCppStackTraceService.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/* BackwardCppStackTraceService.cc (C) 2000-2026 */
9/* */
10/* Function call tracing service using 'backward-cpp'. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/PlatformUtils.h"
15#include "arcane/utils/IStackTraceService.h"
16#include "arcane/utils/StringBuilder.h"
17#include "arcane/utils/Convert.h"
18
20#include "arcane/core/AbstractService.h"
21
22#include "arcane_packages.h"
23#include "arccore/base/internal/DependencyInjection.h"
24
25//TODO: Add the other 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 TraceAccessor
45, public IStackTraceService
46{
47
48 public:
49
50 explicit BackwardCppStackTraceService(const ServiceBuildInfo& sbi)
52 , m_verbose_level(2)
53 , m_human_readable(true)
54 {}
55
56 explicit BackwardCppStackTraceService(ITraceMng* tm)
57 : TraceAccessor(tm)
58 , m_verbose_level(2)
59 , m_human_readable(true)
60 {
61 BackwardCppStackTraceService::build();
62 }
63
64 public:
65
66 void build() override
67 {
68 // 0 : Classic CallStack (function name only)
69 // 1 : Classic CallStack with line number and file for classes/functions outside the Arcane namespace
70 // 2 : (default) Classic CallStack with line number and file for all classes/functions
71 // 3 : Classic CallStack with line number, file for all classes/functions and snippet for classes/functions outside the Arcane namespace
72 // 4 : Classic CallStack with line number, file and snippet for all classes/functions
73 if (const auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_CALLSTACK_VERBOSE", true)) {
74 if (v.value() < 0 || v.value() > 4) {
75 return;
76 }
77 m_verbose_level = v.value();
78 }
79
80 // Allows adding spaces between calls in the call stack and
81 // displaying the line number before the source file path.
82 // Otherwise, the file path and line number are displayed in a way
83 // readable by debuggers/IDEs (path:line).
84 // Default = true.
85 if (const auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_CALLSTACK_HUMAN_READABLE", true)) {
86 m_human_readable = (v.value() != 0);
87 }
88 }
89
90 public:
91
92 StackTrace stackTrace(int first_function) override;
93 StackTrace stackTraceFunction(int function_index) override;
94
95 private:
96
97 Int32 m_verbose_level;
98 bool m_human_readable;
99};
100
101/*---------------------------------------------------------------------------*/
102/*---------------------------------------------------------------------------*/
103
105stackTrace(int first_function)
106{
107 StringBuilder message;
108 FixedStackFrameArray stack_frames;
109 constexpr size_t hexa_buf_size = 100;
110 char hexa[hexa_buf_size + 1];
111
112 backward::StackTrace st;
113 st.skip_n_firsts(first_function);
114 st.load_here(64);
115
116 backward::TraceResolver tr;
117 tr.load_stacktrace(st);
118
119 backward::SnippetFactory sf;
120
121 for (size_t i = 0; i < st.size(); ++i) {
122 backward::ResolvedTrace trace = tr.resolve(st[i]);
123 message += " ";
124 snprintf(hexa, hexa_buf_size, "%14p", trace.addr);
125 message += hexa;
126 message += " ";
127 message += trace.object_function;
128
129 UInt32 src_line = trace.source.line;
130
131 if (m_verbose_level > 0 && src_line > 0) {
132 bool arcane_function = String(trace.object_function).startsWith("Arcane");
133 if (m_verbose_level > 1 || !arcane_function) {
134 auto lines = sf.get_snippet(trace.source.filename, src_line, 5);
135 if (m_human_readable) {
136 message += "\n Line: ";
137 message += src_line;
138 message += " -- File: ";
139 message += trace.source.filename;
140 }
141 else {
142 message += "\n ";
143 message += trace.source.filename;
144 message += ":";
145 message += src_line;
146 }
147 if (m_verbose_level > 3 || (m_verbose_level > 2 && !arcane_function)) {
148 for (const auto& [line_num, line] : lines) {
149 message += (line_num == src_line ? "\n >>> " : "\n ");
150 message += line_num;
151 message += ": ";
152 message += line;
153 }
154 }
155 }
156 }
157
158 if (m_human_readable)
159 message += "\n\n";
160 else
161 message += "\n";
162
163 stack_frames.addFrame(StackFrame(reinterpret_cast<intptr_t>(trace.addr)));
164 }
165
166 return { stack_frames, message };
167}
168
169/*---------------------------------------------------------------------------*/
170/*---------------------------------------------------------------------------*/
171
173stackTraceFunction(int function_index)
174{
175 backward::StackTrace st;
176 st.skip_n_firsts(function_index);
177 st.load_here(1);
178
179 if (st.size() < 1) {
180 return {};
181 }
182 backward::TraceResolver tr;
183 tr.load_stacktrace(st);
184
185 backward::ResolvedTrace trace = tr.resolve(st[0]);
186
187 return { trace.object_function };
188}
189
190/*---------------------------------------------------------------------------*/
191/*---------------------------------------------------------------------------*/
192
194 ServiceProperty("BackwardCppStackTraceService", ST_Application),
196
197ARCANE_DI_REGISTER_PROVIDER(BackwardCppStackTraceService,
198 DependencyInjection::ProviderProperty("BackwardCppStackTraceService"),
199 ARCANE_DI_INTERFACES(IStackTraceService),
200 ARCANE_DI_CONSTRUCTOR(ITraceMng*));
201
202/*---------------------------------------------------------------------------*/
203/*---------------------------------------------------------------------------*/
204
205} // End namespace Arcane
206
207/*---------------------------------------------------------------------------*/
208/*---------------------------------------------------------------------------*/
This file contains the various service factories and macros for registering services.
#define ARCANE_SERVICE_INTERFACE(ainterface)
Macro to declare an interface when registering a service.
StackTrace stackTrace(int first_function) override
Character string indicating the call stack.
StackTrace stackTraceFunction(int function_index) override
Name of a function in the call stack.
Template class for converting a type.
Stores a fixed maximum size list of StackFrame.
void addFrame(const StackFrame &frame)
Adds a frame to the list of frames. If nbFrame() is greater than or equal to MAX_FRAME,...
virtual ITraceMng * traceMng() const =0
Trace manager.
Interface of a function call tracing service.
IApplication * application() const
Access to the associated IApplication.
Structure containing the information to create a service.
Service creation properties.
Stores the addresses corresponding to a call stack. This class is internal and should not be used out...
Information about function call stacks.
Unicode character string constructor.
bool startsWith(const String &s) const
Indicates if the string starts with the characters of s.
Definition String.cc:1111
TraceAccessor(ITraceMng *m)
Constructs an accessor via the trace manager m.
#define ARCANE_REGISTER_SERVICE(aclass, a_service_property,...)
Macro for registering a service.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
std::uint32_t UInt32
Unsigned integer type of 32 bits.
@ ST_Application
The service is used at the application level.
std::int32_t Int32
Signed integer type of 32 bits.