[PATCH] backends: add abi_cfi and register_info callbacks for RISC-V

2018-06-13 Thread Andreas Schwab
From

and GCC source.

Signed-off-by: Andreas Schwab 
---
 backends/Makefile.am  |   2 +-
 backends/riscv_cfi.c  |  75 ++
 backends/riscv_init.c |   4 +
 backends/riscv_regs.c | 177 ++
 4 files changed, 257 insertions(+), 1 deletion(-)
 create mode 100644 backends/riscv_cfi.c
 create mode 100644 backends/riscv_regs.c

diff --git a/backends/Makefile.am b/backends/Makefile.am
index 80aa00e752..0c14ec86b5 100644
--- a/backends/Makefile.am
+++ b/backends/Makefile.am
@@ -131,7 +131,7 @@ cpu_bpf = ../libcpu/libcpu_bpf.a
 libebl_bpf_pic_a_SOURCES = $(bpf_SRCS)
 am_libebl_bpf_pic_a_OBJECTS = $(bpf_SRCS:.c=.os)
 
-riscv_SRCS = riscv_init.c riscv_symbol.c
+riscv_SRCS = riscv_init.c riscv_symbol.c riscv_cfi.c riscv_regs.c
 libebl_riscv_pic_a_SOURCES = $(riscv_SRCS)
 am_libebl_riscv_pic_a_OBJECTS = $(riscv_SRCS:.c=.os)
 
diff --git a/backends/riscv_cfi.c b/backends/riscv_cfi.c
new file mode 100644
index 00..1a84a38237
--- /dev/null
+++ b/backends/riscv_cfi.c
@@ -0,0 +1,75 @@
+/* RISC-V ABI-specified defaults for DWARF CFI.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+ * the GNU Lesser General Public License as published by the Free
+   Software Foundation; either version 3 of the License, or (at
+   your option) any later version
+
+   or
+
+ * the GNU General Public License as published by the Free
+   Software Foundation; either version 2 of the License, or (at
+   your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see .  */
+
+#ifdef HAVE_CONFIG_H
+# include 
+#endif
+
+#include 
+
+#define BACKEND aarch64_
+#include "libebl_CPU.h"
+
+
+int
+riscv_abi_cfi (Ebl *ebl __attribute__ ((unused)), Dwarf_CIE *abi_info)
+{
+  static const uint8_t abi_cfi[] =
+{
+  /* The initial Canonical Frame Address is the value of the
+ Stack Pointer (r2) as setup in the previous frame. */
+  DW_CFA_def_cfa, ULEB128_7 (2), ULEB128_7 (0),
+
+  /* The Stack Pointer (r2) is restored from CFA address by default.  */
+  DW_CFA_val_offset, ULEB128_7 (2), ULEB128_7 (0),
+
+#define SV(n) DW_CFA_same_value, ULEB128_7 (n)
+  /* The return address register contains the return address setup by
+caller.  */
+  SV (1),
+
+  /* Callee-saved registers s0-s11, fs0-fs11.  */
+  SV(8), SV (9), SV (18), SV (19), SV (20), SV (21),
+  SV (22), SV (23), SV (24), SV (25), SV (26), SV (27),
+
+  SV (40), SV (41),  SV (50),  SV (51), SV (52),  SV (53),
+  SV (54), SV (55),  SV (56),  SV (57), SV (58),  SV (59),
+#undef SV
+
+  /* XXX Note: registers intentionally unused by the program,
+for example as a consequence of the procedure call standard
+should be initialized as if by DW_CFA_same_value.  */
+};
+
+  abi_info->initial_instructions = abi_cfi;
+  abi_info->initial_instructions_end = &abi_cfi[sizeof abi_cfi];
+  abi_info->data_alignment_factor = -4;
+
+  abi_info->return_address_register = 1; /* ra.  */
+
+  return 0;
+}
diff --git a/backends/riscv_init.c b/backends/riscv_init.c
index 80be86d3c5..5588a6b7f0 100644
--- a/backends/riscv_init.c
+++ b/backends/riscv_init.c
@@ -51,6 +51,10 @@ riscv_init (Elf *elf __attribute__ ((unused)),
   eh->name = "RISC-V";
   riscv_init_reloc (eh);
   HOOK (eh, reloc_simple_type);
+  HOOK (eh, register_info);
+  HOOK (eh, abi_cfi);
+  /* gcc/config/ #define DWARF_FRAME_REGISTERS.  */
+  eh->frame_nregs = 66;
   HOOK (eh, check_special_symbol);
   HOOK (eh, machine_flag_check);
 
diff --git a/backends/riscv_regs.c b/backends/riscv_regs.c
new file mode 100644
index 00..7b577ca0cb
--- /dev/null
+++ b/backends/riscv_regs.c
@@ -0,0 +1,177 @@
+/* Register names and numbers for RISC-V DWARF.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+ * the GNU Lesser General Public License as published by the Free
+   Software Foundation; either version 3 of the License, or (at
+   your option) any later version
+
+   or
+
+ * the GNU General Public License as published by the Free
+   Software Foundation; either version 2 of the License, or (at
+   your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the

[PATCH] readelf: Handle signedness of DW_FORM_implicit_const and DW_AT_const_value.

2018-06-13 Thread Mark Wielaard
We only handles DW_FORM_sdata as a signed form, but DW_FORM_implicit_const
is also signed by default. For DW_AT_const_value we can do a little better.
GCC encodes some const_values with signed forms, even though the type
is unsigned. Lookup the (base) type of the DIE and display the const value
as their (signed) type/size (if we can determine that).

Add a new testcase run-readelf-const-values.sh that shows that.
With the new testcase the const values would come out as follows:

  name (string) "i"
  const_value  (implicit_const) 18446744073709551615
  name (string) "j"
  const_value  (implicit_const) 18446744073709551615

  name (string) "sc"
  const_value  (sdata) -2
  name (string) "uc"
  const_value  (sdata) -2
  name (string) "ss"
  const_value  (sdata) -16
  name (string) "us"
  const_value  (sdata) -16
  name (string) "si"
  const_value  (sdata) -3
  name (string) "ui"
  const_value  (sdata) -94967296
  name (string) "sl"
  const_value  (sdata) -1
  name (string) "ul"
  const_value  (sdata) -1

With this patch they show up as:

  name (string) "i"
  const_value  (implicit_const) -1
  name (string) "j"
  const_value  (implicit_const) -1

  name (string) "sc"
  const_value  (sdata) -2
  name (string) "uc"
  const_value  (sdata) 254 (-2)
  name (string) "ss"
  const_value  (sdata) -16
  name (string) "us"
  const_value  (sdata) 65520 (-16)
  name (string) "si"
  const_value  (sdata) -3
  name (string) "ui"
  const_value  (sdata) 42 (-94967296)
  name (string) "sl"
  const_value  (sdata) -1
  name (string) "ul"
  const_value  (sdata) 18446744073709551615 (-1)

(for signed/unsigned int char, short and long)

Signed-off-by: Mark Wielaard 
---
 src/ChangeLog |   7 ++
 src/readelf.c | 122 ++
 tests/ChangeLog   |   9 ++
 tests/Makefile.am |   2 +
 tests/run-readelf-const-values.sh | 230 ++
 tests/run-readelf-zdebug-rel.sh   |   2 +-
 tests/testfile-const-values.debug.bz2 | Bin 0 -> 1540 bytes
 7 files changed, 350 insertions(+), 22 deletions(-)
 create mode 100755 tests/run-readelf-const-values.sh
 create mode 100755 tests/testfile-const-values.debug.bz2

diff --git a/src/ChangeLog b/src/ChangeLog
index fd45405..5f381cf 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,10 @@
+2018-06-13  Mark Wielaard  
+
+   * readelf.c (die_type_sign_bytes): New function.
+   (attr_callback): Recognized DW_FORM_implicit_cost as signed. Use
+   die_type_sign_bytes to lookup the signedness and size of const
+   values.
+
 2018-06-11  Mark Wielaard  
 
* readelf.c (print_form_data): Don't reuse readp and readendp when
diff --git a/src/readelf.c b/src/readelf.c
index 3b477ab..5e7061d 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -6869,6 +6869,33 @@ print_debug_frame_section (Dwfl_Module *dwflmod, Ebl 
*ebl, GElf_Ehdr *ehdr,
 }
 
 
+/* Returns the signedness (or false if it cannot be determined) and
+   the byte size (or zero if it cannot be gotten) of the given DIE
+   DW_AT_type attribute.  Uses dwarf_peel_type and dwarf_aggregate_size.  */
+static void
+die_type_sign_bytes (Dwarf_Die *die, bool *is_signed, int *bytes)
+{
+  Dwarf_Attribute attr;
+  Dwarf_Die type;
+
+  *bytes = 0;
+  *is_signed = false;
+
+  if (dwarf_peel_type (dwarf_formref_die (dwarf_attr_integrate (die,
+   DW_AT_type,
+   &attr), &type),
+  &type) == 0)
+{
+  Dwarf_Word val;
+  *is_signed = (dwarf_formudata (dwarf_attr (&type, DW_AT_encoding,
+&attr), &val) == 0
+   && (val == DW_ATE_signed || val == DW_ATE_signed_char));
+
+  if (dwarf_aggregate_size (&type, &val) == 0)
+   *bytes = val;
+}
+}
+
 struct attrcb_args
 {
   Dwfl_Module *dwflmod;
@@ -7300,36 +7327,89 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
}
   else
{
- Dwarf_Sword snum = 0;
- if (form == DW_FORM_sdata)
-   if (unlikely (dwarf_formsdata (attrp, &snum) != 0))
- goto attrval_out;
-
  if (as_hex_id)
{
  printf ("   %*s%-20s (%s) 0x%.16" PRIx64 "\n",
  (int) (level * 2), "", dwarf_attr_name (attr),
  dwarf_form_name (form), num);
}
- else if (values

[PATCH] readelf: While printing .debug_loc make sure that next_off doesn't overflow.

2018-06-13 Thread Mark Wielaard
Found by the afl fuzzer. The next offset (after a locview) comes from a
DIE loclist attribute. This could be a bogus value so large it overflows
the buffer and makes us print past the end of buffer.

Signed-off-by: Mark Wielaard 
---
 src/ChangeLog | 5 +
 src/readelf.c | 4 +++-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/src/ChangeLog b/src/ChangeLog
index 5f381cf..3d266e2 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,8 @@
+2018-06-16  Mark Wielaard  
+
+   * readelf.c (print_debug_loc_section): Make sure next_off doesn't
+   overflow d_buf.
+
 2018-06-13  Mark Wielaard  
 
* readelf.c (die_type_sign_bytes): New function.
diff --git a/src/readelf.c b/src/readelf.c
index 5e7061d..2e7378e 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -9310,7 +9310,9 @@ print_debug_loc_section (Dwfl_Module *dwflmod,
listptr_idx);
  const unsigned char *locp = readp;
  const unsigned char *locendp;
- if (next_off == 0)
+ if (next_off == 0
+ || next_off > (size_t) (endp
+ - (const unsigned char *) data->d_buf))
locendp = endp;
  else
locendp = (const unsigned char *) data->d_buf + next_off;
-- 
1.8.3.1



[PATCH] libdw: Make __libdw_dieabbrev more robust on failure.

2018-06-13 Thread Mark Wielaard
Make sure to always set die->abbrev to DWARF_END_ABBREV on failure.
DWARF_END_ABBREV is also what the function reports on failure. And it
will prevent trying to lookup the abbrev ever again.

Signed-off-by: Mark Wielaard 
---
 libdw/ChangeLog | 5 +
 libdw/libdwP.h  | 5 +++--
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 07a1346b..78321654 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,8 @@
+2018-06-12  Mark Wielaard  
+
+   * libdw.h (__libdw_dieabbrev): Set die->abbrev to DWARF_END_ABBREV
+   on failure.
+
 2018-06-10  Mark Wielaard  
 
* dwarf_attr_integrate.c (dwarf_attr_integrate): Stop after 16 DIE
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index 3d8e145a..eebb7d12 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -653,8 +653,9 @@ __libdw_dieabbrev (Dwarf_Die *die, const unsigned char 
**readp)
   /* Get the abbreviation code.  */
   unsigned int code;
   const unsigned char *addr = die->addr;
-  if (die->cu == NULL || addr >= (const unsigned char *) die->cu->endp)
-   return DWARF_END_ABBREV;
+  if (unlikely (die->cu == NULL
+   || addr >= (const unsigned char *) die->cu->endp))
+   return die->abbrev = DWARF_END_ABBREV;
   get_uleb128 (code, addr, die->cu->endp);
   if (readp != NULL)
*readp = addr;
-- 
2.17.0



[PATCH] readelf: Make sure print_form_data always consumes DW_FORM_strx[1234] data.

2018-06-13 Thread Mark Wielaard
Found by afl-fuzz. When printing DW_FORM_strx[1234] data eu-readelf didn't
increase readp which meant eu-readelf would keep printing the same line
dirs or files encoded with strx[1234] names. This meant that for insane
large dir or file counts eu-readelf would just keep printing endlessly
because we never reached and of the .debug_line buffer.

Signed-off-by: Mark Wielaard 
---
 libdw/ChangeLog   |  4 
 libdw/memory-access.h |  5 +
 src/ChangeLog |  5 +
 src/readelf.c | 12 ++--
 4 files changed, 20 insertions(+), 6 deletions(-)

diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 78321654..6492c976 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,7 @@
+2018-06-12  Mark Wielaard  
+
+   * memory-access.h (read_3ubyte_unaligned_inc): New define.
+
 2018-06-12  Mark Wielaard  
 
* libdw.h (__libdw_dieabbrev): Set die->abbrev to DWARF_END_ABBREV
diff --git a/libdw/memory-access.h b/libdw/memory-access.h
index 22918cb9..a39ad6d2 100644
--- a/libdw/memory-access.h
+++ b/libdw/memory-access.h
@@ -362,6 +362,11 @@ read_3ubyte_unaligned (Dwarf *dbg, const unsigned char *p)
 }
 
 
+#define read_3ubyte_unaligned_inc(Dbg, Addr) \
+  ({ uint32_t t_ = read_2ubyte_unaligned (Dbg, Addr);\
+ Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 3);\
+ t_; })
+
 #define read_addr_unaligned_inc(Nbytes, Dbg, Addr) \
   (assert ((Nbytes) == 4 || (Nbytes) == 8),\
 ((Nbytes) == 4 ? read_4ubyte_unaligned_inc (Dbg, Addr) \
diff --git a/src/ChangeLog b/src/ChangeLog
index fd45405f..fbbb9acb 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,8 @@
+2018-06-12  Mark Wielaard  
+
+   * print_form_data): Don't increase strreadp after use.  Do
+   increase readp for DW_FORM_strx[1234].
+
 2018-06-11  Mark Wielaard  
 
* readelf.c (print_form_data): Don't reuse readp and readendp when
diff --git a/src/readelf.c b/src/readelf.c
index f1858971..17d91735 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -7994,9 +7994,9 @@ print_form_data (Dwarf *dbg, int form, const unsigned 
char *readp,
{
  Dwarf_Off idx;
  if (offset_len == 8)
-   idx = read_8ubyte_unaligned_inc (dbg, strreadp);
+   idx = read_8ubyte_unaligned (dbg, strreadp);
  else
-   idx = read_4ubyte_unaligned_inc (dbg, strreadp);
+   idx = read_4ubyte_unaligned (dbg, strreadp);
 
  data = dbg->sectiondata[IDX_debug_str];
  if (data == NULL || idx >= data->d_size
@@ -8013,25 +8013,25 @@ print_form_data (Dwarf *dbg, int form, const unsigned 
char *readp,
 case DW_FORM_strx1:
   if (readendp - readp < 1)
goto invalid_data;
-  val = *readp;
+  val = *readp++;
   goto strx_val;
 
 case DW_FORM_strx2:
   if (readendp - readp < 2)
goto invalid_data;
-  val = read_2ubyte_unaligned (dbg, readp);
+  val = read_2ubyte_unaligned_inc (dbg, readp);
   goto strx_val;
 
 case DW_FORM_strx3:
   if (readendp - readp < 3)
goto invalid_data;
-  val = read_3ubyte_unaligned (dbg, readp);
+  val = read_3ubyte_unaligned_inc (dbg, readp);
   goto strx_val;
 
 case DW_FORM_strx4:
   if (readendp - readp < 4)
goto invalid_data;
-  val = read_4ubyte_unaligned (dbg, readp);
+  val = read_4ubyte_unaligned_inc (dbg, readp);
   goto strx_val;
 
 default:
-- 
2.17.0



[PATCH] readelf: Check there are at least 4 bytes available for DWARF_FORM_block4.

2018-06-13 Thread Mark Wielaard
Found by afl-fuzz. When printing a DWARF_FORM_block4 we checked there
were only 2 bytes available (copy/paste from DW_FORM_block2 right
before). Obviously we need at least 4 bytes to read the length of a
DW_FORM_block4.

Signed-off-by: Mark Wielaard 
---
 src/ChangeLog | 5 +
 src/readelf.c | 2 +-
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/src/ChangeLog b/src/ChangeLog
index fbbb9acb..5baf82e6 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,8 @@
+2018-06-12  Mark Wielaard  
+
+   * readelf.c (print_form_data): Check we have 4, not 2, bytes
+   available for DW_FORM_block4.
+
 2018-06-12  Mark Wielaard  
 
* print_form_data): Don't increase strreadp after use.  Do
diff --git a/src/readelf.c b/src/readelf.c
index 17d91735..3b477ab0 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -7907,7 +7907,7 @@ print_form_data (Dwarf *dbg, int form, const unsigned 
char *readp,
   break;
 
 case DW_FORM_block4:
-  if (readendp - readp < 2)
+  if (readendp - readp < 4)
goto invalid_data;
   val = read_4ubyte_unaligned_inc (dbg, readp);
   if ((size_t) (readendp - readp) < val)
-- 
2.17.0