LCOV - code coverage report
Current view: top level - libdwfl - argp-std.c (source / functions) Hit Total Coverage
Test: elfutils- Lines: 88 149 59.1 %
Date: 2020-06-11 18:20:19 Functions: 2 3 66.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Standard argp argument parsers for tools using libdwfl.
       2             :    Copyright (C) 2005-2010, 2012, 2015 Red Hat, Inc.
       3             :    This file is part of elfutils.
       4             : 
       5             :    This file is free software; you can redistribute it and/or modify
       6             :    it under the terms of either
       7             : 
       8             :      * the GNU Lesser General Public License as published by the Free
       9             :        Software Foundation; either version 3 of the License, or (at
      10             :        your option) any later version
      11             : 
      12             :    or
      13             : 
      14             :      * the GNU General Public License as published by the Free
      15             :        Software Foundation; either version 2 of the License, or (at
      16             :        your option) any later version
      17             : 
      18             :    or both in parallel, as here.
      19             : 
      20             :    elfutils is distributed in the hope that it will be useful, but
      21             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      22             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      23             :    General Public License for more details.
      24             : 
      25             :    You should have received copies of the GNU General Public License and
      26             :    the GNU Lesser General Public License along with this program.  If
      27             :    not, see <http://www.gnu.org/licenses/>.  */
      28             : 
      29             : #ifdef HAVE_CONFIG_H
      30             : # include <config.h>
      31             : #endif
      32             : 
      33             : #include "libdwflP.h"
      34             : #include <argp.h>
      35             : #include <stdlib.h>
      36             : #include <assert.h>
      37             : #include <libintl.h>
      38             : #include <fcntl.h>
      39             : #include <unistd.h>
      40             : 
      41             : /* gettext helper macros.  */
      42             : #define _(Str) dgettext ("elfutils", Str)
      43             : 
      44             : 
      45             : #define OPT_DEBUGINFO   0x100
      46             : #define OPT_COREFILE    0x101
      47             : 
      48             : static const struct argp_option options[] =
      49             : {
      50             :   { NULL, 0, NULL, 0, N_("Input selection options:"), 0 },
      51             :   { "executable", 'e', "FILE", 0, N_("Find addresses in FILE"), 0 },
      52             :   { "core", OPT_COREFILE, "COREFILE", 0,
      53             :     N_("Find addresses from signatures found in COREFILE"), 0 },
      54             :   { "pid", 'p', "PID", 0,
      55             :     N_("Find addresses in files mapped into process PID"), 0 },
      56             :   { "linux-process-map", 'M', "FILE", 0,
      57             :     N_("Find addresses in files mapped as read from FILE"
      58             :        " in Linux /proc/PID/maps format"), 0 },
      59             :   { "kernel", 'k', NULL, 0, N_("Find addresses in the running kernel"), 0 },
      60             :   { "offline-kernel", 'K', "RELEASE", OPTION_ARG_OPTIONAL,
      61             :     N_("Kernel with all modules"), 0 },
      62             :   { "debuginfo-path", OPT_DEBUGINFO, "PATH", 0,
      63             :     N_("Search path for separate debuginfo files"), 0 },
      64             :   { NULL, 0, NULL, 0, NULL, 0 }
      65             : };
      66             : 
      67             : static char *debuginfo_path;
      68             : 
      69             : static const Dwfl_Callbacks offline_callbacks =
      70             :   {
      71             :     .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo),
      72             :     .debuginfo_path = &debuginfo_path,
      73             : 
      74             :     .section_address = INTUSE(dwfl_offline_section_address),
      75             : 
      76             :     /* We use this table for core files too.  */
      77             :     .find_elf = INTUSE(dwfl_build_id_find_elf),
      78             :   };
      79             : 
      80             : static const Dwfl_Callbacks proc_callbacks =
      81             :   {
      82             :     .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo),
      83             :     .debuginfo_path = &debuginfo_path,
      84             : 
      85             :     .find_elf = INTUSE(dwfl_linux_proc_find_elf),
      86             :   };
      87             : 
      88             : static const Dwfl_Callbacks kernel_callbacks =
      89             :   {
      90             :     .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo),
      91             :     .debuginfo_path = &debuginfo_path,
      92             : 
      93             :     .find_elf = INTUSE(dwfl_linux_kernel_find_elf),
      94             :     .section_address = INTUSE(dwfl_linux_kernel_module_section_address),
      95             :   };
      96             : 
      97             : /* Structure held at state->HOOK.  */
      98             : struct parse_opt
      99             : {
     100             :   Dwfl *dwfl;
     101             :   /* The -e|--executable parameter.  */
     102             :   const char *e;
     103             :   /* The --core parameter.  */
     104             :   const char *core;
     105             : };
     106             : 
     107             : static inline void
     108           0 : failure (Dwfl *dwfl, int errnum, const char *msg, struct argp_state *state)
     109             : {
     110           0 :   if (dwfl != NULL)
     111           0 :     dwfl_end (dwfl);
     112           0 :   if (errnum == -1)
     113           0 :     argp_failure (state, EXIT_FAILURE, 0, "%s: %s",
     114             :                   msg, INTUSE(dwfl_errmsg) (-1));
     115             :   else
     116           0 :     argp_failure (state, EXIT_FAILURE, errnum, "%s", msg);
     117           0 : }
     118             : 
     119             : static inline error_t
     120             : fail (Dwfl *dwfl, int errnum, const char *msg, struct argp_state *state)
     121             : {
     122           0 :   failure (dwfl, errnum, msg, state);
     123           0 :   return errnum == -1 ? EIO : errnum;
     124             : }
     125             : 
     126             : static error_t
     127        1337 : parse_opt (int key, char *arg, struct argp_state *state)
     128             : {
     129        1337 :   switch (key)
     130             :     {
     131         232 :     case ARGP_KEY_INIT:
     132             :       {
     133         232 :         assert (state->hook == NULL);
     134         232 :         struct parse_opt *opt = calloc (1, sizeof (*opt));
     135         232 :         if (opt == NULL)
     136           0 :           failure (NULL, DWFL_E_ERRNO, "calloc", state);
     137         232 :         state->hook = opt;
     138             :       }
     139         232 :       break;
     140             : 
     141           1 :     case OPT_DEBUGINFO:
     142           1 :       debuginfo_path = arg;
     143           1 :       break;
     144             : 
     145         194 :     case 'e':
     146             :       {
     147         194 :         struct parse_opt *opt = state->hook;
     148         194 :         Dwfl *dwfl = opt->dwfl;
     149         194 :         if (dwfl == NULL)
     150             :           {
     151         193 :             dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
     152         193 :             if (dwfl == NULL)
     153           0 :               return fail (dwfl, -1, arg, state);
     154         193 :             opt->dwfl = dwfl;
     155             : 
     156             :             /* Start at zero so if there is just one -e foo.so,
     157             :                the DSO is shown without address bias.  */
     158         193 :             dwfl->offline_next_address = 0;
     159             :           }
     160         194 :         if (dwfl->callbacks != &offline_callbacks)
     161             :           {
     162           0 :           toomany:
     163           0 :             argp_error (state, "%s",
     164             :                         _("only one of -e, -p, -k, -K, or --core allowed"));
     165           0 :             return EINVAL;
     166             :           }
     167         194 :         opt->e = arg;
     168             :       }
     169         194 :       break;
     170             : 
     171           4 :     case 'p':
     172             :       {
     173           4 :         struct parse_opt *opt = state->hook;
     174           4 :         if (opt->dwfl == NULL)
     175             :           {
     176           4 :             Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks);
     177           4 :             int result = INTUSE(dwfl_linux_proc_report) (dwfl, atoi (arg));
     178           4 :             if (result != 0)
     179           0 :               return fail (dwfl, result, arg, state);
     180             : 
     181             :             /* Non-fatal to not be able to attach to process, ignore error.  */
     182           4 :             INTUSE(dwfl_linux_proc_attach) (dwfl, atoi (arg), false);
     183             : 
     184           4 :             opt->dwfl = dwfl;
     185             :           }
     186             :         else
     187             :           goto toomany;
     188             :       }
     189           4 :       break;
     190             : 
     191           6 :     case 'M':
     192             :       {
     193           6 :         struct parse_opt *opt = state->hook;
     194           6 :         if (opt->dwfl == NULL)
     195             :           {
     196           6 :             FILE *f = fopen (arg, "r");
     197           6 :             if (f == NULL)
     198             :               {
     199           0 :                 int code = errno;
     200           0 :                 argp_failure (state, EXIT_FAILURE, code,
     201             :                               "cannot open '%s'", arg);
     202           0 :                 return code;
     203             :               }
     204           6 :             Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks);
     205           6 :             int result = INTUSE(dwfl_linux_proc_maps_report) (dwfl, f);
     206           6 :             fclose (f);
     207           6 :             if (result != 0)
     208           0 :               return fail (dwfl, result, arg, state);
     209           6 :             opt->dwfl = dwfl;
     210             :           }
     211             :         else
     212             :           goto toomany;
     213             :       }
     214           6 :       break;
     215             : 
     216          24 :     case OPT_COREFILE:
     217             :       {
     218          24 :         struct parse_opt *opt = state->hook;
     219          24 :         Dwfl *dwfl = opt->dwfl;
     220          24 :         if (dwfl == NULL)
     221           5 :           opt->dwfl = dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
     222             :         /* Permit -e and --core together.  */
     223          19 :         else if (dwfl->callbacks != &offline_callbacks)
     224             :           goto toomany;
     225          24 :         opt->core = arg;
     226             :       }
     227          24 :       break;
     228             : 
     229           0 :     case 'k':
     230             :       {
     231           0 :         struct parse_opt *opt = state->hook;
     232           0 :         if (opt->dwfl == NULL)
     233             :           {
     234           0 :             Dwfl *dwfl = INTUSE(dwfl_begin) (&kernel_callbacks);
     235           0 :             int result = INTUSE(dwfl_linux_kernel_report_kernel) (dwfl);
     236           0 :             if (result != 0)
     237           0 :               return fail (dwfl, result, _("cannot load kernel symbols"), state);
     238           0 :             result = INTUSE(dwfl_linux_kernel_report_modules) (dwfl);
     239           0 :             if (result != 0)
     240             :               /* Non-fatal to have no modules since we do have the kernel.  */
     241           0 :               argp_failure (state, 0, result, _("cannot find kernel modules"));
     242           0 :             opt->dwfl = dwfl;
     243             :           }
     244             :         else
     245             :           goto toomany;
     246             :       }
     247           0 :       break;
     248             : 
     249           0 :     case 'K':
     250             :       {
     251           0 :         struct parse_opt *opt = state->hook;
     252           0 :         if (opt->dwfl == NULL)
     253             :           {
     254           0 :             Dwfl *dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
     255           0 :             int result = INTUSE(dwfl_linux_kernel_report_offline) (dwfl, arg,
     256             :                                                                    NULL);
     257           0 :             if (result != 0)
     258           0 :               return fail (dwfl, result, _("cannot find kernel or modules"), state);
     259           0 :             opt->dwfl = dwfl;
     260             :           }
     261             :         else
     262             :           goto toomany;
     263             :       }
     264           0 :       break;
     265             : 
     266         208 :     case ARGP_KEY_SUCCESS:
     267             :       {
     268         208 :         struct parse_opt *opt = state->hook;
     269         208 :         Dwfl *dwfl = opt->dwfl;
     270             : 
     271         208 :         if (dwfl == NULL)
     272             :           {
     273             :             /* Default if no -e, -p, or -k, is "-e a.out".  */
     274           0 :             arg = "a.out";
     275           0 :             dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
     276           0 :             if (INTUSE(dwfl_report_offline) (dwfl, "", arg, -1) == NULL)
     277           0 :               return fail (dwfl, -1, arg, state);
     278           0 :             opt->dwfl = dwfl;
     279             :           }
     280             : 
     281         208 :         if (opt->core)
     282             :           {
     283          24 :             int fd = open (opt->core, O_RDONLY);
     284          24 :             if (fd < 0)
     285             :               {
     286           0 :                 int code = errno;
     287           0 :                 argp_failure (state, EXIT_FAILURE, code,
     288             :                               "cannot open '%s'", opt->core);
     289           0 :                 return code;
     290             :               }
     291             : 
     292          24 :             Elf *core;
     293          24 :             Dwfl_Error error = __libdw_open_file (&fd, &core, true, false);
     294          24 :             if (error != DWFL_E_NOERROR)
     295             :               {
     296           0 :                 argp_failure (state, EXIT_FAILURE, 0,
     297           0 :                               _("cannot read ELF core file: %s"),
     298             :                               INTUSE(dwfl_errmsg) (error));
     299           0 :                 return error == DWFL_E_ERRNO ? errno : EIO;
     300             :               }
     301             : 
     302          24 :             int result = INTUSE(dwfl_core_file_report) (dwfl, core, opt->e);
     303          24 :             if (result < 0)
     304             :               {
     305           0 :                 elf_end (core);
     306           0 :                 close (fd);
     307           0 :                 return fail (dwfl, result, opt->core, state);
     308             :               }
     309             : 
     310             :             /* Non-fatal to not be able to attach to core, ignore error.  */
     311          24 :             INTUSE(dwfl_core_file_attach) (dwfl, core);
     312             : 
     313             :             /* Store core Elf and fd in Dwfl to expose with dwfl_end.  */
     314          24 :             if (dwfl->user_core == NULL)
     315             :               {
     316           4 :                 dwfl->user_core = calloc (1, sizeof (struct Dwfl_User_Core));
     317           4 :                 if (dwfl->user_core == NULL)
     318             :                   {
     319           0 :                     argp_failure (state, EXIT_FAILURE, 0,
     320           0 :                                   _("Not enough memory"));
     321           0 :                     return ENOMEM;
     322             :                   }
     323             :               }
     324          24 :             dwfl->user_core->core = core;
     325          24 :             dwfl->user_core->fd = fd;
     326             : 
     327          24 :             if (result == 0)
     328             :               {
     329           0 :                 argp_failure (state, EXIT_FAILURE, 0,
     330           0 :                               _("No modules recognized in core file"));
     331           0 :                 return ENOENT;
     332             :               }
     333             :           }
     334         184 :         else if (opt->e)
     335             :           {
     336         174 :             if (INTUSE(dwfl_report_offline) (dwfl, "", opt->e, -1) == NULL)
     337           0 :               return fail (dwfl, -1, opt->e, state);
     338             :           }
     339             : 
     340             :         /* One of the three flavors has done dwfl_begin and some reporting
     341             :            if we got here.  Tie up the Dwfl and return it to the caller of
     342             :            argp_parse.  */
     343             : 
     344         208 :         int result = INTUSE(dwfl_report_end) (dwfl, NULL, NULL);
     345         208 :         assert (result == 0);
     346             : 
     347             :         /* Update the input all along, so a parent parser can see it.
     348             :            As we free OPT the update below will be no longer active.  */
     349         208 :         *(Dwfl **) state->input = dwfl;
     350         208 :         free (opt);
     351         208 :         state->hook = NULL;
     352             :       }
     353         208 :       break;
     354             : 
     355          22 :     case ARGP_KEY_ERROR:
     356             :       {
     357          22 :         struct parse_opt *opt = state->hook;
     358          22 :         dwfl_end (opt->dwfl);
     359          22 :         free (opt);
     360          22 :         state->hook = NULL;
     361             :       }
     362          22 :       break;
     363             : 
     364             :     default:
     365             :       return ARGP_ERR_UNKNOWN;
     366             :     }
     367             : 
     368             :   /* Update the input all along, so a parent parser can see it.  */
     369         691 :   struct parse_opt *opt = state->hook;
     370         691 :   if (opt)
     371         461 :     *(Dwfl **) state->input = opt->dwfl;
     372             : 
     373             :   return 0;
     374             : }
     375             : 
     376             : static const struct argp libdwfl_argp =
     377             :   { .options = options, .parser = parse_opt };
     378             : 
     379             : const struct argp *
     380         232 : dwfl_standard_argp (void)
     381             : {
     382         232 :   return &libdwfl_argp;
     383             : }

Generated by: LCOV version 1.13