diff options
author | Karel Klic <kklic@redhat.com> | 2009-10-20 15:58:02 +0200 |
---|---|---|
committer | Karel Klic <kklic@redhat.com> | 2009-10-20 15:58:02 +0200 |
commit | 08b9971c3d1635ff1f6d17608e7e99d5ac4b5866 (patch) | |
tree | 1b7dc5c62858b8efdbc610431a21f3564e4d6f3b | |
parent | 9e8a1ba0c9ddfa0108050f6fedc88de63b4b7c3f (diff) | |
parent | 4df20906ef57432edb505ce28179fd979729c975 (diff) | |
download | abrt-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.cpp | 198 | ||||
-rwxr-xr-x | src/Daemon/abrt-debuginfo-install | 65 |
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 |