xref: /third_party/elfutils/tests/emptyfile.c (revision da0c48c4)
1/* Test program for adding a section to an empty ELF file.
2   Copyright (C) 2016 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
19#ifdef HAVE_CONFIG_H
20# include <config.h>
21#endif
22
23#include <errno.h>
24#include <fcntl.h>
25#include <inttypes.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <unistd.h>
30#include "system.h"
31
32#include ELFUTILS_HEADER(elf)
33#include <gelf.h>
34
35
36/* Index of last string added.  Returned by add_string ().  */
37static size_t stridx = 0;
38
39/* Adds a string and returns the offset in the section.  */
40static size_t
41add_string (Elf_Scn *scn, char *str)
42{
43  size_t lastidx = stridx;
44  size_t size = strlen (str) + 1;
45
46  Elf_Data *data = elf_newdata (scn);
47  if (data == NULL)
48    {
49      printf ("cannot create data SHSTRTAB section: %s\n", elf_errmsg (-1));
50      exit (1);
51    }
52
53  data->d_buf = str;
54  data->d_type = ELF_T_BYTE;
55  data->d_size = size;
56  data->d_align = 1;
57  data->d_version = EV_CURRENT;
58
59  stridx += size;
60  printf ("add_string: '%s', stridx: %zd, lastidx: %zd\n",
61	  str, stridx, lastidx);
62  return lastidx;
63}
64
65static void
66check_elf (const char *fname, int class, int use_mmap)
67{
68  printf ("\nfname: %s\n", fname);
69  stridx = 0; // Reset strtab strings index
70
71  int fd = open (fname, O_RDWR | O_CREAT | O_TRUNC, DEFFILEMODE);
72  if (fd == -1)
73    {
74      printf ("cannot open `%s': %s\n", fname, strerror (errno));
75      exit (1);
76    }
77
78  Elf *elf = elf_begin (fd, use_mmap ? ELF_C_WRITE_MMAP : ELF_C_WRITE, NULL);
79  if (elf == NULL)
80    {
81      printf ("cannot create ELF descriptor: %s\n", elf_errmsg (-1));
82      exit (1);
83    }
84
85  // Create an ELF header.
86  if (gelf_newehdr (elf, class) == 0)
87    {
88      printf ("cannot create ELF header: %s\n", elf_errmsg (-1));
89      exit (1);
90    }
91
92  GElf_Ehdr ehdr_mem;
93  GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
94  if (ehdr == NULL)
95    {
96      printf ("cannot get ELF header: %s\n", elf_errmsg (-1));
97      exit (1);
98    }
99
100  // Initialize header.
101  ehdr->e_ident[EI_DATA] = class == ELFCLASS64 ? ELFDATA2LSB : ELFDATA2MSB;
102  ehdr->e_ident[EI_OSABI] = ELFOSABI_GNU;
103  ehdr->e_type = ET_NONE;
104  ehdr->e_machine = EM_X86_64;
105  ehdr->e_version = EV_CURRENT;
106
107  if (gelf_update_ehdr (elf, ehdr) == 0)
108    {
109      printf ("cannot update ELF header: %s\n", elf_errmsg (-1));
110      exit (1);
111    }
112
113  // Write everything to disk.
114  if (elf_update (elf, ELF_C_WRITE) < 0)
115    {
116      printf ("failure in elf_update(WRITE): %s\n", elf_errmsg (-1));
117      exit (1);
118    }
119
120  if (elf_end (elf) != 0)
121    {
122      printf ("failure in elf_end: %s\n", elf_errmsg (-1));
123      exit (1);
124    }
125
126  close (fd);
127
128  /* Reread the ELF from disk now.  */
129  fd = open (fname, O_RDWR);
130  if (fd == -1)
131    {
132      printf ("cannot (re)open `%s': %s\n", fname, strerror (errno));
133      exit (1);
134    }
135
136  elf = elf_begin (fd, use_mmap ? ELF_C_RDWR_MMAP : ELF_C_RDWR, NULL);
137  if (elf == NULL)
138    {
139      printf ("cannot create ELF descriptor read-only: %s\n", elf_errmsg (-1));
140      exit (1);
141    }
142
143  // There are no sections yet.
144  if (elf_nextscn (elf, NULL) != NULL)
145    {
146      printf ("Empty elf had a section???\n");
147      exit (1);
148    }
149
150  // Create strtab section.
151  Elf_Scn *scn = elf_newscn (elf);
152  if (scn == NULL)
153    {
154      printf ("cannot create strings section: %s\n", elf_errmsg (-1));
155      exit (1);
156    }
157
158  // Add an empty string to the table as NUL entry for section zero.
159  add_string (scn, "");
160
161  GElf_Shdr shdr_mem;
162  GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
163  if (shdr == NULL)
164    {
165      printf ("cannot get header for strings section: %s\n", elf_errmsg (-1));
166      exit (1);
167    }
168
169  shdr->sh_type = SHT_STRTAB;
170  shdr->sh_flags = 0;
171  shdr->sh_addr = 0;
172  shdr->sh_link = SHN_UNDEF;
173  shdr->sh_info = SHN_UNDEF;
174  shdr->sh_addralign = 1;
175  shdr->sh_entsize = 0;
176  shdr->sh_name = add_string (scn, ".strtab");
177
178  // We have to store the section strtab index in the ELF header.
179  // So sections have actual names.
180  int ndx = elf_ndxscn (scn);
181  ehdr->e_shstrndx = ndx;
182
183  if (gelf_update_ehdr (elf, ehdr) == 0)
184    {
185      printf ("cannot update ELF header: %s\n", elf_errmsg (-1));
186      exit (1);
187    }
188
189  // Finished strtab section, update the header.
190  if (gelf_update_shdr (scn, shdr) == 0)
191    {
192      printf ("cannot update STRTAB section header: %s\n", elf_errmsg (-1));
193      exit (1);
194    }
195
196  // Write everything to disk.
197  if (elf_update (elf, ELF_C_WRITE) < 0)
198    {
199      printf ("failure in elf_update(WRITE): %s\n", elf_errmsg (-1));
200      exit (1);
201    }
202
203  if (elf_end (elf) != 0)
204    {
205      printf ("failure in elf_end: %s\n", elf_errmsg (-1));
206      exit (1);
207    }
208
209  close (fd);
210
211  // And read it in one last time.
212  fd = open (fname, O_RDONLY);
213  if (fd == -1)
214    {
215      printf ("cannot open `%s' read-only: %s\n", fname, strerror (errno));
216      exit (1);
217    }
218
219  elf = elf_begin (fd, use_mmap ? ELF_C_READ_MMAP : ELF_C_READ, NULL);
220  if (elf == NULL)
221    {
222      printf ("cannot create ELF descriptor read-only: %s\n", elf_errmsg (-1));
223      exit (1);
224    }
225
226  // Is our new section there?
227  scn = elf_nextscn (elf, NULL);
228  if (scn == NULL)
229    {
230      printf ("cannot get new section: %s\n", elf_errmsg (-1));
231      exit (1);
232    }
233
234  shdr = gelf_getshdr (scn, &shdr_mem);
235  if (shdr == NULL)
236    {
237      printf ("cannot get header for new section: %s\n", elf_errmsg (-1));
238      exit (1);
239    }
240
241  size_t shstrndx;
242  if (elf_getshdrstrndx (elf, &shstrndx) < 0)
243    {
244      printf ("elf_getshdrstrndx: %s\n", elf_errmsg (-1));
245      exit (1);
246    }
247
248  const char *sname = elf_strptr (elf, shstrndx, shdr->sh_name);
249  if (sname == NULL || strcmp (sname, ".strtab") != 0)
250    {
251      printf ("Bad section name: %s\n", sname);
252      exit (1);
253    }
254
255  if (elf_end (elf) != 0)
256    {
257      printf ("failure in elf_end: %s\n", elf_errmsg (-1));
258      exit (1);
259    }
260
261  close (fd);
262
263  unlink (fname);
264}
265
266int
267main (int argc __attribute__ ((unused)),
268      char *argv[] __attribute__ ((unused)))
269{
270  elf_version (EV_CURRENT);
271
272  check_elf ("empty.elf.32", ELFCLASS32, 0);
273  check_elf ("empty.elf.32.mmap", ELFCLASS32, 1);
274  check_elf ("empty.elf.64", ELFCLASS64, 0);
275  check_elf ("empty.elf.64.mmap", ELFCLASS64, 1);
276
277  return 0;
278}
279