Blame libdwfl/argp-std.c

Packit 032894
/* Standard argp argument parsers for tools using libdwfl.
Packit 032894
   Copyright (C) 2005-2010, 2012, 2015 Red Hat, Inc.
Packit 032894
   This file is part of elfutils.
Packit 032894
Packit 032894
   This file is free software; you can redistribute it and/or modify
Packit 032894
   it under the terms of either
Packit 032894
Packit 032894
     * the GNU Lesser General Public License as published by the Free
Packit 032894
       Software Foundation; either version 3 of the License, or (at
Packit 032894
       your option) any later version
Packit 032894
Packit 032894
   or
Packit 032894
Packit 032894
     * the GNU General Public License as published by the Free
Packit 032894
       Software Foundation; either version 2 of the License, or (at
Packit 032894
       your option) any later version
Packit 032894
Packit 032894
   or both in parallel, as here.
Packit 032894
Packit 032894
   elfutils is distributed in the hope that it will be useful, but
Packit 032894
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 032894
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 032894
   General Public License for more details.
Packit 032894
Packit 032894
   You should have received copies of the GNU General Public License and
Packit 032894
   the GNU Lesser General Public License along with this program.  If
Packit 032894
   not, see <http://www.gnu.org/licenses/>.  */
Packit 032894
Packit 032894
#ifdef HAVE_CONFIG_H
Packit 032894
# include <config.h>
Packit 032894
#endif
Packit 032894
Packit 032894
#include "libdwflP.h"
Packit 032894
#include <argp.h>
Packit 032894
#include <stdlib.h>
Packit 032894
#include <assert.h>
Packit 032894
#include <libintl.h>
Packit 032894
#include <fcntl.h>
Packit 032894
#include <unistd.h>
Packit 032894
Packit 032894
/* gettext helper macros.  */
Packit 032894
#define _(Str) dgettext ("elfutils", Str)
Packit 032894
Packit 032894
Packit 032894
#define OPT_DEBUGINFO	0x100
Packit 032894
#define OPT_COREFILE	0x101
Packit 032894
Packit 032894
static const struct argp_option options[] =
Packit 032894
{
Packit 032894
  { NULL, 0, NULL, 0, N_("Input selection options:"), 0 },
Packit 032894
  { "executable", 'e', "FILE", 0, N_("Find addresses in FILE"), 0 },
Packit 032894
  { "core", OPT_COREFILE, "COREFILE", 0,
Packit 032894
    N_("Find addresses from signatures found in COREFILE"), 0 },
Packit 032894
  { "pid", 'p', "PID", 0,
Packit 032894
    N_("Find addresses in files mapped into process PID"), 0 },
Packit 032894
  { "linux-process-map", 'M', "FILE", 0,
Packit 032894
    N_("Find addresses in files mapped as read from FILE"
Packit 032894
       " in Linux /proc/PID/maps format"), 0 },
Packit 032894
  { "kernel", 'k', NULL, 0, N_("Find addresses in the running kernel"), 0 },
Packit 032894
  { "offline-kernel", 'K', "RELEASE", OPTION_ARG_OPTIONAL,
Packit 032894
    N_("Kernel with all modules"), 0 },
Packit 032894
  { "debuginfo-path", OPT_DEBUGINFO, "PATH", 0,
Packit 032894
    N_("Search path for separate debuginfo files"), 0 },
Packit 032894
  { NULL, 0, NULL, 0, NULL, 0 }
Packit 032894
};
Packit 032894
Packit 032894
static char *debuginfo_path;
Packit 032894
Packit 032894
static const Dwfl_Callbacks offline_callbacks =
Packit 032894
  {
Packit 032894
    .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo),
Packit 032894
    .debuginfo_path = &debuginfo_path,
Packit 032894
Packit 032894
    .section_address = INTUSE(dwfl_offline_section_address),
Packit 032894
Packit 032894
    /* We use this table for core files too.  */
Packit 032894
    .find_elf = INTUSE(dwfl_build_id_find_elf),
Packit 032894
  };
Packit 032894
Packit 032894
static const Dwfl_Callbacks proc_callbacks =
Packit 032894
  {
Packit 032894
    .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo),
Packit 032894
    .debuginfo_path = &debuginfo_path,
Packit 032894
Packit 032894
    .find_elf = INTUSE(dwfl_linux_proc_find_elf),
Packit 032894
  };
Packit 032894
Packit 032894
static const Dwfl_Callbacks kernel_callbacks =
Packit 032894
  {
Packit 032894
    .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo),
Packit 032894
    .debuginfo_path = &debuginfo_path,
Packit 032894
Packit 032894
    .find_elf = INTUSE(dwfl_linux_kernel_find_elf),
Packit 032894
    .section_address = INTUSE(dwfl_linux_kernel_module_section_address),
Packit 032894
  };
Packit 032894
Packit 032894
/* Structure held at state->HOOK.  */
Packit 032894
struct parse_opt
Packit 032894
{
Packit 032894
  Dwfl *dwfl;
Packit 032894
  /* The -e|--executable parameter.  */
Packit 032894
  const char *e;
Packit 032894
  /* The --core parameter.  */
Packit 032894
  const char *core;
Packit 032894
};
Packit 032894
Packit 032894
static inline void
Packit 032894
failure (Dwfl *dwfl, int errnum, const char *msg, struct argp_state *state)
Packit 032894
{
Packit 032894
  if (dwfl != NULL)
Packit 032894
    dwfl_end (dwfl);
Packit 032894
  if (errnum == -1)
Packit 032894
    argp_failure (state, EXIT_FAILURE, 0, "%s: %s",
Packit 032894
                  msg, INTUSE(dwfl_errmsg) (-1));
Packit 032894
  else
Packit 032894
    argp_failure (state, EXIT_FAILURE, errnum, "%s", msg);
Packit 032894
}
Packit 032894
Packit 032894
static inline error_t
Packit 032894
fail (Dwfl *dwfl, int errnum, const char *msg, struct argp_state *state)
Packit 032894
{
Packit 032894
  failure (dwfl, errnum, msg, state);
Packit 032894
  return errnum == -1 ? EIO : errnum;
Packit 032894
}
Packit 032894
Packit 032894
static error_t
Packit 032894
parse_opt (int key, char *arg, struct argp_state *state)
Packit 032894
{
Packit 032894
  switch (key)
Packit 032894
    {
Packit 032894
    case ARGP_KEY_INIT:
Packit 032894
      {
Packit 032894
	assert (state->hook == NULL);
Packit 032894
	struct parse_opt *opt = calloc (1, sizeof (*opt));
Packit 032894
	if (opt == NULL)
Packit 032894
	  failure (NULL, DWFL_E_ERRNO, "calloc", state);
Packit 032894
	state->hook = opt;
Packit 032894
      }
Packit 032894
      break;
Packit 032894
Packit 032894
    case OPT_DEBUGINFO:
Packit 032894
      debuginfo_path = arg;
Packit 032894
      break;
Packit 032894
Packit 032894
    case 'e':
Packit 032894
      {
Packit 032894
	struct parse_opt *opt = state->hook;
Packit 032894
	Dwfl *dwfl = opt->dwfl;
Packit 032894
	if (dwfl == NULL)
Packit 032894
	  {
Packit 032894
	    dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
Packit 032894
	    if (dwfl == NULL)
Packit 032894
	      return fail (dwfl, -1, arg, state);
Packit 032894
	    opt->dwfl = dwfl;
Packit 032894
Packit 032894
	    /* Start at zero so if there is just one -e foo.so,
Packit 032894
	       the DSO is shown without address bias.  */
Packit 032894
	    dwfl->offline_next_address = 0;
Packit 032894
	  }
Packit 032894
	if (dwfl->callbacks != &offline_callbacks)
Packit 032894
	  {
Packit 032894
	  toomany:
Packit 032894
	    argp_error (state, "%s",
Packit 032894
			_("only one of -e, -p, -k, -K, or --core allowed"));
Packit 032894
	    return EINVAL;
Packit 032894
	  }
Packit 032894
	opt->e = arg;
Packit 032894
      }
Packit 032894
      break;
Packit 032894
Packit 032894
    case 'p':
Packit 032894
      {
Packit 032894
	struct parse_opt *opt = state->hook;
Packit 032894
	if (opt->dwfl == NULL)
Packit 032894
	  {
Packit 032894
	    Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks);
Packit 032894
	    int result = INTUSE(dwfl_linux_proc_report) (dwfl, atoi (arg));
Packit 032894
	    if (result != 0)
Packit 032894
	      return fail (dwfl, result, arg, state);
Packit 032894
Packit 032894
	    /* Non-fatal to not be able to attach to process, ignore error.  */
Packit 032894
	    INTUSE(dwfl_linux_proc_attach) (dwfl, atoi (arg), false);
Packit 032894
Packit 032894
	    opt->dwfl = dwfl;
Packit 032894
	  }
Packit 032894
	else
Packit 032894
	  goto toomany;
Packit 032894
      }
Packit 032894
      break;
Packit 032894
Packit 032894
    case 'M':
Packit 032894
      {
Packit 032894
	struct parse_opt *opt = state->hook;
Packit 032894
	if (opt->dwfl == NULL)
Packit 032894
	  {
Packit 032894
	    FILE *f = fopen (arg, "r");
Packit 032894
	    if (f == NULL)
Packit 032894
	      {
Packit 032894
		int code = errno;
Packit 032894
		argp_failure (state, EXIT_FAILURE, code,
Packit 032894
			      "cannot open '%s'", arg);
Packit 032894
		return code;
Packit 032894
	      }
Packit 032894
	    Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks);
Packit 032894
	    int result = INTUSE(dwfl_linux_proc_maps_report) (dwfl, f);
Packit 032894
	    fclose (f);
Packit 032894
	    if (result != 0)
Packit 032894
	      return fail (dwfl, result, arg, state);
Packit 032894
	    opt->dwfl = dwfl;
Packit 032894
	  }
Packit 032894
	else
Packit 032894
	  goto toomany;
Packit 032894
      }
Packit 032894
      break;
Packit 032894
Packit 032894
    case OPT_COREFILE:
Packit 032894
      {
Packit 032894
	struct parse_opt *opt = state->hook;
Packit 032894
	Dwfl *dwfl = opt->dwfl;
Packit 032894
	if (dwfl == NULL)
Packit 032894
	  opt->dwfl = dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
Packit 032894
	/* Permit -e and --core together.  */
Packit 032894
	else if (dwfl->callbacks != &offline_callbacks)
Packit 032894
	  goto toomany;
Packit 032894
	opt->core = arg;
Packit 032894
      }
Packit 032894
      break;
Packit 032894
Packit 032894
    case 'k':
Packit 032894
      {
Packit 032894
	struct parse_opt *opt = state->hook;
Packit 032894
	if (opt->dwfl == NULL)
Packit 032894
	  {
Packit 032894
	    Dwfl *dwfl = INTUSE(dwfl_begin) (&kernel_callbacks);
Packit 032894
	    int result = INTUSE(dwfl_linux_kernel_report_kernel) (dwfl);
Packit 032894
	    if (result != 0)
Packit 032894
	      return fail (dwfl, result, _("cannot load kernel symbols"), state);
Packit 032894
	    result = INTUSE(dwfl_linux_kernel_report_modules) (dwfl);
Packit 032894
	    if (result != 0)
Packit 032894
	      /* Non-fatal to have no modules since we do have the kernel.  */
Packit 032894
	      argp_failure (state, 0, result, _("cannot find kernel modules"));
Packit 032894
	    opt->dwfl = dwfl;
Packit 032894
	  }
Packit 032894
	else
Packit 032894
	  goto toomany;
Packit 032894
      }
Packit 032894
      break;
Packit 032894
Packit 032894
    case 'K':
Packit 032894
      {
Packit 032894
	struct parse_opt *opt = state->hook;
Packit 032894
	if (opt->dwfl == NULL)
Packit 032894
	  {
Packit 032894
	    Dwfl *dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
Packit 032894
	    int result = INTUSE(dwfl_linux_kernel_report_offline) (dwfl, arg,
Packit 032894
								   NULL);
Packit 032894
	    if (result != 0)
Packit 032894
	      return fail (dwfl, result, _("cannot find kernel or modules"), state);
Packit 032894
	    opt->dwfl = dwfl;
Packit 032894
	  }
Packit 032894
	else
Packit 032894
	  goto toomany;
Packit 032894
      }
Packit 032894
      break;
Packit 032894
Packit 032894
    case ARGP_KEY_SUCCESS:
Packit 032894
      {
Packit 032894
	struct parse_opt *opt = state->hook;
Packit 032894
	Dwfl *dwfl = opt->dwfl;
Packit 032894
Packit 032894
	if (dwfl == NULL)
Packit 032894
	  {
Packit 032894
	    /* Default if no -e, -p, or -k, is "-e a.out".  */
Packit 032894
	    arg = "a.out";
Packit 032894
	    dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
Packit 032894
	    if (INTUSE(dwfl_report_offline) (dwfl, "", arg, -1) == NULL)
Packit 032894
	      return fail (dwfl, -1, arg, state);
Packit 032894
	    opt->dwfl = dwfl;
Packit 032894
	  }
Packit 032894
Packit 032894
	if (opt->core)
Packit 032894
	  {
Packit 032894
	    int fd = open (opt->core, O_RDONLY);
Packit 032894
	    if (fd < 0)
Packit 032894
	      {
Packit 032894
		int code = errno;
Packit 032894
		argp_failure (state, EXIT_FAILURE, code,
Packit 032894
			      "cannot open '%s'", opt->core);
Packit 032894
		return code;
Packit 032894
	      }
Packit 032894
Packit 032894
	    Elf *core;
Packit 032894
	    Dwfl_Error error = __libdw_open_file (&fd, &core, true, false);
Packit 032894
	    if (error != DWFL_E_NOERROR)
Packit 032894
	      {
Packit 032894
		argp_failure (state, EXIT_FAILURE, 0,
Packit 032894
			      _("cannot read ELF core file: %s"),
Packit 032894
			      INTUSE(dwfl_errmsg) (error));
Packit 032894
		return error == DWFL_E_ERRNO ? errno : EIO;
Packit 032894
	      }
Packit 032894
Packit 032894
	    int result = INTUSE(dwfl_core_file_report) (dwfl, core, opt->e);
Packit 032894
	    if (result < 0)
Packit 032894
	      {
Packit 032894
		elf_end (core);
Packit 032894
		close (fd);
Packit 032894
		return fail (dwfl, result, opt->core, state);
Packit 032894
	      }
Packit 032894
Packit 032894
	    /* Non-fatal to not be able to attach to core, ignore error.  */
Packit 032894
	    INTUSE(dwfl_core_file_attach) (dwfl, core);
Packit 032894
Packit 032894
	    /* Store core Elf and fd in Dwfl to expose with dwfl_end.  */
Packit 032894
	    if (dwfl->user_core == NULL)
Packit 032894
	      {
Packit 032894
		dwfl->user_core = calloc (1, sizeof (struct Dwfl_User_Core));
Packit 032894
		if (dwfl->user_core == NULL)
Packit 032894
		  {
Packit 032894
		    argp_failure (state, EXIT_FAILURE, 0,
Packit 032894
				  _("Not enough memory"));
Packit 032894
		    return ENOMEM;
Packit 032894
		  }
Packit 032894
	      }
Packit 032894
	    dwfl->user_core->core = core;
Packit 032894
	    dwfl->user_core->fd = fd;
Packit 032894
Packit 032894
	    if (result == 0)
Packit 032894
	      {
Packit 032894
		argp_failure (state, EXIT_FAILURE, 0,
Packit 032894
			      _("No modules recognized in core file"));
Packit 032894
		return ENOENT;
Packit 032894
	      }
Packit 032894
	  }
Packit 032894
	else if (opt->e)
Packit 032894
	  {
Packit 032894
	    if (INTUSE(dwfl_report_offline) (dwfl, "", opt->e, -1) == NULL)
Packit 032894
	      return fail (dwfl, -1, opt->e, state);
Packit 032894
	  }
Packit 032894
Packit 032894
	/* One of the three flavors has done dwfl_begin and some reporting
Packit 032894
	   if we got here.  Tie up the Dwfl and return it to the caller of
Packit 032894
	   argp_parse.  */
Packit 032894
Packit 032894
	int result = INTUSE(dwfl_report_end) (dwfl, NULL, NULL);
Packit 032894
	assert (result == 0);
Packit 032894
Packit 032894
	/* Update the input all along, so a parent parser can see it.
Packit 032894
	   As we free OPT the update below will be no longer active.  */
Packit 032894
	*(Dwfl **) state->input = dwfl;
Packit 032894
	free (opt);
Packit 032894
	state->hook = NULL;
Packit 032894
      }
Packit 032894
      break;
Packit 032894
Packit 032894
    case ARGP_KEY_ERROR:
Packit 032894
      {
Packit 032894
	struct parse_opt *opt = state->hook;
Packit 032894
	dwfl_end (opt->dwfl);
Packit 032894
	free (opt);
Packit 032894
	state->hook = NULL;
Packit 032894
      }
Packit 032894
      break;
Packit 032894
Packit 032894
    default:
Packit 032894
      return ARGP_ERR_UNKNOWN;
Packit 032894
    }
Packit 032894
Packit 032894
  /* Update the input all along, so a parent parser can see it.  */
Packit 032894
  struct parse_opt *opt = state->hook;
Packit 032894
  if (opt)
Packit 032894
    *(Dwfl **) state->input = opt->dwfl;
Packit 032894
Packit 032894
  return 0;
Packit 032894
}
Packit 032894
Packit 032894
static const struct argp libdwfl_argp =
Packit 032894
  { .options = options, .parser = parse_opt };
Packit 032894
Packit 032894
const struct argp *
Packit 032894
dwfl_standard_argp (void)
Packit 032894
{
Packit 032894
  return &libdwfl_argp;
Packit 032894
}