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