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