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