xref: /onnv-gate/usr/src/cmd/sgs/prof/common/symintOpen.c (revision 6951:59445bec7ef4)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
53621Sab196087  * Common Development and Distribution License (the "License").
63621Sab196087  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21211Smike_s 
22211Smike_s /*
23*6951Sab196087  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24211Smike_s  * Use is subject to license terms.
25211Smike_s  */
26211Smike_s 
270Sstevel@tonic-gate /*	Copyright (c) 1988 AT&T	*/
280Sstevel@tonic-gate /*	  All Rights Reserved  	*/
290Sstevel@tonic-gate 
300Sstevel@tonic-gate 
310Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #include <stdio.h>
340Sstevel@tonic-gate #include <fcntl.h>
35211Smike_s #include <string.h>
36211Smike_s #include "symint.h"
370Sstevel@tonic-gate #include "debug.h"
380Sstevel@tonic-gate 
39211Smike_s /*
400Sstevel@tonic-gate  * symintFcns.c -- symbol information interface routines.
41211Smike_s  *
420Sstevel@tonic-gate  * these routines form a symbol information access
430Sstevel@tonic-gate  * interface, for the profilers to get at object file
440Sstevel@tonic-gate  * information.  this interface was designed to aid
450Sstevel@tonic-gate  * in the COFF to ELF conversion of prof, lprof and friends.
46211Smike_s  *
470Sstevel@tonic-gate  */
480Sstevel@tonic-gate 
490Sstevel@tonic-gate 
50211Smike_s /*
510Sstevel@tonic-gate  * _symintOpen(aout_name)
520Sstevel@tonic-gate  * aout_name 	- char string file name of object file
53211Smike_s  *		to open.
54211Smike_s  *
550Sstevel@tonic-gate  * returns PROF_FILE * - pointer to the PROF_FILE structure built,
56211Smike_s  *			or NULL if fails.
570Sstevel@tonic-gate  */
580Sstevel@tonic-gate 
59211Smike_s /*
60211Smike_s  *
610Sstevel@tonic-gate  * .H 3 "Executable File Open and Close"
62211Smike_s  *
630Sstevel@tonic-gate  * Under COFF, the routine ldopen, given a file name, returns a pointer to a
640Sstevel@tonic-gate  * structure called an LDFILE.  This descriptor is then passed to each of
650Sstevel@tonic-gate  * the library routines (such as read header, read symbol table entry, etc)
660Sstevel@tonic-gate  * to access the information contained in the file.  These calls are spread
670Sstevel@tonic-gate  * throughout the profiling code.
68211Smike_s  *
690Sstevel@tonic-gate  * Under ELF, the file must be opened using a system open call.  The file
700Sstevel@tonic-gate  * descriptor is then passed to a routine which returns a pointer to an
710Sstevel@tonic-gate  * Elf structure.  This pointer is then passed along to another routine which
720Sstevel@tonic-gate  * returns a different pointer which is in turn passed along to another
730Sstevel@tonic-gate  * routine.  In an attempt to avoid disturbing the current format of the
740Sstevel@tonic-gate  * code (by having to pass around different types of pointers), we plan to
750Sstevel@tonic-gate  * build a PROF_FILE descriptor which will then be passed around in the
760Sstevel@tonic-gate  * same way as the pointer to LDFILE.
77211Smike_s  *
780Sstevel@tonic-gate  * Thus, for ELF, an open will consist of opening the file and extracting
790Sstevel@tonic-gate  * enough from it to fill in the PROF_FILE structure.  The code for the
800Sstevel@tonic-gate  * open is as follows; the code for building the symbol table (extracting
810Sstevel@tonic-gate  * information from the sections to fill an array of PROF_SYMBOLS) has
820Sstevel@tonic-gate  * yet to be written.
83211Smike_s  *
840Sstevel@tonic-gate  */
850Sstevel@tonic-gate 
86211Smike_s /*
873621Sab196087  * globals
880Sstevel@tonic-gate  */
890Sstevel@tonic-gate 
900Sstevel@tonic-gate 
910Sstevel@tonic-gate static char
920Sstevel@tonic-gate 	*fail_open_s =	"Unable to open file",
930Sstevel@tonic-gate 	*fail_begin_s =	"Unable to read (begin) file",
940Sstevel@tonic-gate 	*fail_ehdr_s =	"Unable to get elf header in",
950Sstevel@tonic-gate 	*fail_sec_s =	"Unable to get section",
960Sstevel@tonic-gate 	*fail_shd_s =	"Unable to get header for section",
970Sstevel@tonic-gate 	*fail_dat_s =	"Unable to get data for section",
980Sstevel@tonic-gate 	*fail_sym_s =	"Cannot find symbol table section in",
990Sstevel@tonic-gate 	*fail_pfsym_s =	"Unable to process symbols in",
1003621Sab196087 	*fail_buf_s =	"Data buffer is null for section",
1013621Sab196087 	*fail_sym32_s =	"Cannot handle more than 2^32 symbols"
1020Sstevel@tonic-gate 	;
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate 
105211Smike_s /*
1060Sstevel@tonic-gate  * this points at the name of the executable.
1070Sstevel@tonic-gate  */
1080Sstevel@tonic-gate static  char *executableName;
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate 
112211Smike_s /*
1130Sstevel@tonic-gate  * section_data_p() - return ptr to section data,
1140Sstevel@tonic-gate  * 	given section ptr and name of section.
1150Sstevel@tonic-gate  */
1160Sstevel@tonic-gate 
117211Smike_s static Elf_Data *
section_data_p(Elf_Scn * sec_p,char * str)118211Smike_s section_data_p(Elf_Scn *sec_p, char *str)
1190Sstevel@tonic-gate {
1200Sstevel@tonic-gate 	Elf_Data *dat_p;
121211Smike_s 
1220Sstevel@tonic-gate 	if ((dat_p = elf_getdata(sec_p, NULL)) == NULL)
1230Sstevel@tonic-gate 		_err_exit("%s %s in %s.", fail_dat_s, str, executableName);
124211Smike_s 	return (dat_p);
1250Sstevel@tonic-gate }
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate PROF_FILE *
_symintOpen(char * aout_name)129211Smike_s _symintOpen(char *aout_name)
130211Smike_s {
1310Sstevel@tonic-gate /*
132211Smike_s  * Elf file open operation
133211Smike_s  *
134211Smike_s  * - point at executable's name, globally
135211Smike_s  * - open file
136211Smike_s  * - align to current version
137211Smike_s  * - read the elf descriptor and header
138211Smike_s  * - read header-names section descriptor, header, and data
139211Smike_s  * - allocate space for all the section hdrs (pf_shdarr_p).
140211Smike_s  * - set a pointer to the header-names buffer
141211Smike_s  * - search the section headers for
142211Smike_s  *	- debug section header and data
143211Smike_s  *	- line section header and data
144211Smike_s  *	- symbol table header, data, strings, and number of symbols
145211Smike_s  *	  and copy each section hdr into our array.
146211Smike_s  *  - populate the PROF_SYMBOL array and anchor it in (pf_symarr_p).
147211Smike_s  */
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate 	PROF_FILE	*pfile_p;	/* PROF_FILE ptr to return. */
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate 	Elf		*telf_p;
1520Sstevel@tonic-gate 	Elf_Scn		*tscn_p;
1530Sstevel@tonic-gate 	Elf32_Shdr	*tshd_p;
1540Sstevel@tonic-gate 	int		k;
1553621Sab196087 	Elf64_Xword	nsyms_pri = 0, nsyms_aux = 0;
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate 	executableName = aout_name;
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate 	DEBUG_LOC("_symintOpen: top");
160211Smike_s 	if (aout_name == NULL) {
1610Sstevel@tonic-gate 		_err_exit("name of executable is null\n");
1620Sstevel@tonic-gate 	}
1630Sstevel@tonic-gate 	DEBUG_EXP(printf("Attempting to open %s\n", aout_name));
164211Smike_s 	pfile_p = _Malloc(sizeof (PROF_FILE), 1);
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate 	if ((pfile_p->pf_fildes = open(aout_name, O_RDONLY)) == -1)
1670Sstevel@tonic-gate 		_err_exit("%s %s.", fail_open_s, aout_name);
1680Sstevel@tonic-gate 	if ((elf_version(EV_CURRENT)) == EV_NONE)
1690Sstevel@tonic-gate 		_err_exit("Elf library out of date");
170211Smike_s 	if ((pfile_p->pf_elf_p = elf_begin(pfile_p->pf_fildes,
171211Smike_s 	    ELF_C_READ, (Elf *)NULL)) == NULL)
1720Sstevel@tonic-gate 		_err_exit("%s %s.", fail_begin_s, aout_name);
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate 	DEBUG_EXP(printf("elfkind = %d\n", elf_kind(pfile_p->pf_elf_p)));
1750Sstevel@tonic-gate 	if ((pfile_p->pf_elfhd_p = elf32_getehdr(pfile_p->pf_elf_p)) == NULL)
1760Sstevel@tonic-gate 		_err_exit("%s %s.", fail_ehdr_s, aout_name);
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 	DEBUG_LOC("_symintOpen: after call to getehdr");
1790Sstevel@tonic-gate 	telf_p = pfile_p->pf_elf_p;
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate 	tscn_p = elf_getscn(telf_p, k = pfile_p->pf_elfhd_p->e_shstrndx);
1820Sstevel@tonic-gate 	if (tscn_p == NULL)
1830Sstevel@tonic-gate 		_err_exit("%s %d in %s.", fail_sec_s, k, aout_name);
1840Sstevel@tonic-gate 
1853621Sab196087 	if (elf32_getshdr(tscn_p) == NULL)
186211Smike_s 		_err_exit("%s %s in %s.", fail_shd_s, "header names",
187*6951Sab196087 		    aout_name);
1880Sstevel@tonic-gate 	if ((pfile_p->pf_snmdat_p = elf_getdata(tscn_p, NULL)) == NULL)
189211Smike_s 		_err_exit("%s %s in %s.", fail_dat_s, "header names",
190*6951Sab196087 		    aout_name);
191211Smike_s 
192211Smike_s 	DEBUG_EXP(printf("Address of data header = 0x%lx\n",
193211Smike_s 	    pfile_p->pf_snmdat_p));
194211Smike_s 	DEBUG_EXP(printf("d_buf     = 0x%lx\n",
195211Smike_s 	    pfile_p->pf_snmdat_p->d_buf));
196211Smike_s 	DEBUG_EXP(printf("d_type    = %d\n",
197211Smike_s 	    pfile_p->pf_snmdat_p->d_type));
198211Smike_s 	DEBUG_EXP(printf("d_size    = %d\n",
199211Smike_s 	    pfile_p->pf_snmdat_p->d_size));
200211Smike_s 	DEBUG_EXP(printf("d_off     = %d\n",
201211Smike_s 	    pfile_p->pf_snmdat_p->d_off));
202211Smike_s 	DEBUG_EXP(printf("d_align   = %d\n",
203211Smike_s 	    pfile_p->pf_snmdat_p->d_align));
204211Smike_s 	DEBUG_EXP(printf("d_version = %d\n",
205211Smike_s 	    pfile_p->pf_snmdat_p->d_version));
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate 	if (pfile_p->pf_snmdat_p->d_buf == NULL)
208211Smike_s 		_err_exit("%s %s in %s.", fail_buf_s, "header names",
209211Smike_s 		    aout_name);
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate 	DEBUG_LOC("_symintOpen: after call to getdata (for header names)");
2120Sstevel@tonic-gate 
213211Smike_s 	pfile_p->pf_shdarr_p = _Malloc(pfile_p->pf_elfhd_p->e_shentsize,
214211Smike_s 	    pfile_p->pf_elfhd_p->e_shnum);
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 	{
217*6951Sab196087 #ifdef DEBUG
218211Smike_s 	char	*shdnms_p = (char *)pfile_p->pf_snmdat_p->d_buf;
219*6951Sab196087 #endif
2200Sstevel@tonic-gate 
221211Smike_s 	char	*dest_p = (char *)pfile_p->pf_shdarr_p;
222211Smike_s 	int	shdsize = pfile_p->pf_elfhd_p->e_shentsize;
223*6951Sab196087 	int	i = 0;
2243621Sab196087 	int		symtab_found = 0;
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 	tscn_p = 0;
227211Smike_s 	DEBUG_EXP(printf("Section header entry size = %d\n", shdsize));
228211Smike_s 	DEBUG_EXP(printf("First section header name = %s\n", &shdnms_p[1]));
2293621Sab196087 	pfile_p->pf_symdat_aux_p = NULL;
2303621Sab196087 	/*
2313621Sab196087 	 * Scan the section headers looking for a symbol table. Our
2323621Sab196087 	 * preference is to use .symtab, because it contains the full
2333621Sab196087 	 * set of symbols. If we find it, we stop looking immediately
2343621Sab196087 	 * and use it. In the absence of a .symtab section, we are
2353621Sab196087 	 * willing to use the dynamic symbol table (.dynsym), possibly
2363621Sab196087 	 * augmented by the .SUNW_ldynsym, which contains local symbols.
2373621Sab196087 	 */
2380Sstevel@tonic-gate 	while ((tscn_p = elf_nextscn(telf_p, tscn_p)) != NULL) {
2390Sstevel@tonic-gate 		if ((tshd_p = elf32_getshdr(tscn_p)) == NULL)
2400Sstevel@tonic-gate 			_err_exit("%s %d in %s.", fail_shd_s, i, aout_name);
241*6951Sab196087 		i++;
2420Sstevel@tonic-gate 
243211Smike_s 		(void) memcpy(dest_p, tshd_p, shdsize);
244211Smike_s 		dest_p += shdsize;
2450Sstevel@tonic-gate 
246211Smike_s 		DEBUG_EXP(printf("index of section name = %d\n",
247211Smike_s 		    tshd_p->sh_name));
248*6951Sab196087 		DEBUG_EXP(printf("_symintOpen: reading section %s\n",
249*6951Sab196087 		    &shdnms_p[tshd_p->sh_name]));
2503621Sab196087 
2513621Sab196087 		if (symtab_found)
2523621Sab196087 			continue;
2533621Sab196087 		switch (tshd_p->sh_type) {
2543621Sab196087 		case SHT_SYMTAB:
2550Sstevel@tonic-gate 			DEBUG_LOC("_symintOpen: found symbol section");
2563621Sab196087 			pfile_p->pf_symstr_ndx = tshd_p->sh_link;
2573621Sab196087 			pfile_p->pf_symdat_pri_p =
2583621Sab196087 			    section_data_p(tscn_p, "symtab");
2593621Sab196087 			nsyms_pri = tshd_p->sh_size / tshd_p->sh_entsize;
2603621Sab196087 			/* Throw away .SUNW_ldynsym. It is for .dynsym only */
2613621Sab196087 			nsyms_aux = 0;
2623621Sab196087 			pfile_p->pf_symdat_aux_p = NULL;
2633621Sab196087 			/* We have found the best symbol table. Stop looking */
2643621Sab196087 			symtab_found = 1;
2653621Sab196087 			break;
2663621Sab196087 
2673621Sab196087 		case SHT_DYNSYM:
2683621Sab196087 			/* We will use .dynsym if no .symtab is found */
2693621Sab196087 			DEBUG_LOC("_symintOpen: found dynamic symbol section");
2703621Sab196087 			pfile_p->pf_symstr_ndx = tshd_p->sh_link;
2713621Sab196087 			pfile_p->pf_symdat_pri_p =
2723621Sab196087 			    section_data_p(tscn_p, "dynsym");
2733621Sab196087 			nsyms_pri = tshd_p->sh_size / tshd_p->sh_entsize;
2743621Sab196087 			break;
2753621Sab196087 
2763621Sab196087 		case SHT_SUNW_LDYNSYM:
2773621Sab196087 			/* Auxiliary table, used with .dynsym */
2783621Sab196087 			DEBUG_LOC("_symintOpen: found dynamic symbol section");
2793621Sab196087 			pfile_p->pf_symdat_aux_p =
2803621Sab196087 			    section_data_p(tscn_p, "SUNW_ldynsym");
2813621Sab196087 			nsyms_aux = tshd_p->sh_size / tshd_p->sh_entsize;
2823621Sab196087 			break;
2830Sstevel@tonic-gate 		}
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate 	}
2860Sstevel@tonic-gate 	}
2870Sstevel@tonic-gate 
2883621Sab196087 	if (pfile_p->pf_symdat_pri_p == NULL || pfile_p->pf_symstr_ndx == 0)
2890Sstevel@tonic-gate 		_err_exit("%s %s.", fail_sym_s, executableName);
2903621Sab196087 
2913621Sab196087 	pfile_p->pf_nstsyms = (int)(nsyms_pri + nsyms_aux);
2923621Sab196087 	pfile_p->pf_nstsyms_aux = (int)nsyms_aux;
2933621Sab196087 	if ((nsyms_pri + nsyms_aux) != (Elf64_Xword)pfile_p->pf_nstsyms)
2943621Sab196087 		_err_exit("%s %s.", fail_sym32_s, executableName);
2953621Sab196087 
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	DEBUG_LOC("_symintOpen: after for loop that reads the sections");
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 	DEBUG_LOC("_symintOpen: before call to _symintLoad");
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 	if ((pfile_p->pf_symarr_p = _symintLoad(pfile_p)) == NULL)
3020Sstevel@tonic-gate 		_err_exit("%s %s.", fail_pfsym_s, executableName);
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	DEBUG_LOC("_symintOpen: after call to _symintLoad");
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 	/*
307211Smike_s 	 * At this point we might want to include some consistency
308211Smike_s 	 * checks to be sure all is well.  For example, we can check
309211Smike_s 	 * symbol table consistency by comparing "the product of the
310211Smike_s 	 * number of symbols and the size of each symbol" to "the
311211Smike_s 	 * length of the symbol table data".
312211Smike_s 	 *
313211Smike_s 	 * Also, NULL may be a proper value (e.g., the debugger
314211Smike_s 	 * information when there is none) for some things that
315211Smike_s 	 * we cannot afford to be without.  We should check these
316211Smike_s 	 * at this point also.
317211Smike_s 	 */
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 	DEBUG_LOC("_symintOpen: bottom");
320211Smike_s 	return (pfile_p);
3210Sstevel@tonic-gate }
322