summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/plugins/CCpp.cpp1
-rw-r--r--lib/plugins/Makefile.am1
-rw-r--r--lib/utils/Makefile.am4
-rw-r--r--lib/utils/backtrace.c846
-rw-r--r--lib/utils/backtrace.h152
-rw-r--r--lib/utils/backtrace_parser.y684
6 files changed, 0 insertions, 1688 deletions
diff --git a/lib/plugins/CCpp.cpp b/lib/plugins/CCpp.cpp
index 2bae89d6..e5b50c34 100644
--- a/lib/plugins/CCpp.cpp
+++ b/lib/plugins/CCpp.cpp
@@ -24,7 +24,6 @@
#include "abrt_exception.h"
#include "comm_layer_inner.h"
#include "Polkit.h"
-#include "backtrace.h"
using namespace std;
diff --git a/lib/plugins/Makefile.am b/lib/plugins/Makefile.am
index 2e50cc2d..f07b376d 100644
--- a/lib/plugins/Makefile.am
+++ b/lib/plugins/Makefile.am
@@ -66,7 +66,6 @@ UTILS_PATH=$(srcdir)/../utils
# CCpp
libCCpp_la_SOURCES = CCpp.cpp CCpp.h
libCCpp_la_LDFLAGS = -avoid-version
-#libCCpp_la_LIBADD =
libCCpp_la_CPPFLAGS = -Wall -Werror \
-I$(INC_PATH) -I$(UTILS_PATH) \
-DCCPP_HOOK_PATH=\"${libexecdir}/abrt-hook-ccpp\" \
diff --git a/lib/utils/Makefile.am b/lib/utils/Makefile.am
index ac5f4837..79df31e5 100644
--- a/lib/utils/Makefile.am
+++ b/lib/utils/Makefile.am
@@ -3,7 +3,6 @@
lib_LTLIBRARIES = libABRTUtils.la libABRTdUtils.la
HEADER_DIR = $(srcdir)/../../inc
AM_CPPFLAGS = -I$(HEADER_DIR)
-AM_YFLAGS = --verbose
# Not used just yet:
# time.cpp
@@ -27,8 +26,6 @@ libABRTUtils_la_SOURCES = \
abrt_dbus.c abrt_dbus.h \
CrashTypes.cpp \
ABRTException.cpp \
- backtrace.c backtrace.h \
- backtrace_parser.y \
strbuf.c strbuf.h \
abrt_packages.c abrt_packages.h \
hooklib.c hooklib.h \
@@ -53,7 +50,6 @@ libABRTUtils_la_LIBADD = \
$(DBUS_LIBS) \
-ldl
-
libABRTdUtils_la_SOURCES = \
parse_release.cpp \
make_descr.cpp \
diff --git a/lib/utils/backtrace.c b/lib/utils/backtrace.c
deleted file mode 100644
index f507cba3..00000000
--- a/lib/utils/backtrace.c
+++ /dev/null
@@ -1,846 +0,0 @@
-/*
- Copyright (C) 2009 RedHat inc.
-
- 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.
-*/
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include "backtrace.h"
-#include "strbuf.h"
-#include "xfuncs.h"
-
-struct frame *frame_new()
-{
- struct frame *f = malloc(sizeof(struct frame));
- if (!f)
- {
- puts("Error while allocating memory for backtrace frame.");
- exit(5);
- }
-
- f->function = NULL;
- f->number = 0;
- f->sourcefile = NULL;
- f->signal_handler_called = false;
- f->next = NULL;
- return f;
-}
-
-void frame_free(struct frame *f)
-{
- if (f->function)
- free(f->function);
- if (f->sourcefile)
- free(f->sourcefile);
- free(f);
-}
-
-struct frame *frame_add_sibling(struct frame *a, struct frame *b)
-{
- struct frame *aa = a;
- while (aa->next)
- aa = aa->next;
-
- aa->next = b;
- return a;
-}
-
-/* Appends a string representation of 'frame' to the 'str'. */
-static void frame_append_str(struct frame *frame, struct strbuf *str, bool verbose)
-{
- if (verbose)
- strbuf_append_strf(str, " #%d", frame->number);
- else
- strbuf_append_str(str, " ");
-
- if (frame->function)
- strbuf_append_strf(str, " %s", frame->function);
- if (verbose && frame->sourcefile)
- {
- if (frame->function)
- strbuf_append_str(str, " at");
- strbuf_append_strf(str, " %s", frame->sourcefile);
- }
-
- if (frame->signal_handler_called)
- strbuf_append_str(str, " <signal handler called>");
-
- strbuf_append_str(str, "\n");
-}
-
-static bool frame_is_exit_handler(struct frame *frame)
-{
- return (frame->function
- && frame->sourcefile
- && 0 == strcmp(frame->function, "__run_exit_handlers")
- && NULL != strstr(frame->sourcefile, "exit.c"));
-}
-
-/* Checks if a frame contains abort function used
- * by operating system to exit application.
- * E.g. in C it's called "abort" or "raise".
- */
-static bool frame_is_abort_frame(struct frame *frame)
-{
- if (!frame->function || !frame->sourcefile)
- return false;
-
- if (0 == strcmp(frame->function, "raise")
- && (NULL != strstr(frame->sourcefile, "pt-raise.c")
- || NULL != strstr(frame->sourcefile, "/libc.so.6")))
- return true;
- else if (0 == strcmp(frame->function, "exit")
- && NULL != strstr(frame->sourcefile, "exit.c"))
- return true;
- else if (0 == strcmp(frame->function, "abort")
- && (NULL != strstr(frame->sourcefile, "abort.c")
- || NULL != strstr(frame->sourcefile, "/libc.so.6")))
- return true;
- else if (frame_is_exit_handler(frame))
- return true;
-
- return false;
-}
-
-static bool frame_is_noncrash_frame(struct frame *frame)
-{
- /* Abort frames. */
- if (frame_is_abort_frame(frame))
- return true;
-
- if (!frame->function)
- return false;
-
- if (0 == strcmp(frame->function, "__kernel_vsyscall"))
- return true;
-
- if (0 == strcmp(frame->function, "__assert_fail"))
- return true;
-
- if (!frame->sourcefile)
- return false;
-
- /* GDK */
- if (0 == strcmp(frame->function, "gdk_x_error")
- && 0 == strcmp(frame->sourcefile, "gdkmain-x11.c"))
- return true;
-
- /* X.org */
- if (0 == strcmp(frame->function, "_XReply")
- && 0 == strcmp(frame->sourcefile, "xcb_io.c"))
- return true;
- if (0 == strcmp(frame->function, "_XError")
- && 0 == strcmp(frame->sourcefile, "XlibInt.c"))
- return true;
- if (0 == strcmp(frame->function, "XSync")
- && 0 == strcmp(frame->sourcefile, "Sync.c"))
- return true;
- if (0 == strcmp(frame->function, "process_responses")
- && 0 == strcmp(frame->sourcefile, "xcb_io.c"))
- return true;
-
- /* glib */
- if (0 == strcmp(frame->function, "IA__g_log")
- && 0 == strcmp(frame->sourcefile, "gmessages.c"))
- return true;
- if (0 == strcmp(frame->function, "IA__g_logv")
- && 0 == strcmp(frame->sourcefile, "gmessages.c"))
- return true;
- if (0 == strcmp(frame->function, "IA__g_assertion_message")
- && 0 == strcmp(frame->sourcefile, "gtestutils.c"))
- return true;
- if (0 == strcmp(frame->function, "IA__g_assertion_message_expr")
- && 0 == strcmp(frame->sourcefile, "gtestutils.c"))
- return true;
-
- /* DBus */
- if (0 == strcmp(frame->function, "gerror_to_dbus_error_message")
- && 0 == strcmp(frame->sourcefile, "dbus-gobject.c"))
- return true;
- if (0 == strcmp(frame->function, "dbus_g_method_return_error")
- && 0 == strcmp(frame->sourcefile, "dbus-gobject.c"))
- return true;
-
- /* libstdc++ */
- if (0 == strcmp(frame->function, "__gnu_cxx::__verbose_terminate_handler")
- && NULL != strstr(frame->sourcefile, "/vterminate.cc"))
- return true;
- if (0 == strcmp(frame->function, "__cxxabiv1::__terminate")
- && NULL != strstr(frame->sourcefile, "/eh_terminate.cc"))
- return true;
- if (0 == strcmp(frame->function, "std::terminate")
- && NULL != strstr(frame->sourcefile, "/eh_terminate.cc"))
- return true;
- if (0 == strcmp(frame->function, "__cxxabiv1::__cxa_throw")
- && NULL != strstr(frame->sourcefile, "/eh_throw.cc"))
- return true;
-
- return false;
-}
-
-struct thread *thread_new()
-{
- struct thread *t = malloc(sizeof(struct thread));
- if (!t)
- {
- puts("Error while allocating memory for backtrace thread.");
- exit(5);
- }
-
- t->number = 0;
- t->frames = NULL;
- t->next = NULL;
- return t;
-}
-
-void thread_free(struct thread *t)
-{
- while (t->frames)
- {
- struct frame *rm = t->frames;
- t->frames = rm->next;
- frame_free(rm);
- }
-
- free(t);
-}
-
-struct thread *thread_add_sibling(struct thread *a, struct thread *b)
-{
- struct thread *aa = a;
- while (aa->next)
- aa = aa->next;
-
- aa->next = b;
- return a;
-}
-
-static int thread_get_frame_count(struct thread *thread)
-{
- struct frame *f = thread->frames;
- int count = 0;
- while (f)
- {
- f = f->next;
- ++count;
- }
- return count;
-}
-
-/* Appends string representation of 'thread' to the 'str'. */
-static void thread_append_str(struct thread *thread, struct strbuf *str, bool verbose)
-{
- int framecount = thread_get_frame_count(thread);
- if (verbose)
- strbuf_append_strf(str, "Thread no. %d (%d frames)\n", thread->number, framecount);
- else
- strbuf_append_str(str, "Thread\n");
- struct frame *frame = thread->frames;
- while (frame)
- {
- frame_append_str(frame, str, verbose);
- frame = frame->next;
- }
-}
-
-/*
- * Checks whether the thread it contains some known "abort" function.
- * If a frame with the function is found, it is returned.
- * If there are multiple frames with abort function, the lowest
- * one is returned.
- * Nonrecursive.
- */
-struct frame *thread_find_abort_frame(struct thread *thread)
-{
- struct frame *frame = thread->frames;
- struct frame *result = NULL;
- while (frame)
- {
- if (frame_is_abort_frame(frame))
- result = frame;
-
- frame = frame->next;
- }
-
- return result;
-}
-
-static void thread_remove_exit_handlers(struct thread *thread)
-{
- struct frame *frame = thread->frames;
- while (frame)
- {
- if (frame_is_exit_handler(frame))
- {
- /* Delete all frames from the beginning to this frame. */
- while (thread->frames != frame)
- {
- struct frame *rm = thread->frames;
- thread->frames = thread->frames->next;
- frame_free(rm);
- }
- return;
- }
-
- frame = frame->next;
- }
-}
-
-static void thread_remove_noncrash_frames(struct thread *thread)
-{
- struct frame *prev = NULL;
- struct frame *cur = thread->frames;
- while (cur)
- {
- if (frame_is_noncrash_frame(cur))
- {
- /* This frame must be skipped, because it will
- be deleted. */
- if (prev)
- prev->next = cur->next;
- else
- thread->frames = cur->next;
-
- frame_free(cur);
-
- /* Set cur to be valid, as it will be used to
- advance to next item. */
- if (prev)
- cur = prev;
- else
- {
- cur = thread->frames;
- continue;
- }
- }
-
- prev = cur;
- cur = cur->next;
- }
-}
-
-/* Counts the number of quality frames and the number of all frames
- * in a thread.
- * @param ok_count
- * @param all_count
- * Not zeroed. This function just adds the numbers to
- * ok_count and all_count.
- */
-static void thread_rating(struct thread *thread, int *ok_count, int *all_count)
-{
- struct frame *frame = thread->frames;
- while (frame)
- {
- *all_count += 1;
- if (frame->signal_handler_called ||
- (frame->function && 0 != strcmp(frame->function, "??")))
- {
- *ok_count += 1;
- }
- frame = frame->next;
- }
-}
-
-struct backtrace *backtrace_new()
-{
- struct backtrace *bt = malloc(sizeof(struct backtrace));
- if (!bt)
- {
- puts("Error while allocating memory for backtrace.");
- exit(5);
- }
-
- bt->threads = NULL;
- bt->crash = NULL;
- return bt;
-}
-
-void backtrace_free(struct backtrace *bt)
-{
- while (bt->threads)
- {
- struct thread *rm = bt->threads;
- bt->threads = rm->next;
- thread_free(rm);
- }
-
- if (bt->crash)
- frame_free(bt->crash);
-
- free(bt);
-}
-
-static int backtrace_get_thread_count(struct backtrace *bt)
-{
- struct thread *t = bt->threads;
- int count = 0;
- while (t)
- {
- t = t->next;
- ++count;
- }
- return count;
-}
-
-void backtrace_print_tree(struct backtrace *backtrace, bool verbose)
-{
- struct strbuf *strbuf = backtrace_tree_as_str(backtrace, verbose);
- puts(strbuf->buf);
- strbuf_free(strbuf);
-}
-
-struct strbuf *backtrace_tree_as_str(struct backtrace *backtrace, bool verbose)
-{
- struct strbuf *str = strbuf_new();
- if (verbose)
- strbuf_append_strf(str, "Thread count: %d\n", backtrace_get_thread_count(backtrace));
-
- if (backtrace->crash && verbose)
- {
- strbuf_append_str(str, "Crash frame: ");
- frame_append_str(backtrace->crash, str, verbose);
- }
-
- struct thread *thread = backtrace->threads;
- while (thread)
- {
- thread_append_str(thread, str, verbose);
- thread = thread->next;
- }
-
- return str;
-}
-
-void backtrace_remove_threads_except_one(struct backtrace *backtrace,
- struct thread *one)
-{
- while (backtrace->threads)
- {
- struct thread *rm = backtrace->threads;
- backtrace->threads = rm->next;
- if (rm != one)
- thread_free(rm);
- }
-
- one->next = NULL;
- backtrace->threads = one;
-}
-
-/*
- * Loop through all threads and if a single one contains the crash frame on the top,
- * return it. Otherwise, return NULL.
- *
- * If require_abort is true, it is also required that the thread containing
- * the crash frame contains some known "abort" function. In this case there can be
- * multiple threads with the crash frame on the top, but only one of them might
- * contain the abort function to succeed.
- */
-static struct thread *backtrace_find_crash_thread_from_crash_frame(struct backtrace *backtrace,
- bool require_abort)
-{
- /*
- * This code can be extended to compare something else when the function
- * name is not available.
- */
- if (!backtrace->threads || !backtrace->crash || !backtrace->crash->function)
- return NULL;
-
- struct thread *result = NULL;
- struct thread *thread = backtrace->threads;
- while (thread)
- {
- if (thread->frames
- && thread->frames->function
- && 0 == strcmp(thread->frames->function, backtrace->crash->function)
- && (!require_abort || thread_find_abort_frame(thread)))
- {
- if (result == NULL)
- result = thread;
- else
- {
- /* Second frame with the same function. Failure. */
- return NULL;
- }
- }
-
- thread = thread->next;
- }
-
- return result;
-}
-
-struct thread *backtrace_find_crash_thread(struct backtrace *backtrace)
-{
- /* If there is no thread, be silent and report NULL. */
- if (!backtrace->threads)
- return NULL;
-
- /* If there is just one thread, it is simple. */
- if (!backtrace->threads->next)
- return backtrace->threads;
-
- /* If we have a crash frame *and* there is just one thread which has
- * this frame on the top, it is also simple.
- */
- struct thread *thread;
- thread = backtrace_find_crash_thread_from_crash_frame(backtrace, false);
- if (thread)
- return thread;
-
- /* There are multiple threads with a frame indistinguishable from
- * the crash frame on the top of stack.
- * Try to search for known abort functions.
- */
- thread = backtrace_find_crash_thread_from_crash_frame(backtrace, true);
-
- return thread; /* result or null */
-}
-
-void backtrace_limit_frame_depth(struct backtrace *backtrace, int depth)
-{
- if (depth <= 0)
- return;
-
- struct thread *thread = backtrace->threads;
- while (thread)
- {
- struct frame *frame = thread_find_abort_frame(thread);
- if (frame)
- frame = frame->next; /* Start counting from the frame following the abort fr. */
- else
- frame = thread->frames; /* Start counting from the first frame. */
-
- /* Skip some frames to get the required stack depth. */
- int i = depth;
- struct frame *last_frame = NULL;
- while (frame && i)
- {
- last_frame = frame;
- frame = frame->next;
- --i;
- }
-
- /* Delete the remaining frames. */
- if (last_frame)
- last_frame->next = NULL;
-
- while (frame)
- {
- struct frame *rm = frame;
- frame = frame->next;
- frame_free(rm);
- }
-
- thread = thread->next;
- }
-}
-
-void backtrace_remove_exit_handlers(struct backtrace *backtrace)
-{
- struct thread *thread = backtrace->threads;
- while (thread)
- {
- thread_remove_exit_handlers(thread);
- thread = thread->next;
- }
-}
-
-void backtrace_remove_noncrash_frames(struct backtrace *backtrace)
-{
- struct thread *thread = backtrace->threads;
- while (thread)
- {
- thread_remove_noncrash_frames(thread);
- thread = thread->next;
- }
-}
-
-/* Belongs to independent_backtrace(). */
-struct header
-{
- struct strbuf *text;
- struct header *next;
-};
-
-/* Belongs to independent_backtrace(). */
-static struct header *header_new()
-{
- struct header *head = malloc(sizeof(struct header));
- if (!head)
- {
- puts("Error while allocating memory for backtrace header.");
- exit(5);
- }
- head->text = NULL;
- head->next = NULL;
- return head;
-}
-
-/* Recursively frees siblings. */
-/* Belongs to independent_backtrace(). */
-static void header_free(struct header *head)
-{
- if (head->text)
- strbuf_free(head->text);
- if (head->next)
- header_free(head->next);
- free(head);
-}
-
-/* Inserts new header to array if it is not already there. */
-/* Belongs to independent_backtrace(). */
-static void header_set_insert(struct header *cur, struct strbuf *new)
-{
- /* Duplicate found case. */
- if (strcmp(cur->text->buf, new->buf) == 0)
- return;
-
- /* Last item case, insert new header here. */
- if (cur->next == NULL)
- {
- cur->next = header_new();
- cur->next->text = new;
- return;
- }
-
- /* Move to next item in array case. */
- header_set_insert(cur->next, new);
-}
-
-struct strbuf *independent_backtrace(const char *input)
-{
- struct strbuf *header = strbuf_new();
- bool in_bracket = false;
- bool in_quote = false;
- bool in_header = false;
- bool in_digit = false;
- bool has_at = false;
- bool has_filename = false;
- bool has_bracket = false;
- struct header *headers = NULL;
-
- const char *bk = input;
- while (*bk)
- {
- if (bk[0] == '#'
- && bk[1] >= '0' && bk[1] <= '7'
- && bk[2] == ' ' /* take only #0...#7 (8 last stack frames) */
- && !in_quote)
- {
- if (in_header && !has_filename)
- strbuf_clear(header);
- in_header = true;
- }
-
- if (!in_header)
- {
- ++bk;
- continue;
- }
-
- if (isdigit(*bk) && !in_quote && !has_at)
- in_digit = true;
- else if (bk[0] == '\\' && bk[1] == '\"')
- bk++;
- else if (*bk == '\"')
- in_quote = in_quote == true ? false : true;
- else if (*bk == '(' && !in_quote)
- {
- in_bracket = true;
- in_digit = false;
- strbuf_append_char(header, '(');
- }
- else if (*bk == ')' && !in_quote)
- {
- in_bracket = false;
- has_bracket = true;
- in_digit = false;
- strbuf_append_char(header, '(');
- }
- else if (*bk == '\n' && has_filename)
- {
- if (headers == NULL)
- {
- headers = header_new();
- headers->text = header;
- }
- else
- header_set_insert(headers, header);
-
- header = strbuf_new();
- in_bracket = false;
- in_quote = false;
- in_header = false;
- in_digit = false;
- has_at = false;
- has_filename = false;
- has_bracket = false;
- }
- else if (*bk == ',' && !in_quote)
- in_digit = false;
- else if (isspace(*bk) && !in_quote)
- in_digit = false;
- else if (bk[0] == 'a' && bk[1] == 't' && has_bracket && !in_quote)
- {
- has_at = true;
- strbuf_append_char(header, 'a');
- }
- else if (bk[0] == ':' && has_at && isdigit(bk[1]) && !in_quote)
- has_filename = true;
- else if (in_header && !in_digit && !in_quote && !in_bracket)
- strbuf_append_char(header, *bk);
-
- bk++;
- }
-
- strbuf_free(header);
-
- struct strbuf *result = strbuf_new();
- struct header *loop = headers;
- while (loop)
- {
- strbuf_append_str(result, loop->text->buf);
- strbuf_append_char(result, '\n');
- loop = loop->next;
- }
-
- if (headers)
- header_free(headers); /* recursive */
-
- return result;
-}
-
-/* Belongs to backtrace_rate_old(). */
-enum line_rating
-{
- // RATING EXAMPLE
- MissingEverything = 0, // #0 0x0000dead in ?? ()
- MissingFunction = 1, // #0 0x0000dead in ?? () from /usr/lib/libfoobar.so.4
- MissingLibrary = 2, // #0 0x0000dead in foobar()
- MissingSourceFile = 3, // #0 0x0000dead in FooBar::FooBar () from /usr/lib/libfoobar.so.4
- Good = 4, // #0 0x0000dead in FooBar::crash (this=0x0) at /home/user/foobar.cpp:204
- BestRating = Good,
-};
-
-/* Belongs to backtrace_rate_old(). */
-static enum line_rating rate_line(const char *line)
-{
-#define FOUND(x) (strstr(line, x) != NULL)
- /* see the comments at enum line_rating for possible combinations */
- if (FOUND(" at "))
- return Good;
- const char *function = strstr(line, " in ");
- if (function && function[4] == '?') /* " in ??" does not count */
- function = NULL;
- bool library = FOUND(" from ");
- if (function && library)
- return MissingSourceFile;
- if (function)
- return MissingLibrary;
- if (library)
- return MissingFunction;
-
- return MissingEverything;
-#undef FOUND
-}
-
-/* just a fallback function, to be removed one day */
-int backtrace_rate_old(const char *backtrace)
-{
- int i, len;
- int multiplier = 0;
- int rating = 0;
- int best_possible_rating = 0;
- char last_lvl = 0;
-
- /* We look at the frames in reversed order, since:
- * - rate_line() checks starting from the first line of the frame
- * (note: it may need to look at more than one line!)
- * - we increase weight (multiplier) for every frame,
- * so that topmost frames end up most important
- */
- len = 0;
- for (i = strlen(backtrace) - 1; i >= 0; i--)
- {
- if (backtrace[i] == '#'
- && (backtrace[i+1] >= '0' && backtrace[i+1] <= '9') /* #N */
- && (i == 0 || backtrace[i-1] == '\n')) /* it's at line start */
- {
- /* For one, "#0 xxx" always repeats, skip repeats */
- if (backtrace[i+1] == last_lvl)
- continue;
- last_lvl = backtrace[i+1];
-
- char *s = xstrndup(backtrace + i + 1, len);
- /* Replace tabs with spaces, rate_line() does not expect tabs.
- * Actually, even newlines may be there. Example of multiline frame
- * where " at SRCFILE" is on 2nd line:
- * #3 0x0040b35d in __libc_message (do_abort=<value optimized out>,
- * fmt=<value optimized out>) at ../sysdeps/unix/sysv/linux/libc_fatal.c:186
- */
- char *p;
- for (p = s; *p; p++)
- {
- if (*p == '\t' || *p == '\n')
- *p = ' ';
- }
- int lrate = rate_line(s);
- multiplier++;
- rating += lrate * multiplier;
- best_possible_rating += BestRating * multiplier;
- //log("lrate:%d rating:%d best_possible_rating:%d s:'%-.40s'",
- // lrate, rating, best_possible_rating, s);
- free(s);
- len = 0; /* starting new line */
- }
- else
- {
- len++;
- }
- }
-
- /* Bogus 'backtrace' with zero frames? */
- if (best_possible_rating == 0)
- return 0;
-
- /* Returning number of "stars" to show */
- if (rating*10 >= best_possible_rating*8) /* >= 0.8 */
- return 4;
- if (rating*10 >= best_possible_rating*6)
- return 3;
- if (rating*10 >= best_possible_rating*4)
- return 2;
- if (rating*10 >= best_possible_rating*2)
- return 1;
-
- return 0;
-}
-
-float backtrace_quality(struct backtrace *backtrace)
-{
- int ok_count = 0;
- int all_count = 0;
- struct thread *thread = backtrace->threads;
- while (thread)
- {
- thread_rating(thread, &ok_count, &all_count);
- thread = thread->next;
- }
-
- if (all_count == 0)
- return 0;
- return ok_count / (float)all_count;
-}
diff --git a/lib/utils/backtrace.h b/lib/utils/backtrace.h
deleted file mode 100644
index df5def56..00000000
--- a/lib/utils/backtrace.h
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- Backtrace parsing and processing.
-
- If we transform analyzer plugins to separate applications one day,
- this functionality should be moved to CCpp analyzer, which will
- then easily provide what abrt-backtrace utility provides now. Currently
- the code is used by abrt-backtrace, so it is shared in the utils
- library.
-
- Copyright (C) 2009, 2010 RedHat inc.
-
- 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 BACKTRACE_H
-#define BACKTRACE_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stdio.h>
-#include <stdbool.h>
-
-struct frame
-{
- /* Function name, or NULL. */
- char *function;
- /* Frame number. */
- int number;
- /* Name of the source file, or binary file, or NULL. */
- char *sourcefile;
- bool signal_handler_called;
- /* Sibling frame, or NULL if this is the last frame in a thread. */
- struct frame *next;
-};
-
-struct thread
-{
- int number;
- struct frame *frames;
- /* Sibling thread, or NULL if this is the last thread in a backtrace. */
- struct thread *next;
-};
-
-struct backtrace
-{
- struct thread *threads;
- /*
- * The frame where the crash happened according to GDB.
- * It might be that we can not tell to which thread this frame belongs,
- * because all threads end with mutually indistinguishable frames.
- */
- struct frame *crash;
-};
-
-extern struct frame *frame_new();
-extern void frame_free(struct frame *f);
-extern struct frame *frame_add_sibling(struct frame *a, struct frame *b);
-
-extern struct thread *thread_new();
-extern void thread_free(struct thread *t);
-extern struct thread *thread_add_sibling(struct thread *a, struct thread *b);
-extern struct frame *thread_find_abort_frame(struct thread *thread);
-
-extern struct backtrace *backtrace_new();
-extern void backtrace_free(struct backtrace *bt);
-
-/* Prints how internal backtrace representation looks to stdout. */
-extern void backtrace_print_tree(struct backtrace *backtrace, bool verbose);
-
-/* Returns the backtrace tree string representation. */
-extern struct strbuf *backtrace_tree_as_str(struct backtrace *backtrace, bool verbose);
-
-/*
- * Frees all threads except the one provided as parameters.
- * It does not check whether one is a member of backtrace.
- * Caller must know that.
- */
-extern void backtrace_remove_threads_except_one(struct backtrace *backtrace,
- struct thread *one);
-
-/*
- * Search all threads and tries to find the one that caused the crash.
- * It might return NULL if the thread cannot be determined.
- */
-extern struct thread *backtrace_find_crash_thread(struct backtrace *backtrace);
-
-extern void backtrace_limit_frame_depth(struct backtrace *backtrace, int depth);
-
-/*
- * Exit handlers are all stack frames above __run_exit_handlers()
- */
-extern void backtrace_remove_exit_handlers(struct backtrace *backtrace);
-
-/*
- * Removes frames known as not causing crash, but that are often
- * a part of a backtrace.
- */
-extern void backtrace_remove_noncrash_frames(struct backtrace *backtrace);
-
-/* Parses the backtrace and stores it to a structure.
- * @returns
- * Returns the backtrace struct representation, or NULL if the parser failed.
- * Caller of this function is responsible for backtrace_free()ing the returned value.
- * Defined in backtrace_parser.y.
- */
-extern struct backtrace *backtrace_parse(char *input, bool debug_parser, bool debug_scanner);
-
-/* Reads the input file and calculates "independent" backtrace from it. "Independent" means
- * that the memory addresses that differ from run to run are removed from the backtrace, and
- * also variable names and values are removed.
- *
- * This function can be called when backtrace_parse() call fails. It provides a shorter
- * version of backtrace, with a chance that hash calculated from the returned value can be used
- * to detect duplicates. However, this kind of duplicate detection is very low-quality.
- * @returns
- * The independent backtrace. Caller is responsible for calling
- * strbuf_free() on it.
- */
-extern struct strbuf *independent_backtrace(const char *input);
-
-/* Get the quality of backtrace, as a number of "stars".
- * @returns
- * Value 0 to 4.
- */
-extern int backtrace_rate_old(const char *backtrace);
-
-/* Evaluates the quality of the backtrace, meaning the ratio of frames
- * with function name fully known to all frames.
- * @returns
- * A number between 0 and 1. 0 means the lowest quality,
- * 1 means full backtrace is known.
- */
-extern float backtrace_quality(struct backtrace *backtrace);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/lib/utils/backtrace_parser.y b/lib/utils/backtrace_parser.y
deleted file mode 100644
index 8e2fc2b1..00000000
--- a/lib/utils/backtrace_parser.y
+++ /dev/null
@@ -1,684 +0,0 @@
-%{ /* -*- mode: yacc -*-
- Copyright (C) 2009 RedHat inc.
-
- 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.
-*/
-#include <math.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include "backtrace.h"
-#include "strbuf.h"
-
-struct backtrace *g_backtrace;
-
-#define YYDEBUG 1
-#define YYMAXDEPTH 10000000
-void yyerror(char const *s)
-{
- fprintf (stderr, "\nParser error: %s\n", s);
-}
-
-int yylex();
-
-%}
-
-/* This defines the type of yylval */
-%union {
- struct backtrace *backtrace;
- struct thread *thread;
- struct frame *frame;
- char *str;
- int num;
- char c;
-
- struct strbuf *strbuf;
-}
-
-/* Bison declarations. */
-%token END 0 "end of file"
-
-%type <backtrace> backtrace
-%type <thread> threads
- thread
-%type <frame> frames
- frame
- frame_head
- frame_head_1
- frame_head_2
- frame_head_3
- frame_head_4
- frame_head_5
-%type <strbuf> identifier
- hexadecimal_digit_sequence
- hexadecimal_number
- file_name
- file_location
- function_call
- function_name
- digit_sequence
- frame_address_in_function
- identifier_braces
- identifier_braces_inside
- identifier_template
- identifier_template_inside
-%type <c> nondigit
- digit
- hexadecimal_digit
- file_name_char
- identifier_char
- identifier_char_no_templates
- identifier_first_char
- identifier_braces_inside_char
- identifier_template_inside_char
- variables_char
- variables_char_no_framestart
- ws
- ws_nonl
- '(' ')' '+' '-' '/' '.' '_' '~' '[' ']' '\r' '?' '{' '}'
- 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l'
- 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 'u' 'v' 'w' 'x' 'y' 'z'
- 'A' 'B' 'C' 'D' 'E' 'F' 'G' 'H' 'I' 'J' 'K' 'L' 'M' 'N'
- 'O' 'P' 'Q' 'R' 'S' 'T' 'U' 'V' 'W' 'X' 'Y' 'Z'
- '0' '1' '2' '3' '4' '5' '6' '7' '8' '9'
- '\'' '`' ',' '#' '@' '<' '>' '=' ':' '"' ';' ' '
- '\n' '\t' '\\' '!' '*' '%' '|' '^' '&' '$'
-%type <num> frame_start
-
-%destructor { thread_free($$); } <thread>
-%destructor { frame_free($$); } <frame>
-%destructor { strbuf_free($$); } <strbuf>
-
-%start backtrace
-%glr-parser
-%error-verbose
-%locations
-
-%% /* The grammar follows. */
-
-backtrace : /* empty */ %dprec 1
- { $$ = g_backtrace = backtrace_new(); }
- | threads wsa %dprec 2
- {
- $$ = g_backtrace = backtrace_new();
- $$->threads = $1;
- }
- | frame_head wss threads wsa %dprec 4
- {
- $$ = g_backtrace = backtrace_new();
- $$->threads = $3;
- $$->crash = $1;
- }
- | frame wss threads wsa %dprec 3
- {
- $$ = g_backtrace = backtrace_new();
- $$->threads = $3;
- $$->crash = $1;
- }
-;
-
-threads : thread
- | threads '\n' thread { $$ = thread_add_sibling($1, $3); }
-;
-
-thread : keyword_thread wss digit_sequence wsa '(' keyword_thread wss digit_sequence wsa ')' ':' wsa frames
- {
- $$ = thread_new();
- $$->frames = $13;
-
- if (sscanf($3->buf, "%d", &$$->number) != 1)
- {
- printf("Error while parsing thread number '%s'", $3->buf);
- exit(5);
- }
- strbuf_free($3);
- strbuf_free($8);
- }
-;
-
-frames : frame { $$ = $1; }
- | frames frame { $$ = frame_add_sibling($1, $2); }
-;
-
-frame : frame_head_1 wss variables %dprec 3
- | frame_head_2 wss variables %dprec 4
- | frame_head_3 wss variables %dprec 5
- | frame_head_4 wss variables %dprec 2
- | frame_head_5 wss variables %dprec 1
-;
-
-frame_head : frame_head_1 %dprec 3
- | frame_head_2 %dprec 4
- | frame_head_3 %dprec 5
- | frame_head_4 %dprec 2
- | frame_head_5 %dprec 1
-;
-
-frame_head_1 : frame_start wss function_call wsa keyword_at wss file_location
- {
- $$ = frame_new();
- $$->number = $1;
- $$->function = $3->buf;
- strbuf_free_nobuf($3);
- $$->sourcefile = $7->buf;
- strbuf_free_nobuf($7);
- }
-;
-
-frame_head_2 : frame_start wss frame_address_in_function wss keyword_at wss file_location
- {
- $$ = frame_new();
- $$->number = $1;
- $$->function = $3->buf;
- strbuf_free_nobuf($3);
- $$->sourcefile = $7->buf;
- strbuf_free_nobuf($7);
- }
-;
-
-frame_head_3 : frame_start wss frame_address_in_function wss keyword_from wss file_location
- {
- $$ = frame_new();
- $$->number = $1;
- $$->function = $3->buf;
- strbuf_free_nobuf($3);
- $$->sourcefile = $7->buf;
- strbuf_free_nobuf($7);
- }
-;
-
-frame_head_4 : frame_start wss frame_address_in_function
- {
- $$ = frame_new();
- $$->number = $1;
- $$->function = $3->buf;
- strbuf_free_nobuf($3);
- }
-;
-
-frame_head_5 : frame_start wss keyword_sighandler
- {
- $$ = frame_new();
- $$->number = $1;
- $$->signal_handler_called = true;
- }
-
-frame_start: '#' digit_sequence
- {
- if (sscanf($2->buf, "%d", &$$) != 1)
- {
- printf("Error while parsing frame number '%s'.\n", $2->buf);
- exit(5);
- }
- strbuf_free($2);
- }
-;
-
-frame_address_in_function : hexadecimal_number wss keyword_in wss function_call
- {
- strbuf_free($1);
- $$ = $5;
- }
- | hexadecimal_number wss keyword_in wss keyword_vtable wss keyword_for wss function_call
- {
- strbuf_free($1);
- $$ = $9;
- }
-;
-
-file_location : file_name ':' digit_sequence
- {
- $$ = $1;
- strbuf_free($3); /* line number not needed for now */
- }
- | file_name
-;
-
-variables : variables_line '\n'
- | variables_line END
- | variables_line wss_nonl '\n'
- | variables_line wss_nonl END
- | variables variables_line '\n'
- | variables variables_line END
- | variables variables_line wss_nonl '\n'
- | variables variables_line wss_nonl END
- | variables wss_nonl variables_line '\n'
- | variables wss_nonl variables_line END
- | variables wss_nonl variables_line wss_nonl '\n'
- | variables wss_nonl variables_line wss_nonl END
-;
-
-variables_line : variables_char_no_framestart
- | variables_line variables_char
- | variables_line wss_nonl variables_char
-;
-
-variables_char : '#' | variables_char_no_framestart
-;
-
-/* Manually synchronized with function_args_char_base, except the first line. */
-variables_char_no_framestart : digit | nondigit | '"' | '(' | ')' | '\\'
- | '+' | '-' | '<' | '>' | '/' | '.'
- | '[' | ']' | '?' | '\'' | '`' | ','
- | '=' | '{' | '}' | '^' | '&' | '$'
- | ':' | ';' | '!' | '@' | '*'
- | '%' | '|' | '~'
-;
-
-function_call : function_name wss function_args %dprec 3
- | return_type wss_nonl function_name wss function_args %dprec 2
- { $$ = $3; }
- | function_name wss_nonl identifier_template wss function_args %dprec 1
- { $$ = $1; strbuf_free($3); }
-;
-
-return_type : identifier { strbuf_free($1); }
-;
-
-function_name : identifier
- | '?' '?'
- {
- $$ = strbuf_new();
- strbuf_append_str($$, "??");
- }
-;
-
-function_args : '(' wsa ')'
- | '(' wsa function_args_sequence wsa ')'
-;
-
-function_args_sequence : function_args_char
- | function_args_sequence wsa '(' wsa ')'
- | function_args_sequence wsa '(' wsa function_args_string wsa ')'
- | function_args_sequence wsa '(' wsa function_args_sequence wsa ')'
- | function_args_sequence wsa function_args_char
- | function_args_sequence wsa function_args_string
-;
-
-function_args_string : '"' wsa function_args_string_sequence wsa '"'
- | '"' wsa '"'
-;
-
-/* Manually synchronized with variables_char_no_framestart,
- * except the first line.
- */
-function_args_char_base : digit | nondigit | '#'
- | '+' | '-' | '<' | '>' | '/' | '.'
- | '[' | ']' | '?' | '\'' | '`' | ','
- | '=' | '{' | '}' | '^' | '&' | '$'
- | ':' | ';' | '!' | '@' | '*'
- | '%' | '|' | '~'
-;
-function_args_escaped_char : '\\' function_args_char_base
- | '\\' '\\'
- | '\\' '"'
-;
-function_args_char : function_args_char_base
- | function_args_escaped_char
-;
-
-
-function_args_string_sequence : function_args_string_char
- | function_args_string_sequence function_args_string_char
- | function_args_string_sequence wss_nonl function_args_string_char
-;
-
-function_args_string_char : function_args_char | '(' | ')'
-;
-
-file_name : file_name_char { $$ = strbuf_new(); strbuf_append_char($$, $1); }
- | file_name file_name_char { $$ = strbuf_append_char($1, $2); }
-;
-
-file_name_char : digit | nondigit | '-' | '+' | '/' | '.'
-;
-
- /* Function name, sometimes mangled.
- * Example: something@GLIB_2_2
- * CClass::operator=
- */
-identifier : identifier_first_char %dprec 1
- {
- $$ = strbuf_new();
- strbuf_append_char($$, $1);
- }
- | identifier_braces %dprec 1 /* e.g. (anonymous namespace)::WorkerThread */
- | identifier identifier_char %dprec 1
- { $$ = strbuf_append_char($1, $2); }
- | identifier identifier_braces %dprec 1
- {
- $$ = strbuf_append_str($1, $2->buf);
- strbuf_free($2);
- }
- | identifier identifier_template %dprec 2
- {
- $$ = strbuf_append_str($1, $2->buf);
- strbuf_free($2);
- }
-;
-
-identifier_first_char: nondigit
- | '~' /* destructor */
- | '*'
-;
-
-identifier_char_no_templates : digit | nondigit | '@' | '.' | ':' | '='
- | '!' | '*' | '+' | '-' | '[' | ']'
- | '~' | '&' | '/' | '%' | '^'
- | '|' | ','
-;
-
-/* Most of the special characters are required to support C++
- * operator overloading.
- */
-identifier_char : identifier_char_no_templates | '<'| '>'
-;
-
-identifier_braces : '(' ')'
- {
- $$ = strbuf_new();
- strbuf_append_char($$, $1);
- strbuf_append_char($$, $2);
- }
- | '(' identifier_braces_inside ')'
- {
- $$ = strbuf_new();
- strbuf_append_char($$, $1);
- strbuf_append_str($$, $2->buf);
- strbuf_free($2);
- strbuf_append_char($$, $3);
- }
-;
-
-identifier_braces_inside : identifier_braces_inside_char %dprec 1
- {
- $$ = strbuf_new();
- strbuf_append_char($$, $1);
- }
- | identifier_braces_inside identifier_braces_inside_char %dprec 1
- { $$ = strbuf_append_char($1, $2); }
- | identifier_braces_inside '(' identifier_braces_inside ')' %dprec 1
- {
- $$ = strbuf_append_char($1, $2);
- $$ = strbuf_append_str($1, $3->buf);
- strbuf_free($3);
- $$ = strbuf_append_char($1, $4);
- }
- | identifier_braces_inside '(' ')' %dprec 1
- {
- $$ = strbuf_append_char($1, $2);
- $$ = strbuf_append_char($1, $3);
- }
- | identifier_braces_inside identifier_template %dprec 2
- {
- $$ = strbuf_append_str($1, $2->buf);
- strbuf_free($2);
- }
-;
-
-identifier_braces_inside_char : identifier_char | ws_nonl
-;
-
-identifier_template : '<' identifier_template_inside '>'
- {
- $$ = strbuf_new();
- strbuf_append_char($$, $1);
- strbuf_append_str($$, $2->buf);
- strbuf_free($2);
- strbuf_append_char($$, $3);
- }
-;
-
-identifier_template_inside : identifier_template_inside_char
- {
- $$ = strbuf_new();
- strbuf_append_char($$, $1);
- }
- | identifier_template_inside identifier_template_inside_char
- { $$ = strbuf_append_char($1, $2); }
- | identifier_template_inside '<' identifier_template_inside '>'
- {
- $$ = strbuf_append_char($1, $2);
- $$ = strbuf_append_str($1, $3->buf);
- strbuf_free($3);
- $$ = strbuf_append_char($1, $4);
- }
- | identifier_template_inside identifier_braces
- {
- $$ = strbuf_append_str($1, $2->buf);
- strbuf_free($2);
- }
-;
-
-identifier_template_inside_char : identifier_char_no_templates | ws_nonl
-;
-
-digit_sequence : digit { $$ = strbuf_new(); strbuf_append_char($$, $1); }
- | digit_sequence digit { $$ = strbuf_append_char($1, $2); }
-;
-
-hexadecimal_number : '0' 'x' hexadecimal_digit_sequence
- {
- $$ = $3;
- strbuf_prepend_str($$, "0x");
- }
- | '0' 'X' hexadecimal_digit_sequence
- {
- $$ = $3;
- strbuf_prepend_str($$, "0X");
- }
-;
-
-hexadecimal_digit_sequence : hexadecimal_digit
- {
- $$ = strbuf_new();
- strbuf_append_char($$, $1);
- }
- | hexadecimal_digit_sequence hexadecimal_digit
- { $$ = strbuf_append_char($1, $2); }
-;
-
-hexadecimal_digit : digit
- | 'a' | 'b' | 'c' | 'd' | 'e' | 'f'
- | 'A' | 'B' | 'C' | 'D' | 'E' | 'F'
-;
-
-digit : '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
-;
-
-nondigit : 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k'
- | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w'
- | 'x' | 'y' | 'z'
- | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K'
- | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W'
- | 'X' | 'Y' | 'Z'
- | '_'
-;
-
- /* whitespace */
-ws : ws_nonl | '\n' | '\r'
-;
-
- /* No newline.*/
-ws_nonl : '\t' | ' '
-;
-
- /* whitespace sequence without a newline */
-wss_nonl : ws_nonl
- | wss_nonl ws_nonl
-;
-
- /* whitespace sequence */
-wss : ws
- | wss ws
-;
-
- /* whitespace sequence allowed */
-wsa :
- | wss
-;
-
-keyword_in : 'i' 'n'
-;
-
-keyword_at : 'a' 't'
-;
-
-keyword_for : 'f' 'o' 'r'
-;
-
-keyword_vtable : 'v' 't' 'a' 'b' 'l' 'e'
-;
-
-keyword_from : 'f' 'r' 'o' 'm'
-;
-
-keyword_thread: 'T' 'h' 'r' 'e' 'a' 'd'
-;
-
-keyword_sighandler: '<' 's' 'i' 'g' 'n' 'a' 'l' ' ' 'h' 'a' 'n' 'd' 'l' 'e' 'r' ' ' 'c' 'a' 'l' 'l' 'e' 'd' '>'
-;
-
-%%
-
-static bool scanner_echo = false;
-static char *yyin;
-
-int yylex()
-{
- char c = *yyin;
- if (c == '\0')
- return END;
- ++yyin;
-
- /* Debug output. */
- if (scanner_echo)
- putchar(c);
-
- yylval.c = c;
-
- /* Return a single char. */
- return c;
-}
-
-/* This is the function that is actually called from outside.
- * @returns
- * Backtrace structure. Caller is responsible for calling
- * backtrace_free() on this.
- * Returns NULL when parsing failed.
- */
-struct backtrace *backtrace_parse(char *input, bool debug_parser, bool debug_scanner)
-{
- /* Skip the backtrace header information. */
- char *btnoheader_a = strstr(input, "\nThread ");
- char *btnoheader_b = strstr(input, "\n#");
- char *btnoheader = input;
- if (btnoheader_a)
- {
- if (btnoheader_b && btnoheader_b < btnoheader_a)
- btnoheader = btnoheader_b + 1;
- else
- btnoheader = btnoheader_a + 1;
- }
- else if (btnoheader_b)
- btnoheader = btnoheader_b + 1;
-
- /* Bug fixing hack for broken backtraces.
- * Sometimes the empty line is missing before new Thread section.
- * This is against rules, but a bug (now fixed) in Linux kernel caused
- * this.
- */
- char *thread_fixer = btnoheader + 1;
- while ((thread_fixer = strstr(thread_fixer, "\nThread")) != NULL)
- {
- if (thread_fixer[-1] != '\n')
- thread_fixer[-1] = '\n';
-
- ++thread_fixer;
- }
-
- /* Bug fixing hack for GDB - remove wrongly placed newlines from the backtrace.
- * Sometimes there is a newline in the local variable section.
- * This is caused by some GDB hooks.
- * Example: rhbz#538440
- * #1 0x0000000000420939 in sync_deletions (mse=0x0, mfld=0x1b85020)
- * at mail-stub-exchange.c:1119
- * status = <value optimized out>
- * iter = 0x1af38d0
- * known_messages = 0x1b5c460Traceback (most recent call last):
- * File "/usr/share/glib-2.0/gdb/glib.py", line 98, in next
- * if long (node["key_hash"]) >= 2:
- * RuntimeError: Cannot access memory at address 0x11
- *
- * __PRETTY_FUNCTION__ = "sync_deletions"
- * #2 0x0000000000423e6b in refresh_folder (stub=0x1b77f10 [MailStubExchange],
- * ...
- *
- * The code removes every empty line (also those containing only spaces),
- * which is not followed by a new Thread section.
- *
- * rhbz#555251 contains empty lines with spaces
- */
- char *empty_line = btnoheader;
- char *c = btnoheader;
- while (*c)
- {
- if (*c == '\n')
- {
- char *cend = c + 1;
- while (*cend == ' ' || *cend == '\t')
- ++cend;
- if (*cend == '\n' && 0 != strncmp(cend, "\nThread", strlen("\nThread")))
- memmove(c, cend, strlen(cend) + 1);
- }
- ++c;
- }
- while ((empty_line = strstr(empty_line, "\n\n")) != NULL)
- {
- if (0 != strncmp(empty_line, "\n\nThread", strlen("\n\nThread")))
- {
- /* Remove the empty line by converting the first newline to char. */
- empty_line[0] = 'X';
- }
- ++empty_line;
- }
-
- /* Prepare for running parser. */
- g_backtrace = 0;
- yyin = btnoheader;
-#if YYDEBUG == 1
- if (debug_parser)
- yydebug = 1;
-#endif
- scanner_echo = debug_scanner;
-
- /* Parse. */
- int failure = yyparse();
-
- /* Separate debugging output. */
- if (scanner_echo)
- putchar('\n');
-
- if (failure)
- {
- if (g_backtrace)
- {
- backtrace_free(g_backtrace);
- g_backtrace = NULL;
- }
- fprintf(stderr, "Error while parsing backtrace.\n");
- }
-
- return g_backtrace;
-}