summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKarel Klic <kklic@redhat.com>2009-10-20 15:58:02 +0200
committerKarel Klic <kklic@redhat.com>2009-10-20 15:58:02 +0200
commit08b9971c3d1635ff1f6d17608e7e99d5ac4b5866 (patch)
tree1b7dc5c62858b8efdbc610431a21f3564e4d6f3b
parent9e8a1ba0c9ddfa0108050f6fedc88de63b4b7c3f (diff)
parent4df20906ef57432edb505ce28179fd979729c975 (diff)
downloadabrt-08b9971c3d1635ff1f6d17608e7e99d5ac4b5866.tar.gz
abrt-08b9971c3d1635ff1f6d17608e7e99d5ac4b5866.tar.xz
abrt-08b9971c3d1635ff1f6d17608e7e99d5ac4b5866.zip
Merge branch 'master' of ssh://git.fedorahosted.org/git/abrt
-rw-r--r--lib/Plugins/CCpp.cpp198
-rwxr-xr-xsrc/Daemon/abrt-debuginfo-install65
2 files changed, 252 insertions, 11 deletions
diff --git a/lib/Plugins/CCpp.cpp b/lib/Plugins/CCpp.cpp
index 40aadd24..3fedd947 100644
--- a/lib/Plugins/CCpp.cpp
+++ b/lib/Plugins/CCpp.cpp
@@ -373,9 +373,200 @@ static std::string run_unstrip_n(const std::string& pDebugDumpDir)
static void InstallDebugInfos(const std::string& pDebugDumpDir, std::string& build_ids)
{
+ log("Getting module names, file names, build IDs from core file");
+ std::string unstrip_list = run_unstrip_n(pDebugDumpDir);
+
+ log("Builting list of missing debuginfos");
+ // lines look like this:
+ // 0x400000+0x209000 23c77451cf6adff77fc1f5ee2a01d75de6511dda@0x40024c - - [exe]
+ // 0x400000+0x209000 ab3c8286aac6c043fd1bb1cc2a0b88ec29517d3e@0x40024c /bin/sleep /usr/lib/debug/bin/sleep.debug [exe]
+ // 0x7fff313ff000+0x1000 389c7475e3d5401c55953a425a2042ef62c4c7df@0x7fff313ff2f8 . - linux-vdso.so.1
+ vector_string_t missing;
+ char *dup = xstrdup(unstrip_list.c_str());
+ char *p = dup;
+ char c;
+ do {
+ char* end = strchrnul(p, '\n');
+ c = *end;
+ *end = '\0';
+ char* word2 = strchr(p, ' ');
+ if (!word2)
+ continue;
+ word2++;
+ char* endsp = strchr(word2, ' ');
+ if (!endsp)
+ continue;
+ /* endsp points to 2nd space in the line now*/
+
+ /* This filters out linux-vdso.so, among others */
+ if (strstr(endsp, "[exe]") == NULL && endsp[1] != '/')
+ continue;
+ *endsp = '\0';
+ char* at = strchrnul(word2, '@');
+ *at = '\0';
+
+ bool file_exists = 1;
+ if (word2[0] && word2[1] && is_hexstr(word2))
+ {
+ struct stat sb;
+ char *fn = xasprintf("/usr/lib/debug/.build-id/%.2s/%s.debug", word2, word2 + 2);
+ /* Not lstat: this is a symlink and we want link's TARGET to exist */
+ file_exists = stat(fn, &sb) == 0 && S_ISREG(sb.st_mode);
+ free(fn);
+ build_ids += "build-id ";
+ build_ids += word2;
+ build_ids += file_exists ? " (debuginfo present)\n" : " (debuginfo absent)\n";
+ }
+ log("build_id:%s exists:%d", word2, (int)file_exists);
+ if (!file_exists)
+ missing.push_back(word2);
+
+ p = end + 1;
+ } while (c);
+ free(dup);
+
+ if (missing.size() == 0)
+ {
+ log("All debuginfos are present, not installing debuginfo packages");
+ return;
+ }
+ //missing vector is unused for now, but TODO: use it to install only needed debuginfos
+
+ std::string package;
+ {
+ CDebugDump dd;
+ dd.Open(pDebugDumpDir);
+ dd.LoadText(FILENAME_PACKAGE, package);
+ }
+
+ update_client(_("Searching for debug-info packages..."));
+
+ int pipein[2], pipeout[2];
+ xpipe(pipein);
+ xpipe(pipeout);
+
+ pid_t child = fork();
+ if (child < 0)
+ {
+ /*close(pipein[0]); close(pipeout[0]); - why bother */
+ /*close(pipein[1]); close(pipeout[1]); */
+ perror_msg_and_die("fork");
+ }
+ if (child == 0)
+ {
+ close(pipein[1]);
+ close(pipeout[0]);
+ xmove_fd(pipein[0], STDIN_FILENO);
+ xmove_fd(pipeout[1], STDOUT_FILENO);
+ /* Not a good idea, we won't see any error messages */
+ /*close(STDERR_FILENO);*/
+
+ setsid();
+/* Honestly, I do not know what is worse, pk-debuginfo-install or debuginfo-install:
+
+# pk-debuginfo-install -y -- coreutils-7.2-4.fc11
+1. Getting sources list...OK. Found 16 enabled and 23 disabled sources.
+2. Finding debugging sources...OK. Found 0 disabled debuginfo repos.
+3. Enabling debugging sources...OK. Enabled 0 debugging sources.
+4. Finding debugging packages...Failed to find the package : more than one package found for
+Failed to find the package : more than one package found for
+FAILED. Found no packages to install.
+5. Disabling sources previously enabled...OK. Disabled 0 debugging sources.
+
+:( FAIL!
+
+# debuginfo-install -y -- coreutils-7.2-4.fc11
+Loaded plugins: refresh-packagekit
+Another application is holding the yum lock, cannot continue
+
+:( FAIL!
+
+# debuginfo-install -y -- coreutils-7.2-4.fc11
+(second time in a row - it worked)
+
+*/
+ /* log() goes to stderr/syslog, it's ok to use it here */
+ VERB1 log("Executing: %s %s %s %s", "pk-debuginfo-install", "-y", "--", package.c_str());
+ execlp("pk-debuginfo-install", "pk-debuginfo-install", "-y", "--", package.c_str(), NULL);
+ /* fall back */
+ VERB1 log("Executing: %s %s %s %s", "debuginfo-install", "-y", "--", package.c_str());
+ execlp("debuginfo-install", "debuginfo-install", "-y", "--", package.c_str(), NULL);
+ exit(1);
+ }
+
+ close(pipein[0]);
+ close(pipeout[1]);
+
+ /* Should not be needed (we use -y option), but just in case: */
+ safe_write(pipein[1], "y\n", sizeof("y\n")-1);
+ close(pipein[1]);
+
+ update_client(_("Downloading and installing debug-info packages..."));
+
+ FILE *pipeout_fp = fdopen(pipeout[0], "r");
+ if (pipeout_fp == NULL) /* never happens */
+ {
+ close(pipeout[0]);
+ wait(NULL);
+ return;
+ }
+
+/* glx-utils, for example, do not have glx-utils-debuginfo package.
+ * Disabled code was causing failures in backtrace decoding.
+ * This does not seem to be useful.
+ */
+#ifdef COMPLAIN_IF_NO_DEBUGINFO
+ bool already_installed = false;
+#endif
+ char buff[1024];
+ std::string packageName = package.substr(0, package.rfind("-", package.rfind("-")-1));
+ while (fgets(buff, sizeof(buff), pipeout_fp))
+ {
+ int last = strlen(buff) - 1;
+ if (last >= 0 && buff[last] == '\n')
+ buff[last] = '\0';
+
+ /* log(buff); - update_client logs it too */
+ update_client(buff); /* maybe only if buff != ""? */
+
+#ifdef COMPLAIN_IF_NO_DEBUGINFO
+ if (already_installed == false)
+ {
+ /* "Package foo-debuginfo-1.2-5.ARCH already installed and latest version" */
+ char* pn = strstr(buff, packageName.c_str());
+ if (pn)
+ {
+ char* already_str = strstr(pn, "already installed and latest version");
+ if (already_str)
+ {
+ already_installed = true;
+ }
+ }
+ }
+
+ if (already_installed == false &&
+ (strstr(buff, "No debuginfo packages available to install") != NULL ||
+ strstr(buff, "Could not find debuginfo for main pkg") != NULL ||
+ strstr(buff, "Could not find debuginfo pkg for dependency package") != NULL))
+ {
+ fclose(pipeout_fp);
+ kill(child, SIGTERM);
+ wait(NULL);
+ throw CABRTException(EXCEP_PLUGIN, std::string(__func__) + ": cannot install debuginfos for " + pPackage);
+ }
+#endif
+ }
+
+ fclose(pipeout_fp);
+ wait(NULL);
+}
+#if 0
+/* Needs gdb feature from here: https://bugzilla.redhat.com/show_bug.cgi?id=528668 */
+static void InstallDebugInfos(const std::string& pDebugDumpDir, std::string& build_ids)
+{
update_client(_("Searching for debug-info packages..."));
- int pipein[2], pipeout[2]; //TODO: get rid of pipein
+ int pipein[2], pipeout[2]; //TODO: get rid of pipein. Can we use ExecVP?
xpipe(pipein);
xpipe(pipeout);
@@ -400,8 +591,8 @@ static void InstallDebugInfos(const std::string& pDebugDumpDir, std::string& bui
char *coredump = xasprintf("%s/"FILENAME_COREDUMP, pDebugDumpDir.c_str());
char *tempdir = xasprintf("/tmp/abrt-%u-%lu", (int)getpid(), (long)time(NULL));
/* log() goes to stderr/syslog, it's ok to use it here */
- VERB1 log("Executing: %s %s %s %s", "abrt-debuginfo-install", coredump, tempdir, "/"); // "/var/cache/abrt-di"
- execlp("abrt-debuginfo-install", "abrt-debuginfo-install", coredump, tempdir, "/", NULL);
+ VERB1 log("Executing: %s %s %s %s", "abrt-debuginfo-install", coredump, tempdir, "/var/cache/abrt-di");
+ execlp("abrt-debuginfo-install", "abrt-debuginfo-install", coredump, tempdir, "/var/cache/abrt-di", NULL);
exit(1);
}
@@ -447,6 +638,7 @@ static void InstallDebugInfos(const std::string& pDebugDumpDir, std::string& bui
fclose(pipeout_fp);
wait(NULL);
}
+#endif
std::string CAnalyzerCCpp::GetLocalUUID(const std::string& pDebugDumpDir)
{
diff --git a/src/Daemon/abrt-debuginfo-install b/src/Daemon/abrt-debuginfo-install
index fe55250a..fc5380ba 100755
--- a/src/Daemon/abrt-debuginfo-install
+++ b/src/Daemon/abrt-debuginfo-install
@@ -1,4 +1,61 @@
#!/bin/sh
+# Called by abrtd before producing a backtrace.
+# The task of this script is to install debuginfos.
+#
+# Just using [pk-]debuginfo-install does not work well.
+# - they can't install more than one version of debuginfo
+# for a package
+# - their output is unsuitable for scripting
+# - debuginfo-install aborts if yum lock is busy
+# - pk-debuginfo-install was observed to hang
+#
+# Usage: abrt-debuginfo-install CORE TEMPDIR [CACHEDIR]
+# If CACHEDIR is specified, debuginfos should be installed there.
+# If not, debuginfos should be installed into TEMPDIR.
+#
+# Currently, we are called with CACHEDIR set to "/", but in the future
+# it may be omitted or set to something else. script must be ready
+# for those cases too.
+#
+# Output goes to GUI as debuginfo install log. The script should be careful
+# to give useful, but not overly cluttered info to stdout.
+# Additionally, abrt daemon handles "MISSING:xxxx" messages specially:
+# xxxx will be prepended to backtrace. This is used to inform about
+# missing debuginfos.
+#
+# Exitcodes:
+# 0 - all debuginfos are installed
+# 1 - not all debuginfos are installed
+# 2+ - serious problem
+#
+# Algorithm:
+# - Create TEMPDIR
+# - Extract build-ids from coredump
+# - For every build-id, check /usr/lib/debug/.build-id/XX/XXXX.debug
+# and CACHEDIR/usr/lib/debug/.build-id/XX/XXXX.debug
+# - If they all exist, exit 0
+# - Using "yum provides /usr/lib/debug/.build-id/XX/XXXX.debug",
+# figure out which debuginfo packages are needed
+# - Download them using "yumdownloader PACKAGE..."
+# - Unpack them with rpm2cpio | cpio to TEMPDIR
+# - If CACHEDIR is specified, copy usr/lib/debug/.build-id/XX/XXXX.debug
+# to CACHEDIR/usr/lib/debug/.build-id/XX/XXXX.debug and delete TEMPDIR
+# - Report which XX/XXXX.debug are still missing.
+#
+# For better debuggability, eu_unstrip.OUT, yum_provides.OUT etc files
+# are saved in TEMPDIR, and TEMPDIR is not deleted if we exit with exitcode 2
+# ("serious problem").
+#
+# In the future, we may want to use a separate CACHEDIR (say, /var/cache/abrt-di)
+# and use it with this gdb command:
+# set debug-file-directory /usr/lib/debug/.build-id:CACHEDIR/usr/lib/debug/.build-id
+# but current gdb can't handle DIR1:DIR2.
+# So, currently we are called with CACHEDIR set to "/", and don't pass
+# "set debug-file-directory" to gdb.
+# This is ugly, since it messes up /usr/lib/debug/.build-id over time
+# by piling up debuginfos there without any means to control their amount,
+# but it's the only way to make it work with current gdb.
+
core=$1
tempdir=$2
@@ -11,14 +68,6 @@ count_words() {
exec 2>&1
-# Output goes to GUI as debigunfo install log.
-# "MISSING:xxxx" messages result in xxxx being prepended to backtrace
-
-# Exitcodes:
-# 0 - all debuginfos are installed
-# 1 - not all debuginfos are installed
-# 2+ - serious problem
-
test -f "$core" || exit 2
# cachedir is optional
test x"$cachedir" = x"" || test -d "$cachedir" || exit 2