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