1/* Test program for elf_newdata 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// Random data string (16 bytes). 35static char *DATA = "123456789ABCDEF"; 36static size_t DATA_LEN = 16; 37 38static void 39add_section_data (Elf *elf, char *buf, size_t len) 40{ 41 printf ("Adding %zd bytes.\n", len); 42 43 Elf_Scn *scn = elf_getscn (elf, 1); 44 if (scn == NULL) 45 { 46 printf ("couldn't get data section: %s\n", elf_errmsg (-1)); 47 exit (1); 48 } 49 50 Elf_Data *data = elf_newdata (scn); 51 if (data == NULL) 52 { 53 printf ("cannot create newdata for section: %s\n", elf_errmsg (-1)); 54 exit (1); 55 } 56 57 data->d_buf = buf; 58 data->d_type = ELF_T_BYTE; 59 data->d_size = len; 60 data->d_align = 1; 61 data->d_version = EV_CURRENT; 62 63 // Let the library compute the internal structure information. 64 if (elf_update (elf, ELF_C_NULL) < 0) 65 { 66 printf ("failure in elf_update(NULL): %s\n", elf_errmsg (-1)); 67 exit (1); 68 } 69 70} 71 72static Elf * 73create_elf (int fd, int class, int use_mmap) 74{ 75 Elf *elf = elf_begin (fd, use_mmap ? ELF_C_WRITE_MMAP : ELF_C_WRITE, NULL); 76 if (elf == NULL) 77 { 78 printf ("cannot create ELF descriptor: %s\n", elf_errmsg (-1)); 79 exit (1); 80 } 81 82 // Create an ELF header. 83 if (gelf_newehdr (elf, class) == 0) 84 { 85 printf ("cannot create ELF header: %s\n", elf_errmsg (-1)); 86 exit (1); 87 } 88 89 GElf_Ehdr ehdr_mem; 90 GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem); 91 if (ehdr == NULL) 92 { 93 printf ("cannot get ELF header: %s\n", elf_errmsg (-1)); 94 exit (1); 95 } 96 97 // Initialize header. 98 ehdr->e_ident[EI_DATA] = class == ELFCLASS32 ? ELFDATA2LSB : ELFDATA2MSB; 99 ehdr->e_ident[EI_OSABI] = ELFOSABI_GNU; 100 ehdr->e_type = ET_NONE; 101 ehdr->e_machine = class == ELFCLASS32 ? EM_PPC : EM_X86_64; 102 ehdr->e_version = EV_CURRENT; 103 104 // Update the ELF header. 105 if (gelf_update_ehdr (elf, ehdr) == 0) 106 { 107 printf ("cannot update ELF header: %s\n", elf_errmsg (-1)); 108 exit (1); 109 } 110 111 // Create a section. 112 Elf_Scn *scn = elf_newscn (elf); 113 if (scn == NULL) 114 { 115 printf ("cannot create new section: %s\n", elf_errmsg (-1)); 116 exit (1); 117 } 118 119 GElf_Shdr shdr_mem; 120 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); 121 if (shdr == NULL) 122 { 123 printf ("cannot get header for data section: %s\n", elf_errmsg (-1)); 124 exit (1); 125 } 126 127 shdr->sh_type = SHT_PROGBITS; 128 shdr->sh_flags = 0; 129 shdr->sh_addr = 0; 130 shdr->sh_link = SHN_UNDEF; 131 shdr->sh_info = SHN_UNDEF; 132 shdr->sh_addralign = 1; 133 shdr->sh_entsize = 1; 134 shdr->sh_name = 0; 135 136 // Finish section, update the header. 137 if (gelf_update_shdr (scn, shdr) == 0) 138 { 139 printf ("cannot update header for DATA section: %s\n", elf_errmsg (-1)); 140 exit (1); 141 } 142 143 // Add some data to the section. 144 add_section_data (elf, DATA, DATA_LEN); 145 146 // Write everything to disk. 147 if (elf_update (elf, ELF_C_WRITE) < 0) 148 { 149 printf ("failure in elf_update(WRITE): %s\n", elf_errmsg (-1)); 150 exit (1); 151 } 152 153 return elf; 154} 155 156static Elf * 157read_elf (int fd, int use_mmap) 158{ 159 printf ("Reading ELF file\n"); 160 Elf *elf = elf_begin (fd, use_mmap ? ELF_C_RDWR_MMAP : ELF_C_RDWR, NULL); 161 if (elf == NULL) 162 { 163 printf ("cannot create ELF descriptor read-again: %s\n", elf_errmsg (-1)); 164 exit (1); 165 } 166 167 return elf; 168} 169 170static void 171check_section_size (Elf *elf, size_t size) 172{ 173 Elf_Scn *scn = elf_getscn (elf, 1); 174 if (scn == NULL) 175 { 176 printf ("couldn't get data section: %s\n", elf_errmsg (-1)); 177 exit (1); 178 } 179 180 GElf_Shdr shdr_mem; 181 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); 182 if (shdr == NULL) 183 { 184 printf ("cannot get header for DATA section: %s\n", elf_errmsg (-1)); 185 exit (1); 186 } 187 188 if (shdr->sh_size == size) 189 printf ("OK %zd bytes.\n", size); 190 else 191 { 192 printf ("BAD size, expected %zd, got %" PRIu64 "\n", 193 size, shdr->sh_size); 194 exit (-1); 195 } 196} 197 198static void 199check_section_data (Elf *elf, char *data, size_t len, size_t times) 200{ 201 Elf_Scn *scn = elf_getscn (elf, 1); 202 if (scn == NULL) 203 { 204 printf ("couldn't get data section: %s\n", elf_errmsg (-1)); 205 exit (1); 206 } 207 208 Elf_Data *d = NULL; 209 for (size_t i = 0; i < times; i++) 210 { 211 if (d == NULL || i * len >= d->d_off + d->d_size) 212 { 213 d = elf_getdata (scn, d); 214 if (d == NULL) 215 { 216 printf ("cannot get data for section item %zd: %s\n", 217 i, elf_errmsg (-1)); 218 exit (1); 219 } 220 else 221 printf ("OK, section data item %zd (d_off: %" PRId64 222 ", d_size: %zd)\n", i, d->d_off, d->d_size); 223 } 224 char *d_data = (char *) d->d_buf + (len * i) - d->d_off; 225 printf ("%zd data (d_off: %" PRId64 226 ", len * i: %zd): (%p + %" PRId64 ") %s\n", 227 i, d->d_off, len * i, d->d_buf, (len * i) - d->d_off, d_data); 228 if (memcmp (data, d_data, len) != 0) 229 { 230 printf ("Got bad data in section for item %zd.\n", i); 231 exit (1); 232 } 233 } 234} 235 236static void 237check_elf (int class, int use_mmap) 238{ 239 static const char *fname; 240 if (class == ELFCLASS32) 241 fname = use_mmap ? "newdata.elf32.mmap" : "newdata.elf32"; 242 else 243 fname = use_mmap ? "newdata.elf64.mmap" : "newdata.elf64"; 244 245 printf ("\ncheck_elf: %s\n", fname); 246 247 int fd = open (fname, O_RDWR|O_CREAT|O_TRUNC, DEFFILEMODE); 248 if (fd == -1) 249 { 250 printf ("cannot create `%s': %s\n", fname, strerror (errno)); 251 exit (1); 252 } 253 254 Elf *elf = create_elf (fd, class, use_mmap); 255 check_section_size (elf, DATA_LEN); 256 check_section_data (elf, DATA, DATA_LEN, 1); 257 258 // Add some more data (won't be written to disk). 259 add_section_data (elf, DATA, DATA_LEN); 260 check_section_size (elf, 2 * DATA_LEN); 261 check_section_data (elf, DATA, DATA_LEN, 2); 262 263 if (elf_end (elf) != 0) 264 { 265 printf ("failure in elf_end: %s\n", elf_errmsg (-1)); 266 exit (1); 267 } 268 269 close (fd); 270 271 // Read the ELF from disk now. And add new data directly. 272 fd = open (fname, O_RDONLY); 273 if (fd == -1) 274 { 275 printf ("cannot open `%s' read-only: %s\n", fname, strerror (errno)); 276 exit (1); 277 } 278 279 elf = read_elf (fd, use_mmap); 280 check_section_size (elf, DATA_LEN); 281 // But don't check contents, that would read the data... 282 283 // Add some more data. 284 add_section_data (elf, DATA, DATA_LEN); 285 check_section_size (elf, 2 * DATA_LEN); 286 check_section_data (elf, DATA, DATA_LEN, 2); 287 288 // And some more. 289 add_section_data (elf, DATA, DATA_LEN); 290 check_section_size (elf, 3 * DATA_LEN); 291 check_section_data (elf, DATA, DATA_LEN, 3); 292 293 if (elf_end (elf) != 0) 294 { 295 printf ("failure in elf_end: %s\n", elf_errmsg (-1)); 296 exit (1); 297 } 298 299 close (fd); 300 301 // Read the ELF from disk now. And add new data after raw reading. 302 fd = open (fname, O_RDONLY); 303 if (fd == -1) 304 { 305 printf ("cannot open `%s' read-only: %s\n", fname, strerror (errno)); 306 exit (1); 307 } 308 309 elf = read_elf (fd, use_mmap); 310 check_section_size (elf, DATA_LEN); 311 // But don't check contents, that would read the data... 312 313 // Get raw data before adding new data. 314 Elf_Scn *scn = elf_getscn (elf, 1); 315 if (scn == NULL) 316 { 317 printf ("couldn't get data section: %s\n", elf_errmsg (-1)); 318 exit (1); 319 } 320 321 printf ("elf_rawdata\n"); 322 Elf_Data *data = elf_rawdata (scn, NULL); 323 if (data == NULL) 324 { 325 printf ("couldn't get raw data from section: %s\n", elf_errmsg (-1)); 326 exit (1); 327 } 328 329 if (data->d_size != DATA_LEN) 330 { 331 printf ("Unexpected Elf_Data: %zd", data->d_size); 332 exit (1); 333 } 334 335 // Now add more data. 336 add_section_data (elf, DATA, DATA_LEN); 337 check_section_size (elf, 2 * DATA_LEN); 338 check_section_data (elf, DATA, DATA_LEN, 2); 339 340 // And some more. 341 add_section_data (elf, DATA, DATA_LEN); 342 check_section_size (elf, 3 * DATA_LEN); 343 check_section_data (elf, DATA, DATA_LEN, 3); 344 345 if (elf_end (elf) != 0) 346 { 347 printf ("failure in elf_end: %s\n", elf_errmsg (-1)); 348 exit (1); 349 } 350 351 close (fd); 352 353 // Read the ELF from disk now. And add new data after data reading. 354 fd = open (fname, O_RDONLY); 355 if (fd == -1) 356 { 357 printf ("cannot open `%s' read-only: %s\n", fname, strerror (errno)); 358 exit (1); 359 } 360 361 elf = read_elf (fd, use_mmap); 362 check_section_size (elf, DATA_LEN); 363 // Get (converted) data before adding new data. 364 check_section_data (elf, DATA, DATA_LEN, 1); 365 366 printf ("elf_getdata\n"); 367 368 // Now add more data. 369 add_section_data (elf, DATA, DATA_LEN); 370 check_section_size (elf, 2 * DATA_LEN); 371 check_section_data (elf, DATA, DATA_LEN, 2); 372 373 // And some more. 374 add_section_data (elf, DATA, DATA_LEN); 375 check_section_size (elf, 3 * DATA_LEN); 376 check_section_data (elf, DATA, DATA_LEN, 3); 377 378 if (elf_end (elf) != 0) 379 { 380 printf ("failure in elf_end: %s\n", elf_errmsg (-1)); 381 exit (1); 382 } 383 384 close (fd); 385 386 unlink (fname); 387} 388 389int 390main (int argc __attribute__ ((unused)), char *argv[] __attribute__ ((unused))) 391{ 392 // Initialize libelf. 393 elf_version (EV_CURRENT); 394 395 // Fill holes with something non-zero to more easily spot bad data. 396 elf_fill ('X'); 397 398 check_elf (ELFCLASS32, 0); 399 check_elf (ELFCLASS32, 1); 400 check_elf (ELFCLASS64, 0); 401 check_elf (ELFCLASS64, 1); 402 403 return 0; 404} 405