From mboxrd@z Thu Jan 1 00:00:00 1970 Return-path: Received: from moutng.kundenserver.de ([212.227.17.9]) by metis.ext.pengutronix.de with esmtp (Exim 4.72) (envelope-from ) id 1SAhV7-0001WS-4S for ptxdist@pengutronix.de; Thu, 22 Mar 2012 13:52:41 +0100 From: bernhard@bwalle.de Date: Thu, 22 Mar 2012 13:49:03 +0100 Message-Id: <1332420543-27500-2-git-send-email-bernhard@bwalle.de> In-Reply-To: <1332420543-27500-1-git-send-email-bernhard@bwalle.de> References: <1332420543-27500-1-git-send-email-bernhard@bwalle.de> Subject: [ptxdist] [PATCH 2/2] os: Add execinfo::backtrace() Reply-To: ptxdist@pengutronix.de List-Id: PTXdist Development Mailing List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: ptxdist-bounces@pengutronix.de Errors-To: ptxdist-bounces@pengutronix.de To: ptxdist@pengutronix.de Cc: Bernhard Walle From: Bernhard Walle Signed-off-by: Bernhard Walle --- NEWS | 2 +- csstdxx/CMakeLists.txt | 2 ++ csstdxx/os/execinfo.h | 53 ++++++++++++++++++++++++++++++++++ csstdxx/os/execinfo_linux.cpp | 64 +++++++++++++++++++++++++++++++++++++++++ examples/os/CMakeLists.txt | 4 +++ examples/os/backtrace.cpp | 27 +++++++++++++++++ tests/test_os.cpp | 7 +++++ tests/test_os.h | 2 ++ 8 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 csstdxx/os/execinfo_linux.cpp create mode 100644 examples/os/backtrace.cpp diff --git a/NEWS b/NEWS index 752220a..213cda4 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,6 @@ 0.5.1 ----- - * os: Add execinfo::demangleCxxName(). + * os: Add execinfo::demangleCxxName() and execinfo::backtrace(). 0.5.0 ----- diff --git a/csstdxx/CMakeLists.txt b/csstdxx/CMakeLists.txt index 71af070..d26c568 100644 --- a/csstdxx/CMakeLists.txt +++ b/csstdxx/CMakeLists.txt @@ -125,6 +125,8 @@ endif (WITH_SERIAL_BUS_ACCESS) if (CMAKE_SYSTEM_NAME STREQUAL "Linux") set(CSSTDXX_SRC ${CSSTDXX_SRC} + os/execinfo_linux.cpp + datetime/systemclock_linux.cpp io/iotimer_linux.cpp diff --git a/csstdxx/os/execinfo.h b/csstdxx/os/execinfo.h index 49cc21f..7772f4e 100644 --- a/csstdxx/os/execinfo.h +++ b/csstdxx/os/execinfo.h @@ -55,6 +55,59 @@ namespace execinfo { */ std::string demangleCxxName(const char *name, bool *ok=NULL); +/** + * \brief Returns a backtrace from the current stack + * + * It depends on the implementation how the backtrace looks like. Here's an example + * (x86_64, gcc, Linux): + * + * \verbatim +/home/bwalle/devel/CSstdxx/CSstdxx/build/csstdxx/libcsstdxx.so.2(cs::os::execinfo::backtrace()+0x49) [0x7f8e7402594d] +build/examples/os/backtrace(sigsegvhandler(int)+0x18) [0x400ccc] +/lib/libc.so.6(+0x349f0) [0x7f8e72f819f0] +build/examples/os/backtrace(foo(int)+0x1d) [0x400d2d] +build/examples/os/backtrace(foo(int)+0x37) [0x400d47] +build/examples/os/backtrace(foo(int)+0x37) [0x400d47] +build/examples/os/backtrace(foo(int)+0x37) [0x400d47] +build/examples/os/backtrace(foo(int)+0x37) [0x400d47] +build/examples/os/backtrace(foo(int)+0x37) [0x400d47] +build/examples/os/backtrace(foo(int)+0x37) [0x400d47] +build/examples/os/backtrace(foo(int)+0x37) [0x400d47] +build/examples/os/backtrace(foo(int)+0x37) [0x400d47] +build/examples/os/backtrace(foo(int)+0x37) [0x400d47] +build/examples/os/backtrace(foo(int)+0x37) [0x400d47] +build/examples/os/backtrace(foo(int)+0x37) [0x400d47] +build/examples/os/backtrace(foo(int)+0x37) [0x400d47] +build/examples/os/backtrace(foo(int)+0x37) [0x400d47] +build/examples/os/backtrace(foo(int)+0x37) [0x400d47] +build/examples/os/backtrace(foo(int)+0x37) [0x400d47] +build/examples/os/backtrace(foo(int)+0x37) [0x400d47] +build/examples/os/backtrace(foo(int)+0x37) [0x400d47] +build/examples/os/backtrace(foo(int)+0x37) [0x400d47] +build/examples/os/backtrace(foo(int)+0x37) [0x400d47] +build/examples/os/backtrace(foo(int)+0x37) [0x400d47] +build/examples/os/backtrace(main+0x28) [0x400d71] +/lib/libc.so.6(__libc_start_main+0xed) [0x7f8e72f6e38d] +build/examples/os/backtrace() [0x400bf9] +\endverbatim + * + * As you see, the function names are demangled and there \b are function names. + * To get that on Linux/gcc, you must compile your application and all libraries + * from which a backtrace should be obtained with the -rdynamic command line + * parameter. This is the default for CMake. + * + * The example backtrace.cpp shows how to use backtrace to print something + * useful when the application receives a segmentation fault. + * + * \note Don't try to parse the output. Just use it for debugging. + * + * \return the backtrace as shown above on success or an empty string on failure. + * \since 0.5.1 + * \ingroup os_execinfo + * \sa http://en.wikipedia.org/wiki/Name_mangling + */ +std::string backtrace(); + } // namespace execinfo } // namespace os } // namespace cs diff --git a/csstdxx/os/execinfo_linux.cpp b/csstdxx/os/execinfo_linux.cpp new file mode 100644 index 0000000..5516292 --- /dev/null +++ b/csstdxx/os/execinfo_linux.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) Corscience GmbH & Co. KG + * + * Projectname - Redmine:CSstdxx + * Module ID - os + */ + +#include +#include +#include +#include + +#include "execinfo.h" + +#ifdef HAVE_CXXABI_H +# include +#endif + +namespace cs { +namespace os { +namespace execinfo { + +#define BACKTRACE_MAX 100 + +std::string backtrace() +{ + std::stringstream ss; + + void *buffer[100]; + int nptrs = ::backtrace(buffer, BACKTRACE_MAX); + if (nptrs == 0) + return std::string(); + + char **strings = backtrace_symbols(buffer, nptrs); + if (!strings) + return std::string(); + + for (int i = 0; i < nptrs; i++) { + // demangle names if possible + std::string line = strings[i]; + size_t openBrace = line.find('('); + size_t plus = line.find('+', openBrace); + + if ((openBrace == std::string::npos) || (plus == std::string::npos)) { + ss << line << std::endl; + continue; + } + + std::string function = line.substr(openBrace+1, plus-openBrace-1); + function = demangleCxxName(function.c_str()); + + ss << line.substr(0, openBrace+1) + << function + << line.substr(plus) << std::endl; + } + + free(strings); + + return ss.str(); +} + +} // namespace execinfo +} // namespace os +} // namespace cs diff --git a/examples/os/CMakeLists.txt b/examples/os/CMakeLists.txt index e117fb7..4b20733 100644 --- a/examples/os/CMakeLists.txt +++ b/examples/os/CMakeLists.txt @@ -29,6 +29,10 @@ add_executable(c++filt c++filt.cpp) target_link_libraries(c++filt csstdxx) set(EXAMPLE_PROGRAMS ${EXAMPLE_PROGRAMS} c++filt) +add_executable(backtrace backtrace.cpp) +target_link_libraries(backtrace csstdxx) +set(EXAMPLE_PROGRAMS ${EXAMPLE_PROGRAMS} backtrace) + if (INSTALL_CSSTDXX_EXAMPLES) install(TARGETS ${EXAMPLE_PROGRAMS} DESTINATION bin/csstdxx) endif (INSTALL_CSSTDXX_EXAMPLES) diff --git a/examples/os/backtrace.cpp b/examples/os/backtrace.cpp new file mode 100644 index 0000000..ca6bd9d --- /dev/null +++ b/examples/os/backtrace.cpp @@ -0,0 +1,27 @@ +#include +#include +#include + +void sigsegvhandler(int signal) +{ + puts(cs::os::execinfo::backtrace().c_str()); + _exit(1); +} + +int foo(int x) +{ + if (x == 0) { + volatile int *p = NULL; + *p = 20; + return 0; + } + else + return foo(x-1); +} + +int main(int argc, char *argv[]) +{ + signal(SIGSEGV, sigsegvhandler); + foo(20); + return 0; +} diff --git a/tests/test_os.cpp b/tests/test_os.cpp index 683e875..c36e719 100644 --- a/tests/test_os.cpp +++ b/tests/test_os.cpp @@ -477,6 +477,13 @@ void TestExecinfo::testCppDemangle() CPPUNIT_ASSERT_EQUAL(std::string("blablubb"), result); } +void TestExecinfo::testBacktrace() +{ +#ifdef __linux__ + CPPUNIT_ASSERT(!execinfo::backtrace().empty()); +#endif +} + } // namespace os } // namespace cs diff --git a/tests/test_os.h b/tests/test_os.h index a95d0a9..58ba5d3 100644 --- a/tests/test_os.h +++ b/tests/test_os.h @@ -121,10 +121,12 @@ class TestExecinfo : public CppUnit::TestFixture { public: void testCppDemangle(); + void testBacktrace(); private: CPPUNIT_TEST_SUITE(TestExecinfo); CPPUNIT_TEST(testCppDemangle); + CPPUNIT_TEST(testBacktrace); CPPUNIT_TEST_SUITE_END(); }; -- 1.7.9.4 -- ptxdist mailing list ptxdist@pengutronix.de