35#ifdef HAVE_TEUCHOS_STACKTRACE
61#ifdef HAVE_TEUCHOS_LINK
66#ifdef HAVE_TEUCHOS_BFD
72typedef long long unsigned bfd_vma;
85#ifdef HAVE_TEUCHOS_BFD
86 asymbol **symbol_table;
90 std::string function_name;
97bool is_whitespace_char(
const char c)
99 return c ==
' ' || c ==
'\t';
106std::string remove_leading_whitespace(
const std::string &str)
108 if (str.length() && is_whitespace_char(str[0])) {
109 int first_nonwhitespace_index = 0;
110 for (
int i = 0; i < static_cast<int>(str.length()); ++i) {
111 if (!is_whitespace_char(str[i])) {
112 first_nonwhitespace_index = i;
116 return str.substr(first_nonwhitespace_index);
123std::string read_line_from_file(std::string
filename,
unsigned int line_number)
129 if (line_number == 0) {
130 return "Line number must be positive";
134 while (n < line_number) {
136 return "Line not found";
149std::string demangle_function_name(std::string name)
153 if (name.length() == 0) {
158 d = abi::__cxa_demangle(name.c_str(), 0, 0, &status);
171#ifdef HAVE_TEUCHOS_BFD
181void process_section(bfd *abfd, asection *section,
void *_data)
183 line_data *data = (line_data*)_data;
184 if (data->line_found) {
188 if ((bfd_get_section_flags(abfd, section) & SEC_ALLOC) == 0) {
192 bfd_vma section_vma = bfd_get_section_vma(abfd, section);
193 if (data->addr < section_vma) {
198 bfd_size_type section_size = bfd_section_size(abfd, section);
199 if (data->addr >= section_vma + section_size) {
205 bfd_vma offset = data->addr - section_vma - 1;
209 const char *
filename=NULL, *function_name=NULL;
210 data->line_found = bfd_find_nearest_line(abfd, section, data->symbol_table,
211 offset, &
filename, &function_name, &data->line);
218 if (function_name == NULL)
219 data->function_name =
"";
221 data->function_name = function_name;
226int load_symbol_table(bfd *abfd, line_data *data)
228 if ((bfd_get_file_flags(abfd) & HAS_SYMS) == 0)
232 void **symbol_table_ptr =
reinterpret_cast<void **
>(&data->symbol_table);
234 unsigned int symbol_size;
235 n_symbols = bfd_read_minisymbols(abfd,
false, symbol_table_ptr, &symbol_size);
236 if (n_symbols == 0) {
239 if (data->symbol_table != NULL)
240 free(data->symbol_table);
242 n_symbols = bfd_read_minisymbols(abfd,
true, symbol_table_ptr, &symbol_size);
265std::string addr2str(std::string file_name, bfd_vma addr)
267#ifdef HAVE_TEUCHOS_BFD
270 abfd = bfd_openr(file_name.c_str(), NULL);
272 return "Cannot open the binary file '" + file_name +
"'\n";
273 if (bfd_check_format(abfd, bfd_archive))
274 return "Cannot get addresses from the archive '" + file_name +
"'\n";
276 if (!bfd_check_format_matches(abfd, bfd_object, &matching))
277 return "Unknown format of the binary file '" + file_name +
"'\n";
280 data.symbol_table = NULL;
281 data.line_found =
false;
283 if (load_symbol_table(abfd, &data) == 1)
284 return "Failed to load the symbol table from '" + file_name +
"'\n";
286 bfd_map_over_sections(abfd, process_section, &data);
288 if (data.symbol_table != NULL) free(data.symbol_table);
295 std::ostringstream s;
298 if (!data.line_found) {
300 s <<
" File unknown, address: 0x" << (
long long unsigned int) addr;
302 std::string name = demangle_function_name(data.function_name);
303 if (data.filename.length() > 0) {
305 s <<
" File \"" << data.filename <<
"\", line "
306 << data.line <<
", in " << name;
307 const std::string line_text = remove_leading_whitespace(
308 read_line_from_file(data.filename, data.line));
309 if (line_text !=
"") {
310 s <<
"\n " << line_text;
315 s <<
" File unknown, in " << name;
326 bfd_vma addr_in_file;
330#ifdef HAVE_TEUCHOS_LINK
337int shared_lib_callback(
struct dl_phdr_info *info,
338 size_t size,
void *_data)
340 struct match_data *data = (
struct match_data *)_data;
341 for (
int i=0; i < info->dlpi_phnum; i++) {
342 if (info->dlpi_phdr[i].p_type == PT_LOAD) {
343 ElfW(Addr) min_addr = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr;
344 ElfW(Addr) max_addr = min_addr + info->dlpi_phdr[i].p_memsz;
345 if ((data->addr >= min_addr) && (data->addr < max_addr)) {
346 data->filename = info->dlpi_name;
347 data->addr_in_file = data->addr - info->dlpi_addr;
364class StacktraceAddresses {
365 std::vector<bfd_vma> stacktrace_buffer;
366 int impl_stacktrace_depth;
368 StacktraceAddresses(
void *
const *_stacktrace_buffer,
int _size,
int _impl_stacktrace_depth)
369 : impl_stacktrace_depth(_impl_stacktrace_depth)
371 for (
int i=0; i < _size; i++)
372 stacktrace_buffer.push_back((bfd_vma) _stacktrace_buffer[i]);
374 bfd_vma get_address(
int i)
const {
375 return this->stacktrace_buffer[i];
377 int get_size()
const {
378 return this->stacktrace_buffer.size();
380 int get_impl_stacktrace_depth()
const {
381 return this->impl_stacktrace_depth;
393std::string stacktrace2str(
const StacktraceAddresses &stacktrace_addresses)
395 int stack_depth = stacktrace_addresses.get_size() - 1;
397 std::string full_stacktrace_str(
"Traceback (most recent call last):\n");
399#ifdef HAVE_TEUCHOS_BFD
403 const int stack_depth_start = stack_depth;
404 const int stack_depth_end = stacktrace_addresses.get_impl_stacktrace_depth();
405 for (
int i=stack_depth_start; i >= stack_depth_end; i--) {
408 struct match_data match;
409 match.addr = stacktrace_addresses.get_address(i);
410#ifdef HAVE_TEUCHOS_BFD
411 if (dl_iterate_phdr(shared_lib_callback, &match) == 0)
412 return "dl_iterate_phdr() didn't find a match\n";
415 match.addr_in_file = match.addr;
418 if (match.filename.length() > 0) {
422 full_stacktrace_str += addr2str(match.filename, match.addr_in_file);
426 full_stacktrace_str += addr2str(
"/proc/self/exe", match.addr_in_file);
430 return full_stacktrace_str;
434void loc_segfault_callback_print_stack(
int sig_num)
438 *out <<
"\nSegfault caught. Printing stacktrace:\n\n";
439 Teuchos::show_stacktrace();
440 *out <<
"\nDone. Exiting the program.\n";
442 signal(SIGABRT, SIG_DFL);
447void loc_abort_callback_print_stack(
int sig_num)
451 *out <<
"\nAbort caught. Printing stacktrace:\n\n";
452 Teuchos::show_stacktrace();
459 const int STACKTRACE_ARRAY_SIZE = 100;
460 void *stacktrace_array[STACKTRACE_ARRAY_SIZE];
461 const size_t stacktrace_size = backtrace(stacktrace_array,
462 STACKTRACE_ARRAY_SIZE);
463 return rcp(
new StacktraceAddresses(stacktrace_array, stacktrace_size,
464 impl_stacktrace_depth+1));
476void Teuchos::store_stacktrace()
478 const int impl_stacktrace_depth=1;
479 last_stacktrace = get_stacktrace_addresses(impl_stacktrace_depth);
483std::string Teuchos::get_stored_stacktrace()
485 if (last_stacktrace == null) {
489 return stacktrace2str(*last_stacktrace);
494std::string Teuchos::get_stacktrace(
int impl_stacktrace_depth)
497 get_stacktrace_addresses(impl_stacktrace_depth+1);
498 return stacktrace2str(*addresses);
502void Teuchos::show_stacktrace()
506 const int impl_stacktrace_depth=1;
507 *out << Teuchos::get_stacktrace(impl_stacktrace_depth);
511void Teuchos::print_stack_on_segfault()
513 signal(SIGSEGV, loc_segfault_callback_print_stack);
514 signal(SIGABRT, loc_abort_callback_print_stack);
Reference-counted pointer class and non-member templated function implementations.
Functions for returning stacktrace info (GCC only initially).
Smart reference counting pointer class for automatic garbage collection.
Smart reference counting pointer class for automatic garbage collection.
static RCP< FancyOStream > getDefaultOStream()
Get the default output stream object.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Deprecated.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Deprecated.