xref: /titanic_52/usr/src/cmd/sgs/prof/common/symintOpen.c (revision bdfc6d18da790deeec2e0eb09c625902defe2498)
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