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 (). */
36 static size_t stridx = 0;
37
38 /* Some random strings. */
39 static char *str1;
40 static size_t str1_off;
41 static char *str2;
42 static size_t str2_off;
43 static char *str3;
44 static size_t str3_off;
45
46 /* First three strings we write out. They should always be there. */
47 static char *orig_str1;
48 static size_t orig_str1_off;
49 static char *orig_str2;
50 static size_t orig_str2_off;
51 static char *orig_str3;
52 static size_t orig_str3_off;
53
54 static void
check_orig_strings(Elf * elf,int ndx,const char * msg)55 check_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
85 static void
check_strings(Elf * elf,int ndx,const char * msg)86 check_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. */
107 static size_t
add_string(Elf_Scn * scn,char * str)108 add_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
132 static void
check_elf(const char * fname,int class,int use_mmap)133 check_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
381 int
main(int argc,char * argv[])382 main (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