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