Add backtrace building functionality
authorAdam Malinowski <a.malinowsk2@partner.samsung.com>
Mon, 23 Jun 2014 12:09:29 +0000 (14:09 +0200)
committerRafal Krypa <r.krypa@samsung.com>
Thu, 3 Jul 2014 12:19:09 +0000 (14:19 +0200)
Change-Id: I3443b444d6f7a6f507e55a88c36c936274965e3e

packaging/cynara.spec
src/CMakeLists.txt
src/common/CMakeLists.txt
src/common/log/Backtrace.cpp [new file with mode: 0644]
src/common/log/Backtrace.h [new file with mode: 0644]

index 52ffb9a..8f33300 100644 (file)
@@ -14,6 +14,17 @@ BuildRequires: pkgconfig(libsystemd-daemon)
 BuildRequires: pkgconfig(libsystemd-journal)
 %{?systemd_requires}
 
+%global build_type %{?build_type:%build_type}%{!?build_type:RELEASE}
+
+%if %{?build_type} == "DEBUG"
+
+BuildRequires: pkgconfig(libunwind)
+BuildRequires: pkgconfig(zlib)
+BuildRequires: binutils-devel
+
+%endif
+
+
 %description
 service and client libraries (libcynara-client, libcynara-admin)
 
@@ -77,11 +88,12 @@ export FFLAGS="$FFLAGS -DTIZEN_DEBUG_ENABLE"
 export LDFLAGS+="-Wl,--rpath=%{_libdir}"
 
 %cmake . -DVERSION=%{version} \
-        -DCMAKE_BUILD_TYPE=%{?build_type:%build_type}%{!?build_type:DEBUG} \
+        -DCMAKE_BUILD_TYPE=%{?build_type} \
         -DCMAKE_VERBOSE_MAKEFILE=ON
 make %{?jobs:-j%jobs}
 
 %install
+
 rm -rf %{buildroot}
 %make_install
 
index 9c4a23d..6b908c3 100644 (file)
 # @author      Lukasz Wojciechowski <l.wojciechow@partner.samsung.com>
 #
 
-PKG_CHECK_MODULES(CYNARA_DEP
+SET(COMMON_DEPS
     libsystemd-daemon
     libsystemd-journal
+    )
+
+IF (CMAKE_BUILD_TYPE MATCHES "DEBUG")
+SET(COMMON_DEPS
+    ${COMMON_DEPS}
+    libunwind
+    zlib
+    )
+ENDIF (CMAKE_BUILD_TYPE MATCHES "DEBUG")
+
+PKG_CHECK_MODULES(CYNARA_DEP
     REQUIRED
+    ${COMMON_DEPS}
     )
 
 INCLUDE_DIRECTORIES(SYSTEM
index 5d68662..6948492 100644 (file)
@@ -28,6 +28,12 @@ SET(COMMON_SOURCES
     ${COMMON_PATH}/types/PolicyKey.cpp
     )
 
+IF (CMAKE_BUILD_TYPE MATCHES "DEBUG")
+SET(COMMON_SOURCES ${COMMON_SOURCES}
+    ${COMMON_PATH}/log/Backtrace.cpp
+    )
+ENDIF (CMAKE_BUILD_TYPE MATCHES "DEBUG")
+
 ADD_LIBRARY(${TARGET_CYNARA_COMMON} SHARED ${COMMON_SOURCES})
 
 SET_TARGET_PROPERTIES(
@@ -38,8 +44,18 @@ SET_TARGET_PROPERTIES(
         VERSION ${CYNARA_COMMON_VERSION}
     )
 
+IF (CMAKE_BUILD_TYPE MATCHES "DEBUG")
+SET(CYNARA_DBG_LIBRARIES
+    ${CYNARA_DEP_LIBRARIES}
+    -lbfd
+    -liberty
+    -ldl
+    )
+ENDIF (CMAKE_BUILD_TYPE MATCHES "DEBUG")
+
 TARGET_LINK_LIBRARIES(${TARGET_CYNARA_COMMON}
     ${CYNARA_DEP_LIBRARIES}
+    ${CYNARA_DBG_LIBRARIES}
     )
 
 INSTALL(TARGETS ${TARGET_CYNARA_COMMON} DESTINATION ${LIB_INSTALL_DIR})
diff --git a/src/common/log/Backtrace.cpp b/src/common/log/Backtrace.cpp
new file mode 100644 (file)
index 0000000..a58c0ed
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Lukasz Wojciechowski <l.wojciechow@partner.samsung.com>
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+/*
+ * @file        Backtrace.cpp
+ * @author      Adam Malinowski <a.malinowsk2@partner.samsung.com>
+ * @version     1.0
+ * @brief       Implementation of backtrace utility class.
+ */
+
+#include "Backtrace.h"
+
+#include <cxxabi.h>
+#include <log/log.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+namespace Cynara {
+
+Backtrace &Backtrace::getInstance(void) {
+    static Backtrace m_instance(NULL);
+    return m_instance;
+}
+
+Backtrace::Backtrace(bfd *abfd) :
+        m_bfd(abfd), m_found(false), m_pc(0), m_fileName(NULL),
+        m_functionName(NULL), m_lineNumber(0) {
+}
+
+Backtrace::~Backtrace() {
+    if (m_bfd) {
+        bfd_close(m_bfd);
+        LOGD("Binary file closed.");
+    }
+}
+
+bool Backtrace::init(void) {
+    char exePath[BUFSIZ];
+    readlink("/proc/self/exe", exePath, BUFSIZ);
+
+    bfd_init();
+    m_bfd = bfd_openr(exePath, NULL);
+    if (m_bfd) {
+        m_bfd->flags |= BFD_DECOMPRESS;
+        if (bfd_check_format_matches(m_bfd, bfd_object, 0)) {
+            return true;
+        }
+        bfd_close(m_bfd);
+        m_bfd = NULL;
+        LOGE("Binary file check format failed.");
+    } else {
+        LOGE("Failed to open file: %s", exePath);
+    }
+
+    return false;
+}
+
+void Backtrace::findAddressInSection(bfd *abfd, asection *section, void *data) {
+    bfd_vma vma;
+    bfd_size_type size;
+
+    Backtrace *backtrace = static_cast<Backtrace*>(data);
+
+    if (backtrace->m_found) {
+        return;
+    }
+
+    if ((bfd_get_section_flags (abfd, section) & SEC_ALLOC) == 0) {
+        return;
+    }
+
+    vma = bfd_get_section_vma(abfd, section);
+    if (backtrace->m_pc < vma) {
+        return;
+    }
+
+    size = bfd_get_section_size(section);
+    if (backtrace->m_pc >= vma + size) {
+        return;
+    }
+
+    backtrace->m_found = bfd_find_nearest_line(abfd, section, NULL,
+            backtrace->m_pc - vma, &backtrace->m_fileName,
+            &backtrace->m_functionName, &backtrace->m_lineNumber);
+}
+
+void Backtrace::getSourceInfo(unw_word_t proc_address) {
+    char addr[64];
+
+    sprintf(addr, "0x%lx", static_cast<long unsigned int>(proc_address));
+    m_pc = bfd_scan_vma(addr, NULL, 16);
+    m_found = false;
+    bfd_map_over_sections(m_bfd, findAddressInSection, this);
+
+    if (m_found) {
+        while (true) {
+            m_found = bfd_find_inliner_info(m_bfd, &m_fileName, &m_functionName,
+                    &m_lineNumber);
+            if (!m_found)
+                break;
+        }
+    } else {
+        m_fileName = "??";
+        m_functionName = "??";
+        m_lineNumber = 0;
+    }
+}
+
+const std::string Backtrace::buildBacktrace(void) {
+    std::string backtrace;
+    unw_cursor_t cursor;
+    unw_context_t uc;
+    unw_word_t ip, sp;
+    char proc_name[BUFSIZ];
+    char btstr[BUFSIZ];
+    unw_word_t offp;
+    char *realname;
+    int status;
+
+    if (m_bfd == NULL) {
+        init();
+    }
+
+    unw_getcontext(&uc);
+    // get rid of previous function: Backtrace::getBacktrace
+    unw_init_local(&cursor, &uc);
+    unw_step(&cursor);
+    while (unw_step(&cursor) > 0) {
+        unw_get_reg(&cursor, UNW_REG_IP, &ip);
+        unw_get_reg(&cursor, UNW_REG_SP, &sp);
+        unw_get_proc_name(&cursor, proc_name, sizeof(proc_name), &offp);
+        realname = abi::__cxa_demangle(proc_name, 0, 0, &status);
+        getSourceInfo(ip);
+
+        snprintf(btstr, sizeof(btstr), "ip = %lx, sp = %lx, %s, %s:%d\n",
+                (long) ip, (long) sp, realname ? realname : proc_name,
+                m_fileName, m_lineNumber);
+        backtrace += btstr;
+    }
+
+    return backtrace;
+}
+
+const std::string Backtrace::getBacktrace(void) {
+    return getInstance().buildBacktrace();
+}
+
+} /* namespace Cynara */
diff --git a/src/common/log/Backtrace.h b/src/common/log/Backtrace.h
new file mode 100644 (file)
index 0000000..568c921
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Lukasz Wojciechowski <l.wojciechow@partner.samsung.com>
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+/*
+ * @file        Backtrace.h
+ * @author      Adam Malinowski <a.malinowsk2@partner.samsung.com>
+ * @version     1.0
+ * @brief       Header file for backtrace utility class.
+ */
+
+#ifndef SRC_COMMON_LOG_BACKTRACE_H_
+#define SRC_COMMON_LOG_BACKTRACE_H_
+
+// Bellow two defines are needed by /usr/include/bfd.h file.
+// In fact it needs config.h generated by autotools
+// but we dont use autotools to build cynara so we don't have config.h
+// bfd.h checks for these defines
+#define PACKAGE             1
+#define PACKAGE_VERSION     1
+
+#include <bfd.h>
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#include <string>
+
+namespace Cynara {
+
+class Backtrace {
+public:
+#ifdef BUILD_TYPE_DEBUG
+    static const std::string getBacktrace(void);
+#else
+    static const std::string getBacktrace(void) {
+        return "";
+    }
+#endif
+
+private:
+    static Backtrace &getInstance(void);
+
+    Backtrace(bfd *abfd);
+    Backtrace(Backtrace const &) = delete;
+    ~Backtrace();
+
+    void operator=(Backtrace const &) = delete;
+
+    bool init(void);
+    const std::string buildBacktrace(void);
+    static void findAddressInSection(bfd *abfd, asection *section, void *data);
+    void getSourceInfo(unw_word_t proc_address);
+
+private:
+    bfd *m_bfd;
+    bool m_found;
+    bfd_vma m_pc;
+    const char *m_fileName;
+    const char *m_functionName;
+    unsigned int m_lineNumber;
+};
+
+} /* namespace Cynara */
+
+#endif /* SRC_COMMON_LOG_BACKTRACE_H_ */