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