libexcept 1.1.21
Stack trace along C++ exceptions
stack_trace.cpp
Go to the documentation of this file.
1// Copyright (c) 2011-2025 Made to Order Software Corp. All Rights Reserved
2//
3// https://snapwebsites.org/
4// contact@m2osw.com
5//
6// This program is free software; you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation; either version 2 of the License, or
9// (at your option) any later version.
10//
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with this program; if not, write to the Free Software
18// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19
20// self
21//
22#include "libexcept/exception.h"
23
24#include "libexcept/demangle.h"
25
26
27// C++
28//
29#include <iostream>
30#include <memory>
31#include <vector>
32
33
34// C
35//
36#include <backtrace.h>
37#include <execinfo.h>
38#include <link.h>
39#include <unistd.h>
40
41
60namespace libexcept
61{
62namespace
63{
64
65
66
81bool g_extended_stack = false;
82
83
95void error_callback(void * data, char const * msg, int err)
96{
97 static_cast<void>(data);
98
99 std::cerr
100 << "libbacktrace error: "
101 << msg
102 << " ("
103 << err
104 << ")\n";
105}
106
107
119backtrace_state * get_backtrace_state()
120{
121 static backtrace_state * g_backtrace_state = backtrace_create_state(
122 nullptr
123 , 1
125 , nullptr);
126
127 return g_backtrace_state;
128}
129
130
141{
142 typedef std::list<symbol_info> list_t;
143
144 uintptr_t f_pc = 0;
145 std::string f_filename = std::string();
146 std::string f_function = std::string();
147 int f_line = 0;
148};
149
150
172 void * data
173 , uintptr_t pc
174 , char const * filename
175 , int line
176 , char const * function)
177{
178 symbol_info::list_t * info_list(static_cast<symbol_info::list_t *>(data));
179
180 symbol_info info{
181 .f_pc = pc,
182 .f_filename = filename == nullptr ? std::string() : filename,
183 .f_function = function == nullptr ? std::string() : demangle_cpp_name(function),
184 .f_line = line
185 };
186
187 info_list->push_back(info);
188
189 return 0;
190}
191
192
193
194}
195// no name namespace
196
197
198
212void set_extended_stack(bool extended_stack)
213{
214 g_extended_stack = extended_stack;
215}
216
217
230{
231 return g_extended_stack;
232}
233
234
273stack_trace_t collect_stack_trace(int stack_trace_depth)
274{
275 stack_trace_t stack_trace;
276
277 if(stack_trace_depth > 0)
278 {
279 std::vector<void *> array;
280 array.resize(std::max(stack_trace_depth, 1'000));
281 int const size(backtrace(&array[0], stack_trace_depth));
282
283 // save a copy of the system array in our class
284 //
285 std::unique_ptr<char *, decltype(&::free)> stack_string_list(backtrace_symbols(&array[0], size), &::free);
286 if(stack_string_list != nullptr)
287 {
288 for(int idx(0); idx < size; ++idx)
289 {
290 char const * stack_string(stack_string_list.get()[idx]);
291 stack_trace.push_back(stack_string);
292 }
293 }
294 }
295
296 return stack_trace;
297}
298
299
334{
335 stack_trace_t stack_trace;
336
337 if(stack_trace_depth > 0)
338 {
339 std::vector<void *> array;
340 // the libexcept adds 3 frames, hence that +3
341 array.resize(std::max(stack_trace_depth + 3, 1'000));
342 int const size(backtrace(&array[0], stack_trace_depth));
343 backtrace_state * state(get_backtrace_state());
344 for(int idx(0); idx < size; ++idx)
345 {
346 if(state != nullptr)
347 {
348 symbol_info::list_t info_list;
349 backtrace_pcinfo(
350 state
351 , reinterpret_cast<uintptr_t>(array[idx])
352 , backtrace_callback
353 , error_callback
354 , &info_list);
355 bool found(false);
356 for(auto & info : info_list)
357 {
358 if(!info.f_filename.empty())
359 {
360 found = true;
361 if(!g_extended_stack
362 && info.f_function.starts_with("libexcept::"))
363 {
364 // don't include the libexcept::... frames; it's
365 // always the same and not really useful
366 //
367 continue;
368 }
369 if(info.f_function == "main")
370 {
371 if(!g_extended_stack)
372 {
373 // done after that one
374 //
375 idx = size;
376 }
377
378 // this is likely correct, although it could include
379 // the environment and that won't show here
380 //
381 info.f_function = "main(int, char *[])";
382 }
383 std::string result(info.f_filename);
384 result += ':';
385 result += std::to_string(info.f_line);
386 result += " in ";
387 result += info.f_function;
388 stack_trace.push_back(result);
389 }
390 }
391 if(found)
392 {
393 continue;
394 }
395 }
396
397 // use ugly fallback; in most cases those are for system
398 // libraries that do not have symbols available
399 //
400 std::unique_ptr<char *, decltype(&::free)> stack_string_list(backtrace_symbols(&array[idx], 1), &::free);
401 if(stack_string_list.get() != nullptr)
402 {
403 stack_trace.push_back(stack_string_list.get()[0]);
404 }
405 }
406 }
407
408 return stack_trace;
409}
410
411
412
413
414}
415// namespace libexcept
416// vim: ts=4 sw=4 et
Declarations of demangle functions we support.
Declarations of the exception library.
int backtrace_callback(void *data, uintptr_t pc, char const *filename, int line, char const *function)
Call back with backtrace data.
bool g_extended_stack
The extended stack flag.
backtrace_state * get_backtrace_state()
Retrieve a pointer to the backtrace state.
void error_callback(void *data, char const *msg, int err)
Capture errors while running backtrace_pcinfo().
void set_extended_stack(bool extended_stack)
Set the extended stack flag status.
bool get_extended_stack()
Get the extended stack flag status.
stack_trace_t collect_stack_trace(int stack_trace_depth)
Collect the raw stack trace in a list of strings.
std::string demangle_cpp_name(char const *type_id_name)
Demangle the specified type string.
Definition demangle.cpp:95
std::list< std::string > stack_trace_t
The stack trace results.
Definition stack_trace.h:41
stack_trace_t collect_stack_trace_with_line_numbers(int stack_trace_depth)
Collect the stack trace in a list of strings.
Structure used to collect symbol information.

This document is part of the Snap! Websites Project.

Copyright by Made to Order Software Corp.