xref: /third_party/elfutils/tests/elfstrtab.c (revision da0c48c4)
1/* Test program for elf_strptr 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
35/* Index of last string added.  Returned by add_string ().  */
36static size_t stridx = 0;
37
38/* Some random strings.  */
39static char *str1;
40static size_t str1_off;
41static char *str2;
42static size_t str2_off;
43static char *str3;
44static size_t str3_off;
45
46/* First three strings we write out. They should always be there.  */
47static char *orig_str1;
48static size_t orig_str1_off;
49static char *orig_str2;
50static size_t orig_str2_off;
51static char *orig_str3;
52static size_t orig_str3_off;
53
54static void
55check_orig_strings (Elf *elf, int ndx, const char *msg)
56{
57  printf ("checking orig strings: %s\n", msg);
58
59  const char *str = elf_strptr (elf, ndx, 0);
60  printf ("\t'%s'\n", str);
61  if (str == NULL || strcmp ("", str) != 0)
62    exit (1);
63
64  str = elf_strptr (elf, ndx, 1);
65  printf ("\t'%s'\n", str);
66  if (str == NULL || strcmp (".strings", str) != 0)
67    exit (1);
68
69  str = elf_strptr (elf, ndx, orig_str1_off);
70  printf ("\t'%s'\n", str);
71  if (str == NULL || strcmp (orig_str1, str) != 0)
72    exit (1);
73
74  str = elf_strptr (elf, ndx, orig_str2_off);
75  printf ("\t'%s'\n", str);
76  if (str == NULL || strcmp (orig_str2, str) != 0)
77    exit (1);
78
79  str = elf_strptr (elf, ndx, orig_str3_off);
80  printf ("\t'%s'\n", str);
81  if (str == NULL || strcmp (orig_str3, str) != 0)
82    exit (1);
83}
84
85static void
86check_strings (Elf *elf, int ndx, const char *msg)
87{
88  check_orig_strings (elf, ndx, msg);
89
90  const char *str = elf_strptr (elf, ndx, str1_off);
91  printf ("\t'%s'\n", str);
92  if (str == NULL || strcmp (str1, str) != 0)
93    exit (1);
94
95  str = elf_strptr (elf, ndx, str2_off);
96  printf ("\t'%s'\n", str);
97  if (str == NULL || strcmp (str2, str) != 0)
98    exit (1);
99
100  str = elf_strptr (elf, ndx, str3_off);
101  printf ("\t'%s'\n", str);
102  if (str == NULL || strcmp (str3, str) != 0)
103    exit (1);
104}
105
106/* Adds a string and returns the offset in the section.  */
107static size_t
108add_string (Elf_Scn *scn, char *str)
109{
110  size_t lastidx = stridx;
111  size_t size = strlen (str) + 1;
112
113  Elf_Data *data = elf_newdata (scn);
114  if (data == NULL)
115    {
116      printf ("cannot create data SHSTRTAB section: %s\n", elf_errmsg (-1));
117      exit (1);
118    }
119
120  data->d_buf = str;
121  data->d_type = ELF_T_BYTE;
122  data->d_size = size;
123  data->d_align = 1;
124  data->d_version = EV_CURRENT;
125
126  stridx += size;
127  printf ("add_string: '%s', stridx: %zd, lastidx: %zd\n",
128	  str, stridx, lastidx);
129  return lastidx;
130}
131
132static void
133check_elf (const char *fname, int class, int use_mmap)
134{
135  printf ("\nfname: %s\n", fname);
136  stridx = 0;
137
138  int fd = open (fname, O_RDWR | O_CREAT | O_TRUNC, DEFFILEMODE);
139  if (fd == -1)
140    {
141      printf ("cannot open `%s': %s\n", fname, strerror (errno));
142      exit (1);
143    }
144
145  Elf *elf = elf_begin (fd, use_mmap ? ELF_C_WRITE_MMAP : ELF_C_WRITE, NULL);
146  if (elf == NULL)
147    {
148      printf ("cannot create ELF descriptor: %s\n", elf_errmsg (-1));
149      exit (1);
150    }
151
152  // Create an ELF header.
153  if (gelf_newehdr (elf, class) == 0)
154    {
155      printf ("cannot create ELF header: %s\n", elf_errmsg (-1));
156      exit (1);
157    }
158
159  GElf_Ehdr ehdr_mem;
160  GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
161  if (ehdr == NULL)
162    {
163      printf ("cannot get ELF header: %s\n", elf_errmsg (-1));
164      exit (1);
165    }
166
167  // Initialize header.
168  ehdr->e_ident[EI_DATA] = class == ELFCLASS64 ? ELFDATA2LSB : ELFDATA2MSB;
169  ehdr->e_ident[EI_OSABI] = ELFOSABI_GNU;
170  ehdr->e_type = ET_NONE;
171  ehdr->e_machine = EM_X86_64;
172  ehdr->e_version = EV_CURRENT;
173
174  // Create strings section.
175  Elf_Scn *scn = elf_newscn (elf);
176  if (scn == NULL)
177    {
178      printf ("cannot create strings section: %s\n", elf_errmsg (-1));
179      exit (1);
180    }
181
182  // Add an empty string to the table as NUL entry for section zero.
183  add_string (scn, "");
184
185  GElf_Shdr shdr_mem;
186  GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
187  if (shdr == NULL)
188    {
189      printf ("cannot get header for strings section: %s\n", elf_errmsg (-1));
190      exit (1);
191    }
192
193  shdr->sh_type = SHT_STRTAB;
194  shdr->sh_flags = 0;
195  shdr->sh_addr = 0;
196  shdr->sh_link = SHN_UNDEF;
197  shdr->sh_info = SHN_UNDEF;
198  shdr->sh_addralign = 1;
199  shdr->sh_entsize = 0;
200  shdr->sh_name = add_string (scn, ".strings");
201
202  // We have to store the section strtab index in the ELF header.
203  // So sections have actual names.
204  int ndx = elf_ndxscn (scn);
205  ehdr->e_shstrndx = ndx;
206
207  if (gelf_update_ehdr (elf, ehdr) == 0)
208    {
209      printf ("cannot update ELF header: %s\n", elf_errmsg (-1));
210      exit (1);
211    }
212
213  // Add some random strings. These are the original ones. They should
214  // always be there (together with the empty "" and .strings section
215  // name strings.
216  orig_str1 = "elfutils";
217  orig_str1_off = add_string (scn, orig_str1);
218  orig_str2 = "strtabelf";
219  orig_str2_off = add_string (scn, orig_str2);
220  orig_str3 = "three";
221  orig_str3_off = add_string (scn, orig_str3);
222
223  // Finished strings section, update the header.
224  if (gelf_update_shdr (scn, shdr) == 0)
225    {
226      printf ("cannot update STRTAB section header: %s\n", elf_errmsg (-1));
227      exit (1);
228    }
229
230  // Let the library compute the internal structure information.
231  if (elf_update (elf, ELF_C_NULL) < 0)
232    {
233      printf ("failure in elf_update(NULL): %s\n", elf_errmsg (-1));
234      exit (1);
235    }
236
237  // Check our strings are there.
238  check_orig_strings (elf, ndx, "first elf_update, before write");
239
240  // Write everything to disk.
241  if (elf_update (elf, ELF_C_WRITE) < 0)
242    {
243      printf ("failure in elf_update(WRITE): %s\n", elf_errmsg (-1));
244      exit (1);
245    }
246
247  // Check out strings are there.
248  check_orig_strings (elf, ndx, "first elf_update, after write");
249
250  // Add some more random strings.  These will not be written to disk.
251  scn = elf_getscn (elf, ndx);
252  if (scn == NULL)
253    {
254      printf ("couldn't re-get strings section: %s\n", elf_errmsg (-1));
255      exit (1);
256    }
257
258  str1 = "elfutils2";
259  str1_off = add_string (scn, str1);
260  str2 = "strtabelf2";
261  str2_off = add_string (scn, str2);
262  str3 = "three2";
263  str3_off = add_string (scn, str3);
264
265  // Update internal structure information again.
266  if (elf_update (elf, ELF_C_NULL) < 0)
267    {
268      printf ("failure in re-elf_update(NULL): %s\n", elf_errmsg (-1));
269      exit (1);
270    }
271
272  // Check our new strings are there.
273  check_strings (elf, ndx, "first extra strings");
274
275  if (elf_end (elf) != 0)
276    {
277      printf ("failure in elf_end: %s\n", elf_errmsg (-1));
278      exit (1);
279    }
280
281  close (fd);
282
283  /* Read the ELF from disk now.  */
284  fd = open (fname, O_RDWR);
285  if (fd == -1)
286    {
287      printf ("cannot open `%s' read-only: %s\n", fname, strerror (errno));
288      exit (1);
289    }
290
291  elf = elf_begin (fd, use_mmap ? ELF_C_RDWR_MMAP : ELF_C_RDWR, NULL);
292  if (elf == NULL)
293    {
294      printf ("cannot create ELF descriptor read-only: %s\n", elf_errmsg (-1));
295      exit (1);
296    }
297
298  /* Are our strings there?  */
299  check_orig_strings (elf, ndx, "read ELF file, orig strings");
300
301  // Add some more random strings.
302  scn = elf_getscn (elf, ndx);
303  if (scn == NULL)
304    {
305      printf ("couldn't re-get strings section: %s\n", elf_errmsg (-1));
306      exit (1);
307    }
308
309  shdr = gelf_getshdr (scn, &shdr_mem);
310  if (shdr == NULL)
311    {
312      printf ("cannot get header for strings section: %s\n", elf_errmsg (-1));
313      exit (1);
314    }
315
316  // Reset stridx to end of section.
317  printf ("sh_size: %" PRIu64 "\n", shdr->sh_size);
318  stridx = shdr->sh_size;
319
320  str1 = "0123456789";
321  str1_off = add_string (scn, str1);
322  str2 = "supercalifragilisticexpialidocious";
323  str2_off = add_string (scn, str2);
324  str3 = "forty-two";
325  str3_off = add_string (scn, str3);
326
327  // Update internal structure information.
328  if (elf_update (elf, ELF_C_NULL) < 0)
329    {
330      printf ("failure in rw-elf_update(NULL): %s\n", elf_errmsg (-1));
331      exit (1);
332    }
333
334  /* Check our new strings are there.  */
335  check_strings (elf, ndx, "read file, added strings");
336
337  // Write updated ELF file.
338  if (elf_update (elf, ELF_C_WRITE) < 0)
339    {
340      printf ("failure in re-elf_update(NULL): %s\n", elf_errmsg (-1));
341      exit (1);
342    }
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  // And read it in one last time.
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 = elf_begin (fd, use_mmap ? ELF_C_READ_MMAP : ELF_C_READ, NULL);
361  if (elf == NULL)
362    {
363      printf ("cannot create ELF descriptor read-only: %s\n", elf_errmsg (-1));
364      exit (1);
365    }
366
367  /* Are all our strings there?  */
368  check_strings (elf, ndx, "all together now");
369
370  if (elf_end (elf) != 0)
371    {
372      printf ("failure in elf_end: %s\n", elf_errmsg (-1));
373      exit (1);
374    }
375
376  close (fd);
377
378  unlink (fname);
379}
380
381int
382main (int argc __attribute__ ((unused)), char *argv[] __attribute__ ((unused)))
383{
384  elf_version (EV_CURRENT);
385
386  // Fill holes with something non-zero to more easily spot
387  // unterminated strings.
388  elf_fill ('X');
389
390  check_elf ("strtab.elf.32", ELFCLASS32, 0);
391  check_elf ("strtab.elf.32.mmap", ELFCLASS32, 1);
392  check_elf ("strtab.elf.64", ELFCLASS64, 0);
393  check_elf ("strtab.elf.64.mmap", ELFCLASS64, 1);
394
395  return 0;
396}
397
398