Index: rpm-4.4.2.3/build/files.c =================================================================== --- rpm-4.4.2.3.orig/build/files.c 2009-07-24 11:38:22.000000000 +0200 +++ rpm-4.4.2.3/build/files.c 2009-07-24 11:38:30.000000000 +0200 @@ -28,6 +28,10 @@ #define _RPMTE_INTERNAL #include "rpmte.h" +#if HAVE_GELF_H +#include +#endif + #include "buildio.h" #include "legacy.h" /* XXX domd5, expandFileList, compressFileList */ @@ -2485,6 +2489,128 @@ exit: return rc; } + +/* Query the build-id from the ELF file NAME and store it in the newly + allocated *build_id array of size *build_id_size. Returns -1 on + error. */ + +int +getELFBuildId (const char *name, + unsigned char **id, size_t *id_size) +{ + int fd, i; + Elf *elf; + GElf_Ehdr ehdr; + Elf_Data *build_id = NULL; + size_t build_id_offset = 0, build_id_size = 0; + + /* Now query the build-id of the file and add the + corresponding links in the .build-id tree. + The following code is based on tools/debugedit.c. */ + fd = open (name, O_RDONLY); + if (fd < 0) + return -1; + elf = elf_begin (fd, ELF_C_READ_MMAP, NULL); + if (elf == NULL) + { + fprintf (stderr, "cannot open ELF file: %s", + elf_errmsg (-1)); + close (fd); + return -1; + } + if (elf_kind (elf) != ELF_K_ELF + || gelf_getehdr (elf, &ehdr) == NULL + || (ehdr.e_type != ET_DYN + && ehdr.e_type != ET_EXEC + && ehdr.e_type != ET_REL)) + { + elf_end (elf); + close (fd); + return -1; + } + for (i = 0; i < ehdr.e_shnum; ++i) + { + Elf_Scn *s = elf_getscn (elf, i); + GElf_Shdr shdr; + Elf_Data *data; + Elf32_Nhdr nh; + Elf_Data dst = + { + .d_version = EV_CURRENT, .d_type = ELF_T_NHDR, + .d_buf = &nh, .d_size = sizeof nh + }; + Elf_Data src = dst; + + gelf_getshdr (s, &shdr); + if (shdr.sh_type != SHT_NOTE + || !(shdr.sh_flags & SHF_ALLOC)) + continue; + + /* Look for a build-ID note here. */ + data = elf_rawdata (s, NULL); + src.d_buf = data->d_buf; + assert (sizeof (Elf32_Nhdr) == sizeof (Elf64_Nhdr)); + while (data->d_buf + data->d_size - src.d_buf > (int) sizeof nh + && elf32_xlatetom (&dst, &src, ehdr.e_ident[EI_DATA])) + { + Elf32_Word len = sizeof nh + nh.n_namesz; + len = (len + 3) & ~3; + + if (nh.n_namesz == sizeof "GNU" && nh.n_type == 3 + && !memcmp (src.d_buf + sizeof nh, "GNU", sizeof "GNU")) + { + build_id = data; + build_id_offset = src.d_buf + len - data->d_buf; + build_id_size = nh.n_descsz; + break; + } + + len += nh.n_descsz; + len = (len + 3) & ~3; + src.d_buf += len; + } + + if (build_id != NULL) + break; + } + + if (build_id == NULL) + return -1; + + *id = malloc (build_id_size); + *id_size = build_id_size; + memcpy (*id, build_id->d_buf + build_id_offset, build_id_size); + + elf_end (elf); + close (fd); + + return 0; +} + + +static rpmTag copyTagsForDebug[] = { + RPMTAG_EPOCH, + RPMTAG_VERSION, + RPMTAG_RELEASE, + RPMTAG_LICENSE, + RPMTAG_PACKAGER, + RPMTAG_DISTRIBUTION, + RPMTAG_DISTURL, + RPMTAG_VENDOR, + RPMTAG_ICON, + RPMTAG_URL, + RPMTAG_CHANGELOGTIME, + RPMTAG_CHANGELOGNAME, + RPMTAG_CHANGELOGTEXT, + RPMTAG_PREFIXES, + RPMTAG_RHNPLATFORM, + RPMTAG_OS, + RPMTAG_DISTTAG, + RPMTAG_CVSID, + RPMTAG_ARCH, + 0 +}; + /*@-incondefs@*/ int processBinaryFiles(Spec spec, int installSpecialDoc, int test) /*@globals check_fileList @*/ @@ -2492,12 +2618,16 @@ int processBinaryFiles(Spec spec, int in { Package pkg; int res = 0; + char *buildrooturl; check_fileList = newStringBuf(); + buildrooturl = rpmGenPath(spec->rootURL, spec->buildRootURL, NULL); for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) { const char *n, *v, *r; int rc; + int type, count; + char *ap; if (pkg->fileList == NULL) continue; @@ -2508,6 +2638,106 @@ int processBinaryFiles(Spec spec, int in if ((rc = processPackageFiles(spec, pkg, installSpecialDoc, test))) res = rc; + /* BEGIN DEBUGPKG */ +#if HAVE_GELF_H && HAVE_LIBELF + elf_version(EV_CURRENT); + + /* Now we have the file list of pkg in pkg->cpioList. Iterate over + them and build a file list containing debug information for them. */ + if (headerGetEntry (pkg->header, RPMTAG_ARCH, &type, (void **)&ap, &count) + && type == RPM_STRING_TYPE && count == 1 + && strcmp (ap, "noarch") != 0 + && strcmp (ap, "src") != 0) + { + Package dbg; + rpmfi fi = pkg->cpioList; + char tmp[1024]; + const char *name; + StringBuf files = NULL; + + /* Check if the current package has files with debug info + and record them. */ + fi = rpmfiInit (fi, 0); + while (rpmfiNext (fi) >= 0) + { + const char *base; + int i; + unsigned char *build_id; + size_t build_id_size = 0; + struct stat sbuf; + + name = rpmfiFN (fi); + /* Skip leading buildroot. */ + base = name + strlen (buildrooturl); + /* Pre-pend %buildroot/usr/lib/debug and append .debug. */ + snprintf (tmp, 1024, "%s/usr/lib/debug%s.debug", + buildrooturl, base); + /* If that file exists we have debug information for it. */ + if (access (tmp, F_OK) != 0) + continue; + + /* Append the file list preamble. */ + if (!files) + { + files = newStringBuf(); + appendStringBuf(files, "%defattr(-,root,root)\n"); + appendStringBuf(files, "%dir /usr/lib/debug\n"); + appendStringBuf(files, "%dir /usr/lib/debug/.build-id\n"); + } + /* Add the files main debug-info file. */ + snprintf (tmp, 1024, "/usr/lib/debug/%s.debug\n", base); + appendStringBuf(files, tmp); + + /* Do not bother to check build-ids for symbolic links. + We'll handle them for the link target. */ + if (lstat (name, &sbuf) == -1 + || S_ISLNK (sbuf.st_mode)) + continue; + + /* Try to gather the build-id from the binary. */ + if (getELFBuildId (name, &build_id, &build_id_size) == -1) + continue; + + /* From the build-id construct the two links pointing back + to the debug information file and the binary. */ + snprintf (tmp, 1024, "/usr/lib/debug/.build-id/%02x/", + build_id[0]); + for (i = 1; i < build_id_size; ++i) + sprintf (tmp + strlen (tmp), "%02x", build_id[i]); + appendStringBuf(files, tmp); + appendStringBuf(files, "\n"); + appendStringBuf(files, tmp); + appendStringBuf(files, ".debug\n"); + + free (build_id); + } + + /* If there are debuginfo files for this package add a + new debuginfo package. */ + if (files) + { + dbg = newPackage (spec); + headerNVR (pkg->header, &name, NULL, NULL); + /* Set name, summary and group. */ + snprintf (tmp, 1024, "%s-debuginfo", name); + headerAddEntry (dbg->header, RPMTAG_NAME, RPM_STRING_TYPE, tmp, 1); + snprintf (tmp, 1024, "Debug information for package %s", name); + headerAddEntry (dbg->header, RPMTAG_SUMMARY, RPM_STRING_TYPE, + tmp, 1); + headerAddEntry (dbg->header, RPMTAG_GROUP, RPM_STRING_TYPE, + "Development/Debug", 1); + /* Inherit other tags from parent. */ + headerCopyTags (pkg->header, dbg->header, + (int_32 *)copyTagsForDebug); + + /* Build up the files list. */ + dbg->fileList = files; + } + } + + /* END DEBUGPKG */ +#endif + if ((rc = rpmfcGenerateDepends(spec, pkg))) res = rc; } Index: rpm-4.4.2.3/macros.in =================================================================== --- rpm-4.4.2.3.orig/macros.in 2009-07-24 11:38:22.000000000 +0200 +++ rpm-4.4.2.3/macros.in 2009-07-24 11:38:22.000000000 +0200 @@ -173,19 +173,6 @@ # Template for debug information sub-package. %debug_package \ %global __debug_package 1\ -%package debuginfo\ -Summary: Debug information for package %{name}\ -Group: Development/Debug\ -AutoReq: 0\ -AutoProv: 1\ -#Requires: %{?!debug_package_requires:%{name} = %{version}-%{release}}%{?debug_package_requires}\ -%description debuginfo\ -This package provides debug information for package %{name}.\ -Debug information is useful when developing applications that use this\ -package or when debugging this package.\ -%files debuginfo -f debugfiles.list\ -%defattr(-,root,root)\ -\ %package debugsource\ Summary: Debug sources for package %{name}\ Group: Development/Debug\ Index: rpm-4.4.2.3/scripts/find-debuginfo.sh =================================================================== --- rpm-4.4.2.3.orig/scripts/find-debuginfo.sh 2009-07-24 11:38:22.000000000 +0200 +++ rpm-4.4.2.3/scripts/find-debuginfo.sh 2009-07-24 11:38:22.000000000 +0200 @@ -274,19 +274,11 @@ while read nlinks inum f; do fi done || exit -# For each symlink whose target has a .debug file, -# make a .debug symlink to that file. -find $RPM_BUILD_ROOT ! -path "${debugdir}/*" -type l -print | -while read f -do - t=$(readlink -m "$f").debug - f=${f#$RPM_BUILD_ROOT} - t=${t#$RPM_BUILD_ROOT} - if [ -f "$debugdir$t" ]; then - echo "symlinked /usr/lib/debug$t to /usr/lib/debug${f}.debug" - debug_link "/usr/lib/debug$t" "${f}.debug" - fi -done +# We used to make a .debug symlink for each symlink whose target +# has a .debug file to that file. This is not necessary because +# the debuglink section contains only the destination of those links. +# Creating those links anyway results in debuginfo packages for +# devel packages just because of the .so symlinks in them. if [ -s "$SOURCEFILE" ]; then mkdir -p "${RPM_BUILD_ROOT}/usr/src/debug"