[COMMITTED] dwarf.h: Add DW_AT_noreturn.
by Mark Wielaard
DW_AT_noreturn is added by GCC5 for functions that don't return to their
caller. It is set on a DW_TAG_subprogram for the traditional GNU noreturn
attribute, the C11 _Noreturn keyword or C++11 [[noreturn]] attribute. It
is a new DWARF5 extension. This is a constant only addition to dwarf.h.
No other part of elfutils currently depends on this attribute.
Also added to https://fedorahosted.org/elfutils/wiki/DwarfExtensions
Signed-off-by: Mark Wielaard <mjw(a)redhat.com>
---
libdw/ChangeLog | 4 ++++
libdw/dwarf.h | 3 +++
2 files changed, 7 insertions(+)
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 58736a6..7e46e1a 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,7 @@
+2014-11-26 Mark Wielaard <mjw(a)redhat.com>
+
+ * dwarf.h (DW_AT_noreturn): Added.
+
2014-11-11 Mark Wielaard <mjw(a)redhat.com>
* dwarf_getsrclines.c (read_srclines): Do address_size comparison
diff --git a/libdw/dwarf.h b/libdw/dwarf.h
index d03cf5c..d47260e 100644
--- a/libdw/dwarf.h
+++ b/libdw/dwarf.h
@@ -221,6 +221,9 @@ enum
DW_AT_enum_class = 0x6d,
DW_AT_linkage_name = 0x6e,
+ /* DWARF5 attribute values. */
+ DW_AT_noreturn = 0x87,
+
DW_AT_lo_user = 0x2000,
DW_AT_MIPS_fde = 0x2001,
--
1.8.3.1
9 years
[PATCH] dwarf.h: Add DW_LANG_C11, DW_LANG_C_plus_plus_11 and DW_LANG_C_plus_plus_14.
by Mark Wielaard
The following patch is needed to recognize the new DW_LANG constants
that GCC 5 might emit as implemented by this GCC patch:
https://gcc.gnu.org/ml/gcc-patches/2014-11/msg02852.html
Also added to https://fedorahosted.org/elfutils/wiki/DwarfExtensions
GCC 5 can emit these new DWARFv5 draft language constants. Handle them in
dwarf_aggregate_size and dwarf_getfuncs. Also handle DW_LANG_Go in
dwarf_aggregate_size (lower bound for array is zero for Go).
Signed-off-by: Mark Wielaard <mjw(a)redhat.com>
---
libdw/ChangeLog | 11 +++++++++++
libdw/dwarf.h | 4 ++++
libdw/dwarf_aggregate_size.c | 4 ++++
libdw/dwarf_getfuncs.c | 3 ++-
4 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 58736a6..ea9dca1 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,14 @@
+2014-11-24 Mark Wielaard <mjw(a)redhat.com>
+
+ * dwarf.h (DW_LANG_C_plus_plus_11): Added.
+ (DW_LANG_C11): Likewise.
+ (DW_LANG_C_plus_plus_14): Likewise.
+ * dwarf_aggregate_size.c (array_size): Handle DW_LANG_C11,
+ DW_LANG_C_plus_plus_11, DW_LANG_C_plus_plus_14 and DW_LANG_Go
+ lower bound.
+ * dwarf_getfuncs.c (dwarf_getfuncs): Set c_cu to true for
+ DW_LANG_C11.
+
2014-11-11 Mark Wielaard <mjw(a)redhat.com>
* dwarf_getsrclines.c (read_srclines): Do address_size comparison
diff --git a/libdw/dwarf.h b/libdw/dwarf.h
index d03cf5c..3a97ccb 100644
--- a/libdw/dwarf.h
+++ b/libdw/dwarf.h
@@ -583,6 +583,10 @@ enum
DW_LANG_D = 0x0013, /* D */
DW_LANG_Python = 0x0014, /* Python */
DW_LANG_Go = 0x0016, /* Go */
+ DW_LANG_C_plus_plus_11 = 0x001a, /* ISO C++:2011 */
+ DW_LANG_C11 = 0x001d, /* ISO C:2011 */
+ DW_LANG_C_plus_plus_14 = 0x0021, /* ISO C++:2014 */
+
DW_LANG_lo_user = 0x8000,
DW_LANG_Mips_Assembler = 0x8001, /* Assembler */
diff --git a/libdw/dwarf_aggregate_size.c b/libdw/dwarf_aggregate_size.c
index 1666e24..667c274 100644
--- a/libdw/dwarf_aggregate_size.c
+++ b/libdw/dwarf_aggregate_size.c
@@ -103,12 +103,16 @@ array_size (Dwarf_Die *die, Dwarf_Word *size,
case DW_LANG_C:
case DW_LANG_C89:
case DW_LANG_C99:
+ case DW_LANG_C11:
case DW_LANG_C_plus_plus:
+ case DW_LANG_C_plus_plus_11:
+ case DW_LANG_C_plus_plus_14:
case DW_LANG_ObjC:
case DW_LANG_ObjC_plus_plus:
case DW_LANG_Java:
case DW_LANG_D:
case DW_LANG_UPC:
+ case DW_LANG_Go:
lower = 0;
break;
diff --git a/libdw/dwarf_getfuncs.c b/libdw/dwarf_getfuncs.c
index 82894c9..f79b0a7 100644
--- a/libdw/dwarf_getfuncs.c
+++ b/libdw/dwarf_getfuncs.c
@@ -103,7 +103,8 @@ dwarf_getfuncs (Dwarf_Die *cudie, int (*callback) (Dwarf_Die *, void *),
int lang = INTUSE(dwarf_srclang) (cudie);
bool c_cu = (lang == DW_LANG_C89
|| lang == DW_LANG_C
- || lang == DW_LANG_C99);
+ || lang == DW_LANG_C99
+ || lang == DW_LANG_C11);
struct visitor_info v = { callback, arg, (void *) offset, NULL, c_cu };
struct Dwarf_Die_Chain chain = { .die = CUDIE (cudie->cu),
--
1.9.3
9 years
[RFC] fixing addr2line inline info
by Josh Stone
Hi,
I have a simple patch attached to improve the output addr2line -fi. The
problem I had is it failed to identify the parent function name if there
was any lexical_block in the scope hierarchy. For example, try the
following, compiled as the attached testfile-lex-inlines.bz2:
1 // g++ x.cpp -g -fPIC -olibx.so -shared -O3 -fvisibility=hidden
2
3 void foobar()
4 {
5 __asm__ ( "nop" ::: );
6 }
7
8 void foo()
9 {
10 {
11 void (*bar) () = foobar;
12 bar();
13 }
14 }
$ eu-addr2line -f -i -e testfile-lex-inlines.bz2 0x690
foobar inlined at /tmp/x.cpp:12 in _Z3foov
/tmp/x.cpp:9
??
/tmp/x.cpp:12
With my patch:
$ ./src/addr2line -fi -e testfile-lex-inlines.bz2 0x690
foobar inlined at /tmp/x.cpp:12 in _Z3foov
/tmp/x.cpp:9
_Z3foov
/tmp/x.cpp:12
So the name is resolved, and I'm happier. But, as I went to make this a
testcase, I noticed that the ":9" line isn't really correct for "foobar"
-- that's the start of "foo".
There are two candidate lines for 0x690:
[ 33] special opcode 246: address+16 = +0x690 <_Z3foov>, line+4 = 9
[ 34] special opcode 14: address+0 = +0x690 <_Z3foov>, line-4 = 5
So what happens AFAICT, the name is found with dwarf_getscopes(), which
will find the innermost address match. The line is found with
dwfl_module_getsrc, which uses a binary search, making no guarantees if
there are multiple matches. The bsearch happened to pick the first one
in this case. Perhaps this should choose the last matching address to
be approximately innermost?
I also noticed that addr2line's print_dwarf_function() doesn't try to
read linkage_name, although that wouldn't matter for this foobar inline.
It also looks like it's trying to walk up the inline / subprogram
stack, but since dwarf_getscopes chases the abstract_origin, it doesn't
have any of that. So print_dwarf_function() returns false, and it falls
back to dwfl_module_addrname to get the outer name.
With dwarf_getscopes_die this would work, including multiple layers of
inlines, as it later does for -i. But actually, I think having -i makes
this "inlined at ..." message redundant. Binutils addr2line -fi doesn't
print anything like this. Should we just kill that part?
Patch review and other thoughts appreciated...
Josh
9 years
[PATCH] libdw: Always check __libdw_find_attr return value.
by Mark Wielaard
__libdw_find_attr will return NULL and might not set code or form.
Only use code or form if the returned address is not NULL.
Signed-off-by: Mark Wielaard <mjw(a)redhat.com>
---
libdw/ChangeLog | 6 ++++++
libdw/dwarf_attr.c | 4 ++--
libdw/dwarf_hasattr.c | 6 +++---
libdw/dwarf_siblingof.c | 4 ++--
4 files changed, 13 insertions(+), 7 deletions(-)
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index a81c339..2241c70 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,5 +1,11 @@
2014-11-23 Mark Wielaard <mjw(a)redhat.com>
+ * dwarf_attr.c (dwarf_attr): Check __libdw_find_attr return value.
+ * dwarf_hasattr.c (dwarf_hasattr): Likewise.
+ * dwarf_siblingof.c (dwarf_siblingof): Likewise.
+
+2014-11-23 Mark Wielaard <mjw(a)redhat.com>
+
* dwarf_getabbrev.c (__libdw_getabbrev): Don't assert on bad DWARF.
Set libdw errno and return NULL.
diff --git a/libdw/dwarf_attr.c b/libdw/dwarf_attr.c
index 97b0806..f247c1a 100644
--- a/libdw/dwarf_attr.c
+++ b/libdw/dwarf_attr.c
@@ -1,5 +1,5 @@
/* Return specific DWARF attribute of a DIE.
- Copyright (C) 2003, 2005 Red Hat, Inc.
+ Copyright (C) 2003, 2005, 2014 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <drepper(a)redhat.com>, 2003.
@@ -50,6 +50,6 @@ dwarf_attr (die, search_name, result)
/* Always fill in the CU information. */
result->cu = die->cu;
- return result->code == search_name ? result : NULL;
+ return result->valp != NULL && result->code == search_name ? result : NULL;
}
INTDEF(dwarf_attr)
diff --git a/libdw/dwarf_hasattr.c b/libdw/dwarf_hasattr.c
index 7933c1c..fb7e1d5 100644
--- a/libdw/dwarf_hasattr.c
+++ b/libdw/dwarf_hasattr.c
@@ -1,5 +1,5 @@
/* Check whether given DIE has specific attribute.
- Copyright (C) 2003, 2005 Red Hat, Inc.
+ Copyright (C) 2003, 2005, 2014 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <drepper(a)redhat.com>, 2003.
@@ -45,8 +45,8 @@ dwarf_hasattr (die, search_name)
/* Search for the attribute with the given name. */
unsigned int code;
- (void) __libdw_find_attr (die, search_name, &code, NULL);
+ unsigned char *addr = __libdw_find_attr (die, search_name, &code, NULL);
- return code == search_name;
+ return addr != NULL && code == search_name;
}
INTDEF (dwarf_hasattr)
diff --git a/libdw/dwarf_siblingof.c b/libdw/dwarf_siblingof.c
index c54b6c8..f2dc468 100644
--- a/libdw/dwarf_siblingof.c
+++ b/libdw/dwarf_siblingof.c
@@ -1,5 +1,5 @@
/* Return sibling of given DIE.
- Copyright (C) 2003-2010 Red Hat, Inc.
+ Copyright (C) 2003-2010, 2014 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <drepper(a)redhat.com>, 2003.
@@ -72,7 +72,7 @@ dwarf_siblingof (die, result)
/* Find the end of the DIE or the sibling attribute. */
addr = __libdw_find_attr (&this_die, DW_AT_sibling, &sibattr.code,
&sibattr.form);
- if (sibattr.code == DW_AT_sibling)
+ if (addr != NULL && sibattr.code == DW_AT_sibling)
{
Dwarf_Off offset;
sibattr.valp = addr;
--
1.9.3
9 years
[PATCH] libdw: Don't assert in __libdw_getabbrev when seeing bad DWARF.
by Mark Wielaard
Signed-off-by: Mark Wielaard <mjw(a)redhat.com>
---
libdw/ChangeLog | 5 +++++
libdw/dwarf_getabbrev.c | 11 ++++++++---
2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 58736a6..a81c339 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,8 @@
+2014-11-23 Mark Wielaard <mjw(a)redhat.com>
+
+ * dwarf_getabbrev.c (__libdw_getabbrev): Don't assert on bad DWARF.
+ Set libdw errno and return NULL.
+
2014-11-11 Mark Wielaard <mjw(a)redhat.com>
* dwarf_getsrclines.c (read_srclines): Do address_size comparison
diff --git a/libdw/dwarf_getabbrev.c b/libdw/dwarf_getabbrev.c
index 87d89c1..95233cf 100644
--- a/libdw/dwarf_getabbrev.c
+++ b/libdw/dwarf_getabbrev.c
@@ -1,5 +1,5 @@
/* Get abbreviation at given offset.
- Copyright (C) 2003, 2004, 2005, 2006 Red Hat, Inc.
+ Copyright (C) 2003, 2004, 2005, 2006, 2014 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <drepper(a)redhat.com>, 2003.
@@ -31,7 +31,6 @@
# include <config.h>
#endif
-#include <assert.h>
#include <dwarf.h>
#include "libdwP.h"
@@ -97,7 +96,13 @@ __libdw_getabbrev (dbg, cu, offset, lengthp, result)
{
foundit = true;
- assert (abb->offset == offset);
+ if (abb->offset != offset)
+ {
+ /* A duplicate abbrev code at a different offset,
+ that should never happen. */
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ return NULL;
+ }
/* If the caller doesn't need the length we are done. */
if (lengthp == NULL)
--
1.9.3
9 years
[PATCH] libelf: Change signed overflow check to unsigned in elf_getdata_rawchunk.
by Mark Wielaard
Arithmetic of signed values that overflow causes undefined behaviour
Change to explicit unsigned arithmetic overflow check.
Signed-off-by: Mark Wielaard <mjw(a)redhat.com>
---
libelf/ChangeLog | 5 +++++
libelf/elf_getdata_rawchunk.c | 7 ++++---
2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/libelf/ChangeLog b/libelf/ChangeLog
index 8a11563..68fb0fc 100644
--- a/libelf/ChangeLog
+++ b/libelf/ChangeLog
@@ -1,5 +1,10 @@
2014-11-23 Mark Wielaard <mjw(a)redhat.com>
+ * elf_getdata_rawchunk.c (elf_getdata_rawchunk): Change signed
+ overflow check to unsigned.
+
+2014-11-23 Mark Wielaard <mjw(a)redhat.com>
+
* note_xlate.h (elf_cvt_note): Copy over any leftover data if
src != dest. The data is probably part of truncated name/desc.
diff --git a/libelf/elf_getdata_rawchunk.c b/libelf/elf_getdata_rawchunk.c
index f4fbe66..63a9914 100644
--- a/libelf/elf_getdata_rawchunk.c
+++ b/libelf/elf_getdata_rawchunk.c
@@ -1,5 +1,5 @@
/* Return converted data from raw chunk of ELF file.
- Copyright (C) 2007 Red Hat, Inc.
+ Copyright (C) 2007, 2014 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@@ -57,8 +57,9 @@ elf_getdata_rawchunk (elf, offset, size, type)
return NULL;
}
- if (unlikely (offset < 0 || offset + (off64_t) size < offset
- || offset + size > elf->maximum_size))
+ if (unlikely (offset < 0 || (uint64_t) offset > elf->maximum_size
+ || elf->maximum_size - (uint64_t) offset < size))
+
{
/* Invalid request. */
__libelf_seterrno (ELF_E_INVALID_OP);
--
1.9.3
9 years
[PATCH] readelf: Check length for nexthdr overflow in print_debug_aranges_section.
by Mark Wielaard
Signed-off-by: Mark Wielaard <mjw(a)redhat.com>
---
src/ChangeLog | 5 +++++
src/readelf.c | 2 +-
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/ChangeLog b/src/ChangeLog
index aa16b67..19509dc 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,8 @@
+2014-11-23 Mark Wielaard <mjw(a)redhat.com>
+
+ * readelf.c (print_debug_aranges_section): Check length to catch
+ nexthdr overflow.
+
2014-11-21 Mark Wielaard <mjw(a)redhat.com>
* readelf.c (print_attributes): Guard against empty section.
diff --git a/src/readelf.c b/src/readelf.c
index 9bae66d..ffc14fd 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -4693,7 +4693,7 @@ print_debug_aranges_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
printf (gettext ("\n Length: %6" PRIu64 "\n"),
(uint64_t) length);
- if (nexthdr > readendp)
+ if (length > readendp - readp)
goto invalid_data;
if (length == 0)
--
1.9.3
9 years
[PATCH] libelf: Copy over any leftover data from src to dest in elf_cvt_note.
by Mark Wielaard
If any data is left then the data is likely part of the truncated note
name/desc. This probably means the note is corrupted, but it is better
to have the actual data in dest instead of random uninitialized memory.
Signed-off-by: Mark Wielaard <mjw(a)redhat.com>
---
libelf/ChangeLog | 5 +++++
libelf/note_xlate.h | 7 ++++++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/libelf/ChangeLog b/libelf/ChangeLog
index b21714e..8a11563 100644
--- a/libelf/ChangeLog
+++ b/libelf/ChangeLog
@@ -1,3 +1,8 @@
+2014-11-23 Mark Wielaard <mjw(a)redhat.com>
+
+ * note_xlate.h (elf_cvt_note): Copy over any leftover data if
+ src != dest. The data is probably part of truncated name/desc.
+
2014-11-22 Mark Wielaard <mjw(a)redhat.com>
* elf_getphdrnum.c (elf_getphdrnum): Sanity check the
diff --git a/libelf/note_xlate.h b/libelf/note_xlate.h
index 8187e88..aa730bc 100644
--- a/libelf/note_xlate.h
+++ b/libelf/note_xlate.h
@@ -1,5 +1,5 @@
/* Conversion functions for notes.
- Copyright (C) 2007, 2009 Red Hat, Inc.
+ Copyright (C) 2007, 2009, 2014 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@@ -56,4 +56,9 @@ elf_cvt_note (void *dest, const void *src, size_t len, int encode)
src += namesz + descsz;
dest += namesz + descsz;
}
+
+ /* Copy opver any leftover data unconcerted. Probably part of
+ truncated name/desc data. */
+ if (len > 0 && src != dest)
+ memcpy (dest, src, len);
}
--
1.9.3
9 years
[PATCH] Use elf_getphdrnum instead of accessing ehdr->e_phnum directly.
by Mark Wielaard
Using elf_getphdrnum lets us handle ELF files that use more than PN_XNUM
phdrs. And guards against some corrupt files.
Signed-off-by: Mark Wielaard <mjw(a)redhat.com>
---
backends/ChangeLog | 7 +++++++
backends/ppc64_symbol.c | 3 +--
backends/ppc_symbol.c | 16 ++++++++++------
libdwfl/ChangeLog | 5 +++++
libdwfl/link_map.c | 18 +++++++++++++++---
libebl/ChangeLog | 7 +++++++
libebl/ebl-hooks.h | 2 +-
libebl/eblbsspltp.c | 7 +++----
libebl/eblopenbackend.c | 5 ++---
libebl/libebl.h | 2 +-
src/ChangeLog | 12 ++++++++++++
src/elflint.c | 2 +-
src/findtextrel.c | 14 ++++++++++----
src/readelf.c | 7 +------
src/size.c | 7 +++----
src/strip.c | 13 +++++++++----
src/unstrip.c | 26 +++++++++++++++++++-------
17 files changed, 107 insertions(+), 46 deletions(-)
diff --git a/backends/ChangeLog b/backends/ChangeLog
index abd22bf..db1b129 100644
--- a/backends/ChangeLog
+++ b/backends/ChangeLog
@@ -1,3 +1,10 @@
+2014-11-22 Mark Wielaard <mjw(a)redhat.com>
+
+ * ppc64_symbol.c (ppc64_bss_plt_p): Remove ehdr argument.
+ * ppc_symbol.c (find_dyn_got): Likewise. Use elf_getphdrnum.
+ (ppc_check_special_symbol): Call find_dyn_got without ehdr.
+ (ppc_bss_plt_p): Remove ehdr argument.
+
2014-11-17 Mark Wielaard <mjw(a)redhat.com>
* ppc64_init.c (ppc64_init): Check section name is not NULL.
diff --git a/backends/ppc64_symbol.c b/backends/ppc64_symbol.c
index 5a020d8..0feddce 100644
--- a/backends/ppc64_symbol.c
+++ b/backends/ppc64_symbol.c
@@ -108,8 +108,7 @@ ppc64_check_special_symbol (Elf *elf, GElf_Ehdr *ehdr,
/* Check if backend uses a bss PLT in this file. */
bool
-ppc64_bss_plt_p (Elf *elf __attribute__ ((unused)),
- GElf_Ehdr *ehdr __attribute__ ((unused)))
+ppc64_bss_plt_p (Elf *elf __attribute__ ((unused)))
{
return true;
}
diff --git a/backends/ppc_symbol.c b/backends/ppc_symbol.c
index 220f243..c17ab37 100644
--- a/backends/ppc_symbol.c
+++ b/backends/ppc_symbol.c
@@ -1,5 +1,5 @@
/* PPC specific symbolic name handling.
- Copyright (C) 2004, 2005, 2007 Red Hat, Inc.
+ Copyright (C) 2004, 2005, 2007, 2014 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <drepper(a)redhat.com>, 2004.
@@ -81,9 +81,13 @@ ppc_dynamic_tag_check (int64_t tag)
/* Look for DT_PPC_GOT. */
static bool
-find_dyn_got (Elf *elf, GElf_Ehdr *ehdr, GElf_Addr *addr)
+find_dyn_got (Elf *elf, GElf_Addr *addr)
{
- for (int i = 0; i < ehdr->e_phnum; ++i)
+ size_t phnum;
+ if (elf_getphdrnum (elf, &phnum) != 0)
+ return false;
+
+ for (size_t i = 0; i < phnum; ++i)
{
GElf_Phdr phdr_mem;
GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
@@ -127,7 +131,7 @@ ppc_check_special_symbol (Elf *elf, GElf_Ehdr *ehdr, const GElf_Sym *sym,
{
/* In -msecure-plt mode, DT_PPC_GOT is present and must match. */
GElf_Addr gotaddr;
- if (find_dyn_got (elf, ehdr, &gotaddr))
+ if (find_dyn_got (elf, &gotaddr))
return sym->st_value == gotaddr;
/* In -mbss-plt mode, any place in the section is valid. */
@@ -154,8 +158,8 @@ ppc_check_special_symbol (Elf *elf, GElf_Ehdr *ehdr, const GElf_Sym *sym,
/* Check if backend uses a bss PLT in this file. */
bool
-ppc_bss_plt_p (Elf *elf, GElf_Ehdr *ehdr)
+ppc_bss_plt_p (Elf *elf)
{
GElf_Addr addr;
- return ! find_dyn_got (elf, ehdr, &addr);
+ return ! find_dyn_got (elf, &addr);
}
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index 460f4e5..5876fcc 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,8 @@
+2014-11-22 Mark Wielaard <mjw(a)redhat.com>
+
+ * link_map.c (consider_executable): Use elf_getphdrnum.
+ (dwfl_link_map_report): Likewise.
+
2014-11-18 Mark Wielaard <mjw(a)redhat.com>
* dwfl_module_getdwarf.c (find_symtab): Sanity check the data buffer,
diff --git a/libdwfl/link_map.c b/libdwfl/link_map.c
index 272f89b..eaf43b5 100644
--- a/libdwfl/link_map.c
+++ b/libdwfl/link_map.c
@@ -1,5 +1,5 @@
/* Report modules by examining dynamic linker data structures.
- Copyright (C) 2008-2013 Red Hat, Inc.
+ Copyright (C) 2008-2014 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@@ -533,7 +533,11 @@ consider_executable (Dwfl_Module *mod, GElf_Addr at_phdr, GElf_Addr at_entry,
address where &r_debug was written at runtime. */
GElf_Xword align = mod->dwfl->segment_align;
GElf_Addr d_val_vaddr = 0;
- for (uint_fast16_t i = 0; i < ehdr.e_phnum; ++i)
+ size_t phnum;
+ if (elf_getphdrnum (mod->main.elf, &phnum) != 0)
+ return 0;
+
+ for (size_t i = 0; i < phnum; ++i)
{
GElf_Phdr phdr_mem;
GElf_Phdr *phdr = gelf_getphdr (mod->main.elf, i, &phdr_mem);
@@ -813,7 +817,15 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
__libdwfl_seterrno (DWFL_E_LIBELF);
return false;
}
- if (ehdr->e_phnum != phnum || ehdr->e_phentsize != phent)
+ size_t e_phnum;
+ if (elf_getphdrnum (elf, &e_phnum) != 0)
+ {
+ elf_end (elf);
+ close (fd);
+ __libdwfl_seterrno (DWFL_E_LIBELF);
+ return false;
+ }
+ if (e_phnum != phnum || ehdr->e_phentsize != phent)
{
elf_end (elf);
close (fd);
diff --git a/libebl/ChangeLog b/libebl/ChangeLog
index b6a0e63..5e635f2 100644
--- a/libebl/ChangeLog
+++ b/libebl/ChangeLog
@@ -1,3 +1,10 @@
+2014-11-22 Mark Wielaard <mjw(a)redhat.com>
+
+ * ebl-hooks.h (bss_plt_p): Remove ehdr argument.
+ * eblbsspltp.c (ebl_bss_plt_p): Likewise.
+ * eblopenbackend.c (default_bss_plt_p): Likewise.
+ * libebl.h (ebl_bss_plt_p): Likewise.
+
2014-11-17 Mark Wielaard <mjw(a)redhat.com>
* ebldebugscnp.c (ebl_debugscn_p): Check name is not NULL.
diff --git a/libebl/ebl-hooks.h b/libebl/ebl-hooks.h
index e1186f8..2e31446 100644
--- a/libebl/ebl-hooks.h
+++ b/libebl/ebl-hooks.h
@@ -132,7 +132,7 @@ bool EBLHOOK(check_special_symbol) (Elf *, GElf_Ehdr *, const GElf_Sym *,
bool EBLHOOK(check_st_other_bits) (unsigned char st_other);
/* Check if backend uses a bss PLT in this file. */
-bool EBLHOOK(bss_plt_p) (Elf *, GElf_Ehdr *);
+bool EBLHOOK(bss_plt_p) (Elf *);
/* Return location expression to find return value given the
DW_AT_type DIE of a DW_TAG_subprogram DIE. */
diff --git a/libebl/eblbsspltp.c b/libebl/eblbsspltp.c
index 080e7c5..95a5d8a 100644
--- a/libebl/eblbsspltp.c
+++ b/libebl/eblbsspltp.c
@@ -1,5 +1,5 @@
/* Check if backend uses a bss PLT.
- Copyright (C) 2005 Red Hat, Inc.
+ Copyright (C) 2005, 2014 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@@ -35,9 +35,8 @@
bool
-ebl_bss_plt_p (ebl, ehdr)
+ebl_bss_plt_p (ebl)
Ebl *ebl;
- GElf_Ehdr *ehdr;
{
- return ebl == NULL ? false : ebl->bss_plt_p (ebl->elf, ehdr);
+ return ebl == NULL ? false : ebl->bss_plt_p (ebl->elf);
}
diff --git a/libebl/eblopenbackend.c b/libebl/eblopenbackend.c
index bd94759..3a22f53 100644
--- a/libebl/eblopenbackend.c
+++ b/libebl/eblopenbackend.c
@@ -186,7 +186,7 @@ static bool default_check_special_symbol (Elf *elf, GElf_Ehdr *ehdr,
static bool default_check_st_other_bits (unsigned char st_other);
static bool default_check_special_section (Ebl *, int,
const GElf_Shdr *, const char *);
-static bool default_bss_plt_p (Elf *elf, GElf_Ehdr *ehdr);
+static bool default_bss_plt_p (Elf *elf);
static int default_return_value_location (Dwarf_Die *functypedie,
const Dwarf_Op **locops);
static ssize_t default_register_info (Ebl *ebl,
@@ -693,8 +693,7 @@ default_check_st_other_bits (unsigned char st_other __attribute__ ((unused)))
static bool
-default_bss_plt_p (Elf *elf __attribute__ ((unused)),
- GElf_Ehdr *ehdr __attribute__ ((unused)))
+default_bss_plt_p (Elf *elf __attribute__ ((unused)))
{
return false;
}
diff --git a/libebl/libebl.h b/libebl/libebl.h
index bb993bf..7c3c764 100644
--- a/libebl/libebl.h
+++ b/libebl/libebl.h
@@ -201,7 +201,7 @@ extern bool ebl_section_strip_p (Ebl *ebl, const GElf_Ehdr *ehdr,
bool remove_comment, bool only_remove_debug);
/* Check if backend uses a bss PLT in this file. */
-extern bool ebl_bss_plt_p (Ebl *ebl, GElf_Ehdr *ehdr);
+extern bool ebl_bss_plt_p (Ebl *ebl);
/* Return size of entry in SysV-style hash table. */
extern int ebl_sysvhash_entrysize (Ebl *ebl);
diff --git a/src/ChangeLog b/src/ChangeLog
index bab948a..bace91d 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,15 @@
+2014-11-22 Mark Wielaard <mjw(a)redhat.com>
+
+ * elflint.c (check_sections): Call ebl_bss_plt_p without ehdr.
+ * findtextrel.c (process_file): Use elf_getphdrnum.
+ * readelf.c (process_elf_file): Remove redundant ehdr->e_phoff check.
+ (print_phdr): Check phnum.
+ * size.c (show_segments): Use elf_getphdrnum.
+ * strip.c (handle_elf): Likewise.
+ * unstrip.c (copy_elf): Likewise.
+ (copy_elided_sections): Likewise.
+ (handle_file): Likewise.
+
2014-11-18 Mark Wielaard <mjw(a)redhat.com>
* readelf.c (print_cfa_program): Fix sanity check of DW_FORM_block
diff --git a/src/elflint.c b/src/elflint.c
index d6a4774..fbc78ed 100644
--- a/src/elflint.c
+++ b/src/elflint.c
@@ -3532,7 +3532,7 @@ cannot get section header for section [%2zu] '%s': %s\n"),
GElf_Word good_type = special_sections[s].type;
if (IS_KNOWN_SPECIAL (s, ".plt", false)
- && ebl_bss_plt_p (ebl, ehdr))
+ && ebl_bss_plt_p (ebl))
good_type = SHT_NOBITS;
/* In a debuginfo file, any normal section can be SHT_NOBITS.
diff --git a/src/findtextrel.c b/src/findtextrel.c
index 9fd8163..264a06b 100644
--- a/src/findtextrel.c
+++ b/src/findtextrel.c
@@ -1,5 +1,5 @@
/* Locate source files or functions which caused text relocations.
- Copyright (C) 2005-2010, 2012 Red Hat, Inc.
+ Copyright (C) 2005-2010, 2012, 2014 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <drepper(a)redhat.com>, 2005.
@@ -324,14 +324,20 @@ process_file (const char *fname, bool more_than_one)
if (segments == NULL)
error (1, errno, gettext ("while reading ELF file"));
- for (int i = 0; i < ehdr->e_phnum; ++i)
+ size_t phnum;
+ if (elf_getphdrnum (elf, &phnum) != 0)
+ error (1, 0, gettext ("cannot get program header count: %s"),
+ elf_errmsg (-1));
+
+
+ for (size_t i = 0; i < phnum; ++i)
{
GElf_Phdr phdr_mem;
GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
if (phdr == NULL)
{
error (0, 0,
- gettext ("cannot get program header index at offset %d: %s"),
+ gettext ("cannot get program header index at offset %zd: %s"),
i, elf_errmsg (-1));
result = 1;
goto next;
@@ -349,7 +355,7 @@ process_file (const char *fname, bool more_than_one)
if (segments == NULL)
{
error (0, 0, gettext ("\
-cannot get program header index at offset %d: %s"),
+cannot get program header index at offset %zd: %s"),
i, elf_errmsg (-1));
result = 1;
goto next;
diff --git a/src/readelf.c b/src/readelf.c
index 08de798..3b1f035 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -835,11 +835,6 @@ process_elf_file (Dwfl_Module *dwflmod, int fd)
gettext ("cannot determine number of program headers: %s"),
elf_errmsg (-1));
- /* If there isn't actually a program header then set phnum to zero.
- Don't do any extra work. gelf_getphdr will always return NULL. */
- if (ehdr->e_phoff == 0)
- phnum = 0;
-
/* For an ET_REL file, libdwfl has adjusted the in-core shdrs
and may have applied relocation to some sections.
So we need to get a fresh Elf handle on the file to display those. */
@@ -1162,7 +1157,7 @@ There are %d section headers, starting at offset %#" PRIx64 ":\n\
static void
print_phdr (Ebl *ebl, GElf_Ehdr *ehdr)
{
- if (ehdr->e_phnum == 0 || ehdr->e_phoff == 0)
+ if (phnum == 0)
/* No program header, this is OK in relocatable objects. */
return;
diff --git a/src/size.c b/src/size.c
index cb67999..0e7e41e 100644
--- a/src/size.c
+++ b/src/size.c
@@ -600,14 +600,13 @@ show_bsd_totals (void)
static void
show_segments (Elf *elf, const char *fullname)
{
- GElf_Ehdr ehdr_mem;
- GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
- if (ehdr == NULL)
+ size_t phnum;
+ if (elf_getphdrnum (elf, &phnum) != 0)
INTERNAL_ERROR (fullname);
GElf_Off total = 0;
bool first = true;
- for (size_t cnt = 0; cnt < ehdr->e_phnum; ++cnt)
+ for (size_t cnt = 0; cnt < phnum; ++cnt)
{
GElf_Phdr phdr_mem;
GElf_Phdr *phdr;
diff --git a/src/strip.c b/src/strip.c
index c9a1d8d..2b21799 100644
--- a/src/strip.c
+++ b/src/strip.c
@@ -502,6 +502,11 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
error (EXIT_FAILURE, 0,
gettext ("cannot get section header string table index"));
+ /* Get the number of phdrs in the old file. */
+ size_t phnum;
+ if (elf_getphdrnum (elf, &phnum) != 0)
+ error (EXIT_FAILURE, 0, gettext ("cannot get number of phdrs"));
+
/* We now create a new ELF descriptor for the same file. We
construct it almost exactly in the same way with some information
dropped. */
@@ -513,7 +518,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
if (unlikely (gelf_newehdr (newelf, gelf_getclass (elf)) == 0)
|| (ehdr->e_type != ET_REL
- && unlikely (gelf_newphdr (newelf, ehdr->e_phnum) == 0)))
+ && unlikely (gelf_newphdr (newelf, phnum) == 0)))
{
error (0, 0, gettext ("cannot create new file '%s': %s"),
output_fname, elf_errmsg (-1));
@@ -522,7 +527,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
/* Copy over the old program header if needed. */
if (ehdr->e_type != ET_REL)
- for (cnt = 0; cnt < ehdr->e_phnum; ++cnt)
+ for (cnt = 0; cnt < phnum; ++cnt)
{
GElf_Phdr phdr_mem;
GElf_Phdr *phdr = gelf_getphdr (elf, cnt, &phdr_mem);
@@ -537,7 +542,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
debugelf = elf_begin (debug_fd, ELF_C_WRITE_MMAP, NULL);
if (unlikely (gelf_newehdr (debugelf, gelf_getclass (elf)) == 0)
|| (ehdr->e_type != ET_REL
- && unlikely (gelf_newphdr (debugelf, ehdr->e_phnum) == 0)))
+ && unlikely (gelf_newphdr (debugelf, phnum) == 0)))
{
error (0, 0, gettext ("cannot create new file '%s': %s"),
debug_fname, elf_errmsg (-1));
@@ -546,7 +551,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
/* Copy over the old program header if needed. */
if (ehdr->e_type != ET_REL)
- for (cnt = 0; cnt < ehdr->e_phnum; ++cnt)
+ for (cnt = 0; cnt < phnum; ++cnt)
{
GElf_Phdr phdr_mem;
GElf_Phdr *phdr = gelf_getphdr (elf, cnt, &phdr_mem);
diff --git a/src/unstrip.c b/src/unstrip.c
index f6af450..85d5a7e 100644
--- a/src/unstrip.c
+++ b/src/unstrip.c
@@ -257,13 +257,17 @@ copy_elf (Elf *outelf, Elf *inelf)
ELF_CHECK (gelf_update_ehdr (outelf, ehdr),
_("cannot copy ELF header: %s"));
- if (ehdr->e_phnum > 0)
+ size_t phnum;
+ ELF_CHECK (elf_getphdrnum (inelf, &phnum) == 0,
+ _("cannot get number of program headers: %s"));
+
+ if (phnum > 0)
{
- ELF_CHECK (gelf_newphdr (outelf, ehdr->e_phnum),
+ ELF_CHECK (gelf_newphdr (outelf, phnum),
_("cannot create program headers: %s"));
GElf_Phdr phdr_mem;
- for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i)
+ for (size_t i = 0; i < phnum; ++i)
ELF_CHECK (gelf_update_phdr (outelf, i,
gelf_getphdr (inelf, i, &phdr_mem)),
_("cannot copy program header: %s"));
@@ -1823,12 +1827,16 @@ more sections in stripped file than debug file -- arguments reversed?"));
}
while (skip_reloc);
- if (stripped_ehdr->e_phnum > 0)
- ELF_CHECK (gelf_newphdr (unstripped, stripped_ehdr->e_phnum),
+ size_t phnum;
+ ELF_CHECK (elf_getphdrnum (stripped, &phnum) == 0,
+ _("cannot get number of program headers: %s"));
+
+ if (phnum > 0)
+ ELF_CHECK (gelf_newphdr (unstripped, phnum),
_("cannot create program headers: %s"));
/* Copy each program header from the stripped file. */
- for (uint_fast16_t i = 0; i < stripped_ehdr->e_phnum; ++i)
+ for (size_t i = 0; i < phnum; ++i)
{
GElf_Phdr phdr_mem;
GElf_Phdr *phdr = gelf_getphdr (stripped, i, &phdr_mem);
@@ -1863,11 +1871,15 @@ handle_file (const char *output_file, bool create_dirs,
Elf *stripped, const GElf_Ehdr *stripped_ehdr,
Elf *unstripped)
{
+ size_t phnum;
+ ELF_CHECK (elf_getphdrnum (stripped, &phnum) == 0,
+ _("cannot get number of program headers: %s"));
+
/* Determine the address bias between the debuginfo file and the main
file, which may have been modified by prelinking. */
GElf_Addr bias = 0;
if (unstripped != NULL)
- for (uint_fast16_t i = 0; i < stripped_ehdr->e_phnum; ++i)
+ for (size_t i = 0; i < phnum; ++i)
{
GElf_Phdr phdr_mem;
GElf_Phdr *phdr = gelf_getphdr (stripped, i, &phdr_mem);
--
1.9.3
9 years
[PATCH] libelf: elf_getphdrnum sanity check the returned phnum result.
by Mark Wielaard
The internal __elf_getphdrnum_rdlock might return an inconsistent phnum.
Return a sanitized value, or return an error to users that rely on phnum
to be consistent. That way iterating over all phdrs using elf_getphdr
will return consistent results.
Signed-off-by: Mark Wielaard <mjw(a)redhat.com>
---
libelf/ChangeLog | 5 +++++
libelf/elf_getphdrnum.c | 33 +++++++++++++++++++++++++++++++++
2 files changed, 38 insertions(+)
diff --git a/libelf/ChangeLog b/libelf/ChangeLog
index c7e8d30..b21714e 100644
--- a/libelf/ChangeLog
+++ b/libelf/ChangeLog
@@ -1,3 +1,8 @@
+2014-11-22 Mark Wielaard <mjw(a)redhat.com>
+
+ * elf_getphdrnum.c (elf_getphdrnum): Sanity check the
+ __elf_getphdrnum_rdlock result.
+
2014-11-18 Mark Wielaard <mjw(a)redhat.com>
* version_xlate.h (elf_cvt_Verdef): Check for overflow.
diff --git a/libelf/elf_getphdrnum.c b/libelf/elf_getphdrnum.c
index d8e34d7..50b2fdf 100644
--- a/libelf/elf_getphdrnum.c
+++ b/libelf/elf_getphdrnum.c
@@ -97,6 +97,39 @@ elf_getphdrnum (elf, dst)
rwlock_rdlock (elf->lock);
result = __elf_getphdrnum_rdlock (elf, dst);
+
+ /* Do some sanity checking to make sure phnum and phoff are consistent. */
+ Elf64_Off off = (elf->class == ELFCLASS32
+ ? elf->state.elf32.ehdr->e_phoff
+ : elf->state.elf64.ehdr->e_phoff);
+ if (off == 0)
+ {
+ *dst = 0;
+ goto out;
+ }
+
+ if (off >= elf->maximum_size)
+ {
+ __libelf_seterrno (ELF_E_INVALID_DATA);
+ result = -1;
+ goto out;
+ }
+
+ /* Check for too many sections. */
+ size_t phdr_size = (elf->class == ELFCLASS32
+ ? sizeof (Elf32_Phdr) : sizeof (Elf64_Phdr));
+ if (*dst > SIZE_MAX / phdr_size)
+ {
+ __libelf_seterrno (ELF_E_INVALID_DATA);
+ result = -1;
+ goto out;
+ }
+
+ /* Truncated file? Don't return more than can be indexed. */
+ if (elf->maximum_size - off < *dst * phdr_size)
+ *dst = (elf->maximum_size - off) / phdr_size;
+
+out:
rwlock_unlock (elf->lock);
return result;
--
1.9.3
9 years