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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * acom: Append Comment 28 * 29 * This program demonstrates the use of the libelf interface to 30 * modify a ELF file. This program will open an ELF file and 31 * either modify an existing .comment section and/or append 32 * a new .comment section to an existing ELF file. 33 */ 34 35 #include <stdio.h> 36 #include <libelf.h> 37 #include <gelf.h> 38 #include <fcntl.h> 39 #include <unistd.h> 40 #include <stdlib.h> 41 #include <string.h> 42 43 44 static const char *CommentStr = ".comment"; 45 46 static void 47 update_comment(Elf *elf, const char *file, const char *comment) 48 { 49 Elf_Scn *scn = 0; 50 GElf_Shdr shdr; 51 Elf_Data *data; 52 size_t shstrndx; 53 54 if (elf_getshdrstrndx(elf, &shstrndx) == -1) { 55 (void) fprintf(stderr, "%s: gelf_getshdrstrdx() failed: %s\n", 56 file, elf_errmsg(0)); 57 return; 58 } 59 60 while ((scn = elf_nextscn(elf, scn)) != 0) { 61 /* 62 * Do a string compare to examine each section header 63 * to see if it is a ".comment" section. If it is then 64 * this is the section we want to process. 65 */ 66 if (gelf_getshdr(scn, &shdr) == 0) { 67 (void) fprintf(stderr, "%s: elf_getshdr() failed: %s\n", 68 file, elf_errmsg(0)); 69 return; 70 } 71 if (strcmp(CommentStr, elf_strptr(elf, shstrndx, 72 shdr.sh_name)) == 0) 73 break; 74 } 75 76 if (scn == 0) { 77 int ndx; 78 79 (void) printf("%s has no .comment section. " 80 "Creating one...\n", file); 81 /* 82 * First add the ".comment" string to the string table 83 */ 84 if ((scn = elf_getscn(elf, shstrndx)) == 0) { 85 (void) fprintf(stderr, "%s: elf_getscn() failed: %s\n", 86 file, elf_errmsg(0)); 87 return; 88 } 89 if ((data = elf_getdata(scn, 0)) == 0) { 90 (void) fprintf(stderr, "%s: elf_getdata() failed: %s\n", 91 file, elf_errmsg(0)); 92 return; 93 } 94 ndx = data->d_off + data->d_size; 95 if ((data = elf_newdata(scn)) == 0) { 96 (void) fprintf(stderr, "%s: elf_newdata() failed: %s\n", 97 file, elf_errmsg(0)); 98 return; 99 } 100 data->d_buf = (void *)CommentStr; 101 data->d_size = strlen(CommentStr) + 1; 102 data->d_align = 1; 103 104 /* 105 * Add the ".comment" section to the end of the file. 106 * Initialize the fields in the Section Header that 107 * libelf will not fill in. 108 */ 109 if ((scn = elf_newscn(elf)) == 0) { 110 (void) fprintf(stderr, "%s: elf_newscn() failed: %s\n", 111 file, elf_errmsg(0)); 112 return; 113 } 114 if (gelf_getshdr(scn, &shdr) == 0) { 115 (void) fprintf(stderr, "%s: elf_getshdr() failed: %s\n", 116 file, elf_errmsg(0)); 117 return; 118 } 119 shdr.sh_name = ndx; 120 shdr.sh_type = SHT_PROGBITS; 121 shdr.sh_flags = 0; 122 shdr.sh_addr = 0; 123 shdr.sh_link = 0; 124 shdr.sh_info = 0; 125 126 /* 127 * Flush the changes to the underlying elf32 or elf64 128 * section header. 129 */ 130 gelf_update_shdr(scn, &shdr); 131 } 132 133 if (shdr.sh_addr != 0) { 134 (void) printf("%s: .comment section is part of a " 135 "loadable segment, it cannot be changed.\n", file); 136 return; 137 } 138 139 if ((data = elf_newdata(scn)) == 0) { 140 (void) fprintf(stderr, "%s: elf_getdata() failed: %s\n", 141 file, elf_errmsg(0)); 142 return; 143 } 144 data->d_buf = (void *)comment; 145 data->d_size = strlen(comment) + 1; 146 data->d_align = 1; 147 148 if (elf_update(elf, ELF_C_WRITE) == -1) 149 (void) fprintf(stderr, "%s: elf_update() failed: %s\n", file, 150 elf_errmsg(0)); 151 } 152 153 154 int 155 main(int argc, char **argv) 156 { 157 int i; 158 char *new_comment; 159 160 161 if (argc < 3) { 162 (void) printf("usage: %s <new comment> elf_file ...\n", 163 argv[0]); 164 return (1); 165 } 166 167 /* 168 * Initialize the elf library, must be called before elf_begin() 169 * can be called. 170 */ 171 if (elf_version(EV_CURRENT) == EV_NONE) { 172 (void) fprintf(stderr, "elf_version() failed: %s\n", 173 elf_errmsg(0)); 174 return (1); 175 } 176 177 /* 178 * The new comment is passed in through the command line. 179 * This string will be used to update the .comment section of 180 * the specified ELF files. 181 */ 182 new_comment = argv[1]; 183 for (i = 2; i < argc; i++) { 184 int fd; 185 Elf *elf; 186 char *elf_fname; 187 188 elf_fname = argv[i]; 189 if ((fd = open(elf_fname, O_RDWR)) == -1) { 190 perror("open"); 191 continue; 192 } 193 194 /* 195 * Attempt to open an Elf descriptor Read/Write 196 * for each file. 197 */ 198 if ((elf = elf_begin(fd, ELF_C_RDWR, 0)) == NULL) { 199 (void) fprintf(stderr, "elf_begin() failed: %s\n", 200 elf_errmsg(0)); 201 (void) close(fd); 202 continue; 203 } 204 /* 205 * Determine what kind of elf file this is: 206 */ 207 if (elf_kind(elf) == ELF_K_ELF) 208 update_comment(elf, elf_fname, new_comment); 209 else 210 (void) printf("%s not of type ELF_K_ELF. " 211 "elf_kind == %d\n", elf_fname, elf_kind(elf)); 212 213 (void) elf_end(elf); 214 (void) close(fd); 215 } 216 217 return (0); 218 } 219