44 #ifdef HAVE_TEUCHOS_STACKTRACE
70 #ifdef HAVE_TEUCHOS_LINK
75 #ifdef HAVE_TEUCHOS_BFD
81 typedef long long unsigned bfd_vma;
94 #ifdef HAVE_TEUCHOS_BFD
95 asymbol **symbol_table;
99 std::string function_name;
106 bool is_whitespace_char(
const char c)
108 return c ==
' ' || c ==
'\t';
115 std::string remove_leading_whitespace(
const std::string &str)
117 if (str.length() && is_whitespace_char(str[0])) {
118 int first_nonwhitespace_index = 0;
119 for (
int i = 0; i < static_cast<int>(str.length()); ++i) {
120 if (!is_whitespace_char(str[i])) {
121 first_nonwhitespace_index = i;
125 return str.substr(first_nonwhitespace_index);
132 std::string read_line_from_file(std::string
filename,
unsigned int line_number)
134 std::ifstream in(filename.c_str());
138 if (line_number == 0) {
139 return "Line number must be positive";
143 while (n < line_number) {
145 return "Line not found";
158 std::string demangle_function_name(std::string name)
162 if (name.length() == 0) {
167 d = abi::__cxa_demangle(name.c_str(), 0, 0, &status);
180 #ifdef HAVE_TEUCHOS_BFD
190 void process_section(bfd *abfd, asection *section,
void *_data)
192 line_data *data = (line_data*)_data;
193 if (data->line_found) {
197 if ((bfd_get_section_flags(abfd, section) & SEC_ALLOC) == 0) {
201 bfd_vma section_vma = bfd_get_section_vma(abfd, section);
202 if (data->addr < section_vma) {
207 bfd_size_type section_size = bfd_section_size(abfd, section);
208 if (data->addr >= section_vma + section_size) {
214 bfd_vma offset = data->addr - section_vma - 1;
218 const char *filename=NULL, *function_name=NULL;
219 data->line_found = bfd_find_nearest_line(abfd, section, data->symbol_table,
220 offset, &filename, &function_name, &data->line);
222 if (filename == NULL)
227 if (function_name == NULL)
228 data->function_name =
"";
230 data->function_name = function_name;
235 int load_symbol_table(bfd *abfd, line_data *data)
237 if ((bfd_get_file_flags(abfd) & HAS_SYMS) == 0)
241 void **symbol_table_ptr =
reinterpret_cast<void **
>(&data->symbol_table);
243 unsigned int symbol_size;
244 n_symbols = bfd_read_minisymbols(abfd,
false, symbol_table_ptr, &symbol_size);
245 if (n_symbols == 0) {
248 if (data->symbol_table != NULL)
249 free(data->symbol_table);
251 n_symbols = bfd_read_minisymbols(abfd,
true, symbol_table_ptr, &symbol_size);
263 #endif // HAVE_TEUCHOS_BFD
274 std::string addr2str(std::string file_name, bfd_vma addr)
276 #ifdef HAVE_TEUCHOS_BFD
279 abfd = bfd_openr(file_name.c_str(), NULL);
281 return "Cannot open the binary file '" + file_name +
"'\n";
282 if (bfd_check_format(abfd, bfd_archive))
283 return "Cannot get addresses from the archive '" + file_name +
"'\n";
285 if (!bfd_check_format_matches(abfd, bfd_object, &matching))
286 return "Unknown format of the binary file '" + file_name +
"'\n";
289 data.symbol_table = NULL;
290 data.line_found =
false;
292 if (load_symbol_table(abfd, &data) == 1)
293 return "Failed to load the symbol table from '" + file_name +
"'\n";
295 bfd_map_over_sections(abfd, process_section, &data);
297 if (data.symbol_table != NULL) free(data.symbol_table);
304 std::ostringstream s;
307 if (!data.line_found) {
309 s <<
" File unknown, address: 0x" << (
long long unsigned int) addr;
311 std::string name = demangle_function_name(data.function_name);
312 if (data.filename.length() > 0) {
314 s <<
" File \"" << data.filename <<
"\", line "
315 << data.line <<
", in " << name;
316 const std::string line_text = remove_leading_whitespace(
317 read_line_from_file(data.filename, data.line));
318 if (line_text !=
"") {
319 s <<
"\n " << line_text;
324 s <<
" File unknown, in " << name;
335 bfd_vma addr_in_file;
339 #ifdef HAVE_TEUCHOS_LINK
346 int shared_lib_callback(
struct dl_phdr_info *info,
347 size_t size,
void *_data)
349 struct match_data *data = (
struct match_data *)_data;
350 for (
int i=0; i < info->dlpi_phnum; i++) {
351 if (info->dlpi_phdr[i].p_type == PT_LOAD) {
352 ElfW(Addr) min_addr = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr;
353 ElfW(Addr) max_addr = min_addr + info->dlpi_phdr[i].p_memsz;
354 if ((data->addr >= min_addr) && (data->addr < max_addr)) {
355 data->filename = info->dlpi_name;
356 data->addr_in_file = data->addr - info->dlpi_addr;
367 #endif // HAVE_TEUCHOS_LINK
373 class StacktraceAddresses {
374 std::vector<bfd_vma> stacktrace_buffer;
375 int impl_stacktrace_depth;
377 StacktraceAddresses(
void *
const *_stacktrace_buffer,
int _size,
int _impl_stacktrace_depth)
378 : impl_stacktrace_depth(_impl_stacktrace_depth)
380 for (
int i=0; i < _size; i++)
381 stacktrace_buffer.push_back((bfd_vma) _stacktrace_buffer[i]);
383 bfd_vma get_address(
int i)
const {
384 return this->stacktrace_buffer[i];
386 int get_size()
const {
387 return this->stacktrace_buffer.size();
389 int get_impl_stacktrace_depth()
const {
390 return this->impl_stacktrace_depth;
402 std::string stacktrace2str(
const StacktraceAddresses &stacktrace_addresses)
404 int stack_depth = stacktrace_addresses.get_size() - 1;
406 std::string full_stacktrace_str(
"Traceback (most recent call last):\n");
408 #ifdef HAVE_TEUCHOS_BFD
412 const int stack_depth_start = stack_depth;
413 const int stack_depth_end = stacktrace_addresses.get_impl_stacktrace_depth();
414 for (
int i=stack_depth_start; i >= stack_depth_end; i--) {
417 struct match_data match;
418 match.addr = stacktrace_addresses.get_address(i);
419 #ifdef HAVE_TEUCHOS_BFD
420 if (dl_iterate_phdr(shared_lib_callback, &match) == 0)
421 return "dl_iterate_phdr() didn't find a match\n";
424 match.addr_in_file = match.addr;
427 if (match.filename.length() > 0) {
431 full_stacktrace_str += addr2str(match.filename, match.addr_in_file);
435 full_stacktrace_str += addr2str(
"/proc/self/exe", match.addr_in_file);
439 return full_stacktrace_str;
443 void loc_segfault_callback_print_stack(
int sig_num)
447 *out <<
"\nSegfault caught. Printing stacktrace:\n\n";
448 Teuchos::show_stacktrace();
449 *out <<
"\nDone. Exiting the program.\n";
451 signal(SIGABRT, SIG_DFL);
456 void loc_abort_callback_print_stack(
int sig_num)
460 *out <<
"\nAbort caught. Printing stacktrace:\n\n";
461 Teuchos::show_stacktrace();
466 RCP<StacktraceAddresses> get_stacktrace_addresses(
int impl_stacktrace_depth)
468 const int STACKTRACE_ARRAY_SIZE = 100;
469 void *stacktrace_array[STACKTRACE_ARRAY_SIZE];
470 const size_t stacktrace_size = backtrace(stacktrace_array,
471 STACKTRACE_ARRAY_SIZE);
472 return rcp(
new StacktraceAddresses(stacktrace_array, stacktrace_size,
473 impl_stacktrace_depth+1));
477 RCP<StacktraceAddresses> last_stacktrace;
485 void Teuchos::store_stacktrace()
487 const int impl_stacktrace_depth=1;
488 last_stacktrace = get_stacktrace_addresses(impl_stacktrace_depth);
492 std::string Teuchos::get_stored_stacktrace()
494 if (last_stacktrace ==
null) {
498 return stacktrace2str(*last_stacktrace);
503 std::string Teuchos::get_stacktrace(
int impl_stacktrace_depth)
505 RCP<StacktraceAddresses> addresses =
506 get_stacktrace_addresses(impl_stacktrace_depth+1);
507 return stacktrace2str(*addresses);
511 void Teuchos::show_stacktrace()
515 const int impl_stacktrace_depth=1;
516 *out << Teuchos::get_stacktrace(impl_stacktrace_depth);
520 void Teuchos::print_stack_on_segfault()
522 signal(SIGSEGV, loc_segfault_callback_print_stack);
523 signal(SIGABRT, loc_abort_callback_print_stack);
527 #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.