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