From be5c892b3a92406b749d07a7653e1520eb452f8f Mon Sep 17 00:00:00 2001 From: Marcel Loose <loose@astron.nl> Date: Fri, 14 Jan 2011 16:01:11 +0000 Subject: [PATCH] Bug 1592: Merged task branch into the trunk. --- LCS/Common/include/Common/AddressTranslator.h | 60 +++++++--- LCS/Common/include/Common/Backtrace.h | 4 +- LCS/Common/include/Common/SymbolTable.h | 40 +++---- LCS/Common/src/AddressTranslator.cc | 103 +++++++++++++++--- LCS/Common/src/Backtrace.cc | 4 +- LCS/Common/src/SymbolTable.cc | 38 +++---- LCS/Common/test/tBacktrace.cc | 4 +- LCS/Common/test/tSymbolTable.cc | 37 ------- 8 files changed, 166 insertions(+), 124 deletions(-) delete mode 100644 LCS/Common/test/tSymbolTable.cc diff --git a/LCS/Common/include/Common/AddressTranslator.h b/LCS/Common/include/Common/AddressTranslator.h index 32054dae0dc..ec2cc2d82ee 100644 --- a/LCS/Common/include/Common/AddressTranslator.h +++ b/LCS/Common/include/Common/AddressTranslator.h @@ -1,6 +1,6 @@ //# AddressTranslator.h: Translate return addresses to function, file, line. //# -//# Copyright (C) 2002-2008 +//# Copyright (C) 2002-2011 //# ASTRON (Netherlands Institute for Radio Astronomy) //# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands //# @@ -23,20 +23,18 @@ #ifndef LOFAR_COMMON_ADDRESSTRANSLATOR_H #define LOFAR_COMMON_ADDRESSTRANSLATOR_H -//# Never #include <config.h> or #include <lofar_config.h> in a header file! - // \file // Translate return addresses to function, file, line. //# Includes #include <Common/Backtrace.h> -#include <vector> #ifndef HAVE_BFD # warning Binary file descriptor (bfd) package is missing, \ please install the GNU binutils. #else # include <bfd.h> +# include <link.h> # ifdef USE_THREADS # include <pthread.h> # endif @@ -46,12 +44,18 @@ namespace LOFAR { // \ingroup Common // @{ - + // Functor class for translating return addresses to function name, // filename, and line number. // // \note The code is based on the utility addr2line.c in the GNU binutils // 2.16. + // \note For details on handling of shared libraries, please refer to + // - the Linux man page \c dl_iterate_phdr(3) + // - \c util/backtrace-symbols.c in cairo (http://cairographics.org/) + // - \c src/dwarf/Gfind_proc_info-lsb.c:callback() in libunwind + // (http://www.nongnu.org/libunwind/) + class AddressTranslator { public: AddressTranslator(); @@ -81,25 +85,45 @@ namespace LOFAR static pthread_mutex_t mutex; }; # endif - // Helper function to "convert" the member function - // do_find_addresss_in_section() to a void(*), which can be passed as - // argument to bfd_map_over_sections(). + // Helper function to pass the member function #do_find_matching_file() as + // argument to dl_iterate_phdr(). + // \see The Linux man page <tt>dl_iterate_phdr(3)</tt>. + static int find_matching_file(dl_phdr_info*, size_t, void*); + + // Look for the address #pc in the application's shared objects. If found, + // set the member variables #bfdFile and #base_addr. + int do_find_matching_file(dl_phdr_info*); + + // Helper function to pass the member function + // #do_find_address_in_section() as argument to bfd_map_over_sections(). // \see BFD documentation for details (<tt>info bfd</tt>). static void find_address_in_section(bfd*, asection*, void*); - // Find the source code line nearest to - void do_find_address_in_section(bfd*, asection*); + // Look for the address #pc in the section \a section of the symbol table + // associated with the BFD \a abfd. If found, set the member variables + // #filename, #line, and #functionname. + void do_find_address_in_section(bfd* abfd, asection* section); - // Local variables used by translate_addresses() and - // do_find_address_in_section(). + // @name Local variables set by operator() // @{ - bfd_vma pc; - const char* filename; - const char* functionname; - unsigned int line; - bool found; + asymbol** syms; ///< BFD symbol table information + bfd_vma pc; ///< Virtual memory address // @} -#endif + + // @name Local variables set by do_find_matching_file() + // @{ + const char* bfdFile; ///< Filename of the matching shared object + bfd_vma base_addr; ///< Base address of the shared object + // @} + + // @name Local variables set by do_find_address_in_section() + // @{ + const char* filename; ///< Name of matching source file + const char* functionname; ///< Name of matching function + unsigned int line; ///< Line number in matching source file + bool found; ///< Indicates whether a match was found + // @} +#endif /* HAVE_BFD */ }; // @} diff --git a/LCS/Common/include/Common/Backtrace.h b/LCS/Common/include/Common/Backtrace.h index b953a6d6399..dc8e2e49992 100644 --- a/LCS/Common/include/Common/Backtrace.h +++ b/LCS/Common/include/Common/Backtrace.h @@ -1,6 +1,6 @@ //# Backtrace.h: Store stack frame return addresses for self-debugging. //# -//# Copyright (C) 2002-2008 +//# Copyright (C) 2002-2011 //# ASTRON (Netherlands Institute for Radio Astronomy) //# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands //# @@ -30,7 +30,7 @@ # error Backtrace is not supported. #endif -// \def BACKTRACE_MAX_RETURN_ADDRESSES Maximum number of stack frame return +// Maximum number of stack frame return // addresses that will be stored by the Backtrace class (default=50). #ifndef BACKTRACE_MAX_RETURN_ADDRESSES # define BACKTRACE_MAX_RETURN_ADDRESSES 50 diff --git a/LCS/Common/include/Common/SymbolTable.h b/LCS/Common/include/Common/SymbolTable.h index a54ad8d6d37..fcf4c528e85 100644 --- a/LCS/Common/include/Common/SymbolTable.h +++ b/LCS/Common/include/Common/SymbolTable.h @@ -1,6 +1,6 @@ -//# SymbolTable.h: one line description +//# SymbolTable.h: Class holding the symbol table of an object file. //# -//# Copyright (C) 2002-2008 +//# Copyright (C) 2002-2011 //# ASTRON (Netherlands Institute for Radio Astronomy) //# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands //# @@ -39,57 +39,51 @@ namespace LOFAR // \addtogroup Common // @{ - // Class holding the symbol table of the current executable program. It is - // implemented as a Singleton. So, any overhead will only be paid when this - // class is instantiated, which will normally happen when the first - // Backtrace is printed (\e not when the first exception is thrown). + // Class holding the symbol table of an object file. // // \note The code is based on the utility addr2line.c in GNU binutils 2.16. class SymbolTable { public: + // Default constructor. Doesn't read any symbol table into memory. + SymbolTable(); + + // Read the symbol table from \a filename into memory. + SymbolTable(const char* filename); + // Destructor. ~SymbolTable(); - // Return an instance of SymbolTable. When called for the first time - // an instance of SymbolTable is created. Subsequent calls return the - // previously created instance. - static SymbolTable& instance(); - - // Return a pointer to the symbol table + // Return a pointer to the symbol table. asymbol** getSyms() const { return itsSymbols; } - // Return a pointer to the bfd + // Return a pointer to the bfd. bfd* getBfd() const { return itsBfd; } private: - // Default constructor is called from the static member function - // SymbolTable::instance(). - SymbolTable(); - // Disallow copy constructor. SymbolTable(const SymbolTable&); // Disallow assignment operator. SymbolTable& operator=(const SymbolTable&); - // Open the bfd-file and check its format. + // Open the object file \c filename and check its format. // @return True on success. - bool init(); + bool init(const char* filename); - // Read the symbol table from the bfd-file. + // Read the symbol table from the object file. // @return True when read was successful. bool read(); - // Free dynamically allocated memory; close bfd-file. + // Free dynamically allocated memory; close object file. void cleanup(); - // Pointer to the bfd + // Pointer to the binary file descriptor. bfd* itsBfd; - // Pointer to the symbol table. + // Pointer to the internal representation of the symbol table. asymbol** itsSymbols; }; diff --git a/LCS/Common/src/AddressTranslator.cc b/LCS/Common/src/AddressTranslator.cc index 41c197a61ad..81559d7255a 100644 --- a/LCS/Common/src/AddressTranslator.cc +++ b/LCS/Common/src/AddressTranslator.cc @@ -1,6 +1,6 @@ -//# AddressTranslator.cc: one line description +//# AddressTranslator.cc: Translate return addresses to function, file, line. //# -//# Copyright (C) 2002-2008 +//# Copyright (C) 2002-2011 //# ASTRON (Netherlands Institute for Radio Astronomy) //# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands //# @@ -27,16 +27,37 @@ #include <Common/AddressTranslator.h> #include <Common/Backtrace.h> #include <Common/SymbolTable.h> +#include <map> #include <cstdlib> #include <cstring> +#include <boost/shared_ptr.hpp> #ifdef __GNUG__ # include <cxxabi.h> #endif +#include <link.h> + namespace LOFAR { +#ifdef HAVE_BFD + namespace + { + // Map of symbol tables. + // Use the load address of the shared object or executable as key. + typedef std::map< bfd_vma, boost::shared_ptr<SymbolTable> > SymbolTableMap; + + // The map of symbol tables is implemented as a Meyers singleton. + // Use a lock to make access thread-safe. + SymbolTableMap& theSymbolTableMap() + { + static SymbolTableMap symTabMap; + return symTabMap; + } + } +#endif + AddressTranslator::AddressTranslator() { } @@ -55,15 +76,40 @@ namespace LOFAR # ifdef USE_THREADS ScopedLock sc; # endif - bfd* abfd = SymbolTable::instance().getBfd(); - if (!abfd) return; - for (int i = 0; i < size; i++) { + pc = reinterpret_cast<bfd_vma>(addr[i]); + + // Walk through list of shared objects (ref. man dl_iterate_phdr(3)). + // The callback function #find_matching_file() will set #bfdFile and + // #base_addr. + dl_iterate_phdr(find_matching_file, this); + + // Lookup the SymbolTable using #base_addr as key. Create a new entry + // if the symbol table of #bfdFile is not yet present in the map. + SymbolTableMap::iterator it = theSymbolTableMap().find(base_addr); + if(it == theSymbolTableMap().end()) { + it = theSymbolTableMap().insert + (std::make_pair(base_addr, new SymbolTable(bfdFile))).first; + } + + // Get the BFD-handle of the matching SymbolTable object. + bfd* abfd = it->second->getBfd(); + if (!abfd) continue; + + // Get the handle to the symbols of the matching SymbolTable. + if (!syms) continue; + syms = it->second->getSyms(); + + // Calculate offset address inside the matching shared object. + pc -= base_addr; found = false; + // Call the function #find_address_in_section() for each section + // attached to the BFD \a abfd. This function will set #filename, + // #functionname, #line and #found. bfd_map_over_sections(abfd, find_address_in_section, this); - + if (found) { if (functionname && *functionname) { # ifdef __GNUG__ @@ -88,8 +134,6 @@ namespace LOFAR } trace[i].line = line; } - // if (trace[i].function == "main") - // break; } #else (void) addr; // suppress `unused parameter' warning @@ -97,7 +141,6 @@ namespace LOFAR return; } - //##---- P r i v a t e f u n c t i o n s ----##// #ifdef HAVE_BFD @@ -107,6 +150,38 @@ namespace LOFAR AddressTranslator::ScopedLock::mutex = PTHREAD_MUTEX_INITIALIZER; # endif + int AddressTranslator::find_matching_file(dl_phdr_info* info, + size_t size, + void* data) + { + AddressTranslator* obj = static_cast<AddressTranslator*>(data); + return obj->do_find_matching_file(info); + } + + int AddressTranslator::do_find_matching_file(dl_phdr_info* info) + { + // This code is based on util/backtrace-symbols.c from Cairo + // (http://cairographics.org). + const ElfW(Phdr) *phdr = info->dlpi_phdr; + for (int n = info->dlpi_phnum; --n >= 0; phdr++) { + if (phdr->p_type == PT_LOAD) { + ElfW(Addr) vaddr = phdr->p_vaddr + info->dlpi_addr; + if (pc >= vaddr && pc < vaddr + phdr->p_memsz) { + // We found a match + if(info->dlpi_name && *info->dlpi_name) { + bfdFile = info->dlpi_name; + } else { + bfdFile = "/proc/self/exe"; + } + base_addr = info->dlpi_addr; + return 1; + } + } + } + return 0; + } + + void AddressTranslator::find_address_in_section(bfd* abfd, asection* section, void* data) @@ -120,18 +195,14 @@ namespace LOFAR { if (found) return; - - asymbol** syms = SymbolTable::instance().getSyms(); - if (!syms) - return; if ((bfd_get_section_flags (abfd, section) & SEC_ALLOC) == 0) return; - + bfd_vma vma = bfd_get_section_vma (abfd, section); if (pc < vma) return; - + bfd_size_type size = bfd_get_section_size (section); if (pc >= vma + size) return; @@ -139,7 +210,7 @@ namespace LOFAR found = bfd_find_nearest_line (abfd, section, syms, pc - vma, &filename, &functionname, &line); } - + #endif } // namespace LOFAR diff --git a/LCS/Common/src/Backtrace.cc b/LCS/Common/src/Backtrace.cc index a0e369d1fd2..581c2548e48 100644 --- a/LCS/Common/src/Backtrace.cc +++ b/LCS/Common/src/Backtrace.cc @@ -1,6 +1,6 @@ -//# Backtrace.cc: one line description +//# Backtrace.cc: Store stack frame return addresses for self-debugging. //# -//# Copyright (C) 2002-2008 +//# Copyright (C) 2002-2011 //# ASTRON (Netherlands Institute for Radio Astronomy) //# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands //# diff --git a/LCS/Common/src/SymbolTable.cc b/LCS/Common/src/SymbolTable.cc index b8f2f877eff..f4b345f71ff 100644 --- a/LCS/Common/src/SymbolTable.cc +++ b/LCS/Common/src/SymbolTable.cc @@ -1,6 +1,6 @@ -//# SymbolTable.cc: one line description +//# SymbolTable.cc: Class holding the symbol table of an object file. //# -//# Copyright (C) 2002-2008 +//# Copyright (C) 2002-2011 //# ASTRON (Netherlands Institute for Radio Astronomy) //# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands //# @@ -32,46 +32,36 @@ namespace LOFAR { -#if defined(__linux__) - static const char* bfdFile = "/proc/self/exe"; -#elif defined(__sun__) - static const char* bfdFile = "/proc/self/object/a.out"; -#else -# error "Alias for process's executable file, like /proc/self/exe \ -on linux, must be present." -#endif - - SymbolTable::SymbolTable() : itsBfd(0), itsSymbols(0) { - init() && read(); } - SymbolTable::~SymbolTable() + SymbolTable::SymbolTable(const char* filename) : + itsBfd(0), + itsSymbols(0) { - cleanup(); + init(filename) && read(); } - SymbolTable& SymbolTable::instance() + SymbolTable::~SymbolTable() { - static SymbolTable symTab; - return symTab; + cleanup(); } - bool SymbolTable::init() + bool SymbolTable::init(const char* filename) { bfd_init(); - if ((itsBfd = bfd_openr(bfdFile,0)) == 0) { - bfd_perror(bfdFile); + if ((itsBfd = bfd_openr(filename,0)) == 0) { + bfd_perror(filename); return false; } if (!bfd_check_format(itsBfd, bfd_object)) { - bfd_perror(bfdFile); + bfd_perror(filename); return false; } return true; @@ -81,7 +71,7 @@ on linux, must be present." bool SymbolTable::read() { if ((bfd_get_file_flags(itsBfd) & HAS_SYMS) == 0) { - bfd_perror(bfdFile); + bfd_perror(itsBfd->filename); return true; } unsigned int size; @@ -98,7 +88,7 @@ on linux, must be present." symcount = bfd_read_minisymbols(itsBfd, true, symbolUnion.dest, &size); } if (symcount < 0) { - bfd_perror(bfdFile); + bfd_perror(itsBfd->filename); return false; } return true; diff --git a/LCS/Common/test/tBacktrace.cc b/LCS/Common/test/tBacktrace.cc index 7699761e9bd..2633d68b027 100644 --- a/LCS/Common/test/tBacktrace.cc +++ b/LCS/Common/test/tBacktrace.cc @@ -1,6 +1,6 @@ -//# tBacktrace.cc: one line description +//# tBacktrace.cc: Unit test program for the Backtrace/Exception classes. //# -//# Copyright (C) 2002-2008 +//# Copyright (C) 2002-2011 //# ASTRON (Netherlands Institute for Radio Astronomy) //# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands //# diff --git a/LCS/Common/test/tSymbolTable.cc b/LCS/Common/test/tSymbolTable.cc deleted file mode 100644 index 190ca216751..00000000000 --- a/LCS/Common/test/tSymbolTable.cc +++ /dev/null @@ -1,37 +0,0 @@ -//# tSymbolTable.cc: one line description -//# -//# Copyright (C) 2002-2008 -//# ASTRON (Netherlands Institute for Radio Astronomy) -//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands -//# -//# This file is part of the LOFAR software suite. -//# The LOFAR software suite is free software: you can redistribute it and/or -//# modify it under the terms of the GNU General Public License as published -//# by the Free Software Foundation, either version 3 of the License, or -//# (at your option) any later version. -//# -//# The LOFAR software suite is distributed in the hope that it will be useful, -//# but WITHOUT ANY WARRANTY; without even the implied warranty of -//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -//# GNU General Public License for more details. -//# -//# You should have received a copy of the GNU General Public License along -//# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>. -//# -//# $Id$ - -//# Always #include <lofar_config.h> first! -#include <lofar_config.h> - -//# Includes -#include <Common/SymbolTable.h> -#include <Common/LofarLogger.h> - -using namespace LOFAR; - -int main() -{ - INIT_LOGGER("tSymbolTable"); - SymbolTable::instance(); - return 0; -} -- GitLab