xref: /illumos-gate/usr/src/cmd/sgs/libelf/demo/tpcom.c (revision 24da5b34f49324ed742a340010ed5bd3d4e06625)
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 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * tpcom: Threaded Print Comment
31  *
32  * tpcom is a threaded version of the pcom program.  It will create
33  * a new thread for each new ELF descriptor that it examines.  It
34  * will then examine each elf descriptor and print the .comment section
35  * if found.
36  *
37  * This program demonstrates that libelf is MT-Safe and the usage
38  * of elf_begin(ELF_C_READ).
39  */
40 
41 
42 #include <stdio.h>
43 #include <libelf.h>
44 #include <gelf.h>
45 #include <fcntl.h>
46 #include <unistd.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <thread.h>
50 
51 
52 #define	NUMLWPS		32		/* arbitrary number of LWPS */
53 
54 static const char *CommentStr = ".comment";
55 
56 /*
57  * arguments to be passed into process_elf().
58  */
59 typedef struct {
60 	Elf	*pe_elf;
61 	char	*pe_file;		/* elf member name */
62 	int	pe_fd;
63 	short	pe_member;		/* is this an archive member? */
64 } pe_args;
65 
66 
67 static mutex_t	printlock = DEFAULTMUTEX;	/* printlock used to */
68 						/* group output */
69 						/* of comment sections */
70 
71 static void
72 print_comment(Elf *elf, const char *file)
73 {
74 	Elf_Scn *	scn = 0;
75 	GElf_Shdr	shdr;
76 	Elf_Data *	data;
77 	size_t		shstrndx;
78 
79 
80 	if (elf_getshstrndx(elf, &shstrndx) == 0) {
81 		(void) fprintf(stderr, "%s: elf_getshstrndx() failed: %s\n",
82 			file, elf_errmsg(0));
83 		return;
84 	}
85 	while ((scn = elf_nextscn(elf, scn)) != 0) {
86 		/*
87 		 * Do a string compare to examine each section header
88 		 * to see if it is a ".comment" section.  If it is then
89 		 * this is the section we want to process.
90 		 */
91 		if (gelf_getshdr(scn, &shdr) == 0) {
92 			(void) fprintf(stderr,
93 				"%s: elf_getshdr() failed: %s\n",
94 				file, elf_errmsg(0));
95 			return;
96 		}
97 
98 		if (strcmp(CommentStr, elf_strptr(elf, shstrndx,
99 		    shdr.sh_name)) == 0) {
100 			int	i;
101 			char	*ptr;
102 
103 			mutex_lock(&printlock);
104 			(void) printf("%s .comment:\n", file);
105 
106 			/*
107 			 * Get the data associated with the .comment
108 			 * section.
109 			 */
110 			if ((data = elf_getdata(scn, 0)) == 0) {
111 				(void) fprintf(stderr,
112 					"%s: elf_getdata() failed: %s\n",
113 					file, elf_errmsg(0));
114 				mutex_unlock(&printlock);
115 				return;
116 			}
117 			/*
118 			 * Data in a .comment section is a list of 'null'
119 			 * terminated strings.  The following will print
120 			 * one string per line.
121 			 */
122 			for (i = 0, ptr = (char *)data->d_buf;
123 			    i < data->d_size; i++)
124 				if (ptr[i]) {
125 					(void) puts(&ptr[i]);
126 					i += strlen(&ptr[i]);
127 				}
128 			(void) putchar('\n');
129 			mutex_unlock(&printlock);
130 		}
131 	}
132 
133 }
134 
135 
136 static void
137 process_elf(pe_args * pep)
138 {
139 	Elf_Cmd	cmd;
140 	Elf *	_elf;
141 
142 	switch (elf_kind(pep->pe_elf)) {
143 	case ELF_K_ELF:
144 		print_comment(pep->pe_elf, pep->pe_file);
145 		break;
146 	case ELF_K_AR:
147 		cmd = ELF_C_READ;
148 		while ((_elf = elf_begin(pep->pe_fd, cmd,
149 		    pep->pe_elf)) != 0) {
150 			Elf_Arhdr *	arhdr;
151 			pe_args *	_pep;
152 			int		rc;
153 
154 			if ((arhdr = elf_getarhdr(_elf)) == 0) {
155 				(void) fprintf(stderr,
156 					"%s: elf_getarhdr() failed: %s\n",
157 					pep->pe_file, elf_errmsg(0));
158 			}
159 			cmd = elf_next(_elf);
160 			_pep = malloc(sizeof (pe_args));
161 			_pep->pe_elf = _elf;
162 			_pep->pe_file = malloc(strlen(pep->pe_file) +
163 				strlen(arhdr->ar_name) + 5);
164 			(void) sprintf(_pep->pe_file,
165 				"%s(%s)", pep->pe_file, arhdr->ar_name);
166 			_pep->pe_fd = pep->pe_fd;
167 			_pep->pe_member = 1;
168 			if ((rc = thr_create(NULL, 0,
169 			    (void *(*)(void *))process_elf,
170 			    (void *)_pep, THR_DETACHED, 0)) != 0) {
171 				(void) fprintf(stderr,
172 					"thr_create() failed, rc = %d\n", rc);
173 			}
174 		}
175 		break;
176 	default:
177 		if (!pep->pe_member) {
178 			mutex_lock(&printlock);
179 			(void) fprintf(stderr,
180 				"%s: unexpected elf_kind(): 0x%x\n",
181 				pep->pe_file, elf_kind(pep->pe_elf));
182 			mutex_unlock(&printlock);
183 		}
184 	}
185 
186 	(void) elf_end(pep->pe_elf);
187 	if (pep->pe_member)
188 		free(pep->pe_file);
189 	free(pep);
190 	thr_exit(0);
191 }
192 
193 int
194 main(int argc, char ** argv)
195 {
196 	int	i;
197 
198 
199 	if (argc < 2) {
200 		(void) printf("usage: %s elf_file ...\n", argv[0]);
201 		return (1);
202 	}
203 
204 	/*
205 	 * Initialize the elf library, must be called before elf_begin()
206 	 * can be called.
207 	 */
208 	if (elf_version(EV_CURRENT) == EV_NONE) {
209 		(void) fprintf(stderr,
210 			"elf_version() failed: %s\n", elf_errmsg(0));
211 		return (1);
212 	}
213 
214 	/*
215 	 * create an arbitrary number of LWP's to run the
216 	 * threads that will be created.
217 	 */
218 	if (thr_setconcurrency(NUMLWPS) != 0) {
219 		(void) fprintf(stderr, "thread setconcurrency failed\n");
220 		return (1);
221 	}
222 
223 	for (i = 1; i < argc; i++) {
224 		int	fd;
225 		Elf	*elf;
226 		pe_args	*pep;
227 		int	rc;
228 		char	*elf_fname;
229 
230 		elf_fname = argv[i];
231 
232 		if ((fd = open(elf_fname, O_RDONLY)) == -1) {
233 			perror("open");
234 			continue;
235 		}
236 
237 		/*
238 		 * Attempt to open an Elf descriptor Read/Write
239 		 * for each file.
240 		 */
241 		if ((elf = elf_begin(fd, ELF_C_READ, 0)) == NULL) {
242 			mutex_lock(&printlock);
243 			(void) fprintf(stderr, "elf_begin() failed: %s\n",
244 			    elf_errmsg(0));
245 			mutex_unlock(&printlock);
246 			(void) close(fd);
247 			continue;
248 		}
249 		pep = malloc(sizeof (pe_args));
250 		pep->pe_elf = elf;
251 		pep->pe_file = elf_fname;
252 		pep->pe_fd = fd;
253 		pep->pe_member = 0;
254 		if ((rc = thr_create(NULL, 0, (void *(*)(void *))process_elf,
255 		    (void *)pep, THR_DETACHED, 0)) != 0) {
256 			mutex_lock(&printlock);
257 			(void) fprintf(stderr,
258 				"thr_create() failed with code: %d\n", rc);
259 			mutex_unlock(&printlock);
260 			return (1);
261 		}
262 	}
263 
264 	thr_exit(0);
265 	return (0);
266 }
267