/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #pragma ident "%Z%%M% %I% %E% SMI" #include #include #include #include "symint.h" #include "debug.h" /* * symintFcns.c -- symbol information interface routines. * * these routines form a symbol information access * interface, for the profilers to get at object file * information. this interface was designed to aid * in the COFF to ELF conversion of prof, lprof and friends. * */ /* * _symintOpen(aout_name) * aout_name - char string file name of object file * to open. * * returns PROF_FILE * - pointer to the PROF_FILE structure built, * or NULL if fails. */ /* * * .H 3 "Executable File Open and Close" * * Under COFF, the routine ldopen, given a file name, returns a pointer to a * structure called an LDFILE. This descriptor is then passed to each of * the library routines (such as read header, read symbol table entry, etc) * to access the information contained in the file. These calls are spread * throughout the profiling code. * * Under ELF, the file must be opened using a system open call. The file * descriptor is then passed to a routine which returns a pointer to an * Elf structure. This pointer is then passed along to another routine which * returns a different pointer which is in turn passed along to another * routine. In an attempt to avoid disturbing the current format of the * code (by having to pass around different types of pointers), we plan to * build a PROF_FILE descriptor which will then be passed around in the * same way as the pointer to LDFILE. * * Thus, for ELF, an open will consist of opening the file and extracting * enough from it to fill in the PROF_FILE structure. The code for the * open is as follows; the code for building the symbol table (extracting * information from the sections to fill an array of PROF_SYMBOLS) has * yet to be written. * */ /* * globals */ static char *fail_open_s = "Unable to open file", *fail_begin_s = "Unable to read (begin) file", *fail_ehdr_s = "Unable to get elf header in", *fail_sec_s = "Unable to get section", *fail_shd_s = "Unable to get header for section", *fail_dat_s = "Unable to get data for section", *fail_sym_s = "Cannot find symbol table section in", *fail_pfsym_s = "Unable to process symbols in", *fail_buf_s = "Data buffer is null for section", *fail_sym32_s = "Cannot handle more than 2^32 symbols" ; /* * this points at the name of the executable. */ static char *executableName; /* * section_data_p() - return ptr to section data, * given section ptr and name of section. */ static Elf_Data * section_data_p(Elf_Scn *sec_p, char *str) { Elf_Data *dat_p; if ((dat_p = elf_getdata(sec_p, NULL)) == NULL) _err_exit("%s %s in %s.", fail_dat_s, str, executableName); return (dat_p); } PROF_FILE * _symintOpen(char *aout_name) { /* * Elf file open operation * * - point at executable's name, globally * - open file * - align to current version * - read the elf descriptor and header * - read header-names section descriptor, header, and data * - allocate space for all the section hdrs (pf_shdarr_p). * - set a pointer to the header-names buffer * - search the section headers for * - debug section header and data * - line section header and data * - symbol table header, data, strings, and number of symbols * and copy each section hdr into our array. * - populate the PROF_SYMBOL array and anchor it in (pf_symarr_p). */ PROF_FILE *pfile_p; /* PROF_FILE ptr to return. */ Elf *telf_p; Elf_Scn *tscn_p; Elf32_Shdr *tshd_p; int k; Elf64_Xword nsyms_pri = 0, nsyms_aux = 0; executableName = aout_name; DEBUG_LOC("_symintOpen: top"); if (aout_name == NULL) { _err_exit("name of executable is null\n"); } DEBUG_EXP(printf("Attempting to open %s\n", aout_name)); pfile_p = _Malloc(sizeof (PROF_FILE), 1); if ((pfile_p->pf_fildes = open(aout_name, O_RDONLY)) == -1) _err_exit("%s %s.", fail_open_s, aout_name); if ((elf_version(EV_CURRENT)) == EV_NONE) _err_exit("Elf library out of date"); if ((pfile_p->pf_elf_p = elf_begin(pfile_p->pf_fildes, ELF_C_READ, (Elf *)NULL)) == NULL) _err_exit("%s %s.", fail_begin_s, aout_name); DEBUG_EXP(printf("elfkind = %d\n", elf_kind(pfile_p->pf_elf_p))); if ((pfile_p->pf_elfhd_p = elf32_getehdr(pfile_p->pf_elf_p)) == NULL) _err_exit("%s %s.", fail_ehdr_s, aout_name); DEBUG_LOC("_symintOpen: after call to getehdr"); telf_p = pfile_p->pf_elf_p; tscn_p = elf_getscn(telf_p, k = pfile_p->pf_elfhd_p->e_shstrndx); if (tscn_p == NULL) _err_exit("%s %d in %s.", fail_sec_s, k, aout_name); if (elf32_getshdr(tscn_p) == NULL) _err_exit("%s %s in %s.", fail_shd_s, "header names", aout_name); if ((pfile_p->pf_snmdat_p = elf_getdata(tscn_p, NULL)) == NULL) _err_exit("%s %s in %s.", fail_dat_s, "header names", aout_name); DEBUG_EXP(printf("Address of data header = 0x%lx\n", pfile_p->pf_snmdat_p)); DEBUG_EXP(printf("d_buf = 0x%lx\n", pfile_p->pf_snmdat_p->d_buf)); DEBUG_EXP(printf("d_type = %d\n", pfile_p->pf_snmdat_p->d_type)); DEBUG_EXP(printf("d_size = %d\n", pfile_p->pf_snmdat_p->d_size)); DEBUG_EXP(printf("d_off = %d\n", pfile_p->pf_snmdat_p->d_off)); DEBUG_EXP(printf("d_align = %d\n", pfile_p->pf_snmdat_p->d_align)); DEBUG_EXP(printf("d_version = %d\n", pfile_p->pf_snmdat_p->d_version)); if (pfile_p->pf_snmdat_p->d_buf == NULL) _err_exit("%s %s in %s.", fail_buf_s, "header names", aout_name); DEBUG_LOC("_symintOpen: after call to getdata (for header names)"); pfile_p->pf_shdarr_p = _Malloc(pfile_p->pf_elfhd_p->e_shentsize, pfile_p->pf_elfhd_p->e_shnum); { char *shdnms_p = (char *)pfile_p->pf_snmdat_p->d_buf; char *dest_p = (char *)pfile_p->pf_shdarr_p; int shdsize = pfile_p->pf_elfhd_p->e_shentsize; int i; char *s; int symtab_found = 0; tscn_p = 0; DEBUG_EXP(printf("Section header entry size = %d\n", shdsize)); DEBUG_EXP(printf("First section header name = %s\n", &shdnms_p[1])); pfile_p->pf_symdat_aux_p = NULL; /* * Scan the section headers looking for a symbol table. Our * preference is to use .symtab, because it contains the full * set of symbols. If we find it, we stop looking immediately * and use it. In the absence of a .symtab section, we are * willing to use the dynamic symbol table (.dynsym), possibly * augmented by the .SUNW_ldynsym, which contains local symbols. */ while ((tscn_p = elf_nextscn(telf_p, tscn_p)) != NULL) { if ((tshd_p = elf32_getshdr(tscn_p)) == NULL) _err_exit("%s %d in %s.", fail_shd_s, i, aout_name); (void) memcpy(dest_p, tshd_p, shdsize); dest_p += shdsize; s = &shdnms_p[tshd_p->sh_name]; DEBUG_EXP(printf("index of section name = %d\n", tshd_p->sh_name)); DEBUG_EXP(printf("_symintOpen: reading section %s\n", s)); if (symtab_found) continue; switch (tshd_p->sh_type) { case SHT_SYMTAB: DEBUG_LOC("_symintOpen: found symbol section"); pfile_p->pf_symstr_ndx = tshd_p->sh_link; pfile_p->pf_symdat_pri_p = section_data_p(tscn_p, "symtab"); nsyms_pri = tshd_p->sh_size / tshd_p->sh_entsize; /* Throw away .SUNW_ldynsym. It is for .dynsym only */ nsyms_aux = 0; pfile_p->pf_symdat_aux_p = NULL; /* We have found the best symbol table. Stop looking */ symtab_found = 1; break; case SHT_DYNSYM: /* We will use .dynsym if no .symtab is found */ DEBUG_LOC("_symintOpen: found dynamic symbol section"); pfile_p->pf_symstr_ndx = tshd_p->sh_link; pfile_p->pf_symdat_pri_p = section_data_p(tscn_p, "dynsym"); nsyms_pri = tshd_p->sh_size / tshd_p->sh_entsize; break; case SHT_SUNW_LDYNSYM: /* Auxiliary table, used with .dynsym */ DEBUG_LOC("_symintOpen: found dynamic symbol section"); pfile_p->pf_symdat_aux_p = section_data_p(tscn_p, "SUNW_ldynsym"); nsyms_aux = tshd_p->sh_size / tshd_p->sh_entsize; break; } } } if (pfile_p->pf_symdat_pri_p == NULL || pfile_p->pf_symstr_ndx == 0) _err_exit("%s %s.", fail_sym_s, executableName); pfile_p->pf_nstsyms = (int)(nsyms_pri + nsyms_aux); pfile_p->pf_nstsyms_aux = (int)nsyms_aux; if ((nsyms_pri + nsyms_aux) != (Elf64_Xword)pfile_p->pf_nstsyms) _err_exit("%s %s.", fail_sym32_s, executableName); DEBUG_LOC("_symintOpen: after for loop that reads the sections"); DEBUG_LOC("_symintOpen: before call to _symintLoad"); if ((pfile_p->pf_symarr_p = _symintLoad(pfile_p)) == NULL) _err_exit("%s %s.", fail_pfsym_s, executableName); DEBUG_LOC("_symintOpen: after call to _symintLoad"); /* * At this point we might want to include some consistency * checks to be sure all is well. For example, we can check * symbol table consistency by comparing "the product of the * number of symbols and the size of each symbol" to "the * length of the symbol table data". * * Also, NULL may be a proper value (e.g., the debugger * information when there is none) for some things that * we cannot afford to be without. We should check these * at this point also. */ DEBUG_LOC("_symintOpen: bottom"); return (pfile_p); }