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 * pcom: Print Comment
27 *
28 * This program demonstrates the use of the libelf interface to
29 * read an ELF file.  pcom will open an ELF file using
30 * elf_begin(ELF_C_READ) and examine search the ELF file
31 * for a .comment section.  If a .comment section is found it's
32 * contents will be displayed on stdout.
33 */
34
35#include <stdio.h>
36#include <libelf.h>
37#include <gelf.h>
38#include <fcntl.h>
39#include <unistd.h>
40#include <stdlib.h>
41#include <string.h>
42
43
44static const char	*CommentStr = ".comment";
45
46static void
47print_comment(Elf *elf, const char *file)
48{
49	Elf_Scn		*scn = NULL;
50	GElf_Shdr	shdr;
51	Elf_Data	*data;
52	size_t		shstrndx;
53
54
55	(void) printf("%s .comment:\n", file);
56
57	if (elf_getshdrstrndx(elf, &shstrndx) == -1) {
58		(void) fprintf(stderr, "%s: elf_getshdrstrndx() failed: %s\n",
59		    file, elf_errmsg(0));
60		return;
61	}
62
63	while ((scn = elf_nextscn(elf, scn)) != NULL) {
64		/*
65		 * Do a string compare to examine each section header
66		 * to see if it is a ".comment" section.  If it is then
67		 * this is the section we want to process.
68		 */
69		if (gelf_getshdr(scn, &shdr) == NULL) {
70			(void) fprintf(stderr, "%s: elf_getshdr() failed: %s\n",
71			    file, elf_errmsg(0));
72			return;
73		}
74		if (strcmp(CommentStr, elf_strptr(elf, shstrndx,
75		    shdr.sh_name)) == 0) {
76			int	i;
77			char	*ptr;
78
79			/*
80			 * Get the data associated with the .comment
81			 * section.
82			 */
83			if ((data = elf_getdata(scn, NULL)) == NULL) {
84				(void) fprintf(stderr,
85				    "%s: elf_getdata() failed: %s\n",
86				    file, elf_errmsg(0));
87				return;
88			}
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
107static void
108process_elf(Elf *elf, char *file, int fd, int member)
109{
110	Elf_Cmd	cmd;
111	Elf	*_elf;
112
113	switch (elf_kind(elf)) {
114	case ELF_K_ELF:
115		/*
116		 * This is an ELF file, now attempt to find it's
117		 * .comment section and to display it.
118		 */
119		print_comment(elf, file);
120		break;
121	case ELF_K_AR:
122		/*
123		 * Archives contain multiple ELF files, which can each
124		 * in turn be examined with libelf.
125		 *
126		 * The below loop will iterate over each member of the
127		 * archive and recursively call process_elf().
128		 */
129		cmd = ELF_C_READ;
130		while ((_elf = elf_begin(fd, cmd, elf)) != NULL) {
131			Elf_Arhdr	*arhdr;
132			char		buffer[1024];
133
134			arhdr = elf_getarhdr(_elf);
135
136			/*
137			 * Build up file names based off of
138			 * 'archivename(membername)'.
139			 */
140			(void) sprintf(buffer, "%s(%s)", file, arhdr->ar_name);
141
142			/*
143			 * Recursively process the ELF members.
144			 */
145			process_elf(_elf, buffer, fd, 1);
146			cmd = elf_next(_elf);
147			(void) elf_end(_elf);
148		}
149		break;
150	default:
151		if (!member)
152			(void) fprintf(stderr,
153			    "%s: unexpected elf_kind(): 0x%x\n",
154			    file, elf_kind(elf));
155		return;
156	}
157}
158
159int
160main(int argc, char **argv)
161{
162	int	i;
163
164	if (argc < 2) {
165		(void) printf("usage: %s elf_file ...\n", argv[0]);
166		return (1);
167	}
168
169	/*
170	 * Initialize the elf library, must be called before elf_begin()
171	 * can be called.
172	 */
173	if (elf_version(EV_CURRENT) == EV_NONE) {
174		(void) fprintf(stderr,
175		    "elf_version() failed: %s\n", elf_errmsg(0));
176		return (1);
177	}
178
179	for (i = 1; i < argc; i++) {
180		int	fd;
181		Elf	*elf;
182		char	*elf_fname;
183
184		elf_fname = argv[i];
185		if ((fd = open(elf_fname, O_RDONLY)) == -1) {
186			perror("open");
187			continue;
188		}
189
190		/*
191		 * Attempt to open an Elf descriptor Read/Write
192		 * for each file.
193		 */
194		if ((elf = elf_begin(fd, ELF_C_READ, 0)) == NULL) {
195			(void) fprintf(stderr, "elf_begin() failed: %s\n",
196			    elf_errmsg(0));
197			(void) close(fd);
198			continue;
199		}
200
201		/*
202		 * Process each elf descriptor.
203		 */
204		process_elf(elf, elf_fname, fd, 0);
205		(void) elf_end(elf);
206		(void) close(fd);
207	}
208
209	return (0);
210}
211