tpcom.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 * 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
51static const char *CommentStr = ".comment";
52
53/*
54 * arguments to be passed into process_elf().
55 */
56typedef 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
64static mutex_t	printlock = DEFAULTMUTEX;	/* printlock used to */
65						/* group output */
66						/* of comment sections */
67
68static void
69print_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
132static void
133process_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
189int
190main(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