1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 29 /* 30 * dcom: Delete Comment 31 * 32 * This program demonstrates the use of libelf interface to 33 * copy the contents of one ELF file to create a new one. 34 * dcom creates a new ELF file using elf_begin(ELF_C_WRITE). 35 * 36 * In order to delete a section from an ELF file you must 37 * instead create a new ELF file and copy all but the 'selected' 38 * sections to the new ELF file. This is because libelf is 39 * unable to delete any sections from an ELF file, it can 40 * only add them. 41 * 42 * NOTE: While this program works fine for simple ELF objects, 43 * as they get more complex it may not properly update all of the 44 * fields required. This program is *only* an example of how 45 * to do this and not a complete program in itself. 46 */ 47 48 49 #include <stdio.h> 50 #include <libelf.h> 51 #include <gelf.h> 52 #include <fcntl.h> 53 #include <string.h> 54 #include <stdlib.h> 55 #include <unistd.h> 56 #include <sys/types.h> 57 #include <sys/stat.h> 58 #include <sys/param.h> 59 60 61 static const char *CommentStr = ".comment"; 62 63 /* 64 * Build a temporary file name that is in the 65 * same directory as the elf file being processed. 66 */ 67 static char * 68 mkname(const char *bname) 69 { 70 char *ptr; 71 char buffer[MAXPATHLEN]; 72 73 ptr = strcpy(buffer, bname); 74 ptr += strlen(buffer); 75 while (ptr >= buffer) { 76 if (*ptr == '/') { 77 *(ptr + 1) = '\0'; 78 break; 79 } 80 ptr--; 81 } 82 if (ptr < buffer) { 83 buffer[0] = '.'; 84 buffer[1] = '\0'; 85 } 86 return (tempnam(buffer, 0)); 87 } 88 89 90 91 static void 92 delete_comment(Elf *elf, int fd, const char *file) 93 { 94 GElf_Ehdr ehdr; 95 Elf_Scn *scn = 0; 96 char *tfile; 97 Elf *telf; 98 int tfd; 99 GElf_Ehdr tehdr; 100 GElf_Phdr phdr; 101 GElf_Phdr tphdr; 102 size_t shstrndx; 103 size_t shnum; 104 int *shndx; 105 int ndx = 1; 106 int off = 0; 107 struct stat sbuf; 108 109 if (gelf_getehdr(elf, &ehdr) == 0) { 110 (void) fprintf(stderr, "%s: elf_getehdr() failed: %s\n", 111 file, elf_errmsg(0)); 112 return; 113 } 114 115 if (elf_getshnum(elf, &shnum) == 0) { 116 (void) fprintf(stderr, "%s: elf_getshnum() failed: %s\n", 117 file, elf_errmsg(0)); 118 return; 119 } 120 121 if (elf_getshstrndx(elf, &shstrndx) == 0) { 122 (void) fprintf(stderr, "%s: elf_getshstrndx() failed: %s\n", 123 file, elf_errmsg(0)); 124 return; 125 } 126 127 /* 128 * shndx is an array used to map the current section 129 * indexes to the new section indexes. 130 */ 131 shndx = calloc(shnum, sizeof (int)); 132 133 while ((scn = elf_nextscn(elf, scn)) != 0) { 134 GElf_Shdr shdr; 135 136 /* 137 * Do a string compare to examine each section header 138 * to see if it is a ".comment" section. If it is then 139 * this is the section we want to process. 140 */ 141 if (gelf_getshdr(scn, &shdr) == 0) { 142 (void) fprintf(stderr, 143 "%s: elf_getshdr() failed: %s\n", 144 file, elf_errmsg(0)); 145 free(shndx); 146 return; 147 } 148 if (strcmp(CommentStr, elf_strptr(elf, shstrndx, 149 shdr.sh_name)) == 0) { 150 shndx[ndx] = -1; 151 off++; 152 153 /* 154 * If the .comment section is part of a loadable 155 * segment then it can not be delted from the 156 * ELF file. 157 */ 158 if (shdr.sh_addr != 0) { 159 (void) printf("%s: .comment section is " 160 "part of a loadable segment, it " 161 "cannot be deleted.\n", file); 162 free(shndx); 163 return; 164 } 165 } else 166 shndx[ndx] = ndx - off; 167 ndx++; 168 } 169 170 /* 171 * obtain a unique file name and open a file descriptor 172 * pointing to that file. 173 */ 174 tfile = mkname(file); 175 if ((tfd = open(tfile, O_RDWR | O_CREAT, 0600)) == -1) { 176 perror("temp open"); 177 return; 178 } 179 180 /* 181 * Create a new ELF to duplicate the ELF file into. 182 */ 183 if ((telf = elf_begin(tfd, ELF_C_WRITE, 0)) == 0) { 184 (void) fprintf(stderr, "elf_begin(ELF_C_WRITE) failed: %s\n", 185 elf_errmsg(0)); 186 return; 187 } 188 189 if (gelf_newehdr(telf, gelf_getclass(elf)) == 0) { 190 (void) fprintf(stderr, "%s: elf_newehdr() failed: %s\n", 191 file, elf_errmsg(0)); 192 free(shndx); 193 return; 194 } 195 if (gelf_getehdr(telf, &tehdr) == 0) { 196 (void) fprintf(stderr, "%s: elf_getehdr() failed: %s\n", 197 file, elf_errmsg(0)); 198 free(shndx); 199 return; 200 } 201 202 scn = 0; 203 ndx = 1; 204 while ((scn = elf_nextscn(elf, scn)) != 0) { 205 Elf_Scn * tscn; 206 Elf_Data * data; 207 Elf_Data * tdata; 208 GElf_Shdr shdr; 209 GElf_Shdr tshdr; 210 211 if (shndx[ndx] == -1) { 212 ndx++; 213 continue; 214 } 215 216 /* 217 * Duplicate all but the .comment section in the 218 * new file. 219 */ 220 if (gelf_getshdr(scn, &shdr) == 0) { 221 (void) fprintf(stderr, 222 "%s: elf_getshdr() failed: %s\n", 223 file, elf_errmsg(0)); 224 free(shndx); 225 return; 226 } 227 if ((tscn = elf_newscn(telf)) == 0) { 228 (void) fprintf(stderr, 229 "%s: elf_newscn() failed: %s\n", 230 file, elf_errmsg(0)); 231 free(shndx); 232 return; 233 } 234 if (gelf_getshdr(tscn, &tshdr) == 0) { 235 (void) fprintf(stderr, 236 "%s: elf_getshdr() failed: %s\n", 237 file, elf_errmsg(0)); 238 free(shndx); 239 return; 240 } 241 tshdr = shdr; 242 tshdr.sh_link = shndx[shdr.sh_link]; 243 244 /* 245 * The relocation sections sh_info field also contains 246 * a section index that needs to be adjusted. This is 247 * the only section who's sh_info field contains 248 * a section index according to the ABI. 249 * 250 * If their are non-ABI sections who's sh_info field 251 * contains section indexes they will not properly 252 * be updated by this routine. 253 */ 254 if (shdr.sh_type == SHT_REL) 255 tshdr.sh_info = shndx[ndx]; 256 257 /* 258 * Flush the changes to the underlying elf32 or elf64 259 * section header. 260 */ 261 gelf_update_shdr(tscn, &tshdr); 262 263 if ((data = elf_getdata(scn, 0)) == 0) { 264 (void) fprintf(stderr, 265 "%s: elf_getdata() failed: %s\n", 266 file, elf_errmsg(0)); 267 free(shndx); 268 return; 269 } 270 if ((tdata = elf_newdata(tscn)) == 0) { 271 (void) fprintf(stderr, 272 "%s: elf_newdata() failed: %s\n", 273 file, elf_errmsg(0)); 274 free(shndx); 275 return; 276 } 277 *tdata = *data; 278 ndx++; 279 } 280 281 tehdr = ehdr; 282 if (shndx[shstrndx] < SHN_LORESERVE) 283 tehdr.e_shstrndx = shndx[shstrndx]; 284 else { 285 Elf_Scn *_scn; 286 GElf_Shdr shdr0; 287 /* 288 * 'ELF Extended Sections' are enabled - we must 289 * store the shstrndx in Shdr[0].sh_link 290 */ 291 if ((_scn = elf_getscn(telf, 0)) == 0) { 292 (void) fprintf(stderr, 293 "%s: elf_getscn() failed: %s\n", 294 file, elf_errmsg(0)); 295 free(shndx); 296 return; 297 } 298 if (gelf_getshdr(_scn, &shdr0) == 0) { 299 (void) fprintf(stderr, 300 "%s: elf_getshdr() failed: %s\n", 301 file, elf_errmsg(0)); 302 free(shndx); 303 return; 304 } 305 tehdr.e_shstrndx = SHN_XINDEX; 306 shdr0.sh_link = shndx[shstrndx]; 307 gelf_update_shdr(_scn, &shdr0); 308 } 309 gelf_update_ehdr(telf, &tehdr); 310 311 free(shndx); 312 313 /* 314 * Duplicate all program headers contained in the ELF file. 315 */ 316 if (ehdr.e_phnum) { 317 if (gelf_newphdr(telf, ehdr.e_phnum) == 0) { 318 (void) fprintf(stderr, 319 "%s: elf_newphdr() failed: %s\n", 320 file, elf_errmsg(0)); 321 return; 322 } 323 for (ndx = 0; ndx < (int)ehdr.e_phnum; ndx++) { 324 if (gelf_getphdr(elf, ndx, &phdr) == 0 || 325 gelf_getphdr(telf, ndx, &tphdr) == 0) { 326 (void) fprintf(stderr, 327 "%s: elf_getphdr() failed: %s\n", 328 file, elf_errmsg(0)); 329 return; 330 } 331 tphdr = phdr; 332 gelf_update_phdr(telf, ndx, &tphdr); 333 } 334 } 335 336 /* 337 * The new Elf file has now been fully described to libelf. 338 * elf_update() will construct the new Elf file and write 339 * it out to disk. 340 */ 341 if (elf_update(telf, ELF_C_WRITE) == -1) { 342 (void) fprintf(stderr, "elf_update() failed: %s\n", 343 elf_errmsg(0)); 344 (void) elf_end(telf); 345 (void) close(tfd); 346 return; 347 } 348 (void) elf_end(telf); 349 350 /* 351 * set new files permissions to the original files 352 * permissions. 353 */ 354 (void) fstat(fd, &sbuf); 355 (void) fchmod(tfd, sbuf.st_mode); 356 357 (void) close(tfd); 358 359 /* 360 * delete the original file and rename the new file 361 * to the orignal file. 362 */ 363 (void) rename(tfile, file); 364 } 365 366 367 int 368 main(int argc, char ** argv) 369 { 370 int i; 371 372 if (argc < 2) { 373 (void) printf("usage: %s elf_file ...\n", argv[0]); 374 return (1); 375 } 376 377 /* 378 * Initialize the elf library, must be called before elf_begin() 379 * can be called. 380 */ 381 if (elf_version(EV_CURRENT) == EV_NONE) { 382 (void) fprintf(stderr, "elf_version() failed: %s\n", 383 elf_errmsg(0)); 384 return (1); 385 } 386 387 for (i = 1; i < argc; i++) { 388 int fd; 389 Elf *elf; 390 char *elf_fname; 391 392 elf_fname = argv[i]; 393 394 if ((fd = open(elf_fname, O_RDONLY)) == -1) { 395 perror("open"); 396 continue; 397 } 398 399 /* 400 * Attempt to open an Elf descriptor Read/Write 401 * for each file. 402 */ 403 if ((elf = elf_begin(fd, ELF_C_READ, 0)) == NULL) { 404 (void) fprintf(stderr, "elf_begin() failed: %s\n", 405 elf_errmsg(0)); 406 (void) close(fd); 407 continue; 408 } 409 410 /* 411 * Determine what kind of elf file this is: 412 */ 413 if (elf_kind(elf) != ELF_K_ELF) { 414 /* 415 * can only delete comment sections from 416 * ELF files. 417 */ 418 (void) printf("%s not of type ELF_K_ELF. " 419 "elf_kind == %d\n", 420 elf_fname, elf_kind(elf)); 421 } else 422 delete_comment(elf, fd, elf_fname); 423 424 (void) elf_end(elf); 425 (void) close(fd); 426 } 427 428 return (0); 429 } 430