--- /dev/null
+DEBUGEDIT
+
+The debugedit project provides programs and scripts for creating
+debuginfo and source file distributions, collect build-ids and rewrite
+source paths in DWARF data for debugging, tracing and profiling.
+
+It is based on code originally from the rpm project plus libiberty and
+binutils. It depends on the elfutils libelf and libdw libraries to
+read and write ELF files, DWARF data and build-ids.
+
+The project home is https://sourceware.org/debugedit/
+
+RELEASES and CODE
+
+Releases are published at ftp://sourceware.org/pub/debugedit/
+Which can also be found at https://sourceware.org/debugedit/ftp/
+
+To build a release do:
+ ./configure && make && make check
+
+The current debugedit source code can be checked out with
+git clone git://sourceware.org/git/debugedit.git
+
+To build a git checkout do:
+ autoreconf -i -f && ./configure && make && make check
+
+There should be no failures after make check.
+
+BUGS
+
+Please reports bugs at https://sourceware.org/bugzilla/
+
+CONTRIBUTING
+
+The developer mailinglist to send patches to is
+debugedit@sourceware.org.
+https://sourceware.org/ml/debugedit/
+
+To subscribe send an email to debugedit-subscribe@sourceware.org
+Or use the form at https://sourceware.org/mailman/listinfo/debugedit
+
+Please supply patches using git format-patch or using git send-email.
+
+Sign your work
+
+To facilitate tracking of who did what, we've adopted a "sign-off"
+procedure for patches based on the procedure used by the Linux kernel
+project.
+
+The sign-off is a simple line at the end of the explanation for the
+patch, which certifies that you wrote it or otherwise have the right
+to pass it on as a patch under the appropriate licenses. The rules are
+pretty simple: if you can certify the below:
+
+ Developer's Certificate of Origin
+
+ By making a contribution to this project, I certify that:
+
+ (a) The contribution was created in whole or in part by me,
+ and I have the right to submit the contribution under each
+ license indicated in, or otherwise designated as being
+ applicable to, the file.
+
+ (b) The contribution was provided directly to me by some other
+ person who certified (a), and I have not modified it.
+
+ (c) I understand and agree that the project and the
+ contribution are public and that a record of the
+ contribution (including all personal information I submit
+ with it, including my sign-off) is maintained indefinitely
+ and may be redistributed.
+
+then you just add a line saying
+
+Signed-off-by: Random J Developer <random@developer.example.org>
+
+using your real name (sorry, no pseudonyms or anonymous contributions.)
+
+git commit --signoff will add such a Signed-off-by line at the end of
+the commit log message for you.
+
+LICENSES
+
+The debuginfo project as a whole can be redistributed under the GPLv3+
+as described in the COPYING3 file.
+
+Some individual source files may also be redistributed under the
+GPLv2+ as described in the COPYING file or under the LGPLv2+ as
+described in the COPYING.LIB file. See the headers of the individual
+files to learn which licenses apply. All licenses used are upward
+compatible with GPLv3+.
\ No newline at end of file
--- /dev/null
+# -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+# Copyright (C) 2021 Mark J. Wielaard <mark@klomp.org>
+#
+# 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 3 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, see <https://www.gnu.org/licenses/>.
+
+AC_PREREQ([2.69])
+AC_INIT([debugedit], [0.1], [debugedit@sourceware.org])
+AC_CONFIG_SRCDIR([tools/debugedit.c])
+AC_CONFIG_HEADERS([config.h])
+
+# We are using foreign, not gnu, because we don't provide some
+# "standard" files like ChangeLog, AUTHORS, INSTALL, etc.
+AM_INIT_AUTOMAKE([foreign silent-rules subdir-objects
+ no-dist-gzip dist-xz tar-pax
+ -Wall -Wno-portability])
+
+# Silence. Override with make V=1.
+AM_SILENT_RULES([yes])
+
+# autotest directory
+AC_CONFIG_TESTDIR([tests])
+AC_CONFIG_FILES([tests/Makefile tests/atlocal])
+AM_MISSING_PROG([AUTOM4TE], [autom4te])
+
+# Happy to use GNU (or other) system extensions
+AC_USE_SYSTEM_EXTENSIONS
+
+# Checks for programs.
+AC_PROG_AWK
+AC_PROG_CC_C99
+AC_PROG_LN_S
+
+# Only really an issue on 32bit platforms. Makes sure we'll get large off_t.
+AC_SYS_LARGEFILE
+
+# Checks for libraries.
+PKG_PROG_PKG_CONFIG
+PKG_CHECK_MODULES([LIBELF], [libelf])
+PKG_CHECK_MODULES([LIBDW], [libdw])
+
+# Checks for header files.
+AC_CHECK_HEADERS([fcntl.h inttypes.h limits.h malloc.h stddef.h stdint.h stdlib.h string.h unistd.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_CHECK_HEADER_STDBOOL
+AC_C_INLINE
+AC_TYPE_INT8_T
+AC_TYPE_OFF_T
+AC_TYPE_SIZE_T
+AC_TYPE_SSIZE_T
+AC_TYPE_UINT16_T
+AC_TYPE_UINT32_T
+AC_TYPE_UINT8_T
+
+# Checks for library functions.
+AC_FUNC_ALLOCA
+AC_FUNC_ERROR_AT_LINE
+AC_FUNC_MALLOC
+AC_FUNC_MMAP
+AC_FUNC_REALLOC
+AC_CHECK_FUNCS([memchr memset munmap strchr strdup strerror strrchr])
+
+# And generate the output files.
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-#include "system.h"
-
-/* Needed for libelf */
-#define _FILE_OFFSET_BITS 64
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
#include <assert.h>
#include <byteswap.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
-#include <popt.h>
+#include <getopt.h>
#include <gelf.h>
#include <dwarf.h>
+#ifndef MAX
+#define MAX(m, n) ((m) < (n) ? (n) : (m))
+#endif
+
/* Unfortunately strtab manipulation functions were only officially added
to elfutils libdw in 0.167. Before that there were internal unsupported
#include <search.h>
-#include <rpm/rpmio.h>
-#include <rpm/rpmpgp.h>
#include "tools/hashtab.h"
+#include "tools/md5.h"
+#include "tools/sha1.h"
+
#define DW_TAG_partial_unit 0x3c
#define DW_FORM_sec_offset 0x17
#define DW_FORM_exprloc 0x18
return 0;
}
-static struct poptOption optionsTable[] = {
- { "base-dir", 'b', POPT_ARG_STRING, &base_dir, 0,
- "base build directory of objects", NULL },
- { "dest-dir", 'd', POPT_ARG_STRING, &dest_dir, 0,
- "directory to rewrite base-dir into", NULL },
- { "list-file", 'l', POPT_ARG_STRING, &list_file, 0,
- "file where to put list of source and header file names", NULL },
- { "build-id", 'i', POPT_ARG_NONE, &do_build_id, 0,
- "recompute build ID note and print ID on stdout", NULL },
- { "build-id-seed", 's', POPT_ARG_STRING, &build_id_seed, 0,
- "if recomputing the build ID note use this string as hash seed", NULL },
- { "no-recompute-build-id", 'n', POPT_ARG_NONE, &no_recompute_build_id, 0,
- "do not recompute build ID note even when -i or -s are given", NULL },
- { "version", '\0', POPT_ARG_NONE, &show_version, 0,
- "print the debugedit version", NULL },
- POPT_AUTOHELP
- { NULL, 0, 0, NULL, 0, NULL, NULL }
-};
+static struct option optionsTable[] =
+ {
+ { "base-dir", required_argument, 0, 'b' },
+ { "dest-dir", required_argument, 0, 'd' },
+ { "list-file", required_argument, 0, 'l' },
+ { "build-id", no_argument, 0, 'i' },
+ { "build-id-seed", required_argument, 0, 's' },
+ { "no-recompute-build-id", no_argument, 0, 'n' },
+ { "version", no_argument, 0, 'V' },
+ { "help", no_argument, 0, '?' },
+ { "usage", no_argument, 0, 'u' },
+ { NULL, 0, 0, 0 }
+ };
+
+static const char *optionsChars = "b:d:l:is:nV?";
+
+static const char *helpText =
+ "Usage: %s [OPTION...]\n"
+ " -b, --base-dir=STRING base build directory of objects\n"
+ " -d, --dest-dir=STRING directory to rewrite base-dir into\n"
+ " -l, --list-file=STRING file where to put list of source and \n"
+ " header file names\n"
+ " -i, --build-id recompute build ID note and print ID on\n"
+ " stdout\n"
+ " -s, --build-id-seed=STRING if recomputing the build ID note use\n"
+ " this string as hash seed\n"
+ " -n, --no-recompute-build-id do not recompute build ID note even\n"
+ " when-i or -s are given\n"
+ "\n"
+ "Help options:\n"
+ " -?, --help Show this help message\n"
+ " -u, --usage Display brief usage message\n"
+ " -V, --version Show debugedit version\n";
+
+static const char *usageText =
+ "Usage: %s [-in?] [-b|--base-dir STRING] [-d|--dest-dir STRING]\n"
+ " [-l|--list-file STRING] [-i|--build-id] \n"
+ " [-s|--build-id-seed STRING]\n"
+ " [-n|--no-recompute-build-id] [-?|--help] [-u|--usage]\n"
+ " [-V|--version] FILE\n";
+
+static void
+help (const char *progname, bool error)
+{
+ FILE *f = error ? stderr : stdout;
+ fprintf (f, helpText, progname);
+ exit (error ? EXIT_FAILURE : EXIT_SUCCESS);
+}
+
+static void
+usage (const char *progname)
+{
+ printf (usageText, progname);
+ exit (EXIT_SUCCESS);
+}
static DSO *
fdopen_dso (int fd, const char *name)
return NULL;
}
-static const pgpHashAlgo algorithms[] = { PGPHASHALGO_MD5,
- PGPHASHALGO_SHA1, PGPHASHALGO_SHA256, PGPHASHALGO_SHA384, PGPHASHALGO_SHA512 };
-
/* Compute a fresh build ID bit-string from the editted file contents. */
static void
handle_build_id (DSO *dso, Elf_Data *build_id,
size_t build_id_offset, size_t build_id_size)
{
- DIGEST_CTX ctx;
- pgpHashAlgo algorithm;
- int i = sizeof(algorithms)/sizeof(algorithms[0]);
- void *digest = NULL;
- size_t len;
+ /* For now we only handle 16 byte (128 bits) with md5 or 20 bytes
+ (160 bits) with sha1. */
- while (i-- > 0)
- {
- algorithm = algorithms[i];
- if (rpmDigestLength(algorithm) == build_id_size)
- break;
- }
- if (i < 0)
+ if (build_id_size != 16 && build_id_size != 20)
{
fprintf (stderr, "Cannot handle %Zu-byte build ID\n", build_id_size);
exit (1);
}
+ int i = -1;
if (no_recompute_build_id
|| (! dirty_elf && build_id_seed == NULL))
goto print;
/* Clear the old bits so they do not affect the new hash. */
memset ((char *) build_id->d_buf + build_id_offset, 0, build_id_size);
- ctx = rpmDigestInit(algorithm, 0);
+ struct md5_ctx md5_ctx;
+ struct sha1_ctx sha1_ctx;
+
+ if (build_id_size == 16)
+ md5_init_ctx (&md5_ctx);
+ else
+ sha1_init_ctx (&sha1_ctx);
/* If a seed string was given use it to prime the hash. */
if (build_id_seed != NULL)
- rpmDigestUpdate(ctx, build_id_seed, strlen (build_id_seed));
+ {
+ if (build_id_size == 16)
+ md5_process_bytes (build_id_seed, strlen (build_id_seed), &md5_ctx);
+ else
+ sha1_process_bytes (build_id_seed, strlen (build_id_seed), &sha1_ctx);
+ }
/* Slurp the relevant header bits and section contents and feed them
into the hash function. The only bits we ignore are the offset
goto bad;
if (elf64_xlatetom (&x, &x, dso->ehdr.e_ident[EI_DATA]) == NULL)
goto bad;
- rpmDigestUpdate(ctx, x.d_buf, x.d_size);
+
+ if (build_id_size == 16)
+ md5_process_bytes (x.d_buf, x.d_size, &md5_ctx);
+ else
+ sha1_process_bytes (x.d_buf, x.d_size, &sha1_ctx);
}
x.d_type = ELF_T_SHDR;
u.shdr.sh_offset = 0;
if (elf64_xlatetom (&x, &x, dso->ehdr.e_ident[EI_DATA]) == NULL)
goto bad;
- rpmDigestUpdate(ctx, x.d_buf, x.d_size);
+
+ if (build_id_size == 16)
+ md5_process_bytes (x.d_buf, x.d_size, &md5_ctx);
+ else
+ sha1_process_bytes (x.d_buf, x.d_size, &sha1_ctx);
if (u.shdr.sh_type != SHT_NOBITS)
{
Elf_Data *d = elf_getdata (dso->scn[i], NULL);
if (d == NULL)
goto bad;
- rpmDigestUpdate(ctx, d->d_buf, d->d_size);
+
+ if (build_id_size == 16)
+ md5_process_bytes (d->d_buf, d->d_size, &md5_ctx);
+ else
+ sha1_process_bytes (d->d_buf, d->d_size, &sha1_ctx);
}
}
}
- rpmDigestFinal(ctx, &digest, &len, 0);
+ /* Allocate the memory first to make sure alignment is correct. */
+ void *digest = malloc (build_id_size);
+ if (digest == NULL)
+ goto bad;
+
+ if (build_id_size == 16)
+ md5_finish_ctx (&md5_ctx, digest);
+ else
+ sha1_finish_ctx (&sha1_ctx, digest);
+
memcpy((unsigned char *)build_id->d_buf + build_id_offset, digest, build_id_size);
free(digest);
/* Now format the build ID bits in hex to print out. */
{
const uint8_t * id = (uint8_t *)build_id->d_buf + build_id_offset;
- char *hex = pgpHexStr(id, build_id_size);
- puts (hex);
- free(hex);
+ size_t blen = build_id_size;
+ static char const hex[] = "0123456789abcdef";
+ while (blen-- > 0)
+ {
+ size_t i = *id++;
+ printf ("%c%c", hex[(i >> 4) & 0xf], hex[(i) & 0xf]);
+ }
+ printf ("\n");
}
}
DSO *dso;
int fd, i;
const char *file;
- poptContext optCon; /* context for parsing command-line options */
- int nextopt;
- const char **args;
struct stat stat_buf;
Elf_Data *build_id = NULL;
size_t build_id_offset = 0, build_id_size = 0;
- optCon = poptGetContext("debugedit", argc, (const char **)argv, optionsTable, 0);
+ while (1)
+ {
+ int opt_ndx = -1;
+ int c = getopt_long (argc, argv, optionsChars, optionsTable, &opt_ndx);
- while ((nextopt = poptGetNextOpt (optCon)) > 0 || nextopt == POPT_ERROR_BADOPT)
- /* do nothing */ ;
+ if (c == -1)
+ break;
- if (nextopt != -1)
- {
- fprintf (stderr, "Error on option %s: %s.\nRun '%s --help' to see a full list of available command line options.\n",
- poptBadOption (optCon, 0),
- poptStrerror (nextopt),
- argv[0]);
- exit (1);
+ switch (c)
+ {
+ default:
+ case '?':
+ help (argv[0], opt_ndx == -1);
+ break;
+
+ case 'u':
+ usage (argv[0]);
+ break;
+
+ case 'b':
+ base_dir = optarg;
+ break;
+
+ case 'd':
+ dest_dir = optarg;
+ break;
+
+ case 'l':
+ list_file = optarg;
+ break;
+
+ case 'i':
+ do_build_id = 1;
+ break;
+
+ case 's':
+ build_id_seed = optarg;
+ break;
+
+ case 'n':
+ no_recompute_build_id = 1;
+ break;
+
+ case 'V':
+ show_version = 1;
+ break;
+ }
}
if (show_version)
{
- printf("RPM debugedit %s\n", VERSION);
+ printf("debugedit %s\n", VERSION);
exit(EXIT_SUCCESS);
}
- args = poptGetArgs (optCon);
- if (args == NULL || args[0] == NULL || args[1] != NULL)
+ if (optind != argc - 1)
{
- poptPrintHelp(optCon, stdout, 0);
- exit (1);
+ fprintf (stderr, "Need one FILE as input\n");
+ usage (argv[0]);
+ exit(EXIT_FAILURE);
}
if (dest_dir != NULL)
list_file_fd = open (list_file, O_WRONLY|O_CREAT|O_APPEND, 0644);
}
- file = args[0];
+ file = argv[optind];
if (elf_version(EV_CURRENT) == EV_NONE)
{
types_sec = next;
}
- poptFreeContext (optCon);
-
return 0;
}