17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57a5d89c4Sab196087 * Common Development and Distribution License (the "License"). 67a5d89c4Sab196087 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 2192ed1782Smike_s 2292ed1782Smike_s /* 23*1dd08564Sab196087 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 2492ed1782Smike_s * Use is subject to license terms. 2592ed1782Smike_s */ 2692ed1782Smike_s 277c478bd9Sstevel@tonic-gate /* Copyright (c) 1988 AT&T */ 287c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 327c478bd9Sstevel@tonic-gate 337c478bd9Sstevel@tonic-gate #include <stdio.h> 347c478bd9Sstevel@tonic-gate #include <fcntl.h> 3592ed1782Smike_s #include <string.h> 3692ed1782Smike_s #include "symint.h" 377c478bd9Sstevel@tonic-gate #include "debug.h" 387c478bd9Sstevel@tonic-gate 3992ed1782Smike_s /* 407c478bd9Sstevel@tonic-gate * symintFcns.c -- symbol information interface routines. 417c478bd9Sstevel@tonic-gate * 427c478bd9Sstevel@tonic-gate * these routines form a symbol information access 437c478bd9Sstevel@tonic-gate * interface, for the profilers to get at object file 447c478bd9Sstevel@tonic-gate * information. this interface was designed to aid 457c478bd9Sstevel@tonic-gate * in the COFF to ELF conversion of prof, lprof and friends. 467c478bd9Sstevel@tonic-gate * 477c478bd9Sstevel@tonic-gate */ 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate 5092ed1782Smike_s /* 517c478bd9Sstevel@tonic-gate * _symintOpen(aout_name) 527c478bd9Sstevel@tonic-gate * aout_name - char string file name of object file 537c478bd9Sstevel@tonic-gate * to open. 547c478bd9Sstevel@tonic-gate * 557c478bd9Sstevel@tonic-gate * returns PROF_FILE * - pointer to the PROF_FILE structure built, 567c478bd9Sstevel@tonic-gate * or NULL if fails. 577c478bd9Sstevel@tonic-gate */ 587c478bd9Sstevel@tonic-gate 5992ed1782Smike_s /* 607c478bd9Sstevel@tonic-gate * 617c478bd9Sstevel@tonic-gate * .H 3 "Executable File Open and Close" 627c478bd9Sstevel@tonic-gate * 637c478bd9Sstevel@tonic-gate * Under COFF, the routine ldopen, given a file name, returns a pointer to a 647c478bd9Sstevel@tonic-gate * structure called an LDFILE. This descriptor is then passed to each of 657c478bd9Sstevel@tonic-gate * the library routines (such as read header, read symbol table entry, etc) 667c478bd9Sstevel@tonic-gate * to access the information contained in the file. These calls are spread 677c478bd9Sstevel@tonic-gate * throughout the profiling code. 687c478bd9Sstevel@tonic-gate * 697c478bd9Sstevel@tonic-gate * Under ELF, the file must be opened using a system open call. The file 707c478bd9Sstevel@tonic-gate * descriptor is then passed to a routine which returns a pointer to an 717c478bd9Sstevel@tonic-gate * Elf structure. This pointer is then passed along to another routine which 727c478bd9Sstevel@tonic-gate * returns a different pointer which is in turn passed along to another 737c478bd9Sstevel@tonic-gate * routine. In an attempt to avoid disturbing the current format of the 747c478bd9Sstevel@tonic-gate * code (by having to pass around different types of pointers), we plan to 757c478bd9Sstevel@tonic-gate * build a PROF_FILE descriptor which will then be passed around in the 767c478bd9Sstevel@tonic-gate * same way as the pointer to LDFILE. 777c478bd9Sstevel@tonic-gate * 787c478bd9Sstevel@tonic-gate * Thus, for ELF, an open will consist of opening the file and extracting 797c478bd9Sstevel@tonic-gate * enough from it to fill in the PROF_FILE structure. The code for the 807c478bd9Sstevel@tonic-gate * open is as follows; the code for building the symbol table (extracting 817c478bd9Sstevel@tonic-gate * information from the sections to fill an array of PROF_SYMBOLS) has 827c478bd9Sstevel@tonic-gate * yet to be written. 837c478bd9Sstevel@tonic-gate * 847c478bd9Sstevel@tonic-gate */ 857c478bd9Sstevel@tonic-gate 8692ed1782Smike_s /* 877a5d89c4Sab196087 * globals 887c478bd9Sstevel@tonic-gate */ 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate static char 927c478bd9Sstevel@tonic-gate *fail_open_s = "Unable to open file", 937c478bd9Sstevel@tonic-gate *fail_begin_s = "Unable to read (begin) file", 947c478bd9Sstevel@tonic-gate *fail_ehdr_s = "Unable to get elf header in", 957c478bd9Sstevel@tonic-gate *fail_sec_s = "Unable to get section", 967c478bd9Sstevel@tonic-gate *fail_shd_s = "Unable to get header for section", 977c478bd9Sstevel@tonic-gate *fail_dat_s = "Unable to get data for section", 987c478bd9Sstevel@tonic-gate *fail_sym_s = "Cannot find symbol table section in", 997c478bd9Sstevel@tonic-gate *fail_pfsym_s = "Unable to process symbols in", 1007a5d89c4Sab196087 *fail_buf_s = "Data buffer is null for section", 1017a5d89c4Sab196087 *fail_sym32_s = "Cannot handle more than 2^32 symbols" 1027c478bd9Sstevel@tonic-gate ; 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate 10592ed1782Smike_s /* 1067c478bd9Sstevel@tonic-gate * this points at the name of the executable. 1077c478bd9Sstevel@tonic-gate */ 1087c478bd9Sstevel@tonic-gate static char *executableName; 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate 11292ed1782Smike_s /* 1137c478bd9Sstevel@tonic-gate * section_data_p() - return ptr to section data, 1147c478bd9Sstevel@tonic-gate * given section ptr and name of section. 1157c478bd9Sstevel@tonic-gate */ 1167c478bd9Sstevel@tonic-gate 11792ed1782Smike_s static Elf_Data * 11892ed1782Smike_s section_data_p(Elf_Scn *sec_p, char *str) 1197c478bd9Sstevel@tonic-gate { 1207c478bd9Sstevel@tonic-gate Elf_Data *dat_p; 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate if ((dat_p = elf_getdata(sec_p, NULL)) == NULL) 1237c478bd9Sstevel@tonic-gate _err_exit("%s %s in %s.", fail_dat_s, str, executableName); 1247c478bd9Sstevel@tonic-gate return (dat_p); 1257c478bd9Sstevel@tonic-gate } 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate PROF_FILE * 12992ed1782Smike_s _symintOpen(char *aout_name) 13092ed1782Smike_s { 1317c478bd9Sstevel@tonic-gate /* 1327c478bd9Sstevel@tonic-gate * Elf file open operation 1337c478bd9Sstevel@tonic-gate * 1347c478bd9Sstevel@tonic-gate * - point at executable's name, globally 1357c478bd9Sstevel@tonic-gate * - open file 1367c478bd9Sstevel@tonic-gate * - align to current version 1377c478bd9Sstevel@tonic-gate * - read the elf descriptor and header 1387c478bd9Sstevel@tonic-gate * - read header-names section descriptor, header, and data 1397c478bd9Sstevel@tonic-gate * - allocate space for all the section hdrs (pf_shdarr_p). 1407c478bd9Sstevel@tonic-gate * - set a pointer to the header-names buffer 1417c478bd9Sstevel@tonic-gate * - search the section headers for 1427c478bd9Sstevel@tonic-gate * - debug section header and data 1437c478bd9Sstevel@tonic-gate * - line section header and data 1447c478bd9Sstevel@tonic-gate * - symbol table header, data, strings, and number of symbols 1457c478bd9Sstevel@tonic-gate * and copy each section hdr into our array. 1467c478bd9Sstevel@tonic-gate * - populate the PROF_SYMBOL array and anchor it in (pf_symarr_p). 1477c478bd9Sstevel@tonic-gate */ 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate PROF_FILE *pfile_p; /* PROF_FILE ptr to return. */ 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate Elf *telf_p; 1527c478bd9Sstevel@tonic-gate Elf_Scn *tscn_p; 1537c478bd9Sstevel@tonic-gate Elf32_Shdr *tshd_p; 1547c478bd9Sstevel@tonic-gate int k; 1557a5d89c4Sab196087 Elf64_Xword nsyms_pri = 0, nsyms_aux = 0; 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate executableName = aout_name; 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate DEBUG_LOC("_symintOpen: top"); 1607c478bd9Sstevel@tonic-gate if (aout_name == NULL) { 1617c478bd9Sstevel@tonic-gate _err_exit("name of executable is null\n"); 1627c478bd9Sstevel@tonic-gate } 1637c478bd9Sstevel@tonic-gate DEBUG_EXP(printf("Attempting to open %s\n", aout_name)); 16492ed1782Smike_s pfile_p = _Malloc(sizeof (PROF_FILE), 1); 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate if ((pfile_p->pf_fildes = open(aout_name, O_RDONLY)) == -1) 1677c478bd9Sstevel@tonic-gate _err_exit("%s %s.", fail_open_s, aout_name); 1687c478bd9Sstevel@tonic-gate if ((elf_version(EV_CURRENT)) == EV_NONE) 1697c478bd9Sstevel@tonic-gate _err_exit("Elf library out of date"); 17092ed1782Smike_s if ((pfile_p->pf_elf_p = elf_begin(pfile_p->pf_fildes, 17192ed1782Smike_s ELF_C_READ, (Elf *)NULL)) == NULL) 1727c478bd9Sstevel@tonic-gate _err_exit("%s %s.", fail_begin_s, aout_name); 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate DEBUG_EXP(printf("elfkind = %d\n", elf_kind(pfile_p->pf_elf_p))); 1757c478bd9Sstevel@tonic-gate if ((pfile_p->pf_elfhd_p = elf32_getehdr(pfile_p->pf_elf_p)) == NULL) 1767c478bd9Sstevel@tonic-gate _err_exit("%s %s.", fail_ehdr_s, aout_name); 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate DEBUG_LOC("_symintOpen: after call to getehdr"); 1797c478bd9Sstevel@tonic-gate telf_p = pfile_p->pf_elf_p; 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate tscn_p = elf_getscn(telf_p, k = pfile_p->pf_elfhd_p->e_shstrndx); 1827c478bd9Sstevel@tonic-gate if (tscn_p == NULL) 1837c478bd9Sstevel@tonic-gate _err_exit("%s %d in %s.", fail_sec_s, k, aout_name); 1847c478bd9Sstevel@tonic-gate 1857a5d89c4Sab196087 if (elf32_getshdr(tscn_p) == NULL) 18692ed1782Smike_s _err_exit("%s %s in %s.", fail_shd_s, "header names", 18792ed1782Smike_s aout_name); 1887c478bd9Sstevel@tonic-gate if ((pfile_p->pf_snmdat_p = elf_getdata(tscn_p, NULL)) == NULL) 18992ed1782Smike_s _err_exit("%s %s in %s.", fail_dat_s, "header names", 19092ed1782Smike_s aout_name); 1917c478bd9Sstevel@tonic-gate 19292ed1782Smike_s DEBUG_EXP(printf("Address of data header = 0x%lx\n", 19392ed1782Smike_s pfile_p->pf_snmdat_p)); 19492ed1782Smike_s DEBUG_EXP(printf("d_buf = 0x%lx\n", 19592ed1782Smike_s pfile_p->pf_snmdat_p->d_buf)); 19692ed1782Smike_s DEBUG_EXP(printf("d_type = %d\n", 19792ed1782Smike_s pfile_p->pf_snmdat_p->d_type)); 19892ed1782Smike_s DEBUG_EXP(printf("d_size = %d\n", 19992ed1782Smike_s pfile_p->pf_snmdat_p->d_size)); 20092ed1782Smike_s DEBUG_EXP(printf("d_off = %d\n", 20192ed1782Smike_s pfile_p->pf_snmdat_p->d_off)); 20292ed1782Smike_s DEBUG_EXP(printf("d_align = %d\n", 20392ed1782Smike_s pfile_p->pf_snmdat_p->d_align)); 20492ed1782Smike_s DEBUG_EXP(printf("d_version = %d\n", 20592ed1782Smike_s pfile_p->pf_snmdat_p->d_version)); 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate if (pfile_p->pf_snmdat_p->d_buf == NULL) 20892ed1782Smike_s _err_exit("%s %s in %s.", fail_buf_s, "header names", 20992ed1782Smike_s aout_name); 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate DEBUG_LOC("_symintOpen: after call to getdata (for header names)"); 2127c478bd9Sstevel@tonic-gate 21392ed1782Smike_s pfile_p->pf_shdarr_p = _Malloc(pfile_p->pf_elfhd_p->e_shentsize, 2147c478bd9Sstevel@tonic-gate pfile_p->pf_elfhd_p->e_shnum); 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate { 217*1dd08564Sab196087 #ifdef DEBUG 2187c478bd9Sstevel@tonic-gate char *shdnms_p = (char *)pfile_p->pf_snmdat_p->d_buf; 219*1dd08564Sab196087 #endif 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate char *dest_p = (char *)pfile_p->pf_shdarr_p; 2227c478bd9Sstevel@tonic-gate int shdsize = pfile_p->pf_elfhd_p->e_shentsize; 223*1dd08564Sab196087 int i = 0; 2247a5d89c4Sab196087 int symtab_found = 0; 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate tscn_p = 0; 2277c478bd9Sstevel@tonic-gate DEBUG_EXP(printf("Section header entry size = %d\n", shdsize)); 2287c478bd9Sstevel@tonic-gate DEBUG_EXP(printf("First section header name = %s\n", &shdnms_p[1])); 2297a5d89c4Sab196087 pfile_p->pf_symdat_aux_p = NULL; 2307a5d89c4Sab196087 /* 2317a5d89c4Sab196087 * Scan the section headers looking for a symbol table. Our 2327a5d89c4Sab196087 * preference is to use .symtab, because it contains the full 2337a5d89c4Sab196087 * set of symbols. If we find it, we stop looking immediately 2347a5d89c4Sab196087 * and use it. In the absence of a .symtab section, we are 2357a5d89c4Sab196087 * willing to use the dynamic symbol table (.dynsym), possibly 2367a5d89c4Sab196087 * augmented by the .SUNW_ldynsym, which contains local symbols. 2377a5d89c4Sab196087 */ 2387c478bd9Sstevel@tonic-gate while ((tscn_p = elf_nextscn(telf_p, tscn_p)) != NULL) { 2397c478bd9Sstevel@tonic-gate if ((tshd_p = elf32_getshdr(tscn_p)) == NULL) 2407c478bd9Sstevel@tonic-gate _err_exit("%s %d in %s.", fail_shd_s, i, aout_name); 241*1dd08564Sab196087 i++; 2427c478bd9Sstevel@tonic-gate 24392ed1782Smike_s (void) memcpy(dest_p, tshd_p, shdsize); 2447c478bd9Sstevel@tonic-gate dest_p += shdsize; 2457c478bd9Sstevel@tonic-gate 24692ed1782Smike_s DEBUG_EXP(printf("index of section name = %d\n", 24792ed1782Smike_s tshd_p->sh_name)); 248*1dd08564Sab196087 DEBUG_EXP(printf("_symintOpen: reading section %s\n", 249*1dd08564Sab196087 &shdnms_p[tshd_p->sh_name])); 2507a5d89c4Sab196087 2517a5d89c4Sab196087 if (symtab_found) 2527a5d89c4Sab196087 continue; 2537a5d89c4Sab196087 switch (tshd_p->sh_type) { 2547a5d89c4Sab196087 case SHT_SYMTAB: 2557c478bd9Sstevel@tonic-gate DEBUG_LOC("_symintOpen: found symbol section"); 2567a5d89c4Sab196087 pfile_p->pf_symstr_ndx = tshd_p->sh_link; 2577a5d89c4Sab196087 pfile_p->pf_symdat_pri_p = 2587a5d89c4Sab196087 section_data_p(tscn_p, "symtab"); 2597a5d89c4Sab196087 nsyms_pri = tshd_p->sh_size / tshd_p->sh_entsize; 2607a5d89c4Sab196087 /* Throw away .SUNW_ldynsym. It is for .dynsym only */ 2617a5d89c4Sab196087 nsyms_aux = 0; 2627a5d89c4Sab196087 pfile_p->pf_symdat_aux_p = NULL; 2637a5d89c4Sab196087 /* We have found the best symbol table. Stop looking */ 2647a5d89c4Sab196087 symtab_found = 1; 2657a5d89c4Sab196087 break; 2667a5d89c4Sab196087 2677a5d89c4Sab196087 case SHT_DYNSYM: 2687a5d89c4Sab196087 /* We will use .dynsym if no .symtab is found */ 2697a5d89c4Sab196087 DEBUG_LOC("_symintOpen: found dynamic symbol section"); 2707a5d89c4Sab196087 pfile_p->pf_symstr_ndx = tshd_p->sh_link; 2717a5d89c4Sab196087 pfile_p->pf_symdat_pri_p = 2727a5d89c4Sab196087 section_data_p(tscn_p, "dynsym"); 2737a5d89c4Sab196087 nsyms_pri = tshd_p->sh_size / tshd_p->sh_entsize; 2747a5d89c4Sab196087 break; 2757a5d89c4Sab196087 2767a5d89c4Sab196087 case SHT_SUNW_LDYNSYM: 2777a5d89c4Sab196087 /* Auxiliary table, used with .dynsym */ 2787a5d89c4Sab196087 DEBUG_LOC("_symintOpen: found dynamic symbol section"); 2797a5d89c4Sab196087 pfile_p->pf_symdat_aux_p = 2807a5d89c4Sab196087 section_data_p(tscn_p, "SUNW_ldynsym"); 2817a5d89c4Sab196087 nsyms_aux = tshd_p->sh_size / tshd_p->sh_entsize; 2827a5d89c4Sab196087 break; 2837c478bd9Sstevel@tonic-gate } 2847c478bd9Sstevel@tonic-gate 2857c478bd9Sstevel@tonic-gate } 2867c478bd9Sstevel@tonic-gate } 2877c478bd9Sstevel@tonic-gate 2887a5d89c4Sab196087 if (pfile_p->pf_symdat_pri_p == NULL || pfile_p->pf_symstr_ndx == 0) 2897c478bd9Sstevel@tonic-gate _err_exit("%s %s.", fail_sym_s, executableName); 2907a5d89c4Sab196087 2917a5d89c4Sab196087 pfile_p->pf_nstsyms = (int)(nsyms_pri + nsyms_aux); 2927a5d89c4Sab196087 pfile_p->pf_nstsyms_aux = (int)nsyms_aux; 2937a5d89c4Sab196087 if ((nsyms_pri + nsyms_aux) != (Elf64_Xword)pfile_p->pf_nstsyms) 2947a5d89c4Sab196087 _err_exit("%s %s.", fail_sym32_s, executableName); 2957a5d89c4Sab196087 2967c478bd9Sstevel@tonic-gate 2977c478bd9Sstevel@tonic-gate DEBUG_LOC("_symintOpen: after for loop that reads the sections"); 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate DEBUG_LOC("_symintOpen: before call to _symintLoad"); 3007c478bd9Sstevel@tonic-gate 3017c478bd9Sstevel@tonic-gate if ((pfile_p->pf_symarr_p = _symintLoad(pfile_p)) == NULL) 3027c478bd9Sstevel@tonic-gate _err_exit("%s %s.", fail_pfsym_s, executableName); 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate DEBUG_LOC("_symintOpen: after call to _symintLoad"); 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate /* 3077c478bd9Sstevel@tonic-gate * At this point we might want to include some consistency 3087c478bd9Sstevel@tonic-gate * checks to be sure all is well. For example, we can check 3097c478bd9Sstevel@tonic-gate * symbol table consistency by comparing "the product of the 3107c478bd9Sstevel@tonic-gate * number of symbols and the size of each symbol" to "the 3117c478bd9Sstevel@tonic-gate * length of the symbol table data". 3127c478bd9Sstevel@tonic-gate * 3137c478bd9Sstevel@tonic-gate * Also, NULL may be a proper value (e.g., the debugger 3147c478bd9Sstevel@tonic-gate * information when there is none) for some things that 3157c478bd9Sstevel@tonic-gate * we cannot afford to be without. We should check these 3167c478bd9Sstevel@tonic-gate * at this point also. 3177c478bd9Sstevel@tonic-gate */ 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate DEBUG_LOC("_symintOpen: bottom"); 3207c478bd9Sstevel@tonic-gate return (pfile_p); 3217c478bd9Sstevel@tonic-gate } 322