acom.c revision 9900:1b86d65a4f9e
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
44static const char	*CommentStr =	".comment";
45
46static void
47update_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
154int
155main(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