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 2007 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 char *shdnms_p = (char *)pfile_p->pf_snmdat_p->d_buf; 218 219 char *dest_p = (char *)pfile_p->pf_shdarr_p; 220 int shdsize = pfile_p->pf_elfhd_p->e_shentsize; 221 int i; 222 char *s; 223 int symtab_found = 0; 224 225 tscn_p = 0; 226 DEBUG_EXP(printf("Section header entry size = %d\n", shdsize)); 227 DEBUG_EXP(printf("First section header name = %s\n", &shdnms_p[1])); 228 pfile_p->pf_symdat_aux_p = NULL; 229 /* 230 * Scan the section headers looking for a symbol table. Our 231 * preference is to use .symtab, because it contains the full 232 * set of symbols. If we find it, we stop looking immediately 233 * and use it. In the absence of a .symtab section, we are 234 * willing to use the dynamic symbol table (.dynsym), possibly 235 * augmented by the .SUNW_ldynsym, which contains local symbols. 236 */ 237 while ((tscn_p = elf_nextscn(telf_p, tscn_p)) != NULL) { 238 if ((tshd_p = elf32_getshdr(tscn_p)) == NULL) 239 _err_exit("%s %d in %s.", fail_shd_s, i, aout_name); 240 241 (void) memcpy(dest_p, tshd_p, shdsize); 242 dest_p += shdsize; 243 244 s = &shdnms_p[tshd_p->sh_name]; 245 DEBUG_EXP(printf("index of section name = %d\n", 246 tshd_p->sh_name)); 247 DEBUG_EXP(printf("_symintOpen: reading section %s\n", s)); 248 249 if (symtab_found) 250 continue; 251 switch (tshd_p->sh_type) { 252 case SHT_SYMTAB: 253 DEBUG_LOC("_symintOpen: found symbol section"); 254 pfile_p->pf_symstr_ndx = tshd_p->sh_link; 255 pfile_p->pf_symdat_pri_p = 256 section_data_p(tscn_p, "symtab"); 257 nsyms_pri = tshd_p->sh_size / tshd_p->sh_entsize; 258 /* Throw away .SUNW_ldynsym. It is for .dynsym only */ 259 nsyms_aux = 0; 260 pfile_p->pf_symdat_aux_p = NULL; 261 /* We have found the best symbol table. Stop looking */ 262 symtab_found = 1; 263 break; 264 265 case SHT_DYNSYM: 266 /* We will use .dynsym if no .symtab is found */ 267 DEBUG_LOC("_symintOpen: found dynamic symbol section"); 268 pfile_p->pf_symstr_ndx = tshd_p->sh_link; 269 pfile_p->pf_symdat_pri_p = 270 section_data_p(tscn_p, "dynsym"); 271 nsyms_pri = tshd_p->sh_size / tshd_p->sh_entsize; 272 break; 273 274 case SHT_SUNW_LDYNSYM: 275 /* Auxiliary table, used with .dynsym */ 276 DEBUG_LOC("_symintOpen: found dynamic symbol section"); 277 pfile_p->pf_symdat_aux_p = 278 section_data_p(tscn_p, "SUNW_ldynsym"); 279 nsyms_aux = tshd_p->sh_size / tshd_p->sh_entsize; 280 break; 281 } 282 283 } 284 } 285 286 if (pfile_p->pf_symdat_pri_p == NULL || pfile_p->pf_symstr_ndx == 0) 287 _err_exit("%s %s.", fail_sym_s, executableName); 288 289 pfile_p->pf_nstsyms = (int)(nsyms_pri + nsyms_aux); 290 pfile_p->pf_nstsyms_aux = (int)nsyms_aux; 291 if ((nsyms_pri + nsyms_aux) != (Elf64_Xword)pfile_p->pf_nstsyms) 292 _err_exit("%s %s.", fail_sym32_s, executableName); 293 294 295 DEBUG_LOC("_symintOpen: after for loop that reads the sections"); 296 297 DEBUG_LOC("_symintOpen: before call to _symintLoad"); 298 299 if ((pfile_p->pf_symarr_p = _symintLoad(pfile_p)) == NULL) 300 _err_exit("%s %s.", fail_pfsym_s, executableName); 301 302 DEBUG_LOC("_symintOpen: after call to _symintLoad"); 303 304 /* 305 * At this point we might want to include some consistency 306 * checks to be sure all is well. For example, we can check 307 * symbol table consistency by comparing "the product of the 308 * number of symbols and the size of each symbol" to "the 309 * length of the symbol table data". 310 * 311 * Also, NULL may be a proper value (e.g., the debugger 312 * information when there is none) for some things that 313 * we cannot afford to be without. We should check these 314 * at this point also. 315 */ 316 317 DEBUG_LOC("_symintOpen: bottom"); 318 return (pfile_p); 319 } 320