[complement-svn] SF.net SVN: complement: [1740] trunk/complement/explore
Status: Pre-Alpha
Brought to you by:
complement
From: <com...@us...> - 2007-09-24 18:49:16
|
Revision: 1740 http://complement.svn.sourceforge.net/complement/?rev=1740&view=rev Author: complement Date: 2007-09-24 11:49:09 -0700 (Mon, 24 Sep 2007) Log Message: ----------- print call stack to ostream, initial implementation; store call stack when thread created; useful for debugging; macro to force store call stack when thread created; recompilation required when changed; bfd library required for call stack printing; initial test for call stack output; libxmt: version 1.14.0 Modified Paths: -------------- trunk/complement/explore/include/config/feature.h trunk/complement/explore/include/mt/xmt.h trunk/complement/explore/lib/mt/ChangeLog trunk/complement/explore/lib/mt/Makefile trunk/complement/explore/lib/mt/Makefile.inc trunk/complement/explore/lib/mt/ut/mt_test.cc trunk/complement/explore/lib/mt/ut/mt_test.h trunk/complement/explore/lib/mt/ut/mt_test_suite.cc trunk/complement/explore/lib/mt/xmt.cc Added Paths: ----------- trunk/complement/explore/include/mt/callstack.h trunk/complement/explore/lib/mt/callstack.cc Modified: trunk/complement/explore/include/config/feature.h =================================================================== --- trunk/complement/explore/include/config/feature.h 2007-09-18 09:31:26 UTC (rev 1739) +++ trunk/complement/explore/include/config/feature.h 2007-09-24 18:49:09 UTC (rev 1740) @@ -112,4 +112,11 @@ # define __FIT_TYPENAME_ARG #endif /* __FIT_NEED_TYPENAME_IN_ARGS_BUG */ +/* + Store information about stack before create thread in xmt::Thread; + useful for debugging. +*/ + +#define __FIT_CREATE_THREAD_STACK_INFO + #endif /* __config_feature_h */ Added: trunk/complement/explore/include/mt/callstack.h =================================================================== --- trunk/complement/explore/include/mt/callstack.h (rev 0) +++ trunk/complement/explore/include/mt/callstack.h 2007-09-24 18:49:09 UTC (rev 1740) @@ -0,0 +1,22 @@ +// -*- C++ -*- Time-stamp: <07/08/03 09:47:53 ptr> + +/* + * Copyright (c) 2007 + * Petr Ovtchenkov + * + * Licensed under the Academic Free License version 3.0 + * + */ + +#ifndef __mt_callstack_h +#define __mt_callstack_h + +#include <ostream> + +namespace xmt { + +void callstack( std::ostream& ); + +} // namespace xmt + +#endif Modified: trunk/complement/explore/include/mt/xmt.h =================================================================== --- trunk/complement/explore/include/mt/xmt.h 2007-09-18 09:31:26 UTC (rev 1739) +++ trunk/complement/explore/include/mt/xmt.h 2007-09-24 18:49:09 UTC (rev 1740) @@ -1538,7 +1538,9 @@ size_t _param_sz; unsigned _flags; size_t _stack_sz; // stack size, if not 0 - // mutex _llock; +#ifdef __FIT_CREATE_THREAD_STACK_INFO + std::string _stack_on_create; +#endif friend class Init; // extern "C", wrap for thread_create // #ifdef __unix Modified: trunk/complement/explore/lib/mt/ChangeLog =================================================================== --- trunk/complement/explore/lib/mt/ChangeLog 2007-09-18 09:31:26 UTC (rev 1739) +++ trunk/complement/explore/lib/mt/ChangeLog 2007-09-24 18:49:09 UTC (rev 1740) @@ -1,3 +1,21 @@ +2007-09-24 Petr Ovtchenkov <pt...@is...> + + * callstack.h, callstack.cc: print call stack to ostream, initial + implementation; + + * xmt.h, xmt.cc: store call stack when thread created; useful for + debugging; + + * config/feature.h: macro to force store call stack when thread + created; recompilation required when changed; + + * Makefile: bfd library required for call stack printing; + + * ut/mt_test.cc, ut/mt_test.h, ut/mt_test_suite.cc: initial test for + call stack output. + + * libxmt: version 1.14.0 + 2007-09-18 Petr Ovtchenkov <pt...@is...> * xmt.h, xmt.cc: removed intermediate _xcall, use direct call of _call Modified: trunk/complement/explore/lib/mt/Makefile =================================================================== --- trunk/complement/explore/lib/mt/Makefile 2007-09-18 09:31:26 UTC (rev 1739) +++ trunk/complement/explore/lib/mt/Makefile 2007-09-24 18:49:09 UTC (rev 1740) @@ -8,6 +8,8 @@ INCLUDES += -I$(SRCROOT)/include HEADERS_BASE = $(SRCROOT)/include/mt $(SRCROOT)/include/config $(SRCROOT)/include/misc +LDLIBS += -ldl -lbfd + check: all-shared $(MAKE) -C ut all-shared (cd ut; ${OUTPUT_DIR}/mt_ut) || exit 1 Modified: trunk/complement/explore/lib/mt/Makefile.inc =================================================================== --- trunk/complement/explore/lib/mt/Makefile.inc 2007-09-18 09:31:26 UTC (rev 1739) +++ trunk/complement/explore/lib/mt/Makefile.inc 2007-09-24 18:49:09 UTC (rev 1740) @@ -2,7 +2,7 @@ LIBNAME = xmt MAJOR = 1 -MINOR = 13 +MINOR = 14 PATCH = 0 -SRC_CC = xmt.cc thr_mgr.cc time.cc uid.cc shm.cc +SRC_CC = xmt.cc thr_mgr.cc time.cc uid.cc shm.cc callstack.cc SRC_C = fl.c Added: trunk/complement/explore/lib/mt/callstack.cc =================================================================== --- trunk/complement/explore/lib/mt/callstack.cc (rev 0) +++ trunk/complement/explore/lib/mt/callstack.cc 2007-09-24 18:49:09 UTC (rev 1740) @@ -0,0 +1,304 @@ +// -*- C++ -*- Time-stamp: <07/09/21 22:45:51 ptr> + +/* + * Copyright (c) 2007 + * Petr Ovtchenkov + * + * Licensed under the Academic Free License version 3.0 + * + */ + +/** + * Derived from: + * http://www.tlug.org.za/wiki/index.php/Obtaining_a_stack_trace_in_C_upon_SIGSEGV + * + * This code is in the public domain. Use it as you see fit, some credit + * would be appreciated, but is not a prerequisite for usage. Feedback + * on it's use would encourage further development and maintenance. + * + * Author: Jaco Kroon <ja...@kr...> + * + * Copyright (C) 2005 - 2006 Jaco Kroon + */ + +#include <config/feature.h> + +// #define _GNU_SOURCE +// #include <memory.h> +// #include <stdlib.h> +// #include <stdio.h> + +#include <bfd.h> +#include <signal.h> +#include <ucontext.h> +#include <dlfcn.h> +#include <execinfo.h> + +#ifdef __FIT_CPP_DEMANGLE +# include <cxxabi.h> +#endif + +#if 1 +#if defined(REG_RIP) +# define SIGSEGV_STACK_IA64 +// # define REGFORMAT "%016lx" +#elif defined(REG_EIP) +# define SIGSEGV_STACK_X86 +// # define REGFORMAT "%08x" +#else +# define SIGSEGV_STACK_GENERIC +// # define REGFORMAT "%x" +#endif +#endif + +#include <cstring> + +#include <mt/callstack.h> +#include <iomanip> +#include <string> +#include <sstream> + +namespace xmt { + +using namespace std; + +class BFD_Init +{ + public: + BFD_Init() + { + bfd_init(); + bfd_set_default_target( "i686-pc-linux-gnu" ); + } +}; + +BFD_Init init; + +struct params_collect +{ + bfd_boolean found; + bfd_vma pc; + asymbol **syms; + const char *fname; + const char *funcname; + unsigned line; +}; + +void find_address_in_section( bfd *abfd, asection *section, void *data ) +{ + bfd_boolean& found = static_cast<params_collect *>(data)->found; + + if ( found ) { + return; + } + + if ( (bfd_get_section_flags(abfd, section) & SEC_ALLOC) == 0 ) { + return; + } + + bfd_vma vma = bfd_get_section_vma( abfd, section ); + bfd_vma& pc = static_cast<params_collect *>(data)->pc; + if ( pc < vma ) { + return; + } + + bfd_size_type size = bfd_get_section_size( section ); + if ( pc >= vma + size ) { + return; + } + + found = bfd_find_nearest_line( abfd, section, + static_cast<params_collect *>(data)->syms, pc - vma, + &static_cast<params_collect *>(data)->fname, + &static_cast<params_collect *>(data)->funcname, + &static_cast<params_collect *>(data)->line ); +} + +int extract_info( const char *fname, void *addr, string& file, unsigned& line ) +{ + bfd *abfd = bfd_openr( fname, 0 ); + if ( abfd == 0 ) { + return -1; + } + + char **matching; + if ( !bfd_check_format_matches( abfd, bfd_object, &matching ) ) { + // free (matching); + return -2; + } + + // slurp_symtab (abfd); + asymbol **syms = 0; // Symbol table + + if ( ( bfd_get_file_flags(abfd) & HAS_SYMS ) != 0 ) { + long symcount; + unsigned int size; + + symcount = bfd_read_minisymbols( abfd, 0, (void **)&syms, &size ); + if ( symcount == 0 ) { + symcount = bfd_read_minisymbols( abfd, 1, (void **)&syms, &size ); + } + + if ( symcount < 0 ) { + if ( syms != 0 ) { + free( syms ); + } + bfd_close( abfd ); + return -3; + } + } + + params_collect pars; + pars.found = 0; + pars.syms = syms; + + // translate_addresses (abfd, 0); + + // for ( ; ; ) { + pars.pc = reinterpret_cast<bfd_vma>(addr); + bfd_map_over_sections( abfd, find_address_in_section, reinterpret_cast<void *>(&pars) ); + if ( pars.found == 0 ) { + if ( syms != 0 ) { + free( syms ); + } + bfd_close( abfd ); + return -4; + } + + file = pars.fname; + line = pars.line; + + // } + if ( syms != 0 ) { + free( syms ); + } + + bfd_close( abfd ); + + return 0; +} + +void callstack( std::ostream& s ) +{ + // s.clear(); + +#if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64) + ucontext_t ucontext; + + getcontext( &ucontext ); + + int f = 0; + Dl_info dlinfo; + void **bp = 0; + void *ip = 0; +# if defined(SIGSEGV_STACK_IA64) + ip = (void*)ucontext.uc_mcontext.gregs[REG_RIP]; + bp = (void**)ucontext.uc_mcontext.gregs[REG_RBP]; +# elif defined(SIGSEGV_STACK_X86) + ip = (void*)ucontext.uc_mcontext.gregs[REG_EIP]; + bp = (void**)ucontext.uc_mcontext.gregs[REG_EBP]; +# endif + string file; + unsigned line; + + while ( bp && ip ) { + if ( !dladdr( ip, &dlinfo ) ) { + break; + } + + const char *symname = dlinfo.dli_sname; +#ifdef __FIT_CPP_DEMANGLE + int status = 0; + char *tmp = symname == 0 ? 0 : __cxxabiv1::__cxa_demangle( symname, 0, 0, &status ); + + if ( status == 0 && tmp != 0 ) { + symname = tmp; + } +#endif + + // int res; + + // if ( string( "obj/gcc/so_g/mt_ut" ) == dlinfo.dli_fname ) { + if ( /* (res = extract_info( dlinfo.dli_fname, ip, file, line )) != 0 */ false ) { + file = "??"; + line = 0; + // s << "*** " << res << " " << dlinfo.dli_fname << endl; + } else { + file = "??"; + line = 0; + } + // } else { + // file = "??"; + // line = 0; + // } + + s << '#' << setw(2) << setiosflags(ios_base::left) << f++ << " " << ip + << " in " << (symname == 0 ? "?" : symname ) + << " at " << /* "...\n" */ file << ":" << line << '\n'; + // << "+" << (static_cast<char *>(ip) - static_cast<char *>(dlinfo.dli_saddr)) + // << "> (" << dlinfo.dli_fname << ")\n"; +#ifdef __FIT_CPP_DEMANGLE + if ( tmp ) { + free(tmp); + } +#endif + + if ( dlinfo.dli_sname && !strcmp( dlinfo.dli_sname, "main" ) ) { + break; + } + + ip = bp[1]; + bp = (void**)bp[0]; + } +#else + const int btsz = 50; + void *bt[btsz]; + + size_t sz = backtrace( bt, btsz ); + char **line = backtrace_symbols( bt, sz ); + + Dl_info dlinfo; + // string file; + // unsigned line; + + for ( int i = 0; i < sz; ++i ) { + stringstream ss( line[i] ); + // s << line[i] << '\n'; + string nm; + void *addr; + char c; + ss >> nm >> c >> hex >> addr; + + if ( !dladdr( addr, &dlinfo ) ) { + continue; + } + + const char *symname = dlinfo.dli_sname; +#ifdef __FIT_CPP_DEMANGLE + int status = 0; + char *tmp = symname == 0 ? 0 : __cxxabiv1::__cxa_demangle( symname, 0, 0, &status ); + + if ( status == 0 && tmp != 0 ) { + symname = tmp; + } +#endif + + // int res = extract_info(); + + s << '#' << setw(2) << setiosflags(ios_base::left) << i << " " << addr + << " in " << (symname == 0 ? "..." : symname) + << " at " << "...\n"; + // s << "== " << nm << " / '" << c << "' " << addr << "\n"; +#ifdef __FIT_CPP_DEMANGLE + if ( tmp ) { + free(tmp); + } +#endif + } + + free( line ); +#endif +} + +} // namespace xmt + Modified: trunk/complement/explore/lib/mt/ut/mt_test.cc =================================================================== --- trunk/complement/explore/lib/mt/ut/mt_test.cc 2007-09-18 09:31:26 UTC (rev 1739) +++ trunk/complement/explore/lib/mt/ut/mt_test.cc 2007-09-24 18:49:09 UTC (rev 1740) @@ -13,6 +13,7 @@ #include <mt/xmt.h> #include <mt/shm.h> #include <mt/thr_mgr.h> +#include <mt/callstack.h> #include <sys/shm.h> #include <sys/wait.h> @@ -27,6 +28,13 @@ using namespace std; namespace fs = boost::filesystem; +int EXAM_IMPL(mt_test::callstack) +{ + xmt::callstack( cerr ); + + return EXAM_RESULT; +} + /* ****************************************************** * Degenerate case: check that one thread pass throw * own barrier. Modified: trunk/complement/explore/lib/mt/ut/mt_test.h =================================================================== --- trunk/complement/explore/lib/mt/ut/mt_test.h 2007-09-18 09:31:26 UTC (rev 1739) +++ trunk/complement/explore/lib/mt/ut/mt_test.h 2007-09-24 18:49:09 UTC (rev 1740) @@ -19,6 +19,7 @@ class mt_test { public: + int EXAM_DECL(callstack); int EXAM_DECL(barrier); int EXAM_DECL(join_test); int EXAM_DECL(barrier2); Modified: trunk/complement/explore/lib/mt/ut/mt_test_suite.cc =================================================================== --- trunk/complement/explore/lib/mt/ut/mt_test_suite.cc 2007-09-18 09:31:26 UTC (rev 1739) +++ trunk/complement/explore/lib/mt/ut/mt_test_suite.cc 2007-09-24 18:49:09 UTC (rev 1740) @@ -1,4 +1,4 @@ -// -*- C++ -*- Time-stamp: <07/09/05 00:29:06 ptr> +// -*- C++ -*- Time-stamp: <07/09/21 22:41:08 ptr> /* * Copyright (c) 2006, 2007 @@ -27,6 +27,7 @@ exam::test_suite t( "libxmt test" ); mt_test test; +#if 0 t.add( timespec_diff, "timespec_diff" ); t.add( signal_1_test, "signal_1_test" ); // You can't throw exception from signal handler @@ -34,9 +35,12 @@ // by this reason next test is commented: // t.add( signal_2_test, "signal_2_test" ); t.add( signal_3_test, "signal_3_test" ); +#endif exam::test_suite::test_case_type tc[3]; + // t.add( &mt_test::callstack, test, "callstack" ); + tc[0] = t.add( &mt_test::barrier, test, "mt_test::barrier" ); tc[1] = t.add( &mt_test::join_test, test, "mt_test::join_test" ); tc[2] = t.add( &mt_test::yield, test, "mt_test::yield", Modified: trunk/complement/explore/lib/mt/xmt.cc =================================================================== --- trunk/complement/explore/lib/mt/xmt.cc 2007-09-18 09:31:26 UTC (rev 1739) +++ trunk/complement/explore/lib/mt/xmt.cc 2007-09-24 18:49:09 UTC (rev 1740) @@ -20,6 +20,7 @@ #include <fcntl.h> #include <mt/xmt.h> +#include <mt/callstack.h> #include <cstring> #ifndef _WIN32 @@ -359,7 +360,13 @@ if ( (_flags & (daemon | detached)) != 0 ) { // not joinable // Locker lk( _llock ); if ( _id != bad_thread_id ) { // still run? - cerr << "Crash on daemon thread exit expected, threas id " << _id << endl; + cerr << "Suspected crash of daemon thread, threas id " << _id << endl; +#ifdef __FIT_CREATE_THREAD_STACK_INFO + cerr << "Stack when thread was created:\n" << _stack_on_create << endl; +#endif + std::stringstream s; + callstack( s ); + cerr << "Current stack is:\n" << s.str() << endl; } } @@ -701,6 +708,15 @@ _param_sz = psz; int err = 0; +#ifdef __FIT_CREATE_THREAD_STACK_INFO + // _stack_on_create + { + std::stringstream s; + callstack( s ); + _stack_on_create = s.str(); + } +#endif + #ifdef _PTHREADS pthread_attr_t attr; if ( _flags != 0 || _stack_sz != 0 ) { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |