LCOV - code coverage report
Current view: top level - debuginfod - debuginfod-find.c (source / functions) Hit Total Coverage
Test: elfutils-0.191 Lines: 86 97 88.7 %
Date: 2024-05-12 22:47:49 Functions: 3 3 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 42 52 80.8 %

           Branch data     Line data    Source code
       1                 :            : /* Command-line frontend for retrieving ELF / DWARF / source files
       2                 :            :    from the debuginfod.
       3                 :            :    Copyright (C) 2019-2020 Red Hat, Inc.
       4                 :            :    This file is part of elfutils.
       5                 :            : 
       6                 :            :    This file is free software; you can redistribute it and/or modify
       7                 :            :    it under the terms of the GNU General Public License as published by
       8                 :            :    the Free Software Foundation; either version 3 of the License, or
       9                 :            :    (at your option) any later version.
      10                 :            : 
      11                 :            :    elfutils is distributed in the hope that it will be useful, but
      12                 :            :    WITHOUT ANY WARRANTY; without even the implied warranty of
      13                 :            :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14                 :            :    General Public License for more details.
      15                 :            : 
      16                 :            :    You should have received a copy of the GNU General Public License
      17                 :            :    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
      18                 :            : 
      19                 :            : 
      20                 :            : #include "config.h"
      21                 :            : #include "printversion.h"
      22                 :            : #include "debuginfod.h"
      23                 :            : #include <errno.h>
      24                 :            : #include <stdio.h>
      25                 :            : #include <stdlib.h>
      26                 :            : #include <string.h>
      27                 :            : #include <time.h>
      28                 :            : #include <argp.h>
      29                 :            : #include <unistd.h>
      30                 :            : #include <fcntl.h>
      31                 :            : #include <gelf.h>
      32                 :            : #include <libdwelf.h>
      33                 :            : 
      34                 :            : 
      35                 :            : /* Name and version of program.  */
      36                 :            : ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
      37                 :            : 
      38                 :            : /* Bug report address.  */
      39                 :            : ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
      40                 :            : 
      41                 :            : /* Short description of program.  */
      42                 :            : static const char doc[] = N_("Request debuginfo-related content "
      43                 :            :                              "from debuginfods listed in $" DEBUGINFOD_URLS_ENV_VAR ".");
      44                 :            : 
      45                 :            : /* Strings for arguments in help texts.  */
      46                 :            : static const char args_doc[] = N_("debuginfo BUILDID\n"
      47                 :            :                                   "debuginfo PATH\n"
      48                 :            :                                   "executable BUILDID\n"
      49                 :            :                                   "executable PATH\n"
      50                 :            :                                   "source BUILDID /FILENAME\n"
      51                 :            :                                   "source PATH /FILENAME\n"
      52                 :            :                                   "section BUILDID SECTION-NAME\n"
      53                 :            :                                   "section PATH SECTION-NAME\n");
      54                 :            : 
      55                 :            : 
      56                 :            : /* Definitions of arguments for argp functions.  */
      57                 :            : static const struct argp_option options[] =
      58                 :            :   {
      59                 :            :    { "verbose", 'v', NULL, 0, "Increase verbosity.", 0 },
      60                 :            :    { NULL, 0, NULL, 0, NULL, 0 }
      61                 :            :   };
      62                 :            : 
      63                 :            : /* debuginfod connection handle.  */
      64                 :            : static debuginfod_client *client;
      65                 :            : static int verbose;
      66                 :            : 
      67                 :         80 : int progressfn(debuginfod_client *c __attribute__((__unused__)),
      68                 :            :                long a, long b)
      69                 :            : {
      70                 :         80 :   static bool first = true;
      71                 :         80 :   static struct timespec last;
      72                 :         80 :   struct timespec now;
      73                 :         80 :   uint64_t delta;
      74         [ +  + ]:         80 :   if (!first)
      75                 :            :     {
      76                 :         52 :       clock_gettime (CLOCK_MONOTONIC, &now);
      77                 :         52 :       delta = ((now.tv_sec - last.tv_sec) * 1000000
      78                 :         52 :                + (now.tv_nsec - last.tv_nsec) / 1000);
      79                 :            :     }
      80                 :            :   else
      81                 :            :     {
      82                 :         28 :       first = false;
      83                 :         28 :       delta = 250000;
      84                 :            :     }
      85                 :            : 
      86                 :            :   /* Show progress the first time and then at most 5 times a second. */
      87         [ -  + ]:         80 :   if (delta > 200000)
      88                 :            :     {
      89                 :         28 :       fprintf (stderr, "Progress %ld / %ld\n", a, b);
      90                 :         28 :       clock_gettime (CLOCK_MONOTONIC, &last);
      91                 :            :     }
      92                 :         80 :   return 0;
      93                 :            : }
      94                 :            : 
      95                 :            : 
      96                 :       1872 : static error_t parse_opt (int key, char *arg, struct argp_state *state)
      97                 :            : {
      98                 :       1872 :   (void) arg;
      99                 :       1872 :   (void) state;
     100         [ +  + ]:       1872 :   switch (key)
     101                 :            :     {
     102                 :        102 :     case 'v': verbose++;
     103                 :        102 :       debuginfod_set_progressfn (client, & progressfn);
     104         [ +  + ]:        102 :       if (verbose > 1)
     105                 :         64 :         debuginfod_set_verbose_fd (client, STDERR_FILENO);
     106                 :            :       break;
     107                 :            :     default: return ARGP_ERR_UNKNOWN;
     108                 :            :     }
     109                 :            :   return 0;
     110                 :            : }
     111                 :            : 
     112                 :            : 
     113                 :            : /* Data structure to communicate with argp functions.  */
     114                 :            : static struct argp argp =
     115                 :            :   {
     116                 :            :    options, parse_opt, args_doc, doc, NULL, NULL, NULL
     117                 :            :   };
     118                 :            : 
     119                 :            : 
     120                 :            : 
     121                 :            : int
     122                 :        354 : main(int argc, char** argv)
     123                 :            : {
     124                 :        354 :   elf_version (EV_CURRENT);
     125                 :            : 
     126                 :        354 :   client = debuginfod_begin ();
     127         [ -  + ]:        354 :   if (client == NULL)
     128                 :            :     {
     129                 :          0 :       fprintf(stderr, "Couldn't create debuginfod client context\n");
     130                 :          0 :       return 1;
     131                 :            :     }
     132                 :            : 
     133                 :            :   /* Exercise user data pointer, to support testing only. */
     134                 :        354 :   debuginfod_set_user_data (client, (void *)"Progress");
     135                 :            : 
     136                 :        354 :   int remaining;
     137                 :        354 :   (void) argp_parse (&argp, argc, argv, ARGP_IN_ORDER|ARGP_NO_ARGS, &remaining, NULL);
     138                 :            : 
     139   [ +  -  +  + ]:        354 :   if (argc < 2 || remaining+1 >= argc) /* no arguments or at least two non-option words */
     140                 :            :     {
     141                 :          2 :       argp_help (&argp, stderr, ARGP_HELP_USAGE, argv[0]);
     142                 :          2 :       return 1;
     143                 :            :     }
     144                 :            : 
     145                 :            :   /* If we were passed an ELF file name in the BUILDID slot, look in there. */
     146                 :        352 :   unsigned char* build_id = (unsigned char*) argv[remaining+1];
     147                 :        352 :   int build_id_len = 0; /* assume text */
     148                 :            : 
     149                 :        352 :   int any_non_hex = 0;
     150                 :        352 :   int i;
     151         [ +  + ]:      14118 :   for (i = 0; build_id[i] != '\0'; i++)
     152         [ +  + ]:      13766 :     if ((build_id[i] >= '0' && build_id[i] <= '9') ||
     153                 :            :         (build_id[i] >= 'a' && build_id[i] <= 'f'))
     154                 :            :       ;
     155                 :            :     else
     156                 :        462 :       any_non_hex = 1;
     157                 :            : 
     158                 :        352 :   int fd = -1;
     159                 :        352 :   Elf* elf = NULL;
     160         [ +  + ]:        352 :   if (any_non_hex) /* raw build-id */
     161                 :            :     {
     162                 :         12 :       fd = open ((char*) build_id, O_RDONLY);
     163         [ +  - ]:         12 :       if (fd < 0)
     164                 :          0 :         fprintf (stderr, "Cannot open %s: %s\n", build_id, strerror(errno));
     165                 :            :     }
     166                 :         12 :   if (fd >= 0)
     167                 :            :     {
     168                 :         12 :       elf = dwelf_elf_begin (fd);
     169         [ +  - ]:         12 :       if (elf == NULL)
     170                 :          0 :         fprintf (stderr, "Cannot open as ELF file %s: %s\n", build_id,
     171                 :            :                  elf_errmsg (-1));
     172                 :            :     }
     173                 :          0 :   if (elf != NULL)
     174                 :            :     {
     175                 :         12 :       const void *extracted_build_id;
     176                 :         12 :       ssize_t s = dwelf_elf_gnu_build_id(elf, &extracted_build_id);
     177         [ +  - ]:         12 :       if (s > 0)
     178                 :            :         {
     179                 :            :           /* Success: replace the build_id pointer/len with the binary blob
     180                 :            :              that elfutils is keeping for us.  It'll remain valid until elf_end(). */
     181                 :         12 :           build_id = (unsigned char*) extracted_build_id;
     182                 :         12 :           build_id_len = s;
     183                 :            :         }
     184                 :            :       else
     185                 :         12 :         fprintf (stderr, "Cannot extract build-id from %s: %s\n", build_id, elf_errmsg(-1));
     186                 :            :     }
     187                 :            : 
     188                 :        352 :   char *cache_name;
     189                 :        352 :   int rc = 0;
     190                 :            : 
     191                 :            :   /* Check whether FILETYPE is valid and call the appropriate
     192                 :            :      debuginfod_find_* function. If FILETYPE is "source"
     193                 :            :      then ensure a FILENAME was also supplied as an argument.  */
     194         [ +  + ]:        352 :   if (strcmp(argv[remaining], "debuginfo") == 0)
     195                 :        142 :     rc = debuginfod_find_debuginfo(client,
     196                 :            :                                    build_id, build_id_len,
     197                 :            :                                    &cache_name);
     198         [ +  + ]:        210 :   else if (strcmp(argv[remaining], "executable") == 0)
     199                 :        132 :     rc = debuginfod_find_executable(client,
     200                 :            :                                     build_id, build_id_len,
     201                 :            :                                     &cache_name);
     202         [ +  + ]:         78 :   else if (strcmp(argv[remaining], "source") == 0)
     203                 :            :     {
     204   [ +  -  -  + ]:         62 :       if (remaining+2 == argc || argv[remaining+2][0] != '/')
     205                 :            :         {
     206                 :          0 :           fprintf(stderr, "If FILETYPE is \"source\" then absolute /FILENAME must be given\n");
     207                 :          0 :           return 1;
     208                 :            :         }
     209                 :         62 :       rc = debuginfod_find_source(client,
     210                 :            :                                   build_id, build_id_len,
     211                 :            :                                   argv[remaining+2], &cache_name);
     212                 :            :     }
     213         [ +  - ]:         16 :   else if (strcmp(argv[remaining], "section") == 0)
     214                 :            :     {
     215         [ -  + ]:         16 :       if (remaining+2 >= argc)
     216                 :            :         {
     217                 :          0 :           fprintf(stderr,
     218                 :            :                   "If FILETYPE is \"section\" then a section name must be given\n");
     219                 :          0 :           return 1;
     220                 :            :         }
     221                 :         16 :       rc = debuginfod_find_section(client, build_id, build_id_len,
     222                 :         16 :                                    argv[remaining+2], &cache_name);
     223                 :            :     }
     224                 :            :   else
     225                 :            :     {
     226                 :          0 :       argp_help (&argp, stderr, ARGP_HELP_USAGE, argv[0]);
     227                 :          0 :       return 1;
     228                 :            :     }
     229                 :            : 
     230         [ +  + ]:        352 :   if (verbose)
     231                 :            :     {
     232                 :         36 :       const char* headers = debuginfod_get_headers(client);
     233         [ +  + ]:         36 :       if (headers)
     234                 :         20 :         fprintf(stderr, "Headers:\n%s", headers);
     235                 :         36 :       const char* url = debuginfod_get_url (client);
     236         [ +  + ]:         36 :       if (url != NULL)
     237                 :         20 :         fprintf(stderr, "Downloaded from %s\n", url);
     238                 :            :     }
     239                 :            : 
     240                 :        352 :   debuginfod_end (client);
     241         [ +  + ]:        352 :   if (elf)
     242                 :         12 :     elf_end(elf);
     243         [ +  + ]:        352 :   if (fd >= 0)
     244                 :         12 :     close (fd);
     245                 :            : 
     246         [ +  + ]:        352 :   if (rc < 0)
     247                 :            :     {
     248                 :         36 :       fprintf(stderr, "Server query failed: %s\n", strerror(-rc));
     249                 :         36 :       return 1;
     250                 :            :     }
     251                 :            :   else
     252                 :        316 :     close (rc);
     253                 :            : 
     254                 :        316 :   printf("%s\n", cache_name);
     255                 :        316 :   free (cache_name);
     256                 :            : 
     257                 :        316 :   return 0;
     258                 :            : }

Generated by: LCOV version 1.16