32 #include "Teuchos_VerboseObject.hpp"
35 #ifdef HAVE_TEUCHOS_STACKTRACE
61 #ifdef HAVE_TEUCHOS_LINK
66 #ifdef HAVE_TEUCHOS_BFD
72 typedef long long unsigned bfd_vma;
85 #ifdef HAVE_TEUCHOS_BFD
86 asymbol **symbol_table;
90 std::string function_name;
97 bool is_whitespace_char(
const char c)
99 return c ==
' ' || c ==
'\t';
106 std::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);
123 std::string read_line_from_file(std::string filename,
unsigned int line_number)
125 std::ifstream in(filename.c_str());
129 if (line_number == 0) {
130 return "Line number must be positive";
134 while (n < line_number) {
136 return "Line not found";
149 std::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
181 void 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);
213 if (filename == NULL)
216 data->filename = filename;
218 if (function_name == NULL)
219 data->function_name =
"";
221 data->function_name = function_name;
226 int 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);
254 #endif // HAVE_TEUCHOS_BFD
265 std::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;
325 std::string filename;
326 bfd_vma addr_in_file;
330 #ifdef HAVE_TEUCHOS_LINK
337 int 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;
358 #endif // HAVE_TEUCHOS_LINK
364 class 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;
393 std::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;
434 void 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);
447 void loc_abort_callback_print_stack(
int sig_num)
451 *out <<
"\nAbort caught. Printing stacktrace:\n\n";
452 Teuchos::show_stacktrace();
457 RCP<StacktraceAddresses> get_stacktrace_addresses(
int impl_stacktrace_depth)
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));
468 RCP<StacktraceAddresses> last_stacktrace;
476 void Teuchos::store_stacktrace()
478 const int impl_stacktrace_depth=1;
479 last_stacktrace = get_stacktrace_addresses(impl_stacktrace_depth);
483 std::string Teuchos::get_stored_stacktrace()
485 if (last_stacktrace == null) {
489 return stacktrace2str(*last_stacktrace);
494 std::string Teuchos::get_stacktrace(
int impl_stacktrace_depth)
496 RCP<StacktraceAddresses> addresses =
497 get_stacktrace_addresses(impl_stacktrace_depth+1);
498 return stacktrace2str(*addresses);
502 void Teuchos::show_stacktrace()
506 const int impl_stacktrace_depth=1;
507 *out << Teuchos::get_stacktrace(impl_stacktrace_depth);
511 void Teuchos::print_stack_on_segfault()
513 signal(SIGSEGV, loc_segfault_callback_print_stack);
514 signal(SIGABRT, loc_abort_callback_print_stack);
518 #endif // HAVE_TEUCHOS_STACKTRACE
RCP< T > rcp(const boost::shared_ptr< T > &sptr)
Conversion function that takes in a boost::shared_ptr object and spits out a Teuchos::RCP object...
Functions for returning stacktrace info (GCC only initially).
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Deprecated.
static RCP< FancyOStream > getDefaultOStream()
Get the default output stream object.
int size(const Comm< Ordinal > &comm)
Get the number of processes in the communicator.
Smart reference counting pointer class for automatic garbage collection.
Reference-counted pointer class and non-member templated function implementations.