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 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1988 AT&T */ 28 /* All Rights Reserved */ 29 30 31 #pragma ident "%Z%%M% %I% %E% SMI" 32 33 #include <stdio.h> 34 #include <fcntl.h> 35 #include <string.h> 36 #include "symint.h" 37 #include "debug.h" 38 39 /* 40 * symintFcns.c -- symbol information interface routines. 41 * 42 * these routines form a symbol information access 43 * interface, for the profilers to get at object file 44 * information. this interface was designed to aid 45 * in the COFF to ELF conversion of prof, lprof and friends. 46 * 47 */ 48 49 50 /* 51 * _symintOpen(aout_name) 52 * aout_name - char string file name of object file 53 * to open. 54 * 55 * returns PROF_FILE * - pointer to the PROF_FILE structure built, 56 * or NULL if fails. 57 */ 58 59 /* 60 * 61 * .H 3 "Executable File Open and Close" 62 * 63 * Under COFF, the routine ldopen, given a file name, returns a pointer to a 64 * structure called an LDFILE. This descriptor is then passed to each of 65 * the library routines (such as read header, read symbol table entry, etc) 66 * to access the information contained in the file. These calls are spread 67 * throughout the profiling code. 68 * 69 * Under ELF, the file must be opened using a system open call. The file 70 * descriptor is then passed to a routine which returns a pointer to an 71 * Elf structure. This pointer is then passed along to another routine which 72 * returns a different pointer which is in turn passed along to another 73 * routine. In an attempt to avoid disturbing the current format of the 74 * code (by having to pass around different types of pointers), we plan to 75 * build a PROF_FILE descriptor which will then be passed around in the 76 * same way as the pointer to LDFILE. 77 * 78 * Thus, for ELF, an open will consist of opening the file and extracting 79 * enough from it to fill in the PROF_FILE structure. The code for the 80 * open is as follows; the code for building the symbol table (extracting 81 * information from the sections to fill an array of PROF_SYMBOLS) has 82 * yet to be written. 83 * 84 */ 85 86 /* 87 * globals 88 */ 89 90 91 static char 92 *fail_open_s = "Unable to open file", 93 *fail_begin_s = "Unable to read (begin) file", 94 *fail_ehdr_s = "Unable to get elf header in", 95 *fail_sec_s = "Unable to get section", 96 *fail_shd_s = "Unable to get header for section", 97 *fail_dat_s = "Unable to get data for section", 98 *fail_sym_s = "Cannot find symbol table section in", 99 *fail_pfsym_s = "Unable to process symbols in", 100 *fail_buf_s = "Data buffer is null for section", 101 *fail_sym32_s = "Cannot handle more than 2^32 symbols" 102 ; 103 104 105 /* 106 * this points at the name of the executable. 107 */ 108 static char *executableName; 109 110 111 112 /* 113 * section_data_p() - return ptr to section data, 114 * given section ptr and name of section. 115 */ 116 117 static Elf_Data * 118 section_data_p(Elf_Scn *sec_p, char *str) 119 { 120 Elf_Data *dat_p; 121 122 if ((dat_p = elf_getdata(sec_p, NULL)) == NULL) 123 _err_exit("%s %s in %s.", fail_dat_s, str, executableName); 124 return (dat_p); 125 } 126 127 128 PROF_FILE * 129 _symintOpen(char *aout_name) 130 { 131 /* 132 * Elf file open operation 133 * 134 * - point at executable's name, globally 135 * - open file 136 * - align to current version 137 * - read the elf descriptor and header 138 * - read header-names section descriptor, header, and data 139 * - allocate space for all the section hdrs (pf_shdarr_p). 140 * - set a pointer to the header-names buffer 141 * - search the section headers for 142 * - debug section header and data 143 * - line section header and data 144 * - symbol table header, data, strings, and number of symbols 145 * and copy each section hdr into our array. 146 * - populate the PROF_SYMBOL array and anchor it in (pf_symarr_p). 147 */ 148 149 PROF_FILE *pfile_p; /* PROF_FILE ptr to return. */ 150 151 Elf *telf_p; 152 Elf_Scn *tscn_p; 153 Elf32_Shdr *tshd_p; 154 int k; 155 Elf64_Xword nsyms_pri = 0, nsyms_aux = 0; 156 157 executableName = aout_name; 158 159 DEBUG_LOC("_symintOpen: top"); 160 if (aout_name == NULL) { 161 _err_exit("name of executable is null\n"); 162 } 163 DEBUG_EXP(printf("Attempting to open %s\n", aout_name)); 164 pfile_p = _Malloc(sizeof (PROF_FILE), 1); 165 166 if ((pfile_p->pf_fildes = open(aout_name, O_RDONLY)) == -1) 167 _err_exit("%s %s.", fail_open_s, aout_name); 168 if ((elf_version(EV_CURRENT)) == EV_NONE) 169 _err_exit("Elf library out of date"); 170 if ((pfile_p->pf_elf_p = elf_begin(pfile_p->pf_fildes, 171 ELF_C_READ, (Elf *)NULL)) == NULL) 172 _err_exit("%s %s.", fail_begin_s, aout_name); 173 174 DEBUG_EXP(printf("elfkind = %d\n", elf_kind(pfile_p->pf_elf_p))); 175 if ((pfile_p->pf_elfhd_p = elf32_getehdr(pfile_p->pf_elf_p)) == NULL) 176 _err_exit("%s %s.", fail_ehdr_s, aout_name); 177 178 DEBUG_LOC("_symintOpen: after call to getehdr"); 179 telf_p = pfile_p->pf_elf_p; 180 181 tscn_p = elf_getscn(telf_p, k = pfile_p->pf_elfhd_p->e_shstrndx); 182 if (tscn_p == NULL) 183 _err_exit("%s %d in %s.", fail_sec_s, k, aout_name); 184 185 if (elf32_getshdr(tscn_p) == NULL) 186 _err_exit("%s %s in %s.", fail_shd_s, "header names", 187 aout_name); 188 if ((pfile_p->pf_snmdat_p = elf_getdata(tscn_p, NULL)) == NULL) 189 _err_exit("%s %s in %s.", fail_dat_s, "header names", 190 aout_name); 191 192 DEBUG_EXP(printf("Address of data header = 0x%lx\n", 193 pfile_p->pf_snmdat_p)); 194 DEBUG_EXP(printf("d_buf = 0x%lx\n", 195 pfile_p->pf_snmdat_p->d_buf)); 196 DEBUG_EXP(printf("d_type = %d\n", 197 pfile_p->pf_snmdat_p->d_type)); 198 DEBUG_EXP(printf("d_size = %d\n", 199 pfile_p->pf_snmdat_p->d_size)); 200 DEBUG_EXP(printf("d_off = %d\n", 201 pfile_p->pf_snmdat_p->d_off)); 202 DEBUG_EXP(printf("d_align = %d\n", 203 pfile_p->pf_snmdat_p->d_align)); 204 DEBUG_EXP(printf("d_version = %d\n", 205 pfile_p->pf_snmdat_p->d_version)); 206 207 if (pfile_p->pf_snmdat_p->d_buf == NULL) 208 _err_exit("%s %s in %s.", fail_buf_s, "header names", 209 aout_name); 210 211 DEBUG_LOC("_symintOpen: after call to getdata (for header names)"); 212 213 pfile_p->pf_shdarr_p = _Malloc(pfile_p->pf_elfhd_p->e_shentsize, 214 pfile_p->pf_elfhd_p->e_shnum); 215 216 { 217 #ifdef DEBUG 218 char *shdnms_p = (char *)pfile_p->pf_snmdat_p->d_buf; 219 #endif 220 221 char *dest_p = (char *)pfile_p->pf_shdarr_p; 222 int shdsize = pfile_p->pf_elfhd_p->e_shentsize; 223 int i = 0; 224 int symtab_found = 0; 225 226 tscn_p = 0; 227 DEBUG_EXP(printf("Section header entry size = %d\n", shdsize)); 228 DEBUG_EXP(printf("First section header name = %s\n", &shdnms_p[1])); 229 pfile_p->pf_symdat_aux_p = NULL; 230 /* 231 * Scan the section headers looking for a symbol table. Our 232 * preference is to use .symtab, because it contains the full 233 * set of symbols. If we find it, we stop looking immediately 234 * and use it. In the absence of a .symtab section, we are 235 * willing to use the dynamic symbol table (.dynsym), possibly 236 * augmented by the .SUNW_ldynsym, which contains local symbols. 237 */ 238 while ((tscn_p = elf_nextscn(telf_p, tscn_p)) != NULL) { 239 if ((tshd_p = elf32_getshdr(tscn_p)) == NULL) 240 _err_exit("%s %d in %s.", fail_shd_s, i, aout_name); 241 i++; 242 243 (void) memcpy(dest_p, tshd_p, shdsize); 244 dest_p += shdsize; 245 246 DEBUG_EXP(printf("index of section name = %d\n", 247 tshd_p->sh_name)); 248 DEBUG_EXP(printf("_symintOpen: reading section %s\n", 249 &shdnms_p[tshd_p->sh_name])); 250 251 if (symtab_found) 252 continue; 253 switch (tshd_p->sh_type) { 254 case SHT_SYMTAB: 255 DEBUG_LOC("_symintOpen: found symbol section"); 256 pfile_p->pf_symstr_ndx = tshd_p->sh_link; 257 pfile_p->pf_symdat_pri_p = 258 section_data_p(tscn_p, "symtab"); 259 nsyms_pri = tshd_p->sh_size / tshd_p->sh_entsize; 260 /* Throw away .SUNW_ldynsym. It is for .dynsym only */ 261 nsyms_aux = 0; 262 pfile_p->pf_symdat_aux_p = NULL; 263 /* We have found the best symbol table. Stop looking */ 264 symtab_found = 1; 265 break; 266 267 case SHT_DYNSYM: 268 /* We will use .dynsym if no .symtab is found */ 269 DEBUG_LOC("_symintOpen: found dynamic symbol section"); 270 pfile_p->pf_symstr_ndx = tshd_p->sh_link; 271 pfile_p->pf_symdat_pri_p = 272 section_data_p(tscn_p, "dynsym"); 273 nsyms_pri = tshd_p->sh_size / tshd_p->sh_entsize; 274 break; 275 276 case SHT_SUNW_LDYNSYM: 277 /* Auxiliary table, used with .dynsym */ 278 DEBUG_LOC("_symintOpen: found dynamic symbol section"); 279 pfile_p->pf_symdat_aux_p = 280 section_data_p(tscn_p, "SUNW_ldynsym"); 281 nsyms_aux = tshd_p->sh_size / tshd_p->sh_entsize; 282 break; 283 } 284 285 } 286 } 287 288 if (pfile_p->pf_symdat_pri_p == NULL || pfile_p->pf_symstr_ndx == 0) 289 _err_exit("%s %s.", fail_sym_s, executableName); 290 291 pfile_p->pf_nstsyms = (int)(nsyms_pri + nsyms_aux); 292 pfile_p->pf_nstsyms_aux = (int)nsyms_aux; 293 if ((nsyms_pri + nsyms_aux) != (Elf64_Xword)pfile_p->pf_nstsyms) 294 _err_exit("%s %s.", fail_sym32_s, executableName); 295 296 297 DEBUG_LOC("_symintOpen: after for loop that reads the sections"); 298 299 DEBUG_LOC("_symintOpen: before call to _symintLoad"); 300 301 if ((pfile_p->pf_symarr_p = _symintLoad(pfile_p)) == NULL) 302 _err_exit("%s %s.", fail_pfsym_s, executableName); 303 304 DEBUG_LOC("_symintOpen: after call to _symintLoad"); 305 306 /* 307 * At this point we might want to include some consistency 308 * checks to be sure all is well. For example, we can check 309 * symbol table consistency by comparing "the product of the 310 * number of symbols and the size of each symbol" to "the 311 * length of the symbol table data". 312 * 313 * Also, NULL may be a proper value (e.g., the debugger 314 * information when there is none) for some things that 315 * we cannot afford to be without. We should check these 316 * at this point also. 317 */ 318 319 DEBUG_LOC("_symintOpen: bottom"); 320 return (pfile_p); 321 } 322