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