[Rpm-maint] [PATCH] Generate -debuginfo packages from /usr/lib/debug automatically

devzero2000 pinto.elia at gmail.com
Thu Aug 13 12:32:26 UTC 2009


On Thu, Jul 23, 2009 at 11:39 AM, Richard Guenther <rguenther at suse.de>wrote:

>
> As part of the 4th Hackweek at SUSE I sat down and finally made
> debuginfo packages per sub-package possible.  Currently for openSUSE
> we have one global %name-debuginfo and one %name-debugsource package.
> %name-debuginfo contains debug information extracted from the binaries
> and stored in the usual /usr/lib/debug shadow tree, including
> GNU build-id symlinks pointing back to it from the
> /usr/lib/debug/.build-id tree.
>
> One issue with that single debuginfo package is its size.  The goal
> was to at least have one debuginfo package per shared library package.
>
> The following patch ontop of the openSUSE Factory rpm package source
> (yeah, I know ...) implements that by leaving the debuginfo package
> creation completely to RPM (while the debuginfo extraction is still
> done with the find-debuginfo.sh helper in the post install hook).
>
> processBinaryFiles was deemed the correct place to do this as we
> need an expanded file list for a package to determine the corresponding
> set of debuginfo files.  They are available after processPackageFiles,
> so the patch appends new packages to the spec after this point.
>
> The patch works (though it isn't in production yet).  For the
> openSUSE rpm package the following sub-packages are now generated:
>
> popt-1.7-50.2.x86_64.rpm
> popt-debuginfo-1.7-50.2.x86_64.rpm
> popt-devel-1.7-50.2.x86_64.rpm
> rpm-4.4.2.3-50.2.x86_64.rpm
> rpm-debuginfo-4.4.2.3-50.2.x86_64.rpm
> rpm-debugsource-4.4.2.3-50.2.x86_64.rpm
> rpm-devel-4.4.2.3-50.2.x86_64.rpm
> rpm-devel-static-4.4.2.3-50.2.x86_64.rpm
> rpm-4.4.2.3-50.2.src.rpm
>
> for the openSUSE gcc43 package we create
>
> cpp43-4.3.3_20090714-2.1.i586.rpm
> cpp43-debuginfo-4.3.3_20090714-2.1.i586.rpm
> gcc43-4.3.3_20090714-2.1.i586.rpm
> gcc43-ada-4.3.3_20090714-2.1.i586.rpm
> gcc43-ada-debuginfo-4.3.3_20090714-2.1.i586.rpm
> gcc43-c++-4.3.3_20090714-2.1.i586.rpm
> gcc43-c++-debuginfo-4.3.3_20090714-2.1.i586.rpm
> gcc43-debuginfo-4.3.3_20090714-2.1.i586.rpm
> gcc43-debugsource-4.3.3_20090714-2.1.i586.rpm
> gcc43-fortran-4.3.3_20090714-2.1.i586.rpm
> gcc43-fortran-debuginfo-4.3.3_20090714-2.1.i586.rpm
> gcc43-info-4.3.3_20090714-2.1.i586.rpm
> gcc43-locale-4.3.3_20090714-2.1.i586.rpm
> gcc43-obj-c++-4.3.3_20090714-2.1.i586.rpm
> gcc43-obj-c++-debuginfo-4.3.3_20090714-2.1.i586.rpm
> gcc43-objc-4.3.3_20090714-2.1.i586.rpm
> gcc43-objc-debuginfo-4.3.3_20090714-2.1.i586.rpm
> libada43-4.3.3_20090714-2.1.i586.rpm
> libada43-debuginfo-4.3.3_20090714-2.1.i586.rpm
> libgcc43-4.3.3_20090714-2.1.i586.rpm
> libgcc43-debuginfo-4.3.3_20090714-2.1.i586.rpm
> libgfortran43-4.3.3_20090714-2.1.i586.rpm
> libgfortran43-debuginfo-4.3.3_20090714-2.1.i586.rpm
> libgomp43-4.3.3_20090714-2.1.i586.rpm
> libgomp43-debuginfo-4.3.3_20090714-2.1.i586.rpm
> libobjc43-4.3.3_20090714-2.1.i586.rpm
> libobjc43-debuginfo-4.3.3_20090714-2.1.i586.rpm
> libstdc++43-4.3.3_20090714-2.1.i586.rpm
> libstdc++43-debuginfo-4.3.3_20090714-2.1.i586.rpm
> libstdc++43-devel-4.3.3_20090714-2.1.i586.rpm
> libstdc++43-doc-4.3.3_20090714-2.1.i586.rpm
> libgcc43-debuginfo-x86-4.3.3_20090714-2.1.ia64.rpm
> libgcc43-x86-4.3.3_20090714-2.1.ia64.rpm
> libstdc++43-debuginfo-x86-4.3.3_20090714-2.1.ia64.rpm
> libstdc++43-x86-4.3.3_20090714-2.1.ia64.rpm
> gcc43-4.3.3_20090714-2.1.src.rpm
>
> note the chance to install
> libstdc++43-debuginfo-4.3.3_20090714-2.1.i586.rpm without also
> getting debug information for the Ada frontend for example.
>
> If there is interest in this feature and the approach I took is
> deemed viable I can work to move this patch to the current rpm git head.
>
> Thanks for comments (please CC me, I am not subscribed to this list),
> Richard.
>
> --
> Richard Guenther <rguenther at suse.de>
> Novell / SUSE Labs
> SUSE LINUX Products GmbH - Nuernberg - AG Nuernberg - HRB 16746 - GF:
> Markus Rex
>
>
> Index: rpm-4.4.2.3/build/files.c
> ===================================================================
> --- rpm-4.4.2.3.orig/build/files.c      2009-07-22 14:07:58.000000000 +0200
> +++ rpm-4.4.2.3/build/files.c   2009-07-23 11:21:14.000000000 +0200
> @@ -28,6 +28,10 @@
>  #define        _RPMTE_INTERNAL
>  #include "rpmte.h"
>
> +#if HAVE_GELF_H
> +#include <gelf.h>
> +#endif
> +
>  #include "buildio.h"
>
>  #include "legacy.h"    /* XXX domd5, expandFileList, compressFileList */
> @@ -2485,6 +2489,129 @@ 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,
> +    RPMTAG_SUSEBUILDCNT,

SIA. But RPMTAG_SUSEBUILDCNT is a local - e.g. non upstream - SUSE rpm tag.

>
> +    0
> +};
> +
>  /*@-incondefs@*/
>  int processBinaryFiles(Spec spec, int installSpecialDoc, int test)
>        /*@globals check_fileList @*/
> @@ -2498,6 +2625,8 @@ int processBinaryFiles(Spec spec, int in
>     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 +2637,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 (spec->buildRootURL);
> +               /* Pre-pend %buildroot/usr/lib/debug and append .debug.  */
> +               snprintf (tmp, 1024, "%s/usr/lib/debug%s.debug",
> +                         spec->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-22 14:07:58.000000000 +0200
> +++ rpm-4.4.2.3/macros.in       2009-07-22 14:08:05.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-22
> 14:07:58.000000000 +0200
> +++ rpm-4.4.2.3/scripts/find-debuginfo.sh       2009-07-23
> 11:24:47.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"
> _______________________________________________
> Rpm-maint mailing list
> Rpm-maint at lists.rpm.org
> http://lists.rpm.org/mailman/listinfo/rpm-maint
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.rpm.org/pipermail/rpm-maint/attachments/20090813/53cfd7fd/attachment-0001.htm>


More information about the Rpm-maint mailing list