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