diff options
Diffstat (limited to 'debuginfod/debuginfod-find.c')
| -rw-r--r-- | debuginfod/debuginfod-find.c | 91 |
1 files changed, 80 insertions, 11 deletions
diff --git a/debuginfod/debuginfod-find.c b/debuginfod/debuginfod-find.c index 8bd3a3db..83a43ce4 100644 --- a/debuginfod/debuginfod-find.c +++ b/debuginfod/debuginfod-find.c @@ -1,6 +1,6 @@ /* Command-line frontend for retrieving ELF / DWARF / source files from the debuginfod. - Copyright (C) 2019 Red Hat, Inc. + Copyright (C) 2019-2020 Red Hat, Inc. This file is part of elfutils. This file is free software; you can redistribute it and/or modify @@ -25,6 +25,10 @@ #include <stdlib.h> #include <string.h> #include <argp.h> +#include <unistd.h> +#include <fcntl.h> +#include <gelf.h> +#include <libdwelf.h> /* Name and version of program. */ @@ -39,8 +43,12 @@ static const char doc[] = N_("Request debuginfo-related content " /* Strings for arguments in help texts. */ static const char args_doc[] = N_("debuginfo BUILDID\n" + "debuginfo PATH\n" "executable BUILDID\n" - "source BUILDID /FILENAME"); + "executable PATH\n" + "source BUILDID /FILENAME\n" + "source PATH /FILENAME\n"); + /* Definitions of arguments for argp functions. */ static const struct argp_option options[] = @@ -51,6 +59,7 @@ static const struct argp_option options[] = /* debuginfod connection handle. */ static debuginfod_client *client; +static int verbose; int progressfn(debuginfod_client *c __attribute__((__unused__)), long a, long b) @@ -66,7 +75,8 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state) (void) state; switch (key) { - case 'v': debuginfod_set_progressfn (client, & progressfn); break; + case 'v': verbose++; + debuginfod_set_progressfn (client, & progressfn); break; default: return ARGP_ERR_UNKNOWN; } return 0; @@ -84,6 +94,8 @@ static struct argp argp = int main(int argc, char** argv) { + elf_version (EV_CURRENT); + client = debuginfod_begin (); if (client == NULL) { @@ -91,6 +103,9 @@ main(int argc, char** argv) return 1; } + /* Exercise user data pointer, to support testing only. */ + debuginfod_set_user_data (client, (void *)"Progress"); + int remaining; (void) argp_parse (&argp, argc, argv, ARGP_IN_ORDER|ARGP_NO_ARGS, &remaining, NULL); @@ -100,29 +115,72 @@ main(int argc, char** argv) return 1; } - int rc; + /* If we were passed an ELF file name in the BUILDID slot, look in there. */ + unsigned char* build_id = (unsigned char*) argv[remaining+1]; + int build_id_len = 0; /* assume text */ + + int any_non_hex = 0; + int i; + for (i = 0; build_id[i] != '\0'; i++) + if ((build_id[i] >= '0' && build_id[i] <= '9') || + (build_id[i] >= 'a' && build_id[i] <= 'f')) + ; + else + any_non_hex = 1; + + int fd = -1; + Elf* elf = NULL; + if (any_non_hex) /* raw build-id */ + { + fd = open ((char*) build_id, O_RDONLY); + if (fd < 0) + fprintf (stderr, "Cannot open %s: %s\n", build_id, strerror(errno)); + } + if (fd >= 0) + { + elf = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, NULL); + if (elf == NULL) + fprintf (stderr, "Cannot elf_begin %s: %s\n", build_id, elf_errmsg(-1)); + } + if (elf != NULL) + { + const void *extracted_build_id; + ssize_t s = dwelf_elf_gnu_build_id(elf, &extracted_build_id); + if (s > 0) + { + /* Success: replace the build_id pointer/len with the binary blob + that elfutils is keeping for us. It'll remain valid until elf_end(). */ + build_id = (unsigned char*) extracted_build_id; + build_id_len = s; + } + else + fprintf (stderr, "Cannot extract build-id from %s: %s\n", build_id, elf_errmsg(-1)); + } + char *cache_name; + int rc = 0; /* Check whether FILETYPE is valid and call the appropriate debuginfod_find_* function. If FILETYPE is "source" then ensure a FILENAME was also supplied as an argument. */ if (strcmp(argv[remaining], "debuginfo") == 0) rc = debuginfod_find_debuginfo(client, - (unsigned char *)argv[remaining+1], 0, + build_id, build_id_len, &cache_name); else if (strcmp(argv[remaining], "executable") == 0) rc = debuginfod_find_executable(client, - (unsigned char *)argv[remaining+1], 0, + build_id, build_id_len, &cache_name); else if (strcmp(argv[remaining], "source") == 0) { - if (remaining+2 == argc || argv[3][0] != '/') + if (remaining+2 == argc || argv[remaining+2][0] != '/') { fprintf(stderr, "If FILETYPE is \"source\" then absolute /FILENAME must be given\n"); return 1; } - rc = debuginfod_find_source(client, (unsigned char *)argv[remaining+1], - 0, argv[remaining+2], &cache_name); + rc = debuginfod_find_source(client, + build_id, build_id_len, + argv[remaining+2], &cache_name); } else { @@ -130,6 +188,19 @@ main(int argc, char** argv) return 1; } + if (verbose) + { + const char* url = debuginfod_get_url (client); + if (url != NULL) + fprintf(stderr, "Downloaded from %s\n", url); + } + + debuginfod_end (client); + if (elf) + elf_end(elf); + if (fd >= 0) + close (fd); + if (rc < 0) { fprintf(stderr, "Server query failed: %s\n", strerror(-rc)); @@ -137,9 +208,7 @@ main(int argc, char** argv) } printf("%s\n", cache_name); - free (cache_name); - debuginfod_end (client); return 0; } |
