Imported Upstream version 0.160
[platform/upstream/elfutils.git] / libdwfl / argp-std.c
index 2ef4555..42b7e78 100644 (file)
@@ -1,5 +1,5 @@
 /* Standard argp argument parsers for tools using libdwfl.
-   Copyright (C) 2005-2010 Red Hat, Inc.
+   Copyright (C) 2005-2010, 2012 Red Hat, Inc.
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -90,6 +90,16 @@ static const Dwfl_Callbacks kernel_callbacks =
     .section_address = INTUSE(dwfl_linux_kernel_module_section_address),
   };
 
+/* Structure held at state->HOOK.  */
+struct parse_opt
+{
+  Dwfl *dwfl;
+  /* The -e|--executable parameter.  */
+  const char *e;
+  /* The --core parameter.  */
+  const char *core;
+};
+
 static error_t
 parse_opt (int key, char *arg, struct argp_state *state)
 {
@@ -111,152 +121,145 @@ parse_opt (int key, char *arg, struct argp_state *state)
 
   switch (key)
     {
+    case ARGP_KEY_INIT:
+      {
+       assert (state->hook == NULL);
+       struct parse_opt *opt = calloc (1, sizeof (*opt));
+       if (opt == NULL)
+         failure (NULL, DWFL_E_ERRNO, "calloc");
+       state->hook = opt;
+      }
+      break;
+
     case OPT_DEBUGINFO:
       debuginfo_path = arg;
       break;
 
     case 'e':
       {
-       Dwfl *dwfl = state->hook;
+       struct parse_opt *opt = state->hook;
+       Dwfl *dwfl = opt->dwfl;
        if (dwfl == NULL)
          {
            dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
            if (dwfl == NULL)
              return fail (dwfl, -1, arg);
-           state->hook = dwfl;
+           opt->dwfl = dwfl;
 
            /* Start at zero so if there is just one -e foo.so,
               the DSO is shown without address bias.  */
            dwfl->offline_next_address = 0;
          }
-       if (dwfl->callbacks == &offline_callbacks)
-         {
-           if (INTUSE(dwfl_report_offline) (dwfl, "", arg, -1) == NULL)
-             return fail (dwfl, -1, arg);
-           state->hook = dwfl;
-         }
-       else
+       if (dwfl->callbacks != &offline_callbacks)
          {
          toomany:
            argp_error (state, "%s",
                        _("only one of -e, -p, -k, -K, or --core allowed"));
            return EINVAL;
          }
+       opt->e = arg;
       }
       break;
 
     case 'p':
-      if (state->hook == NULL)
-       {
-         Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks);
-         int result = INTUSE(dwfl_linux_proc_report) (dwfl, atoi (arg));
-         if (result != 0)
-           return fail (dwfl, result, arg);
-         state->hook = dwfl;
-       }
-      else
-       goto toomany;
+      {
+       struct parse_opt *opt = state->hook;
+       if (opt->dwfl == NULL)
+         {
+           Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks);
+           int result = INTUSE(dwfl_linux_proc_report) (dwfl, atoi (arg));
+           if (result != 0)
+             return fail (dwfl, result, arg);
+
+           /* Non-fatal to not be able to attach to process, ignore error.  */
+           INTUSE(dwfl_linux_proc_attach) (dwfl, atoi (arg), false);
+
+           opt->dwfl = dwfl;
+         }
+       else
+         goto toomany;
+      }
       break;
 
     case 'M':
-      if (state->hook == NULL)
-       {
-         FILE *f = fopen (arg, "r");
-         if (f == NULL)
-         nofile:
-           {
-             int code = errno;
-             argp_failure (state, EXIT_FAILURE, code,
-                           "cannot open '%s'", arg);
-             return code;
-           }
-         Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks);
-         int result = INTUSE(dwfl_linux_proc_maps_report) (dwfl, f);
-         fclose (f);
-         if (result != 0)
-           return fail (dwfl, result, arg);
-         state->hook = dwfl;
-       }
-      else
-       goto toomany;
+      {
+       struct parse_opt *opt = state->hook;
+       if (opt->dwfl == NULL)
+         {
+           FILE *f = fopen (arg, "r");
+           if (f == NULL)
+             {
+               int code = errno;
+               argp_failure (state, EXIT_FAILURE, code,
+                             "cannot open '%s'", arg);
+               return code;
+             }
+           Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks);
+           int result = INTUSE(dwfl_linux_proc_maps_report) (dwfl, f);
+           fclose (f);
+           if (result != 0)
+             return fail (dwfl, result, arg);
+           opt->dwfl = dwfl;
+         }
+       else
+         goto toomany;
+      }
       break;
 
     case OPT_COREFILE:
       {
-       Dwfl *dwfl = state->hook;
+       struct parse_opt *opt = state->hook;
+       Dwfl *dwfl = opt->dwfl;
        if (dwfl == NULL)
-         state->hook = dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
+         opt->dwfl = dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
        /* Permit -e and --core together.  */
        else if (dwfl->callbacks != &offline_callbacks)
          goto toomany;
-
-       int fd = open64 (arg, O_RDONLY);
-       if (fd < 0)
-         goto nofile;
-
-       Elf *core;
-       Dwfl_Error error = __libdw_open_file (&fd, &core, true, false);
-       if (error != DWFL_E_NOERROR)
-         {
-           argp_failure (state, EXIT_FAILURE, 0,
-                         _("cannot read ELF core file: %s"),
-                         INTUSE(dwfl_errmsg) (error));
-           return error == DWFL_E_ERRNO ? errno : EIO;
-         }
-
-       int result = INTUSE(dwfl_core_file_report) (dwfl, core);
-       if (result < 0)
-         {
-           elf_end (core);
-           close (fd);
-           return fail (dwfl, result, arg);
-         }
-
-       /* From now we leak FD and CORE.  */
-
-       if (result == 0)
-         {
-           argp_failure (state, EXIT_FAILURE, 0,
-                         _("No modules recognized in core file"));
-           return ENOENT;
-         }
+       opt->core = arg;
       }
       break;
 
     case 'k':
-      if (state->hook == NULL)
-       {
-         Dwfl *dwfl = INTUSE(dwfl_begin) (&kernel_callbacks);
-         int result = INTUSE(dwfl_linux_kernel_report_kernel) (dwfl);
-         if (result != 0)
-           return fail (dwfl, result, _("cannot load kernel symbols"));
-         result = INTUSE(dwfl_linux_kernel_report_modules) (dwfl);
-         if (result != 0)
-           /* Non-fatal to have no modules since we do have the kernel.  */
-           failure (dwfl, result, _("cannot find kernel modules"));
-         state->hook = dwfl;
-       }
-      else
-       goto toomany;
+      {
+       struct parse_opt *opt = state->hook;
+       if (opt->dwfl == NULL)
+         {
+           Dwfl *dwfl = INTUSE(dwfl_begin) (&kernel_callbacks);
+           int result = INTUSE(dwfl_linux_kernel_report_kernel) (dwfl);
+           if (result != 0)
+             return fail (dwfl, result, _("cannot load kernel symbols"));
+           result = INTUSE(dwfl_linux_kernel_report_modules) (dwfl);
+           if (result != 0)
+             /* Non-fatal to have no modules since we do have the kernel.  */
+             failure (dwfl, result, _("cannot find kernel modules"));
+           opt->dwfl = dwfl;
+         }
+       else
+         goto toomany;
+      }
       break;
 
     case 'K':
-      if (state->hook == NULL)
-       {
-         Dwfl *dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
-         int result = INTUSE(dwfl_linux_kernel_report_offline) (dwfl, arg,
-                                                                NULL);
-         if (result != 0)
-           return fail (dwfl, result, _("cannot find kernel or modules"));
-         state->hook = dwfl;
-       }
-      else
-       goto toomany;
+      {
+       struct parse_opt *opt = state->hook;
+       if (opt->dwfl == NULL)
+         {
+           Dwfl *dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
+           int result = INTUSE(dwfl_linux_kernel_report_offline) (dwfl, arg,
+                                                                  NULL);
+           if (result != 0)
+             return fail (dwfl, result, _("cannot find kernel or modules"));
+           opt->dwfl = dwfl;
+         }
+       else
+         goto toomany;
+      }
       break;
 
     case ARGP_KEY_SUCCESS:
       {
-       Dwfl *dwfl = state->hook;
+       struct parse_opt *opt = state->hook;
+       Dwfl *dwfl = opt->dwfl;
 
        if (dwfl == NULL)
          {
@@ -265,7 +268,54 @@ parse_opt (int key, char *arg, struct argp_state *state)
            dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
            if (INTUSE(dwfl_report_offline) (dwfl, "", arg, -1) == NULL)
              return fail (dwfl, -1, arg);
-           state->hook = dwfl;
+           opt->dwfl = dwfl;
+         }
+
+       if (opt->core)
+         {
+           int fd = open64 (opt->core, O_RDONLY);
+           if (fd < 0)
+             {
+               int code = errno;
+               argp_failure (state, EXIT_FAILURE, code,
+                             "cannot open '%s'", opt->core);
+               return code;
+             }
+
+           Elf *core;
+           Dwfl_Error error = __libdw_open_file (&fd, &core, true, false);
+           if (error != DWFL_E_NOERROR)
+             {
+               argp_failure (state, EXIT_FAILURE, 0,
+                             _("cannot read ELF core file: %s"),
+                             INTUSE(dwfl_errmsg) (error));
+               return error == DWFL_E_ERRNO ? errno : EIO;
+             }
+
+           int result = INTUSE(dwfl_core_file_report) (dwfl, core, opt->e);
+           if (result < 0)
+             {
+               elf_end (core);
+               close (fd);
+               return fail (dwfl, result, opt->core);
+             }
+
+           /* Non-fatal to not be able to attach to core, ignore error.  */
+           INTUSE(dwfl_core_file_attach) (dwfl, core);
+
+           /* From now we leak FD and CORE.  */
+
+           if (result == 0)
+             {
+               argp_failure (state, EXIT_FAILURE, 0,
+                             _("No modules recognized in core file"));
+               return ENOENT;
+             }
+         }
+       else if (opt->e)
+         {
+           if (INTUSE(dwfl_report_offline) (dwfl, "", opt->e, -1) == NULL)
+             return fail (dwfl, -1, opt->e);
          }
 
        /* One of the three flavors has done dwfl_begin and some reporting
@@ -274,12 +324,22 @@ parse_opt (int key, char *arg, struct argp_state *state)
 
        int result = INTUSE(dwfl_report_end) (dwfl, NULL, NULL);
        assert (result == 0);
+
+       /* Update the input all along, so a parent parser can see it.
+          As we free OPT the update below will be no longer active.  */
+       *(Dwfl **) state->input = dwfl;
+       free (opt);
+       state->hook = NULL;
       }
       break;
 
     case ARGP_KEY_ERROR:
-      dwfl_end (state->hook);
-      state->hook = NULL;
+      {
+       struct parse_opt *opt = state->hook;
+       dwfl_end (opt->dwfl);
+       free (opt);
+       state->hook = NULL;
+      }
       break;
 
     default:
@@ -287,7 +347,10 @@ parse_opt (int key, char *arg, struct argp_state *state)
     }
 
   /* Update the input all along, so a parent parser can see it.  */
-  *(Dwfl **) state->input = state->hook;
+  struct parse_opt *opt = state->hook;
+  if (opt)
+    *(Dwfl **) state->input = opt->dwfl;
+
   return 0;
 }
 
@@ -299,15 +362,3 @@ dwfl_standard_argp (void)
 {
   return &libdwfl_argp;
 }
-
-#ifdef _MUDFLAP
-/* In the absence of a mudflap wrapper for argp_parse, or a libc compiled
-   with -fmudflap, we'll see spurious errors for using the struct argp_state
-   on argp_parse's stack.  */
-
-void __attribute__ ((constructor))
-__libdwfl_argp_mudflap_options (void)
-{
-  __mf_set_options ("-heur-stack-bound");
-}
-#endif