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