Mercurial > hg > release > heapstats-1.0
view agent/src/symbolFinder.cpp @ 27:24f77b8a62fe
Bug 1587: Refactor to improve the messaging and gathering the symbols.
reviewed-by: yasuenag
author | KUBOTA Yuji <kubota.yuji@lab.ntt.co.jp> |
---|---|
date | Tue, 19 Nov 2013 21:22:04 +0900 |
parents | 1d573d30fe94 |
children | bbf8065fcd37 |
line wrap: on
line source
/*! * \file symbolFinder.cpp * \brief This file is used by search symbol in library. * Copyright (C) 2011-2013 Nippon Telegraph and Telephone Corporation * * This program 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 2 * of the License, or (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stddef.h> #include <limits.h> #include <link.h> #include <bfd.h> #include <errno.h> #include <sys/stat.h> #include "symbolFinder.hpp" #include "util.hpp" /*! * \brief Flag of BFD libarary is already initialized. */ bool TSymbolFinder::initFlag = false; /*! * \brief Create record stored library information. * \param libinfo [out] Record of library information. * \param libPath [in] Target library path. */ inline void createLibInfo(TLibraryInfo *libinfo, char const* libPath) { libinfo->libname_len = strlen(libPath); libinfo->libname = (char *)malloc(libinfo->libname_len + 1); /* If failure allocate memory. */ if (unlikely(libinfo->libname == NULL)) { return; } strcpy(libinfo->libname, libPath); } /*! * \brief Callback function of dl_iterate_phdr(3). * \param info [in] Information of loaded library on memory. * \param size [in] Size of library area on memory. * \param data [in] User data. * \return Continues callback loop if value is 0.<br> * Abort callback loop if value is 1. */ static int libraryCallback(struct dl_phdr_info *info, size_t size, void *data) { TLibraryInfo *libinfo = (TLibraryInfo *)data; /* If library is need. */ if (strncmp(info->dlpi_name, libinfo->libname, libinfo->libname_len) == 0) { /* Clean old string. */ free(libinfo->libname); /* Store library information. */ createLibInfo(libinfo, info->dlpi_name); libinfo->baseaddr = info->dlpi_addr; /* Abort callback loop. */ return 1; } return 0; } /*! * \brief TSymbolFinder constructor. */ TSymbolFinder::TSymbolFinder(void) { if (unlikely(!initFlag)) { initFlag = false; /* Global initialize. */ bfd_init(); } /* Zero clear records. */ memset(&libBfdInfo, 0, sizeof(libBfdInfo)); memset(&debugBfdInfo, 0, sizeof(debugBfdInfo)); memset(&targetLibInfo, 0, sizeof(targetLibInfo)); } /*! * \brief TSymbolFinder destructor. */ TSymbolFinder::~TSymbolFinder() { /* Cleanup. */ free(targetLibInfo.libname); targetLibInfo.libname = NULL; if (likely(libBfdInfo.bfdInfo != NULL)) { bfd_close(libBfdInfo.bfdInfo); libBfdInfo.bfdInfo = NULL; } if (likely(debugBfdInfo.bfdInfo != NULL)) { bfd_close(debugBfdInfo.bfdInfo); debugBfdInfo.bfdInfo = NULL; } if (likely(libBfdInfo.staticSyms != NULL)) { free(libBfdInfo.staticSyms); libBfdInfo.staticSyms = NULL; } if (likely(debugBfdInfo.staticSyms != NULL)) { free(debugBfdInfo.staticSyms); debugBfdInfo.staticSyms = NULL; } if (likely(libBfdInfo.dynSyms != NULL)) { free(libBfdInfo.dynSyms); libBfdInfo.dynSyms = NULL; } if (likely(debugBfdInfo.dynSyms != NULL)) { free(debugBfdInfo.dynSyms); debugBfdInfo.dynSyms = NULL; } } /*! * \brief Load target libaray. * \param pathPattern [in] Pattern of target library path. * \return Is success load library.<br> */ bool TSymbolFinder::loadLibrary(const char *pathPattern) { /* Sanity check. */ if (unlikely(pathPattern == NULL)) { PRINT_WARN_MSG("Failure allocate library path."); return false; } /* Initialize. */ createLibInfo(&targetLibInfo, pathPattern); targetLibInfo.baseaddr = ((ptrdiff_t)0); /* If failure allocate memory. */ if (unlikely(targetLibInfo.libname == NULL)) { PRINT_WARN_MSG("Failure allocate library path."); return false; } /* Search target library on memory. */ if (unlikely(dl_iterate_phdr(&libraryCallback, &targetLibInfo) == 0)) { PRINT_WARN_MSG("Failure search library on memory."); free(targetLibInfo.libname); return false; } /* Load library with bfd record. */ loadLibraryInfo(targetLibInfo.libname, &libBfdInfo); /* If bfd record has the symbols, no need to search debuginfo */ if (libBfdInfo.hasSymtab && libBfdInfo.staticSymCnt > 0 && libBfdInfo.dynSymCnt > 0) { return true; } char dbgInfoPath[PATH_MAX]; dbgInfoPath[0] = '\0'; /* Try to get debuginfo path from .note.gnu.build-id */ asection *buid_id_section = bfd_get_section_by_name( libBfdInfo.bfdInfo, ".note.gnu.build-id"); if(buid_id_section != NULL){ TBuildIdInfo *buildID; if(bfd_malloc_and_get_section(libBfdInfo.bfdInfo, buid_id_section, (bfd_byte **)&buildID)){ sprintf(dbgInfoPath, DEBUGINFO_DIR "/.build-id/%02hhx/", *(&(buildID->contents) + buildID->name_size)); for(unsigned int Cnt = buildID->name_size + 1; Cnt < buildID->name_size + buildID->hash_size; Cnt++){ char digitChars[3]; sprintf(digitChars, "%02hhx", *(&(buildID->contents) + Cnt)); strcat(dbgInfoPath, digitChars); } strcat(dbgInfoPath, DEBUGINFO_SUFFIX); } if(buildID != NULL){ free(buildID); } } if(dbgInfoPath[0] == '\0'){ /* Try to get debuginfo path from .gnu_debuglink */ char *buf = bfd_follow_gnu_debuglink(libBfdInfo.bfdInfo, DEBUGINFO_DIR); if(buf != NULL){ strcpy(dbgInfoPath, buf); free(buf); } } if(dbgInfoPath[0] != '\0'){ /* Load library's debuginfo with bfd record. */ struct stat st = {0}; if (unlikely(stat(&(dbgInfoPath[0]), &st) != 0)) { PRINT_WARN_MSG_HEADER << "Cannot read debuginfo from " << dbgInfoPath << NEWLINE; } else { PRINT_DEBUG_MSG_HEADER << "Try to read debuginfo from " << dbgInfoPath << NEWLINE; loadLibraryInfo(dbgInfoPath, &debugBfdInfo); } } if((debugBfdInfo.staticSymCnt == 0) && (debugBfdInfo.dynSymCnt == 0)){ PRINT_WARN_MSG_HEADER << "The same version of debuginfo not found: " << libBfdInfo.bfdInfo->filename << NEWLINE; } /* If failure both load process. */ if (unlikely(libBfdInfo.staticSymCnt == 0 && debugBfdInfo.staticSymCnt == 0 && libBfdInfo.dynSymCnt == 0 && debugBfdInfo.dynSymCnt == 0)) { PRINT_WARN_MSG("Failure load information about library."); free(targetLibInfo.libname); targetLibInfo.libname = NULL; return false; } return true; } /*! * \brief Find symbol in target library. * \param symbol [in] Symbol string. * \return Address of designated symbol.<br> * value is null if process is failure. */ void *TSymbolFinder::findSymbol(char const* symbol) { void *result = NULL; /* Search symbol in library as static symbol. */ if (likely(libBfdInfo.staticSymCnt != 0)) { result = doFindSymbol(&libBfdInfo, symbol, false); } if (unlikely(result == NULL)) { /* Search symbol in library's debuginfo. */ if (likely(debugBfdInfo.staticSymCnt != 0)) { result = doFindSymbol(&debugBfdInfo, symbol, false); } } /* Search symbol in library as dynamic symbol. */ if (unlikely(result == NULL)) { /* Search symbol in library. */ if (likely(libBfdInfo.dynSymCnt != 0)) { result = doFindSymbol(&libBfdInfo, symbol, true); } } if (unlikely(result == NULL)) { /* Search symbol in library's debuginfo. */ if (likely(debugBfdInfo.dynSymCnt != 0)) { result = doFindSymbol(&debugBfdInfo, symbol, true); } } if (likely(result != NULL)) { /* Convert absolute symbol address. */ result = getAbsoluteAddress(result); } return result; } /*! * \brief Load target libaray information. * \param path [in] Target library path. * \param libInfo [out] BFD information record.<br> * Value is null if process is failure. */ void TSymbolFinder::loadLibraryInfo(char const* path, TLibBFDInfo *libInfo) { bfd *bfdDesc = NULL; /* Open library. */ bfdDesc = bfd_openr(path, NULL); if (unlikely(bfdDesc == NULL)) { return; } /* If illegal format. */ if(!bfd_check_format(bfdDesc, bfd_object)) { bfd_close(bfdDesc); return; } /* If library don't have symbol. */ if (!(bfd_get_file_flags(bfdDesc) & HAS_SYMS)) { bfd_close(bfdDesc); return; } asymbol *syms = NULL; /* Create empty symbol as temporary working space. */ syms = bfd_make_empty_symbol(bfdDesc); if (unlikely(syms == NULL)) { bfd_close(bfdDesc); return; } /* Library is legal binary file. */ libInfo->bfdInfo = bfdDesc; /* Load static symbols. */ libInfo->staticSymCnt = bfd_read_minisymbols(bfdDesc, 0, (void **)&libInfo->staticSyms, &libInfo->staticSymSize); /* Load dynamic symbols. */ libInfo->dynSymCnt = bfd_read_minisymbols(bfdDesc, 1, (void **)&libInfo->dynSyms, &libInfo->dynSymSize); /* Check .symtab section. If there are no symbols in the BFD, * below function returns the size of terminal Null pointer or 0 */ libInfo->hasSymtab = (bfd_get_symtab_upper_bound(bfdDesc) > sizeof(NULL)); libInfo->workSym = syms; } /*! * \brief Find symbol in target library to use BFD. * \param libInfo [in] BFD information record. * \param symbol [in] Symbol string. * \param isDynSym [in] Symbol is dynamic symbol. * \return Address of designated symbol.<br> * value is null if process is failure. */ void *TSymbolFinder::doFindSymbol(TLibBFDInfo *libInfo, char const* symbol, bool isDynSym) { bfd *bfdDesc = libInfo->bfdInfo; asymbol *syms = libInfo->workSym; char *miniSymsEntry = NULL; int miniSymCnt = 0; int dyn = ((isDynSym) ? 1 : 0); void *result = NULL; unsigned int size = 0; /* Load symbol list from binary file. */ if (isDynSym) { miniSymCnt = libInfo->dynSymCnt; miniSymsEntry = libInfo->dynSyms; size = libInfo->dynSymSize; } else { miniSymCnt = libInfo->staticSymCnt; miniSymsEntry = libInfo->staticSyms; size = libInfo->staticSymSize; } /* Search symbol. */ for (int idx = 0; idx < miniSymCnt; idx++) { /* Convert symbol to normally symbol. */ asymbol *symEntry = bfd_minisymbol_to_symbol(bfdDesc, dyn, miniSymsEntry, syms); if (strcmp(bfd_asymbol_name(symEntry), symbol) == 0) { /* Found target symbol. */ result = (void *)bfd_asymbol_value(symEntry); break; } /* Move next symbol entry. */ miniSymsEntry += (ptrdiff_t)size; } return result; }