Arcane  v4.1.2.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
DbgHelpStackTraceService.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/* DbgHelpStackTraceService.cc (C) 2000-2025 */
9/* */
10/* Service de trace des appels de fonctions utilisant 'DbgHelp'. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/String.h"
15#include "arcane/utils/IStackTraceService.h"
16#include "arcane/utils/ISymbolizerService.h"
17#include "arcane/utils/NotImplementedException.h"
18#include "arcane/utils/StringBuilder.h"
19
20#include "arccore/base/internal/DependencyInjection.h"
21
22#include "arcane/core/AbstractService.h"
24
25#include <Windows.h>
26#include <winnt.h>
27#include <DbgHelp.h>
28#include <string>
29#include <iostream>
30
31// TODO: protéger les appels à Sym* car les méthodes ne sont pas thread-safe.
32// TODO: ne pas retourner le chemin complet des fichiers mais uniquement les
33// 3 ou 4 derniers.
34
35/*---------------------------------------------------------------------------*/
36/*---------------------------------------------------------------------------*/
37
38namespace Arcane
39{
40
41/*---------------------------------------------------------------------------*/
42/*---------------------------------------------------------------------------*/
43
44class ARCANE_STD_EXPORT DbgHelpSymContainer
45{
46public:
47 void init()
48 {
49 _init();
50 }
51
52 FixedStackFrameArray getStackFrames(int first_function)
53 {
55 _init();
56 if (!m_is_good)
57 return frames;
58 _getStack(first_function,frames);
59 return frames;
60 }
61 String getStackSymbols(ConstArrayView<StackFrame> frames)
62 {
63 return _getStackSymbols(frames);
64 }
65
66 private:
67 void _init()
68 {
69 if (m_is_init)
70 return;
71 m_is_init = true;
72 ::SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES);
73 if (!::SymInitialize(::GetCurrentProcess(), nullptr, true)) {
74 m_is_good = false;
75 return;
76 }
77 m_is_good = true;
78 }
79 void _getStack(int first_function, FixedStackFrameArray& frames);
80 String _getStackSymbols(ConstArrayView<StackFrame> frames);
81private:
82 bool m_is_init = false;
83 bool m_is_good = false;
84};
85
86/*---------------------------------------------------------------------------*/
87/*---------------------------------------------------------------------------*/
88
89void DbgHelpSymContainer::
90_getStack(int first_function, FixedStackFrameArray& frames)
91{
92 // Ajoute (+2) pour prendre en compte l'appel à cette méthode et celle du dessus.
93 PVOID addrs[FixedStackFrameArray::MAX_FRAME] = { 0 };
94 USHORT nb_frame = CaptureStackBackTrace(first_function + 2, FixedStackFrameArray::MAX_FRAME, addrs, NULL);
95 for (USHORT i = 0; i < nb_frame; i++) {
96 frames.addFrame(StackFrame((intptr_t)addrs[i]));
97 }
98}
99
100/*---------------------------------------------------------------------------*/
101/*---------------------------------------------------------------------------*/
102
103String DbgHelpSymContainer::
104_getStackSymbols(ConstArrayView<StackFrame> frames)
105{
106 StringBuilder sb;
107 _init();
108 if (!m_is_good)
109 return String();
110 int nb_frame = frames.size();
111 for (USHORT i = 0; i < nb_frame; i++) {
112 DWORD64 addr = (DWORD64)frames[i].address();
113 // Allocate a buffer large enough to hold the symbol information on the stack and get
114 // a pointer to the buffer. We also have to set the size of the symbol structure itself
115 // and the number of bytes reserved for the name.
116 ULONG64 buffer[(sizeof(SYMBOL_INFO) + 1024 + sizeof(ULONG64) - 1) / sizeof(ULONG64)] = { 0 };
117 SYMBOL_INFO* info = (SYMBOL_INFO*)buffer;
118 info->SizeOfStruct = sizeof(SYMBOL_INFO);
119 info->MaxNameLen = 1024;
120
121 // Attempt to get information about the symbol and add it to our output parameter.
122 DWORD64 displacement = 0;
123 if (::SymFromAddr(::GetCurrentProcess(), addr, &displacement, info)) {
124
125 // Attempt to retrieve line number information.
126 DWORD line_displacement = 0;
127 IMAGEHLP_LINE64 line = {};
128 line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
129 BOOL has_line = SymGetLineFromAddr64(GetCurrentProcess(), addr, &line_displacement, &line);
130 sb.append(std::string_view(info->Name, info->NameLen));
131 sb.append("()");
132 if (has_line) {
133 sb.append(" ");
134 sb.append(line.FileName);
135 sb.append(":");
136 sb.append(String::fromNumber(line.LineNumber));
137 }
138 sb.append("\n");
139 }
140 }
141 return sb.toString();
142}
143
144/*---------------------------------------------------------------------------*/
145/*---------------------------------------------------------------------------*/
146
147namespace
148{
149 std::shared_ptr<DbgHelpSymContainer> m_sym_container;
150 std::shared_ptr<DbgHelpSymContainer> _getStaticContainer()
151 {
152 if (!m_sym_container.get())
153 m_sym_container = std::make_shared<DbgHelpSymContainer>();
154 return m_sym_container;
155 }
156}
157
158/*---------------------------------------------------------------------------*/
159/*---------------------------------------------------------------------------*/
160
161/*---------------------------------------------------------------------------*/
162/*---------------------------------------------------------------------------*/
166class DbgHelpStackTraceService
167: public TraceAccessor
168, public IStackTraceService
169{
170 public:
171
172 explicit DbgHelpStackTraceService(const ServiceBuildInfo& sbi)
174 {
175 }
176 explicit DbgHelpStackTraceService(ITraceMng* tm)
177 : TraceAccessor(tm)
178 {
179 }
180
181 public:
182
183 void build() {}
184
185 public:
186
187 StackTrace stackTrace(int first_function) override;
188 StackTrace stackTraceFunction(int function_index) override;
189
190 private:
191 std::shared_ptr<DbgHelpSymContainer> m_sym_container;
192 DbgHelpSymContainer* _getContainer()
193 {
194 if (!m_sym_container.get())
195 m_sym_container = _getStaticContainer();
196 return m_sym_container.get();
197 }
198};
199
200/*---------------------------------------------------------------------------*/
201/*---------------------------------------------------------------------------*/
202
204stackTrace(int first_function)
205{
206 DbgHelpSymContainer* c = _getContainer();
207 FixedStackFrameArray frames = c->getStackFrames(first_function);
208 String text = c->getStackSymbols(frames.view());
209 return StackTrace(frames,text);
210}
211
212/*---------------------------------------------------------------------------*/
213/*---------------------------------------------------------------------------*/
214
216stackTraceFunction(int function_index)
217{
218 return StackTrace();
219}
220
221/*---------------------------------------------------------------------------*/
222/*---------------------------------------------------------------------------*/
223
224/*---------------------------------------------------------------------------*/
225/*---------------------------------------------------------------------------*/
229class DbgHelpSymbolizerService
230: public TraceAccessor
231, public ISymbolizerService
232{
233 public:
234
235 explicit DbgHelpSymbolizerService(const ServiceBuildInfo& sbi)
237 {}
238 explicit DbgHelpSymbolizerService(ITraceMng* tm)
239 : TraceAccessor(tm)
240 {
241 }
242
243 public:
244
245 void build() {}
246
247 public:
248
250 {
251 return _getContainer()->getStackSymbols(frames);
252 }
253
254 private:
255 std::shared_ptr<DbgHelpSymContainer> m_sym_container;
256 DbgHelpSymContainer* _getContainer()
257 {
258 if (!m_sym_container.get())
259 m_sym_container = _getStaticContainer();
260 return m_sym_container.get();
261 }
262};
263
264/*---------------------------------------------------------------------------*/
265/*---------------------------------------------------------------------------*/
266
268 ServiceProperty("DbgHelpStackTraceService",ST_Application),
270
272 ServiceProperty("DbgHelpSymbolizerService",ST_Application),
274
275ARCANE_DI_REGISTER_PROVIDER(DbgHelpStackTraceService,
276 DependencyInjection::ProviderProperty("DbgHelpStackTraceService"),
277 ARCANE_DI_INTERFACES(IStackTraceService),
278 ARCANE_DI_CONSTRUCTOR(ITraceMng*));
279
280ARCANE_DI_REGISTER_PROVIDER(DbgHelpSymbolizerService,
281 DependencyInjection::ProviderProperty("DbgHelpSymbolizerService"),
282 ARCANE_DI_INTERFACES(ISymbolizerService),
283 ARCANE_DI_CONSTRUCTOR(ITraceMng*));
284
285/*---------------------------------------------------------------------------*/
286/*---------------------------------------------------------------------------*/
287
288} // End namespace Arcane
289
290/*---------------------------------------------------------------------------*/
291/*---------------------------------------------------------------------------*/
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.
Service de trace des appels de fonctions utilisant 'DbgHelp'.
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.
Service de trace des appels de fonctions utilisant la libunwind.
String stackTrace(ConstArrayView< StackFrame > frames) override
Informations pour la pile d'appel frames.
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.
Interface du gestionnaire de traces.
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.
Informations sur la pile d'appel des fonctions.
Chaîne de caractères unicode.
TraceAccessor(ITraceMng *m)
Construit un accesseur via le gestionnaire de trace m.
#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 -*-
@ ST_Application
Le service s'utilise au niveau de l'application.