>From 9e86511b2d7818011e311ef03a131d7983901e22 Mon Sep 17 00:00:00 2001
From: Karel Klic <kklic@redhat.com>
Date: Mon, 30 Aug 2010 18:51:01 +0200
Subject: [PATCH 2/2] Integrate the btparser library for backtrace processing.

---
 configure.ac            |    3 +-
 lib/plugins/CCpp.cpp    |  279 +++++++++++++----------------------------------
 lib/plugins/Makefile.am |    4 +-
 3 files changed, 78 insertions(+), 208 deletions(-)

diff --git a/configure.ac b/configure.ac
index 4260ff4..2d9e0f7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -47,7 +47,8 @@ PKG_CHECK_MODULES([LIBNOTIFY], [libnotify])
 #PKG_CHECK_MODULES([NSS], [nss])
 PKG_CHECK_MODULES([XMLRPC], [xmlrpc])
 PKG_CHECK_MODULES([XMLRPC_CLIENT], [xmlrpc_client])
-PKG_CHECK_MODULES([POLKIT],[polkit-gobject-1])
+PKG_CHECK_MODULES([POLKIT], [polkit-gobject-1])
+PKG_CHECK_MODULES([BTPARSER], [btparser])
 
 PKG_PROG_PKG_CONFIG
 AC_ARG_WITH([systemdsystemunitdir],
diff --git a/lib/plugins/CCpp.cpp b/lib/plugins/CCpp.cpp
index 7665cad..9ca10a4 100644
--- a/lib/plugins/CCpp.cpp
+++ b/lib/plugins/CCpp.cpp
@@ -20,13 +20,15 @@
 */
 #include <set>
 #include <iomanip>
+#include <btparser/backtrace.h>
+#include <btparser/frame.h>
+#include <btparser/location.h>
 #include "abrtlib.h"
 #include "CCpp.h"
 #include "abrt_exception.h"
 #include "debug_dump.h"
 #include "comm_layer_inner.h"
 #include "Polkit.h"
-#include "backtrace.h"
 #include "CCpp_sha1.h"
 
 using namespace std;
@@ -597,134 +599,18 @@ string CAnalyzerCCpp::GetGlobalUUID(const char *pDebugDumpDir)
         return string("");
     }
 
-    if (dd_exist(dd, FILENAME_GLOBAL_UUID))
+    if (!dd_exist(dd, FILENAME_GLOBAL_UUID))
     {
-        char *uuid = dd_loadtxt(dd, FILENAME_GLOBAL_UUID);
+        VERB1 log(_("Unable to find %s in %s"), FILENAME_GLOBAL_UUID, pDebugDumpDir);
         dd_close(dd);
-        string ret = uuid;
-        free(uuid);
-        return ret;
+        return string("");
     }
-    else
-    {
-        // Compatibility code.
-        // This whole block should be deleted for Fedora 14.
-        log(_("Getting global universal unique identification..."));
-
-        string backtrace_path = concat_path_file(pDebugDumpDir, FILENAME_BACKTRACE);
-        char *executable = dd_loadtxt(dd, FILENAME_EXECUTABLE);
-        char *package = dd_loadtxt(dd, FILENAME_PACKAGE);
-        char *uid_str = m_bBacktrace ? dd_loadtxt(dd, CD_UID) : xstrdup("");
-
-        string independent_backtrace;
-        if (m_bBacktrace)
-        {
-            /* Run abrt-backtrace to get independent backtrace suitable
-               to UUID calculation. */
-            char *backtrace_path = concat_path_file(pDebugDumpDir, FILENAME_BACKTRACE);
-            char *args[7];
-            args[0] = (char*)"abrt-backtrace";
-            args[1] = (char*)"--single-thread";
-            args[2] = (char*)"--remove-exit-handlers";
-            args[3] = (char*)"--frame-depth=5";
-            args[4] = (char*)"--remove-noncrash-frames";
-            args[5] = backtrace_path;
-            args[6] = NULL;
-
-            int pipeout[2];
-            xpipe(pipeout); /* stdout of abrt-backtrace */
-
-            fflush(NULL);
-            pid_t child = fork();
-            if (child == -1)
-                perror_msg_and_die("fork");
-            if (child == 0)
-            {
-                VERB1 log("Executing %s", args[0]);
-
-                xmove_fd(pipeout[1], STDOUT_FILENO);
-                close(pipeout[0]); /* read side of the pipe */
-
-                /* abrt-backtrace is executed under the user's uid and gid. */
-                uid_t uid = xatoi_u(uid_str);
-                struct passwd* pw = getpwuid(uid);
-                gid_t gid = pw ? pw->pw_gid : uid;
-                setgroups(1, &gid);
-                xsetregid(gid, gid);
-                xsetreuid(uid, uid);
-
-                execvp(args[0], args);
-                VERB1 perror_msg("Can't execute '%s'", args[0]);
-                exit(1);
-            }
-
-            free(backtrace_path);
-            close(pipeout[1]); /* write side of the pipe */
-
-            /* Read the result from abrt-backtrace. */
-            int r;
-            char buff[1024];
-            while ((r = safe_read(pipeout[0], buff, sizeof(buff) - 1)) > 0)
-            {
-                buff[r] = '\0';
-                independent_backtrace += buff;
-            }
-            close(pipeout[0]);
-
-            /* Wait until it exits, and check the exit status. */
-            errno = 0;
-            int status;
-            waitpid(child, &status, 0);
-            if (!WIFEXITED(status))
-            {
-                perror_msg("abrt-backtrace not executed properly, "
-                           "status: %x signal: %d", status, WIFSIGNALED(status));
-            }
-            else
-            {
-                int exit_status = WEXITSTATUS(status);
-                if (exit_status == 79) /* EX_PARSINGFAILED */
-                {
-                    /* abrt-backtrace returns alternative backtrace
-                       representation in this case, so everything will work
-                       as expected except worse duplication detection */
-                    log_msg("abrt-backtrace failed to parse the backtrace");
-                }
-                else if (exit_status == 80) /* EX_THREADDETECTIONFAILED */
-                {
-                    /* abrt-backtrace returns backtrace with all threads
-                       in this case, so everything will work as expected
-                       except worse duplication detection */
-                    log_msg("abrt-backtrace failed to determine crash frame");
-                }
-                else if (exit_status != 0)
-                {
-                    /* this is unexpected problem and it should be investigated */
-                    error_msg("abrt-backtrace run failed, exit value: %d",
-                              exit_status);
-                }
-            }
-
-            /*VERB1 log("abrt-backtrace result: %s", independent_backtrace.c_str());*/
-        }
-        /* else: no backtrace, independent_backtrace == ""
-           no backtrace => rating = 0
-        */
-        else
-        {
-            dd_savetxt(dd, FILENAME_RATING, "0");
-        }
-        dd_close(dd);
-
-        char *hash_str = xasprintf("%s%s%s", package, executable, independent_backtrace.c_str());
-        free(package);
-        free(executable);
-
-        string hash = create_hash(hash_str);
-        free(hash_str);
 
-        return hash;
-    }
+    char *uuid = dd_loadtxt(dd, FILENAME_GLOBAL_UUID);
+    dd_close(dd);
+    string ret = uuid;
+    free(uuid);
+    return ret;
 }
 
 static bool DebuginfoCheckPolkit(uid_t uid)
@@ -811,6 +697,8 @@ void CAnalyzerCCpp::CreateReport(const char *pDebugDumpDir, int force)
     else
         VERB1 log(_("Skipping the debuginfo installation"));
 
+    free(uid);
+
     /* Create and store backtrace. */
     char *backtrace_str = get_backtrace(pDebugDumpDir, m_sDebugInfoDirs.c_str());
     if (!backtrace_str)
@@ -835,91 +723,72 @@ void CAnalyzerCCpp::CreateReport(const char *pDebugDumpDir, int force)
     if (m_bMemoryMap)
         dd_savetxt(dd, FILENAME_MEMORYMAP, "memory map of the crashed C/C++ application, not implemented yet");
 
-    /* Compute and store UUID from the backtrace. */
-    char *backtrace_cpy = xstrdup(backtrace_str);
+    /* Parse the backtrace to get more information. */
+    char *backtrace_str_ptr = backtrace_str;
+    struct btp_backtrace *backtrace = NULL;
+    struct btp_location location;
+    btp_location_init(&location);
+    if (!btp_backtrace_parse(&backtrace_str_ptr, &backtrace, &location))
+    {
+        VERB1 log(_("Backtrace parsing failed for %s"), pDebugDumpDir);
+        VERB1 log("%d:%d: %s", location.line, location.column, location.message);
+        /* If the parser failed compute the UUID from the executable
+           and package only.  This is not supposed to happen often.
+           Do not store the rating, as we do not know how good the
+           backtrace is. */
+        struct strbuf *emptybt = strbuf_new();
+        strbuf_prepend_str(emptybt, executable);
+        strbuf_prepend_str(emptybt, package);
+        dd_savetxt(dd, FILENAME_GLOBAL_UUID, create_hash(emptybt->buf).c_str());
+        strbuf_free(emptybt);
+        free(backtrace_str);
+        free(package);
+        free(executable);
+        dd_close(dd);
+        return;
+    }
+    free(backtrace_str);
 
-    struct backtrace *backtrace = backtrace_parse(backtrace_cpy, false, false);
-    free(backtrace_cpy);
+    /* Compute UUID. */
+    char *str_hash_core = btp_backtrace_get_duplication_hash(backtrace);
+    struct strbuf *str_hash = strbuf_new();
+    strbuf_append_str(str_hash, package);
+    strbuf_append_str(str_hash, executable);
+    strbuf_append_str(str_hash, str_hash_core);
+    dd_savetxt(dd, FILENAME_GLOBAL_UUID, create_hash(str_hash->buf).c_str());
+    strbuf_free(str_hash);
+    free(str_hash_core);
+
+    /* Compute the backtrace rating. */
+    float quality = btp_backtrace_quality_complex(backtrace);
+    const char *rating;
+    if (quality < 0.6f)
+        rating = "0";
+    else if (quality < 0.7f)
+        rating = "1";
+    else if (quality < 0.8f)
+        rating = "2";
+    else if (quality < 0.9f)
+        rating = "3";
+    else
+        rating = "4";
+    dd_savetxt(dd, FILENAME_RATING, rating);
 
-    if (backtrace)
+    /* Get the function name from the crash frame. */
+    struct btp_frame *crash_frame = btp_backtrace_get_crash_frame(backtrace);
+    if (crash_frame)
     {
-        /* Get the quality of the full backtrace. */
-        float q1 = backtrace_quality(backtrace);
-
-        /* Remove all the other threads except the crash thread. */
-        struct thread *crash_thread = backtrace_find_crash_thread(backtrace);
-        if (crash_thread)
-            backtrace_remove_threads_except_one(backtrace, crash_thread);
-        else
-            log_msg("Detection of crash thread failed");
-
-        /* Get the quality of the crash thread. */
-        float q2 = backtrace_quality(backtrace);
-
-        backtrace_remove_noncrash_frames(backtrace);
-
-        /* Do the frame removal now. */
-        backtrace_limit_frame_depth(backtrace, 5);
-        /* Frame removal can be done before removing exit handlers. */
-        backtrace_remove_exit_handlers(backtrace);
-
-        /* Get the quality of frames around the crash. */
-        float q3 = backtrace_quality(backtrace);
-
-        /* Compute UUID. */
-        struct strbuf *bt = backtrace_tree_as_str(backtrace, false);
-        strbuf_prepend_str(bt, executable);
-        strbuf_prepend_str(bt, package);
-        dd_savetxt(dd, FILENAME_GLOBAL_UUID, create_hash(bt->buf).c_str());
-        strbuf_free(bt);
-
-        /* Compute and store backtrace rating. */
-        /* Compute and store backtrace rating. The crash frame
-           is more important that the others. The frames around
-           the crash are more important than the rest.  */
-        float qtot = 0.25f * q1 + 0.35f * q2 + 0.4f * q3;
-
-        /* Turn the quality to rating. */
-        const char *rating;
-        if (qtot < 0.6f)      rating = "0";
-        else if (qtot < 0.7f) rating = "1";
-        else if (qtot < 0.8f) rating = "2";
-        else if (qtot < 0.9f) rating = "3";
-        else                  rating = "4";
-        dd_savetxt(dd, FILENAME_RATING, rating);
-
-        /* Get the function name from the crash frame. */
-        if (crash_thread)
+        if (crash_frame->function_name &&
+            0 != strcmp(crash_frame->function_name, "??"))
         {
-            struct frame *crash_frame = crash_thread->frames;
-            struct frame *abort_frame = thread_find_abort_frame(crash_thread);
-            if (abort_frame)
-                crash_frame = abort_frame->next;
-            if (crash_frame && crash_frame->function && 0 != strcmp(crash_frame->function, "??"))
-                dd_savetxt(dd, FILENAME_CRASH_FUNCTION, crash_frame->function);
+            dd_savetxt(dd, FILENAME_CRASH_FUNCTION, crash_frame->function_name);
         }
-
-        backtrace_free(backtrace);
+        btp_frame_free(crash_frame);
     }
-    else
-    {
-        /* If the parser failed fall back to the independent backtrace. */
-        /* If we write and use a hand-written parser instead of the bison one,
-           the parser never fails, and it will be possible to get rid of
-           the independent_backtrace and backtrace_rate_old. */
-        struct strbuf *ibt = independent_backtrace(backtrace_str);
-        strbuf_prepend_str(ibt, executable);
-        strbuf_prepend_str(ibt, package);
-        dd_savetxt(dd, FILENAME_GLOBAL_UUID, create_hash(ibt->buf).c_str());
-        strbuf_free(ibt);
-
-        /* Compute and store backtrace rating. */
-        /* Crash frame is not known so store nothing. */
-        dd_savetxt(dd, FILENAME_RATING, to_string(backtrace_rate_old(backtrace_str)).c_str());
-    }
-    free(executable);
+
+    btp_backtrace_free(backtrace);
     free(package);
-    free(backtrace_str);
+    free(executable);
     dd_close(dd);
 }
 
diff --git a/lib/plugins/Makefile.am b/lib/plugins/Makefile.am
index a896e14..e995f17 100644
--- a/lib/plugins/Makefile.am
+++ b/lib/plugins/Makefile.am
@@ -66,9 +66,9 @@ UTILS_PATH=$(srcdir)/../utils
 # CCpp
 libCCpp_la_SOURCES = CCpp.cpp CCpp.h CCpp_sha1.cpp CCpp_sha1.h
 libCCpp_la_LDFLAGS = -avoid-version
-#libCCpp_la_LIBADD =
+libCCpp_la_LIBADD = $(BTPARSER_LIBS)
 libCCpp_la_CPPFLAGS = -Wall -Werror \
-    -I$(INC_PATH) -I$(UTILS_PATH) \
+    -I$(INC_PATH) -I$(UTILS_PATH) $(BTPARSER_CFLAGS) \
     -DCCPP_HOOK_PATH=\"${libexecdir}/abrt-hook-ccpp\" \
     -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
     -DLOCALSTATEDIR='"$(localstatedir)"'
-- 
1.7.2.2

