On Sat, Oct 24, 2020 at 03:05:55PM -0600, Tom Tromey wrote:
> Mark> Clearly DW_FORM_strx3 and DW_FORM_addrx3 aren't used much
> Mark> (given that it is an index value between larger than 65536).
> 
> I don't even really see the need for a 3-byte form.
> Anyway if it helps, gdb gets this wrong too -- gdb always uses
> little-endian, which seems wrong, but I didn't know how to write a
> real-life test case.

How about the attached? It isn't very fancy, but it would have caught
the bug you found. And might be nice in case we ever refactor the
read_unaligned code.

Cheers,

Mark
>From 3d1439319a7b575bf67ca4032e1cd609019c5f9b Mon Sep 17 00:00:00 2001
From: Mark Wielaard <m...@klomp.org>
Date: Sun, 25 Oct 2020 20:40:33 +0100
Subject: [PATCH] tests: Add read_unaligned testcase

Run tests/read_unaligned 1 on a big endian and little endian machine
to generate the le_mem and be_mem arrays. The one byte variants are
kind of impossible to get wrong, but including them makes sure the
other variants are not naturally aligned in memory.

Signed-off-by: Mark Wielaard <m...@klomp.org>
---
 tests/ChangeLog        |   6 +
 tests/Makefile.am      |   5 +-
 tests/read_unaligned.c | 564 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 573 insertions(+), 2 deletions(-)
 create mode 100644 tests/read_unaligned.c

diff --git a/tests/ChangeLog b/tests/ChangeLog
index 5f075df8..e352f724 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,9 @@
+2020-10-25  Mark Wielaard  <m...@klomp.org>
+
+	* read_unaligned.c: New test.
+	* Makefile.am (check_PROGRAMS, TESTS): Add read_unaligned.
+	(read_unaligned_LDADD): New variable.
+
 2020-10-22  Tom Tromey  <t...@tromey.com>
 
 	PR26773
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 568a9f8d..345c780f 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -63,7 +63,7 @@ check_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \
 		  all-dwarf-ranges unit-info next_cfi \
 		  elfcopy addsections xlate_notes elfrdwrnop \
 		  dwelf_elf_e_machine_string \
-		  getphdrnum leb128
+		  getphdrnum leb128 read_unaligned
 
 asm_TESTS = asm-tst1 asm-tst2 asm-tst3 asm-tst4 asm-tst5 \
 	    asm-tst6 asm-tst7 asm-tst8 asm-tst9
@@ -186,7 +186,7 @@ TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \
 	run-disasm-riscv64.sh \
 	run-pt_gnu_prop-tests.sh \
 	run-getphdrnum.sh run-test-includes.sh \
-	leb128
+	leb128 read_unaligned
 
 if !BIARCH
 export ELFUTILS_DISABLE_BIARCH = 1
@@ -696,6 +696,7 @@ elfrdwrnop_LDADD = $(libelf)
 dwelf_elf_e_machine_string_LDADD = $(libelf) $(libdw)
 getphdrnum_LDADD = $(libelf) $(libdw)
 leb128_LDADD = $(libelf) $(libdw)
+read_unaligned_LDADD = $(libelf) $(libdw)
 
 # We want to test the libelf header against the system elf.h header.
 # Don't include any -I CPPFLAGS. Except when we install our own elf.h.
diff --git a/tests/read_unaligned.c b/tests/read_unaligned.c
new file mode 100644
index 00000000..15e0c002
--- /dev/null
+++ b/tests/read_unaligned.c
@@ -0,0 +1,564 @@
+/* Test program for read_[type]_unaligned.
+   Copyright (C) 2020, Red Hat Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   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 a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <assert.h>
+#include <endian.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include "../libdw/libdwP.h"
+#include "../libdw/memory-access.h"
+
+union u8
+{
+  uint8_t v;
+  unsigned char c[1];
+};
+
+union s8
+{
+  int8_t v;
+  unsigned char c[1];
+};
+
+union u16
+{
+  uint16_t v;
+  unsigned char c[2];
+};
+
+union s16
+{
+  int16_t v;
+  unsigned char c[2];
+};
+
+union u24
+{
+  uint32_t v:24;
+  unsigned char c[3];
+} __attribute__((packed));
+
+union u32
+{
+  uint32_t v;
+  unsigned char c[4];
+};
+
+union s32
+{
+  int32_t v;
+  unsigned char c[4];
+};
+
+union u64
+{
+  uint64_t v;
+  unsigned char c[8];
+};
+
+union s64
+{
+  uint64_t v;
+  unsigned char c[8];
+};
+
+uint8_t u8_nums[] =
+  {
+   0,
+   1,
+   UINT8_MAX / 2 - 1,
+   UINT8_MAX / 2,
+   UINT8_MAX / 2 + 1,
+   UINT8_MAX,
+   UINT8_MAX -1
+  };
+
+int8_t s8_nums[] =
+  {
+   INT8_MIN,
+   INT8_MIN + 1,
+   -1,
+   0,
+   1,
+   INT8_MAX,
+   INT8_MAX - 1
+  };
+
+uint16_t u16_nums[] =
+  {
+   0,
+   1,
+   UINT16_MAX / 2 - 1,
+   UINT16_MAX / 2,
+   UINT16_MAX / 2 + 1,
+   UINT16_MAX,
+   UINT16_MAX -1
+  };
+
+int16_t s16_nums[] =
+  {
+   INT16_MIN,
+   INT16_MIN + 1,
+   -1,
+   0,
+   1,
+   INT16_MAX,
+   INT16_MAX - 1
+  };
+
+#define UINT24_MAX 0xffffff
+
+uint32_t u24_nums[] =
+  {
+   0,
+   1,
+   UINT24_MAX / 2 - 1,
+   UINT24_MAX / 2,
+   UINT24_MAX / 2 + 1,
+   UINT24_MAX,
+   UINT24_MAX -1
+  };
+
+uint32_t u32_nums[] =
+  {
+   0,
+   1,
+   UINT32_MAX / 2 - 1,
+   UINT32_MAX / 2,
+   UINT32_MAX / 2 + 1,
+   UINT32_MAX,
+   UINT32_MAX -1
+  };
+
+int32_t s32_nums[] =
+  {
+   INT32_MIN,
+   INT32_MIN + 1,
+   -1,
+   0,
+   1,
+   INT32_MAX,
+   INT32_MAX - 1
+  };
+
+uint64_t u64_nums[] =
+  {
+   0,
+   1,
+   UINT64_MAX / 2 - 1,
+   UINT64_MAX / 2,
+   UINT64_MAX / 2 + 1,
+   UINT64_MAX,
+   UINT64_MAX -1
+  };
+
+int64_t s64_nums[] =
+  {
+   INT64_MIN,
+   INT64_MIN + 1,
+   -1,
+   0,
+   1,
+   INT64_MAX,
+   INT64_MAX - 1
+  };
+
+static unsigned char le_mem[] =
+  {
+    /* u8 */
+    0x00,
+    0x01,
+    0x7e,
+    0x7f,
+    0x80,
+    0xff,
+    0xfe,
+    /* s8 */
+    0x80,
+    0x81,
+    0xff,
+    0x00,
+    0x01,
+    0x7f,
+    0x7e,
+    /* u16 */
+    0x00, 0x00,
+    0x01, 0x00,
+    0xfe, 0x7f,
+    0xff, 0x7f,
+    0x00, 0x80,
+    0xff, 0xff,
+    0xfe, 0xff,
+    /* s16 */
+    0x00, 0x80,
+    0x01, 0x80,
+    0xff, 0xff,
+    0x00, 0x00,
+    0x01, 0x00,
+    0xff, 0x7f,
+    0xfe, 0x7f,
+    /* u24 */
+    0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00,
+    0xfe, 0xff, 0x7f,
+    0xff, 0xff, 0x7f,
+    0x00, 0x00, 0x80,
+    0xff, 0xff, 0xff,
+    0xfe, 0xff, 0xff,
+    /* u32 */
+    0x00, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00,
+    0xfe, 0xff, 0xff, 0x7f,
+    0xff, 0xff, 0xff, 0x7f,
+    0x00, 0x00, 0x00, 0x80,
+    0xff, 0xff, 0xff, 0xff,
+    0xfe, 0xff, 0xff, 0xff,
+    /* s32 */
+    0x00, 0x00, 0x00, 0x80,
+    0x01, 0x00, 0x00, 0x80,
+    0xff, 0xff, 0xff, 0xff,
+    0x00, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00,
+    0xff, 0xff, 0xff, 0x7f,
+    0xfe, 0xff, 0xff, 0x7f,
+    /* u64 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    /* s64 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
+    0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
+  };
+
+static unsigned char be_mem[] =
+  {
+    /* u8 */
+    0x00,
+    0x01,
+    0x7e,
+    0x7f,
+    0x80,
+    0xff,
+    0xfe,
+    /* s8 */
+    0x80,
+    0x81,
+    0xff,
+    0x00,
+    0x01,
+    0x7f,
+    0x7e,
+    /* u16 */
+    0x00, 0x00,
+    0x00, 0x01,
+    0x7f, 0xfe,
+    0x7f, 0xff,
+    0x80, 0x00,
+    0xff, 0xff,
+    0xff, 0xfe,
+    /* s16 */
+    0x80, 0x00,
+    0x80, 0x01,
+    0xff, 0xff,
+    0x00, 0x00,
+    0x00, 0x01,
+    0x7f, 0xff,
+    0x7f, 0xfe,
+    /* u24 */
+    0x00, 0x00, 0x00,
+    0x00, 0x00, 0x01,
+    0x7f, 0xff, 0xfe,
+    0x7f, 0xff, 0xff,
+    0x80, 0x00, 0x00,
+    0xff, 0xff, 0xff,
+    0xff, 0xff, 0xfe,
+    /* u32 */
+    0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x01,
+    0x7f, 0xff, 0xff, 0xfe,
+    0x7f, 0xff, 0xff, 0xff,
+    0x80, 0x00, 0x00, 0x00,
+    0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xfe,
+    /* s32 */
+    0x80, 0x00, 0x00, 0x00,
+    0x80, 0x00, 0x00, 0x01,
+    0xff, 0xff, 0xff, 0xff,
+    0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x01,
+    0x7f, 0xff, 0xff, 0xff,
+    0x7f, 0xff, 0xff, 0xfe,
+    /* u64 */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+    0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
+    0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
+    /* s64 */
+    0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+    0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
+  };
+
+int
+main (int argc, char **argv __attribute__((unused)))
+{
+  /* No arguments means check, otherwise Write out the memory array.  */
+  bool write = false;
+  if (argc > 1)
+    write = true;
+
+  bool is_le = (BYTE_ORDER == LITTLE_ENDIAN);
+
+  if (write)
+    {
+      if (is_le)
+	printf ("static unsigned char le_mem[] =\n");
+      else
+	printf ("static unsigned char be_mem[] =\n");
+      printf ("  {\n");
+    }
+
+  Dwarf dbg_le = { .other_byte_order = !is_le };
+  Dwarf dbg_be = { .other_byte_order = is_le };
+
+  unsigned char *p_le = le_mem;
+  unsigned char *p_be = be_mem;
+
+  union u8 u8;
+  if (write)
+    printf ("    /* u8 */\n");
+  for (size_t i = 0; i < sizeof (u8_nums) / sizeof (u8); i++)
+    {
+      if (write)
+	{
+	  u8.v = u8_nums[i];
+	  printf ("    0x%02" PRIx8 ",\n", u8.c[0]);
+	}
+      else
+	{
+	  uint8_t v = *p_le++;
+	  assert (v == u8_nums[i]);
+	  v = *p_be++;
+	  assert (v == u8_nums[i]);
+	}
+    }
+
+  union s8 s8;
+  if (write)
+    printf ("    /* s8 */\n");
+  for (size_t i = 0; i < sizeof (s8_nums) / sizeof (s8); i++)
+    {
+      if (write)
+	{
+	  s8.v = s8_nums[i];
+	  printf ("    0x%02" PRIx8 ",\n", s8.c[0]);
+	}
+      else
+	{
+	  int8_t v = *p_le++;
+	  assert (v == s8_nums[i]);
+	  v = *p_be++;
+	  assert (v == s8_nums[i]);
+	}
+    }
+
+  union u16 u16;
+  if (write)
+    printf ("    /* u16 */\n");
+  for (size_t i = 0; i < sizeof (u16_nums) / sizeof (u16); i++)
+    {
+      if (write)
+	{
+	  u16.v = u16_nums[i];
+	  printf ("    0x%02" PRIx8 ", ", u16.c[0]);
+	  printf ("0x%02" PRIx8 ",\n", u16.c[1]);
+	}
+      else
+	{
+	  uint16_t v = read_2ubyte_unaligned_inc (&dbg_le, p_le);
+	  assert (v == u16_nums[i]);
+	  v = read_2ubyte_unaligned_inc (&dbg_be, p_be);
+	  assert (v == u16_nums[i]);
+	}
+    }
+
+  union s16 s16;
+  if (write)
+    printf ("    /* s16 */\n");
+  for (size_t i = 0; i < sizeof (s16_nums) / sizeof (s16); i++)
+    {
+      if (write)
+	{
+	  s16.v = s16_nums[i];
+	  printf ("    0x%02" PRIx8 ", ", s16.c[0]);
+	  printf ("0x%02" PRIx8 ",\n", s16.c[1]);
+	}
+      else
+	{
+	  int16_t v = read_2sbyte_unaligned_inc (&dbg_le, p_le);
+	  assert (v == s16_nums[i]);
+	  v = read_2sbyte_unaligned_inc (&dbg_be, p_be);
+	  assert (v == s16_nums[i]);
+	}
+    }
+
+  union u24 u24;
+  if (write)
+    printf ("    /* u24 */\n");
+  for (size_t i = 0; i < sizeof (u24_nums) / sizeof (uint32_t); i++)
+    {
+      if (write)
+	{
+	  u24.v = u24_nums[i];
+	  printf ("    0x%02" PRIx8 ", ", u24.c[0]);
+	  printf ("0x%02" PRIx8 ", ", u24.c[1]);
+	  printf ("0x%02" PRIx8 ",\n", u24.c[2]);
+	}
+      else
+	{
+	  uint32_t v = read_3ubyte_unaligned_inc (&dbg_le, p_le);
+	  assert (v == u24_nums[i]);
+	  v = read_3ubyte_unaligned_inc (&dbg_be, p_be);
+	  assert (v == u24_nums[i]);
+	}
+    }
+
+  union u32 u32;
+  if (write)
+    printf ("    /* u32 */\n");
+  for (size_t i = 0; i < sizeof (u32_nums) / sizeof (u32); i++)
+    {
+      if (write)
+	{
+	  u32.v = u32_nums[i];
+	  printf ("    0x%02" PRIx8 ", ", u32.c[0]);
+	  printf ("0x%02" PRIx8 ", ", u32.c[1]);
+	  printf ("0x%02" PRIx8 ", ", u32.c[2]);
+	  printf ("0x%02" PRIx8 ",\n", u32.c[3]);
+	}
+      else
+	{
+	  uint32_t v = read_4ubyte_unaligned_inc (&dbg_le, p_le);
+	  assert (v == u32_nums[i]);
+	  v = read_4ubyte_unaligned_inc (&dbg_be, p_be);
+	  assert (v == u32_nums[i]);
+	}
+    }
+
+  union s32 s32;
+  if (write)
+    printf ("    /* s32 */\n");
+  for (size_t i = 0; i < sizeof (s32_nums) / sizeof (s32); i++)
+    {
+      if (write)
+	{
+	  s32.v = s32_nums[i];
+	  printf ("    0x%02" PRIx8 ", ", s32.c[0]);
+	  printf ("0x%02" PRIx8 ", ", s32.c[1]);
+	  printf ("0x%02" PRIx8 ", ", s32.c[2]);
+	  printf ("0x%02" PRIx8 ",\n", s32.c[3]);
+	}
+      else
+	{
+	  int32_t v = read_4sbyte_unaligned_inc (&dbg_le, p_le);
+	  assert (v == s32_nums[i]);
+	  v = read_4sbyte_unaligned_inc (&dbg_be, p_be);
+	  assert (v == s32_nums[i]);
+	}
+    }
+
+  union u64 u64;
+  if (write)
+    printf ("    /* u64 */\n");
+  for (size_t i = 0; i < sizeof (u64_nums) / sizeof (u64); i++)
+    {
+      if (write)
+	{
+	  u64.v = u64_nums[i];
+	  printf ("    0x%02" PRIx8 ", ", u64.c[0]);
+	  printf ("0x%02" PRIx8 ", ", u64.c[1]);
+	  printf ("0x%02" PRIx8 ", ", u64.c[2]);
+	  printf ("0x%02" PRIx8 ", ", u64.c[3]);
+	  printf ("0x%02" PRIx8 ", ", u64.c[4]);
+	  printf ("0x%02" PRIx8 ", ", u64.c[5]);
+	  printf ("0x%02" PRIx8 ", ", u64.c[6]);
+	  printf ("0x%02" PRIx8 ",\n", u64.c[7]);
+	}
+      else
+	{
+	  uint64_t v = read_8ubyte_unaligned_inc (&dbg_le, p_le);
+	  assert (v == u64_nums[i]);
+	  v = read_8ubyte_unaligned_inc (&dbg_be, p_be);
+	  assert (v == u64_nums[i]);
+	}
+    }
+
+  union s64 s64;
+  if (write)
+    printf ("    /* s64 */\n");
+  for (size_t i = 0; i < sizeof (s64_nums) / sizeof (s64); i++)
+    {
+      if (write)
+	{
+	  s64.v = s64_nums[i];
+	  printf ("    0x%02" PRIx8 ", ", s64.c[0]);
+	  printf ("0x%02" PRIx8 ", ", s64.c[1]);
+	  printf ("0x%02" PRIx8 ", ", s64.c[2]);
+	  printf ("0x%02" PRIx8 ", ", s64.c[3]);
+	  printf ("0x%02" PRIx8 ", ", s64.c[4]);
+	  printf ("0x%02" PRIx8 ", ", s64.c[5]);
+	  printf ("0x%02" PRIx8 ", ", s64.c[6]);
+	  printf ("0x%02" PRIx8 ",\n", s64.c[7]);
+	}
+      else
+	{
+	  int64_t v = read_8sbyte_unaligned_inc (&dbg_le, p_le);
+	  assert (v == s64_nums[i]);
+	  v = read_8sbyte_unaligned_inc (&dbg_be, p_be);
+	  assert (v == s64_nums[i]);
+	}
+    }
+
+  if (write)
+    printf ("  };\n");
+  else
+    {
+      assert (p_le == le_mem + sizeof (le_mem));
+      assert (p_be == be_mem + sizeof (be_mem));
+    }
+
+  return 0;
+}
-- 
2.20.1

Reply via email to