Arcane  v3.14.10.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-2022 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-2019 */
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 "arcane/AbstractService.h"
21#include "arcane/ServiceFactory.h"
22
23#include <Windows.h>
24#include <winnt.h>
25#include <DbgHelp.h>
26#include <string>
27#include <iostream>
28
29// TODO: protéger les appels à Sym* car les méthodes ne sont pas thread-safe.
30// TODO: ne pas retourner le chemin complet des fichiers mais uniquement les
31// 3 ou 4 derniers.
32
33/*---------------------------------------------------------------------------*/
34/*---------------------------------------------------------------------------*/
35
36namespace Arcane
37{
38
39/*---------------------------------------------------------------------------*/
40/*---------------------------------------------------------------------------*/
41
42class ARCANE_STD_EXPORT DbgHelpSymContainer
43{
44public:
45 void init()
46 {
47 _init();
48 }
49
50 FixedStackFrameArray getStackFrames(int first_function)
51 {
53 _init();
54 if (!m_is_good)
55 return frames;
56 _getStack(first_function,frames);
57 return frames;
58 }
60 {
61 return _getStackSymbols(frames);
62 }
63
64 private:
65 void _init()
66 {
67 if (m_is_init)
68 return;
69 m_is_init = true;
71 if (!::SymInitialize(::GetCurrentProcess(), nullptr, true)) {
72 m_is_good = false;
73 return;
74 }
75 m_is_good = true;
76 }
77 void _getStack(int first_function, FixedStackFrameArray& frames);
79private:
80 bool m_is_init = false;
81 bool m_is_good = false;
82};
83
84/*---------------------------------------------------------------------------*/
85/*---------------------------------------------------------------------------*/
86
87void DbgHelpSymContainer::
89{
90 // Ajoute (+2) pour prendre en compte l'appel à cette méthode et celle du dessus.
91 PVOID addrs[FixedStackFrameArray::MAX_FRAME] = { 0 };
92 USHORT nb_frame = CaptureStackBackTrace(first_function + 2, FixedStackFrameArray::MAX_FRAME, addrs, NULL);
93 for (USHORT i = 0; i < nb_frame; i++) {
94 frames.addFrame(StackFrame((intptr_t)addrs[i]));
95 }
96}
97
98/*---------------------------------------------------------------------------*/
99/*---------------------------------------------------------------------------*/
100
101String DbgHelpSymContainer::
102_getStackSymbols(ConstArrayView<StackFrame> frames)
103{
104 StringBuilder sb;
105 _init();
106 if (!m_is_good)
107 return String();
108 int nb_frame = frames.size();
109 for (USHORT i = 0; i < nb_frame; i++) {
110 DWORD64 addr = (DWORD64)frames[i].address();
111 // Allocate a buffer large enough to hold the symbol information on the stack and get
112 // a pointer to the buffer. We also have to set the size of the symbol structure itself
113 // and the number of bytes reserved for the name.
114 ULONG64 buffer[(sizeof(SYMBOL_INFO) + 1024 + sizeof(ULONG64) - 1) / sizeof(ULONG64)] = { 0 };
115 SYMBOL_INFO* info = (SYMBOL_INFO*)buffer;
116 info->SizeOfStruct = sizeof(SYMBOL_INFO);
117 info->MaxNameLen = 1024;
118
119 // Attempt to get information about the symbol and add it to our output parameter.
120 DWORD64 displacement = 0;
121 if (::SymFromAddr(::GetCurrentProcess(), addr, &displacement, info)) {
122
123 // Attempt to retrieve line number information.
124 DWORD line_displacement = 0;
125 IMAGEHLP_LINE64 line = {};
126 line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
127 BOOL has_line = SymGetLineFromAddr64(GetCurrentProcess(), addr, &line_displacement, &line);
128 sb.append(std::string_view(info->Name, info->NameLen));
129 sb.append("()");
130 if (has_line) {
131 sb.append(" ");
132 sb.append(line.FileName);
133 sb.append(":");
134 sb.append(String::fromNumber(line.LineNumber));
135 }
136 sb.append("\n");
137 }
138 }
139 return sb.toString();
140}
141
142/*---------------------------------------------------------------------------*/
143/*---------------------------------------------------------------------------*/
144
145namespace
146{
147 std::shared_ptr<DbgHelpSymContainer> m_sym_container;
148 std::shared_ptr<DbgHelpSymContainer> _getStaticContainer()
149 {
150 if (!m_sym_container.get())
151 m_sym_container = std::make_shared<DbgHelpSymContainer>();
152 return m_sym_container;
153 }
154}
155
156/*---------------------------------------------------------------------------*/
157/*---------------------------------------------------------------------------*/
158
159/*---------------------------------------------------------------------------*/
160/*---------------------------------------------------------------------------*/
164class ARCANE_STD_EXPORT DbgHelpStackTraceService
165: public AbstractService
166, public IStackTraceService
167{
168 public:
169
171 : AbstractService(sbi) { }
172
173 public:
174
175 void build() override {}
176
177 public:
178
179 StackTrace stackTrace(int first_function) override;
180 StackTrace stackTraceFunction(int function_index) override;
181
182 private:
183 std::shared_ptr<DbgHelpSymContainer> m_sym_container;
184 DbgHelpSymContainer* _getContainer()
185 {
186 if (!m_sym_container.get())
187 m_sym_container = _getStaticContainer();
188 return m_sym_container.get();
189 }
190};
191
192/*---------------------------------------------------------------------------*/
193/*---------------------------------------------------------------------------*/
194
197{
198 std::cout << "GET STACK TRACE1\n";
199 DbgHelpSymContainer* c = _getContainer();
200 FixedStackFrameArray frames = c->getStackFrames(first_function);
201 String text = c->getStackSymbols(frames.view());
202 return StackTrace(frames,text);
203}
204
205/*---------------------------------------------------------------------------*/
206/*---------------------------------------------------------------------------*/
207
210{
211 std::cout << "GET STACK TRACE2\n";
212 return StackTrace();
213}
214
215/*---------------------------------------------------------------------------*/
216/*---------------------------------------------------------------------------*/
217
218/*---------------------------------------------------------------------------*/
219/*---------------------------------------------------------------------------*/
223class ARCANE_STD_EXPORT DbgHelpSymbolizerService
224: public AbstractService
225, public ISymbolizerService
226{
227 private:
228 public:
231 {}
232
233 public:
234 void build() override {}
235
236 public:
238 {
239 return _getContainer()->getStackSymbols(frames);
240 }
241
242 private:
243 std::shared_ptr<DbgHelpSymContainer> m_sym_container;
244 DbgHelpSymContainer* _getContainer()
245 {
246 if (!m_sym_container.get())
247 m_sym_container = _getStaticContainer();
248 return m_sym_container.get();
249 }
250};
251
252/*---------------------------------------------------------------------------*/
253/*---------------------------------------------------------------------------*/
254
255ARCANE_REGISTER_SERVICE(DbgHelpStackTraceService,
256 ServiceProperty("DbgHelpStackTraceService",ST_Application),
257 ARCANE_SERVICE_INTERFACE(IStackTraceService));
258
259ARCANE_REGISTER_SERVICE(DbgHelpSymbolizerService,
260 ServiceProperty("DbgHelpSymbolizerService",ST_Application),
261 ARCANE_SERVICE_INTERFACE(ISymbolizerService));
262
263/*---------------------------------------------------------------------------*/
264/*---------------------------------------------------------------------------*/
265
266} // End namespace Arcane
267
268/*---------------------------------------------------------------------------*/
269/*---------------------------------------------------------------------------*/
#define ARCANE_SERVICE_INTERFACE(ainterface)
Macro pour déclarer une interface lors de l'enregistrement d'un service.
Classe de base d'un service.
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.
void build() override
Construction de niveau build du service.
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.
void build() override
Construction de niveau build du service.
String stackTrace(ConstArrayView< StackFrame > frames) override
Informations pour la pile d'appel frames.
Interface d'un service de récupération des symboles du code source.
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Definition Lima.cc:120
Structure contenant les informations pour créer un service.
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.
Informations sur la pile d'appel des fonctions.
Chaîne de caractères unicode.
#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.