xref: /illumos-gate/usr/src/cmd/sgs/libelf/demo/pcom.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  * pcom: Print Comment
28  *
29  * This program demonstrates the use of the libelf interface to
30  * read an ELF file.  pcom will open an ELF file using
31  * elf_begin(ELF_C_READ) and examine search the ELF file
32  * for a .comment section.  If a .comment section is found it's
33  * contents will be displayed on stdout.
34  */
35 
36 #include <stdio.h>
37 #include <libelf.h>
38 #include <gelf.h>
39 #include <fcntl.h>
40 #include <unistd.h>
41 #include <stdlib.h>
42 #include <string.h>
43 
44 
45 static const char	*CommentStr = ".comment";
46 
47 static void
48 print_comment(Elf *elf, const char *file)
49 {
50 	Elf_Scn		*scn = 0;
51 	GElf_Shdr	shdr;
52 	Elf_Data	*data;
53 	size_t		shstrndx;
54 
55 
56 	(void) printf("%s .comment:\n", file);
57 
58 	if (elf_getshdrstrndx(elf, &shstrndx) == -1) {
59 		(void) fprintf(stderr, "%s: elf_getshdrstrndx() failed: %s\n",
60 		    file, elf_errmsg(0));
61 		return;
62 	}
63 
64 	while ((scn = elf_nextscn(elf, scn)) != 0) {
65 		/*
66 		 * Do a string compare to examine each section header
67 		 * to see if it is a ".comment" section.  If it is then
68 		 * this is the section we want to process.
69 		 */
70 		if (gelf_getshdr(scn, &shdr) == 0) {
71 			(void) fprintf(stderr, "%s: elf_getshdr() failed: %s\n",
72 			    file, elf_errmsg(0));
73 			return;
74 		}
75 		if (strcmp(CommentStr, elf_strptr(elf, shstrndx,
76 		    shdr.sh_name)) == 0) {
77 			int	i;
78 			char	*ptr;
79 
80 			/*
81 			 * Get the data associated with the .comment
82 			 * section.
83 			 */
84 			if ((data = elf_getdata(scn, 0)) == 0) {
85 				(void) fprintf(stderr,
86 				    "%s: elf_getdata() failed: %s\n",
87 				    file, elf_errmsg(0));
88 				return;
89 			}
90 			/*
91 			 * Data in a .comment section is a list of 'null'
92 			 * terminated strings.  The following will print
93 			 * one string per line.
94 			 */
95 			for (i = 0, ptr = (char *)data->d_buf;
96 			    i < data->d_size; i++)
97 				if (ptr[i]) {
98 					(void) puts(&ptr[i]);
99 					i += strlen(&ptr[i]);
100 				}
101 			(void) putchar('\n');
102 		}
103 	}
104 
105 }
106 
107 
108 static void
109 process_elf(Elf *elf, char *file, int fd, int member)
110 {
111 	Elf_Cmd	cmd;
112 	Elf	*_elf;
113 
114 	switch (elf_kind(elf)) {
115 	case ELF_K_ELF:
116 		/*
117 		 * This is an ELF file, now attempt to find it's
118 		 * .comment section and to display it.
119 		 */
120 		print_comment(elf, file);
121 		break;
122 	case ELF_K_AR:
123 		/*
124 		 * Archives contain multiple ELF files, which can each
125 		 * in turn be examined with libelf.
126 		 *
127 		 * The below loop will iterate over each member of the
128 		 * archive and recursivly call process_elf() for processing.
129 		 */
130 		cmd = ELF_C_READ;
131 		while ((_elf = elf_begin(fd, cmd, elf)) != 0) {
132 			Elf_Arhdr	*arhdr;
133 			char		buffer[1024];
134 
135 			arhdr = elf_getarhdr(_elf);
136 
137 			/*
138 			 * Build up file names based off of
139 			 * 'archivename(membername)'.
140 			 */
141 			(void) sprintf(buffer, "%s(%s)", file, arhdr->ar_name);
142 
143 			/*
144 			 * recursivly process the ELF members.
145 			 */
146 			process_elf(_elf, buffer, fd, 1);
147 			cmd = elf_next(_elf);
148 			(void) elf_end(_elf);
149 		}
150 		break;
151 	default:
152 		if (!member)
153 			(void) fprintf(stderr,
154 			    "%s: unexpected elf_kind(): 0x%x\n",
155 			    file, elf_kind(elf));
156 		return;
157 	}
158 }
159 
160 int
161 main(int argc, char **argv)
162 {
163 	int	i;
164 
165 
166 	if (argc < 2) {
167 		(void) printf("usage: %s elf_file ...\n", 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,
177 		    "elf_version() failed: %s\n", elf_errmsg(0));
178 		return (1);
179 	}
180 
181 	for (i = 1; 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_RDONLY)) == -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_READ, 0)) == NULL) {
197 			(void) fprintf(stderr, "elf_begin() failed: %s\n",
198 			    elf_errmsg(0));
199 			(void) close(fd);
200 			continue;
201 		}
202 
203 		/*
204 		 * Process each elf descriptor.
205 		 */
206 		process_elf(elf, elf_fname, fd, 0);
207 		(void) elf_end(elf);
208 		(void) close(fd);
209 	}
210 
211 	return (0);
212 }
213