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