]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
libebl: Add ebl_func_addr_mask plus ARM backend implementation.
authorMark Wielaard <mjw@redhat.com>
Sat, 14 Jun 2014 15:15:37 +0000 (17:15 +0200)
committerMark Wielaard <mjw@redhat.com>
Sun, 22 Jun 2014 11:47:48 +0000 (13:47 +0200)
The ARM EABI says that the zero bit of function symbol st_value indicates
whether the symbol points to a THUMB or ARM function. Also the return
value address in an unwind will contain the same extra bit to indicate
whether to return to a regular ARM or THUMB function. Add a new ebl
function to mask off such bits and turn a function value into a function
address so that we get the actual value that a function symbol or return
address points to. It isn't easily possible to reuse the existing
ebl_resolve_sym_value for this purpose, so we end up with another hook
that can be used from dwfl_module_getsym, handle_cfi and elflint.

Signed-off-by: Mark Wielaard <mjw@redhat.com>
12 files changed:
backends/ChangeLog
backends/arm_init.c
libdwfl/ChangeLog
libdwfl/dwfl_module_getsym.c
libdwfl/frame_unwind.c
libebl/ChangeLog
libebl/ebl-hooks.h
libebl/eblinitreg.c
libebl/libebl.h
libebl/libeblP.h
src/ChangeLog
src/elflint.c

index 7eda035c3d3c48abdf507bc830bf57db7651dd41..c846a958dfeca6bc3116f18f7683ea8f019e9f55 100644 (file)
@@ -1,3 +1,7 @@
+2014-06-17  Mark Wielaard  <mjw@redhat.com>
+
+       * arm_init.c (arm_init): Set func_addr_mask.
+
 2014-06-20  Petr Machata  <pmachata@redhat.com>
 
        * alpha_retval.c (alpha_return_value_location): Call
index 92e6cd51552a3058f89970ac86940acd3a055725..3283c978b1cb743e95b0e3f701e1501add44127e 100644 (file)
@@ -69,5 +69,8 @@ arm_init (elf, machine, eh, ehlen)
   eh->frame_nregs = 16;
   HOOK (eh, set_initial_registers_tid);
 
+  /* Bit zero encodes whether an function address is THUMB or ARM. */
+  eh->func_addr_mask = ~(GElf_Addr)1;
+
   return MODVERSION;
 }
index f1bc1a796094725c1c4d5a9b852ff42bd1421b4c..e11b7d1d64c4a626dbab92ddd1e772d654555950 100644 (file)
@@ -1,3 +1,8 @@
+2014-06-17  Mark Wielaard  <mjw@redhat.com>
+
+       * frame_unwind.c (handle_cfi): Use ebl_func_addr_mask.
+       * dwfl_module_getsym.c (__libdwfl_getsym): Likewise.
+
 2014-06-15  Mark Wielaard  <mjw@redhat.com>
 
        * linux-core-attach.c (core_memory_read): Use libdw/memory-access.h
index 917d0620dc3a5121b44c3ba10ce35bbbceb80d83..42d2b6792eb19d53327ab91e35ac8ff191476bba 100644 (file)
@@ -1,5 +1,5 @@
 /* Find debugging and symbol information for a module in libdwfl.
-   Copyright (C) 2006-2013 Red Hat, Inc.
+   Copyright (C) 2006-2014 Red Hat, Inc.
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -119,7 +119,7 @@ __libdwfl_getsym (Dwfl_Module *mod, int ndx, GElf_Sym *sym, GElf_Addr *addr,
      descriptors).  */
 
   char *ident;
-  GElf_Addr st_value = sym->st_value;
+  GElf_Addr st_value = sym->st_value & ebl_func_addr_mask (mod->ebl);
   *resolved = false;
   if (! adjust_st_value && mod->e_type != ET_REL && alloc
       && (GELF_ST_TYPE (sym->st_info) == STT_FUNC
index 18c808b2811ece256aaec80f2d8abcde13826ee5..16cebd083f27326f72a028979c11a416c89dd604 100644 (file)
@@ -1,5 +1,5 @@
 /* Get previous frame state for an existing frame state.
-   Copyright (C) 2013 Red Hat, Inc.
+   Copyright (C) 2013, 2014 Red Hat, Inc.
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -582,6 +582,10 @@ handle_cfi (Dwfl_Frame *state, Dwarf_Addr pc, Dwarf_CFI *cfi, Dwarf_Addr bias)
          continue;
        }
 
+      /* Some architectures encode some extra info in the return address.  */
+      if (regno == frame->fde->cie->return_address_register)
+       regval &= ebl_func_addr_mask (ebl);
+
       /* This is another strange PPC[64] case.  There are two
         registers numbers that can represent the same DWARF return
         register number.  We only want one to actually set the return
index 7198d5ec81a1f9f3718a7e7a3339d6f2a7c8651e..5ec710166287eea05da0155b9d339a308c38a3b7 100644 (file)
@@ -1,3 +1,9 @@
+2014-06-17  Mark Wielaard  <mjw@redhat.com>
+
+       * eblinitreg.c (ebl_func_addr_mask): New function.
+       * libebl.h (ebl_func_addr_mask): Define.
+       * libeblP.h (struct ebl): Add func_addr_mask.
+
 2014-05-19  Mark Wielaard  <mjw@redhat.com>
 
        * Makefile.am (gen_SOURCES): Add eblcheckreloctargettype.c.
index 65c62ec67e3461c36ef85fae4f27577c5cc292d1..e1186f86f595b27e20890de8e18ddde1ce9950be 100644 (file)
@@ -187,7 +187,7 @@ bool EBLHOOK(unwind) (Ebl *ebl, Dwarf_Addr pc, ebl_tid_registers_t *setfunc,
                      bool *signal_framep);
 
 /* Returns true if the value can be resolved to an address in an
-   allocated section, which will be returned in *SHNDXP.
+   allocated section, which will be returned in *ADDR.
    (e.g. function descriptor resolving)  */
 bool EBLHOOK(resolve_sym_value) (Ebl *ebl, GElf_Addr *addr);
 
index 8909c50016d34d5c375cf73787c6c92e085899aa..5729b3ccdf37f2f40a450c719bb94562f32a574b 100644 (file)
@@ -1,5 +1,5 @@
 /* Fetch live process Dwfl_Frame from PID.
-   Copyright (C) 2013 Red Hat, Inc.
+   Copyright (C) 2013, 2014 Red Hat, Inc.
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -49,3 +49,10 @@ ebl_frame_nregs (Ebl *ebl)
 {
   return ebl == NULL ? 0 : ebl->frame_nregs;
 }
+
+GElf_Addr
+ebl_func_addr_mask (Ebl *ebl)
+{
+  return ((ebl == NULL || ebl->func_addr_mask == 0)
+         ? ~(GElf_Addr)0 : ebl->func_addr_mask);
+}
index d05751fae3e548eff5ef878a1ed1edb01e6170a6..bb993bf0a124c01471a84dba6931d30150692b4c 100644 (file)
@@ -1,5 +1,5 @@
 /* Interface for libebl.
-   Copyright (C) 2000-2010, 2013 Red Hat, Inc.
+   Copyright (C) 2000-2010, 2013, 2014 Red Hat, Inc.
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -409,6 +409,17 @@ extern bool ebl_set_initial_registers_tid (Ebl *ebl,
 extern size_t ebl_frame_nregs (Ebl *ebl)
   __nonnull_attribute__ (1);
 
+/* Mask to use for function symbol or unwind return addresses in case
+   the architecture adds some extra non-address bits to it.  This is
+   different from ebl_resolve_sym_value which only works for actual
+   symbol addresses (in non-ET_REL files) that might resolve to an
+   address in a different section.  ebl_func_addr_mask is called to
+   turn a given function value into the a real address or offset (the
+   original value might not be a real address).  This works for all
+   cases where an actual function address (or offset in ET_REL symbol
+   tables) is needed.  */
+extern GElf_Addr ebl_func_addr_mask (Ebl *ebl);
+
 /* Convert *REGNO as is in DWARF to a lower range suitable for
    Dwarf_Frame->REGS indexing.  */
 extern bool ebl_dwarf_to_regno (Ebl *ebl, unsigned *regno)
index f91c2a0d8a2f7fa9a3022552adab23ab558fee54..dbd67f3ef5b44b3b49fdfd0feb1440e5428f3c16 100644 (file)
@@ -1,5 +1,5 @@
 /* Internal definitions for interface for libebl.
-   Copyright (C) 2000-2009, 2013 Red Hat, Inc.
+   Copyright (C) 2000-2009, 2013, 2014 Red Hat, Inc.
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -64,6 +64,12 @@ struct ebl
      Ebl architecture can unwind iff FRAME_NREGS > 0.  */
   size_t frame_nregs;
 
+  /* Mask to use to turn a function value into a real function address
+     in case the architecture adds some extra non-address bits to it.
+     If not initialized (0) then ebl_func_addr_mask will return ~0,
+     otherwise it should be the actual mask to use.  */
+  GElf_Addr func_addr_mask;
+
   /* Function descriptor load address and table as used by
      ebl_resolve_sym_value if available for this arch.  */
   GElf_Addr fd_addr;
index 7e680361ab907d3047e2c0f82241c53c878f2d95..30234237f796e851c7bd103d7c0042476b1858c0 100644 (file)
@@ -1,3 +1,7 @@
+2014-06-14  Mark Wielaard  <mjw@redhat.com>
+
+       * elflint (check_symtab): Use ebl_func_addr_mask on st_value.
+
 2014-05-27  Mark Wielaard  <mjw@redhat.com>
 
        * readelf.c (print_debug): Skip section if name is NULL.
index bf6d044bb1a18b7d33aacfbfba93d3894d5714fa..5568c65cee26d00fc07c15218b13d959aba539d5 100644 (file)
@@ -768,12 +768,18 @@ section [%2d] '%s': symbol %zu: function in COMMON section is nonsense\n"),
            {
              GElf_Addr sh_addr = (ehdr->e_type == ET_REL ? 0
                                   : destshdr->sh_addr);
+             GElf_Addr st_value;
+             if (GELF_ST_TYPE (sym->st_info) == STT_FUNC
+                 || (GELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC))
+               st_value = sym->st_value & ebl_func_addr_mask (ebl);
+             else
+               st_value = sym->st_value;
              if (GELF_ST_TYPE (sym->st_info) != STT_TLS)
                {
                  if (! ebl_check_special_symbol (ebl, ehdr, sym, name,
                                                  destshdr))
                    {
-                     if (sym->st_value - sh_addr > destshdr->sh_size)
+                     if (st_value - sh_addr > destshdr->sh_size)
                        {
                          /* GNU ld has severe bugs.  When it decides to remove
                             empty sections it leaves symbols referencing them
@@ -798,7 +804,7 @@ section [%2d] '%s': symbol %zu: function in COMMON section is nonsense\n"),
 section [%2d] '%s': symbol %zu: st_value out of bounds\n"),
                                   idx, section_name (ebl, idx), cnt);
                        }
-                     else if ((sym->st_value - sh_addr
+                     else if ((st_value - sh_addr
                                + sym->st_size) > destshdr->sh_size)
                        ERROR (gettext ("\
 section [%2d] '%s': symbol %zu does not fit completely in referenced section [%2d] '%s'\n"),
@@ -818,12 +824,12 @@ section [%2d] '%s': symbol %zu: referenced section [%2d] '%s' does not have SHF_
                    {
                      /* For object files the symbol value must fall
                         into the section.  */
-                     if (sym->st_value > destshdr->sh_size)
+                     if (st_value > destshdr->sh_size)
                        ERROR (gettext ("\
 section [%2d] '%s': symbol %zu: st_value out of bounds of referenced section [%2d] '%s'\n"),
                               idx, section_name (ebl, idx), cnt,
                               (int) xndx, section_name (ebl, xndx));
-                     else if (sym->st_value + sym->st_size
+                     else if (st_value + sym->st_size
                               > destshdr->sh_size)
                        ERROR (gettext ("\
 section [%2d] '%s': symbol %zu does not fit completely in referenced section [%2d] '%s'\n"),
@@ -852,20 +858,20 @@ section [%2d] '%s': symbol %zu: TLS symbol but no TLS program header entry\n"),
                        }
                      else
                        {
-                         if (sym->st_value
+                         if (st_value
                              < destshdr->sh_offset - phdr->p_offset)
                            ERROR (gettext ("\
 section [%2d] '%s': symbol %zu: st_value short of referenced section [%2d] '%s'\n"),
                                   idx, section_name (ebl, idx), cnt,
                                   (int) xndx, section_name (ebl, xndx));
-                         else if (sym->st_value
+                         else if (st_value
                                   > (destshdr->sh_offset - phdr->p_offset
                                      + destshdr->sh_size))
                            ERROR (gettext ("\
 section [%2d] '%s': symbol %zu: st_value out of bounds of referenced section [%2d] '%s'\n"),
                                   idx, section_name (ebl, idx), cnt,
                                   (int) xndx, section_name (ebl, xndx));
-                         else if (sym->st_value + sym->st_size
+                         else if (st_value + sym->st_size
                                   > (destshdr->sh_offset - phdr->p_offset
                                      + destshdr->sh_size))
                            ERROR (gettext ("\