xref: /illumos-gate/usr/src/cmd/sgs/libelf/demo/acom.c (revision 56f33205c9ed776c3c909e07d52e94610a675740)
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