]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
libdwfl/
authorJan Kratochvil <jan.kratochvil@redhat.com>
Wed, 17 Oct 2012 22:11:30 +0000 (00:11 +0200)
committerJan Kratochvil <jan.kratochvil@redhat.com>
Thu, 29 Nov 2012 11:50:26 +0000 (12:50 +0100)
* argp-std.c: Update Copyright year.
(offline_find_elf): New function.
(offline_callbacks): Use it for find_elf.
(struct parse_opt): New.
(parse_opt): New key ARGP_KEY_INIT.  In other make hook struct
parse_opt pointer from former Dwfl pointer.  Delay 'e and OPT_COREFILE
processing till ARGP_KEY_SUCCESS.  Initialize state->input already from
ARGP_KEY_SUCCESS.  Modify the cleanup in ARGP_KEY_ERROR.  Make the
final state->input initialization optional.
* dwfl_end.c: Update Copyright year.
(dwfl_end): Free executable_for_core.
* libdwflP.h: Update Copyright year.
(struct Dwfl): New field executable_for_core.

tests/
* run-addrname-test.sh: New test for PIE relocation.
* testfile70.core.bz2: New file.
* testfile70.exec.bz2: New file.
* Makefile.am (EXTRA_DIST): Add testfile70.core.bz2 and
testfile70.exec.bz2 .

Signed-off-by: Jan Kratochvil <jan.kratochvil@redhat.com>
libdwfl/ChangeLog
libdwfl/argp-std.c
libdwfl/dwfl_end.c
libdwfl/libdwflP.h
tests/ChangeLog
tests/Makefile.am
tests/run-addrname-test.sh
tests/testfile70.core.bz2 [new file with mode: 0644]
tests/testfile70.exec.bz2 [new file with mode: 0644]

index 7673346251298703f038339cb6ae0604ec04ed90..bea55cfb7f867553545a4c0688d5fd27c17406d9 100644 (file)
@@ -1,3 +1,19 @@
+2012-11-29  Jan Kratochvil  <jan.kratochvil@redhat.com>
+
+       * argp-std.c: Update Copyright year.
+       (offline_find_elf): New function.
+       (offline_callbacks): Use it for find_elf.
+       (struct parse_opt): New.
+       (parse_opt): New key ARGP_KEY_INIT.  In other make hook struct
+       parse_opt pointer from former Dwfl pointer.  Delay 'e and OPT_COREFILE
+       processing till ARGP_KEY_SUCCESS.  Initialize state->input already from
+       ARGP_KEY_SUCCESS.  Modify the cleanup in ARGP_KEY_ERROR.  Make the
+       final state->input initialization optional.
+       * dwfl_end.c: Update Copyright year.
+       (dwfl_end): Free executable_for_core.
+       * libdwflP.h: Update Copyright year.
+       (struct Dwfl): New field executable_for_core.
+
 2012-11-20  Jan Kratochvil  <jan.kratochvil@redhat.com>
 
        * dwfl_report_elf.c (__libdwfl_report_elf): Simplify START and BIAS
index 2ef4555ccb04635ac62a7ba498741e2b7c117e06..7584054afd0cca6b65f0a33d7cebc28a603714dd 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
@@ -60,6 +60,32 @@ static const struct argp_option options[] =
   { NULL, 0, NULL, 0, NULL, 0 }
 };
 
+/* Wrapper to provide proper FILE_NAME for -e|--executable.  */
+static int
+offline_find_elf (Dwfl_Module *mod, void **userdata, const char *modname,
+                 Dwarf_Addr base, char **file_name, Elf **elfp)
+{
+  if (modname != NULL && (strcmp (modname, "[exe]") == 0
+                         || strcmp (modname, "[pie]") == 0)
+      && mod->dwfl->executable_for_core)
+    {
+      /* When both --core and --executable are given in whatever order
+        dwfl_core_file_report is called first and this callback will replace
+        the Dwfl_Module main.name with the recorded --executable file when the
+        modname is [exe] or [pie] (which then triggers opening and reporting
+        of the executable).  */
+      char *e_dup = strdup (mod->dwfl->executable_for_core);
+      if (e_dup)
+       {
+         free (*file_name);
+         *file_name = e_dup;
+         return -1;
+       }
+    }
+  return INTUSE(dwfl_build_id_find_elf) (mod, userdata, modname, base,
+                                         file_name, elfp);
+}
+
 static char *debuginfo_path;
 
 static const Dwfl_Callbacks offline_callbacks =
@@ -70,7 +96,7 @@ static const Dwfl_Callbacks offline_callbacks =
     .section_address = INTUSE(dwfl_offline_section_address),
 
     /* We use this table for core files too.  */
-    .find_elf = INTUSE(dwfl_build_id_find_elf),
+    .find_elf = offline_find_elf,
   };
 
 static const Dwfl_Callbacks proc_callbacks =
@@ -90,6 +116,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 +147,142 @@ 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);
+           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)
+           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);
+           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 +291,49 @@ 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)
+             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, opt->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;
+             }
+
+           if (opt->e)
+             dwfl->executable_for_core = strdup (opt->e);
+         }
+       else if (opt->e)
+         {
+           if (INTUSE(dwfl_report_offline) (dwfl, "", opt->e, -1) == NULL)
+             return fail (dwfl, -1, arg);
          }
 
        /* One of the three flavors has done dwfl_begin and some reporting
@@ -274,12 +342,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 +365,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;
 }
 
index fd38e0feac94cc7cb6459a58a201a7fc40d1edce..94fcfc6e92c869cc4d534a970f9656cb7bc29239 100644 (file)
@@ -1,5 +1,5 @@
 /* Finish a session using libdwfl.
-   Copyright (C) 2005, 2008 Red Hat, Inc.
+   Copyright (C) 2005, 2008, 2012 Red Hat, Inc.
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -46,5 +46,6 @@ dwfl_end (Dwfl *dwfl)
       __libdwfl_module_free (dead);
     }
 
+  free (dwfl->executable_for_core);
   free (dwfl);
 }
index ca8be2f2a557374afd0c142a4d3903c6d439d8bc..806ebcd97d5ef4ec16dbd581faf6431c53931670 100644 (file)
@@ -1,5 +1,5 @@
 /* Internal definitions for libdwfl.
-   Copyright (C) 2005-2011 Red Hat, Inc.
+   Copyright (C) 2005-2012 Red Hat, Inc.
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -108,6 +108,8 @@ struct Dwfl
   GElf_Off lookup_tail_vaddr;
   GElf_Off lookup_tail_offset;
   int lookup_tail_ndx;
+
+  char *executable_for_core;   /* --executable if --core was specified.  */
 };
 
 #define OFFLINE_REDZONE                0x10000
index edb82b482b5665ba25e4b7b1f35f13f51e35cf3a..5b06b85f493472549d5cebc342ab7008ea391e5a 100644 (file)
@@ -1,3 +1,11 @@
+2012-11-29  Jan Kratochvil  <jan.kratochvil@redhat.com>
+
+       * run-addrname-test.sh: New test for PIE relocation.
+       * testfile70.core.bz2: New file.
+       * testfile70.exec.bz2: New file.
+       * Makefile.am (EXTRA_DIST): Add testfile70.core.bz2 and
+       testfile70.exec.bz2 .
+
 2012-10-27  Jan Kratochvil  <jan.kratochvil@redhat.com>
 
        * Makefile.am (EXTRA_DIST): Add testfile64.bz2, testfile65.bz2,
index f2d2484af7e7ae2e5acf843352c1b6c4eb99aa62..6808bd1342fef37d429cfd43542cf6b72f717e9a 100644 (file)
@@ -180,7 +180,8 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
             testfile60.bz2 testfile61.bz2 \
             run-readelf-vmcoreinfo.sh testfile62.bz2 \
             run-readelf-mixed-corenote.sh testfile63.bz2 testfile64.bz2 \
-            testfile65.bz2 testfile69.core.bz2 testfile69.so.bz2
+            testfile65.bz2 testfile69.core.bz2 testfile69.so.bz2 \
+            testfile70.core.bz2 testfile70.exec.bz2
 
 if USE_VALGRIND
 valgrind_cmd="valgrind -q --trace-children=yes --error-exitcode=1"
index cc8aa335ac2c3ece0201ecbee43180399430be3a..99abf9dbccfc6dff3b633ed85576394f3b200fae 100755 (executable)
@@ -306,4 +306,14 @@ libglobal+0x9
 ??:0
 EOF
 
+testfiles testfile70.exec testfile70.core
+testrun_compare ../src/addr2line -S -e testfile70.exec --core=testfile70.core 0x7ff2cfe9b6b5 <<\EOF
+main+0x9
+??:0
+EOF
+testrun_compare ../src/addr2line -S --core=testfile70.core -e testfile70.exec 0x7ff2cfe9b6b5 <<\EOF
+main+0x9
+??:0
+EOF
+
 exit 0
diff --git a/tests/testfile70.core.bz2 b/tests/testfile70.core.bz2
new file mode 100644 (file)
index 0000000..6c47c6d
Binary files /dev/null and b/tests/testfile70.core.bz2 differ
diff --git a/tests/testfile70.exec.bz2 b/tests/testfile70.exec.bz2
new file mode 100644 (file)
index 0000000..f1b969a
Binary files /dev/null and b/tests/testfile70.exec.bz2 differ