Files
mfem/general/error.cpp
T

142 lines
3.6 KiB
C++

// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "error.hpp"
#include "array.hpp"
#include <cstdlib>
#include <iostream>
#include "communication.hpp"
#include "globalostream.hpp"
#ifdef MFEM_USE_LIBUNWIND
#define UNW_LOCAL_ONLY
#define UNW_NAME_LEN 512
#include <libunwind.h>
#include <cxxabi.h>
#if defined(__APPLE__) || defined(__linux__)
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <dlfcn.h>
#endif
#endif // MFEM_USE_LIBUNWIND
#ifdef MFEM_USE_MPI
#include <mpi.h>
#endif
namespace mfem
{
void mfem_backtrace(int mode, int depth)
{
#ifdef MFEM_USE_LIBUNWIND
char name[UNW_NAME_LEN];
unw_cursor_t cursor;
unw_context_t uc;
unw_word_t ip, offp;
int err = unw_getcontext(&uc);
err = err ? err : unw_init_local(&cursor, &uc);
Array<unw_word_t> addrs;
while (unw_step(&cursor) > 0 && addrs.Size() != depth)
{
err = err ? err : unw_get_proc_name(&cursor, name, UNW_NAME_LEN, &offp);
err = err ? err : unw_get_reg(&cursor, UNW_REG_IP, &ip);
if (err) { break; }
char *name_p = name;
int demangle_status;
// __cxa_demangle is not standard, but works with GCC, Intel, PGI, Clang
char *name_demangle =
abi::__cxa_demangle(name, NULL, NULL, &demangle_status);
if (demangle_status == 0) // use mangled name if something goes wrong
{
name_p = name_demangle;
}
merr << addrs.Size() << ") [0x" << std::hex << ip - 1 << std::dec
<< "]: " << name_p << std::endl;
addrs.Append(ip - 1);
if (demangle_status == 0)
{
free(name_demangle);
}
}
#if defined(__APPLE__) || defined(__linux__)
if (addrs.Size() > 0 && (mode & 1))
{
merr << "\nLookup backtrace source lines:";
const char *fname = NULL;
for (int i = 0; i < addrs.Size(); i++)
{
Dl_info info;
err = !dladdr((void*)addrs[i], &info);
if (err)
{
fname = "<exe>";
}
else if (fname != info.dli_fname)
{
fname = info.dli_fname;
merr << '\n';
#ifdef __linux__
merr << "addr2line -C -e " << fname;
#else
merr << "atos -o " << fname << " -l "
<< (err ? 0 : info.dli_fbase);
#endif
}
merr << " 0x" << std::hex << addrs[i] << std::dec;
}
merr << '\n';
}
#endif
#endif // MFEM_USE_LIBUNWIND
}
void mfem_error(const char *msg)
{
if (msg)
{
// NOTE: By default, each call of the "operator <<" method of the
// merr object results in flushing the I/O stream, which can be a
// very bad thing if all your processors try to do it at the same time.
merr << "\n\n" << msg << "\n";
}
#ifdef MFEM_USE_LIBUNWIND
merr << "Backtrace:" << std::endl;
mfem_backtrace(1, -1);
merr << std::endl;
#endif
#ifdef MFEM_USE_MPI
int init_flag, fin_flag;
MPI_Initialized(&init_flag);
MPI_Finalized(&fin_flag);
if (init_flag && !fin_flag) { MPI_Abort(global_mpi_comm, 1); }
#endif
std::abort(); // force crash by calling abort
}
void mfem_warning(const char *msg)
{
if (msg)
{
mout << "\n\n" << msg << std::endl;
}
}
}