1From 94cb85c3cbc59811de11869d1c1ce4f9bdb7f67c Mon Sep 17 00:00:00 2001 2From: Aleksei Vetrov <vvvvvv@google.com> 3Date: Thu, 11 Jul 2024 19:29:32 +0000 4Subject: [PATCH] libdwfl: Make dwfl_report_offline_memory work with 5 ELF_C_READ_MMAP 6To: elfutils-devel@sourceware.org 7Cc: kernel-team@android.com, 8 maennich@google.com, 9 vvvvvv@google.com 10 11elf_memory open mode recently changed from ELF_C_READ to 12ELF_C_READ_MMAP. This broken dwfl_report_offline_memory that changes 13mode to ELF_C_READ_MMAP_PRIVATE to be compatible with subsequent 14elf_begin on embedded ELF files. 15 16The proper implementation of dwfl_report_offline_memory doesn't change 17open mode and subsequent elf_begin invocations simply use cmd from the 18reference Elf*. 19 20Add tests to exercise Elf* to trigger the bug caused by incorrect cmd 21set to Elf*. 22 23 * libdwfl/offline.c (process_archive): Use archive->cmd 24 instead of hardcoded ELF_C_READ_MMAP_PRIVATE. 25 * libdwfl/open.c (libdw_open_elf): Use elf->cmd instead of 26 hardcoded ELF_C_READ_MMAP_PRIVATE. 27 (__libdw_open_elf_memory): Don't override (*elfp)->cmd. 28 * tests/Makefile.am (dwfl_report_offline_memory): Add libelf 29 as dependency. 30 * tests/dwfl-report-offline-memory.c: Add count_sections to 31 exercise Elf* from dwfl_report_offline_memory. 32 * tests/run-dwfl-report-offline-memory.sh: Add expected number 33 of sections to test invocations. 34 35Signed-off-by: Aleksei Vetrov <vvvvvv@google.com> 36--- 37 libdwfl/offline.c | 5 ++-- 38 libdwfl/open.c | 4 +--- 39 tests/Makefile.am | 2 +- 40 tests/dwfl-report-offline-memory.c | 32 ++++++++++++++++++++++--- 41 tests/run-dwfl-report-offline-memory.sh | 6 ++--- 42 5 files changed, 37 insertions(+), 12 deletions(-) 43 44diff --git a/libdwfl/offline.c b/libdwfl/offline.c 45index e9ab0cc1..24e9e180 100644 46--- a/libdwfl/offline.c 47+++ b/libdwfl/offline.c 48@@ -32,6 +32,7 @@ 49 # include <config.h> 50 #endif 51 52+#include "libelfP.h" 53 #include "libdwflP.h" 54 #include <fcntl.h> 55 56@@ -254,7 +255,7 @@ process_archive (Dwfl *dwfl, const char *name, const char *file_name, int fd, 57 { 58 Dwfl_Module *mod = NULL; 59 /* elf_begin supports opening archives even with fd == -1 passed. */ 60- Elf *member = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, archive); 61+ Elf *member = elf_begin (fd, archive->cmd, archive); 62 if (unlikely (member == NULL)) /* Empty archive. */ 63 { 64 __libdwfl_seterrno (DWFL_E_BADELF); 65@@ -263,7 +264,7 @@ process_archive (Dwfl *dwfl, const char *name, const char *file_name, int fd, 66 67 while (process_archive_member (dwfl, name, file_name, predicate, 68 fd, member, &mod) != ELF_C_NULL) 69- member = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, archive); 70+ member = elf_begin (fd, archive->cmd, archive); 71 72 /* We can drop the archive Elf handle even if we're still using members 73 in live modules. When the last module's elf_end on a member returns 74diff --git a/libdwfl/open.c b/libdwfl/open.c 75index d0f357ed..43b29fa9 100644 76--- a/libdwfl/open.c 77+++ b/libdwfl/open.c 78@@ -151,7 +151,7 @@ libdw_open_elf (int *fdp, Elf **elfp, bool close_on_fail, bool archive_ok, 79 elf->state.ar.elf_ar_hdr.ar_name = "libdwfl is faking you out"; 80 elf->state.ar.elf_ar_hdr.ar_size = elf->maximum_size - offset; 81 elf->state.ar.offset = offset - sizeof (struct ar_hdr); 82- Elf *subelf = elf_begin (-1, ELF_C_READ_MMAP_PRIVATE, elf); 83+ Elf *subelf = elf_begin (-1, elf->cmd, elf); 84 elf->kind = ELF_K_NONE; 85 if (unlikely (subelf == NULL)) 86 error = DWFL_E_LIBELF; 87@@ -215,8 +215,6 @@ __libdw_open_elf_memory (char *data, size_t size, Elf **elfp, bool archive_ok) 88 { 89 return DWFL_E_LIBELF; 90 } 91- /* Allow using this ELF as reference for subsequent elf_begin calls. */ 92- (*elfp)->cmd = ELF_C_READ_MMAP_PRIVATE; 93 return libdw_open_elf (&fd, elfp, false, archive_ok, true, false, true); 94 } 95 96diff --git a/tests/Makefile.am b/tests/Makefile.am 97index 77f9b90d..cfed54b7 100644 98--- a/tests/Makefile.am 99+++ b/tests/Makefile.am 100@@ -792,7 +792,7 @@ test_elf_cntl_gelf_getshdr_LDADD = $(libelf) 101 dwflsyms_LDADD = $(libdw) $(libelf) $(argp_LDADD) 102 dwfllines_LDADD = $(libeu) $(libdw) $(libelf) $(argp_LDADD) 103 dwfl_report_elf_align_LDADD = $(libeu) $(libdw) 104-dwfl_report_offline_memory_LDADD = $(libeu) $(libdw) 105+dwfl_report_offline_memory_LDADD = $(libeu) $(libdw) $(libelf) 106 dwfl_report_segment_contiguous_LDADD = $(libdw) $(libebl) $(libelf) 107 varlocs_LDADD = $(libeu) $(libdw) $(libelf) $(argp_LDADD) 108 backtrace_LDADD = $(libeu) $(libdw) $(libelf) $(argp_LDADD) 109diff --git a/tests/dwfl-report-offline-memory.c b/tests/dwfl-report-offline-memory.c 110index b3b4d9bd..3ecb66b9 100644 111--- a/tests/dwfl-report-offline-memory.c 112+++ b/tests/dwfl-report-offline-memory.c 113@@ -18,14 +18,19 @@ 114 #include <config.h> 115 116 #include <assert.h> 117+#include <errno.h> 118+#include <error.h> 119 #include <fcntl.h> 120 #include <locale.h> 121 #include <stdio.h> 122 #include <stdio_ext.h> 123 #include <stdlib.h> 124+#include <string.h> 125 #include <unistd.h> 126+ 127 #include ELFUTILS_HEADER(dwfl) 128-#include "system.h" 129+#include ELFUTILS_HEADER(elf) 130+#include <gelf.h> 131 132 133 static const Dwfl_Callbacks offline_callbacks = 134@@ -45,6 +50,20 @@ count_modules (Dwfl_Module *mod __attribute__ ((unused)), 135 return DWARF_CB_OK; 136 } 137 138+static int 139+count_sections (Elf *elf) 140+{ 141+ int result = 0; 142+ Elf_Scn *section = NULL; 143+ GElf_Shdr header; 144+ while ((section = elf_nextscn (elf, section)) != NULL) 145+ { 146+ assert (gelf_getshdr (section, &header) != NULL); 147+ result += 1; 148+ } 149+ return result; 150+} 151+ 152 int 153 main (int argc, char **argv) 154 { 155@@ -54,10 +73,11 @@ main (int argc, char **argv) 156 /* Set locale. */ 157 (void) setlocale (LC_ALL, ""); 158 159- if (argc != 3) 160+ if (argc != 4) 161 error (-1, 0, 162 "usage: dwfl_report_offline_memory [filename] " 163- "[expected number of modules]"); 164+ "[expected number of modules] " 165+ "[expected number of sections]"); 166 167 const char *fname = argv[1]; 168 int fd = open (fname, O_RDONLY); 169@@ -100,6 +120,12 @@ main (int argc, char **argv) 170 assert (endptr && !*endptr); 171 assert (number_of_modules == expected_number_of_modules); 172 173+ GElf_Addr loadbase = 0; 174+ Elf *elf = dwfl_module_getelf (mod, &loadbase); 175+ int number_of_sections = count_sections (elf); 176+ int expected_number_of_sections = atoi (argv[3]); 177+ assert (number_of_sections == expected_number_of_sections); 178+ 179 dwfl_end (dwfl); 180 free (data); 181 182diff --git a/tests/run-dwfl-report-offline-memory.sh b/tests/run-dwfl-report-offline-memory.sh 183index 85f43f53..84c7f999 100755 184--- a/tests/run-dwfl-report-offline-memory.sh 185+++ b/tests/run-dwfl-report-offline-memory.sh 186@@ -26,8 +26,8 @@ testfiles testarchive64.a 187 # bzip2 -zf test-ar-duplicates.a 188 testfiles test-ar-duplicates.a 189 190-testrun ${abs_builddir}/dwfl-report-offline-memory ./testfile-dwfl-report-elf-align-shlib.so 1 191-testrun ${abs_builddir}/dwfl-report-offline-memory ./testarchive64.a 3 192-testrun ${abs_builddir}/dwfl-report-offline-memory ./test-ar-duplicates.a 1 193+testrun ${abs_builddir}/dwfl-report-offline-memory ./testfile-dwfl-report-elf-align-shlib.so 1 24 194+testrun ${abs_builddir}/dwfl-report-offline-memory ./testarchive64.a 3 10 195+testrun ${abs_builddir}/dwfl-report-offline-memory ./test-ar-duplicates.a 1 7 196 197 exit 0 198-- 1992.45.2.993.g49e7a77208-goog 200 201