xref: /third_party/elfutils/tests/newdata.c (revision da0c48c4)
1/* Test program for elf_newdata function.
2   Copyright (C) 2015 Red Hat, Inc.
3   This file is part of elfutils.
4
5   This file is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 3 of the License, or
8   (at your option) any later version.
9
10   elfutils is distributed in the hope that it will be useful, but
11   WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17
18#ifdef HAVE_CONFIG_H
19# include <config.h>
20#endif
21
22#include <errno.h>
23#include <fcntl.h>
24#include <inttypes.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <unistd.h>
29#include "system.h"
30
31#include ELFUTILS_HEADER(elf)
32#include <gelf.h>
33
34// Random data string (16 bytes).
35static char *DATA = "123456789ABCDEF";
36static size_t DATA_LEN = 16;
37
38static void
39add_section_data (Elf *elf, char *buf, size_t len)
40{
41  printf ("Adding %zd bytes.\n", len);
42
43  Elf_Scn *scn = elf_getscn (elf, 1);
44  if (scn == NULL)
45    {
46      printf ("couldn't get data section: %s\n", elf_errmsg (-1));
47      exit (1);
48    }
49
50  Elf_Data *data = elf_newdata (scn);
51  if (data == NULL)
52    {
53      printf ("cannot create newdata for section: %s\n", elf_errmsg (-1));
54      exit (1);
55    }
56
57  data->d_buf = buf;
58  data->d_type = ELF_T_BYTE;
59  data->d_size = len;
60  data->d_align = 1;
61  data->d_version = EV_CURRENT;
62
63  // Let the library compute the internal structure information.
64  if (elf_update (elf, ELF_C_NULL) < 0)
65    {
66      printf ("failure in elf_update(NULL): %s\n", elf_errmsg (-1));
67      exit (1);
68    }
69
70}
71
72static Elf *
73create_elf (int fd, int class, int use_mmap)
74{
75  Elf *elf = elf_begin (fd, use_mmap ? ELF_C_WRITE_MMAP : ELF_C_WRITE, NULL);
76  if (elf == NULL)
77    {
78      printf ("cannot create ELF descriptor: %s\n", elf_errmsg (-1));
79      exit (1);
80    }
81
82  // Create an ELF header.
83  if (gelf_newehdr (elf, class) == 0)
84    {
85      printf ("cannot create ELF header: %s\n", elf_errmsg (-1));
86      exit (1);
87    }
88
89  GElf_Ehdr ehdr_mem;
90  GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
91  if (ehdr == NULL)
92    {
93      printf ("cannot get ELF header: %s\n", elf_errmsg (-1));
94      exit (1);
95    }
96
97  // Initialize header.
98  ehdr->e_ident[EI_DATA] = class == ELFCLASS32 ? ELFDATA2LSB : ELFDATA2MSB;
99  ehdr->e_ident[EI_OSABI] = ELFOSABI_GNU;
100  ehdr->e_type = ET_NONE;
101  ehdr->e_machine = class == ELFCLASS32 ? EM_PPC : EM_X86_64;
102  ehdr->e_version = EV_CURRENT;
103
104  // Update the ELF header.
105  if (gelf_update_ehdr (elf, ehdr) == 0)
106    {
107      printf ("cannot update ELF header: %s\n", elf_errmsg (-1));
108      exit (1);
109    }
110
111  // Create a section.
112  Elf_Scn *scn = elf_newscn (elf);
113  if (scn == NULL)
114    {
115      printf ("cannot create new section: %s\n", elf_errmsg (-1));
116      exit (1);
117    }
118
119  GElf_Shdr shdr_mem;
120  GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
121  if (shdr == NULL)
122    {
123      printf ("cannot get header for data section: %s\n", elf_errmsg (-1));
124      exit (1);
125    }
126
127  shdr->sh_type = SHT_PROGBITS;
128  shdr->sh_flags = 0;
129  shdr->sh_addr = 0;
130  shdr->sh_link = SHN_UNDEF;
131  shdr->sh_info = SHN_UNDEF;
132  shdr->sh_addralign = 1;
133  shdr->sh_entsize = 1;
134  shdr->sh_name = 0;
135
136  // Finish section, update the header.
137  if (gelf_update_shdr (scn, shdr) == 0)
138    {
139      printf ("cannot update header for DATA section: %s\n", elf_errmsg (-1));
140      exit (1);
141    }
142
143  // Add some data to the section.
144  add_section_data (elf, DATA, DATA_LEN);
145
146  // Write everything to disk.
147  if (elf_update (elf, ELF_C_WRITE) < 0)
148    {
149      printf ("failure in elf_update(WRITE): %s\n", elf_errmsg (-1));
150      exit (1);
151    }
152
153  return elf;
154}
155
156static Elf *
157read_elf (int fd, int use_mmap)
158{
159  printf ("Reading ELF file\n");
160  Elf *elf = elf_begin (fd, use_mmap ? ELF_C_RDWR_MMAP : ELF_C_RDWR, NULL);
161  if (elf == NULL)
162    {
163      printf ("cannot create ELF descriptor read-again: %s\n", elf_errmsg (-1));
164      exit (1);
165    }
166
167  return elf;
168}
169
170static void
171check_section_size (Elf *elf, size_t size)
172{
173  Elf_Scn *scn = elf_getscn (elf, 1);
174  if (scn == NULL)
175    {
176      printf ("couldn't get data section: %s\n", elf_errmsg (-1));
177      exit (1);
178    }
179
180  GElf_Shdr shdr_mem;
181  GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
182  if (shdr == NULL)
183    {
184      printf ("cannot get header for DATA section: %s\n", elf_errmsg (-1));
185      exit (1);
186    }
187
188  if (shdr->sh_size == size)
189    printf ("OK %zd bytes.\n", size);
190  else
191    {
192      printf ("BAD size, expected %zd, got %" PRIu64 "\n",
193	      size, shdr->sh_size);
194      exit (-1);
195    }
196}
197
198static void
199check_section_data (Elf *elf, char *data, size_t len, size_t times)
200{
201  Elf_Scn *scn = elf_getscn (elf, 1);
202  if (scn == NULL)
203    {
204      printf ("couldn't get data section: %s\n", elf_errmsg (-1));
205      exit (1);
206    }
207
208  Elf_Data *d = NULL;
209  for (size_t i = 0; i < times; i++)
210    {
211      if (d == NULL || i * len >= d->d_off + d->d_size)
212	{
213	  d = elf_getdata (scn, d);
214	  if (d == NULL)
215	    {
216	      printf ("cannot get data for section item %zd: %s\n",
217		      i, elf_errmsg (-1));
218	      exit (1);
219	    }
220	  else
221	    printf ("OK, section data item %zd (d_off: %" PRId64
222		    ", d_size: %zd)\n", i, d->d_off, d->d_size);
223	}
224      char *d_data = (char *) d->d_buf + (len * i) - d->d_off;
225      printf ("%zd data (d_off: %" PRId64
226	      ", len * i: %zd): (%p + %" PRId64 ") %s\n",
227	      i, d->d_off, len * i, d->d_buf, (len * i) - d->d_off, d_data);
228      if (memcmp (data, d_data, len) != 0)
229	{
230	  printf ("Got bad data in section for item %zd.\n", i);
231	  exit (1);
232	}
233    }
234}
235
236static void
237check_elf (int class, int use_mmap)
238{
239  static const char *fname;
240  if (class == ELFCLASS32)
241    fname = use_mmap ? "newdata.elf32.mmap" : "newdata.elf32";
242  else
243    fname = use_mmap ? "newdata.elf64.mmap" : "newdata.elf64";
244
245  printf ("\ncheck_elf: %s\n", fname);
246
247  int fd = open (fname, O_RDWR|O_CREAT|O_TRUNC, DEFFILEMODE);
248  if (fd == -1)
249    {
250      printf ("cannot create `%s': %s\n", fname, strerror (errno));
251      exit (1);
252    }
253
254  Elf *elf = create_elf (fd, class, use_mmap);
255  check_section_size (elf, DATA_LEN);
256  check_section_data (elf, DATA, DATA_LEN, 1);
257
258  // Add some more data (won't be written to disk).
259  add_section_data (elf, DATA, DATA_LEN);
260  check_section_size (elf, 2 * DATA_LEN);
261  check_section_data (elf, DATA, DATA_LEN, 2);
262
263  if (elf_end (elf) != 0)
264    {
265      printf ("failure in elf_end: %s\n", elf_errmsg (-1));
266      exit (1);
267    }
268
269  close (fd);
270
271  // Read the ELF from disk now.  And add new data directly.
272  fd = open (fname, O_RDONLY);
273  if (fd == -1)
274    {
275      printf ("cannot open `%s' read-only: %s\n", fname, strerror (errno));
276      exit (1);
277    }
278
279  elf = read_elf (fd, use_mmap);
280  check_section_size (elf, DATA_LEN);
281  // But don't check contents, that would read the data...
282
283  // Add some more data.
284  add_section_data (elf, DATA, DATA_LEN);
285  check_section_size (elf, 2 * DATA_LEN);
286  check_section_data (elf, DATA, DATA_LEN, 2);
287
288  // And some more.
289  add_section_data (elf, DATA, DATA_LEN);
290  check_section_size (elf, 3 * DATA_LEN);
291  check_section_data (elf, DATA, DATA_LEN, 3);
292
293  if (elf_end (elf) != 0)
294    {
295      printf ("failure in elf_end: %s\n", elf_errmsg (-1));
296      exit (1);
297    }
298
299  close (fd);
300
301  // Read the ELF from disk now.  And add new data after raw reading.
302  fd = open (fname, O_RDONLY);
303  if (fd == -1)
304    {
305      printf ("cannot open `%s' read-only: %s\n", fname, strerror (errno));
306      exit (1);
307    }
308
309  elf = read_elf (fd, use_mmap);
310  check_section_size (elf, DATA_LEN);
311  // But don't check contents, that would read the data...
312
313  // Get raw data before adding new data.
314  Elf_Scn *scn = elf_getscn (elf, 1);
315  if (scn == NULL)
316    {
317      printf ("couldn't get data section: %s\n", elf_errmsg (-1));
318      exit (1);
319    }
320
321  printf ("elf_rawdata\n");
322  Elf_Data *data = elf_rawdata (scn, NULL);
323  if (data == NULL)
324    {
325      printf ("couldn't get raw data from section: %s\n", elf_errmsg (-1));
326      exit (1);
327    }
328
329  if (data->d_size != DATA_LEN)
330    {
331      printf ("Unexpected Elf_Data: %zd", data->d_size);
332      exit (1);
333    }
334
335  // Now add more data.
336  add_section_data (elf, DATA, DATA_LEN);
337  check_section_size (elf, 2 * DATA_LEN);
338  check_section_data (elf, DATA, DATA_LEN, 2);
339
340  // And some more.
341  add_section_data (elf, DATA, DATA_LEN);
342  check_section_size (elf, 3 * DATA_LEN);
343  check_section_data (elf, DATA, DATA_LEN, 3);
344
345  if (elf_end (elf) != 0)
346    {
347      printf ("failure in elf_end: %s\n", elf_errmsg (-1));
348      exit (1);
349    }
350
351  close (fd);
352
353  // Read the ELF from disk now.  And add new data after data reading.
354  fd = open (fname, O_RDONLY);
355  if (fd == -1)
356    {
357      printf ("cannot open `%s' read-only: %s\n", fname, strerror (errno));
358      exit (1);
359    }
360
361  elf = read_elf (fd, use_mmap);
362  check_section_size (elf, DATA_LEN);
363  // Get (converted) data before adding new data.
364  check_section_data (elf, DATA, DATA_LEN, 1);
365
366  printf ("elf_getdata\n");
367
368  // Now add more data.
369  add_section_data (elf, DATA, DATA_LEN);
370  check_section_size (elf, 2 * DATA_LEN);
371  check_section_data (elf, DATA, DATA_LEN, 2);
372
373  // And some more.
374  add_section_data (elf, DATA, DATA_LEN);
375  check_section_size (elf, 3 * DATA_LEN);
376  check_section_data (elf, DATA, DATA_LEN, 3);
377
378  if (elf_end (elf) != 0)
379    {
380      printf ("failure in elf_end: %s\n", elf_errmsg (-1));
381      exit (1);
382    }
383
384  close (fd);
385
386  unlink (fname);
387}
388
389int
390main (int argc __attribute__ ((unused)), char *argv[] __attribute__ ((unused)))
391{
392  // Initialize libelf.
393  elf_version (EV_CURRENT);
394
395  // Fill holes with something non-zero to more easily spot bad data.
396  elf_fill ('X');
397
398  check_elf (ELFCLASS32, 0);
399  check_elf (ELFCLASS32, 1);
400  check_elf (ELFCLASS64, 0);
401  check_elf (ELFCLASS64, 1);
402
403  return 0;
404}
405