xref: /titanic_51/usr/src/cmd/sgs/prof/common/symintLoad.c (revision 8eea8e29cc4374d1ee24c25a07f45af132db3499)
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 /*	Copyright (c) 1988 AT&T	*/
23 /*	  All Rights Reserved  	*/
24 
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29 *	File: symintLoad.c
30 *	Date: 12/15/88
31 *
32 *	This file provides code to build the profiling symbol array
33 *	(array of PROF_SYMBOL).  This array contains all of the
34 *	symbol table information plus selected debug information for
35 *	each file and each function that has a coverage array.
36 *
37 *	The symbol table contains entries for every file, every
38 *	function, and every coverage array.  The debug information
39 *	has corresponding entries except that there are no entries
40 *	for the coverage arrays.  (This may change later.)
41 *
42 *	The algorithm for building the profiling symbol array
43 *	consists of scanning the symbol table for file, function,
44 *	and coverage array entries and building an entry for each.
45 *	The construction of an entry is constrained by the
46 *	following factors:
47 *
48 *		- An entry is built for every file.
49 *
50 *		- An entry is built for a function only if there
51 *		is a corresponding coverage array for the function.
52 *
53 *		- Entries must be ordered in the sense that each
54 *		non-file entry points to its owner file and each
55 *		file entry points to the next file (or null).
56 *
57 *		- The assembler specification (see C Issue 5 3B2
58 *		Assembler System Test Specification by Howe, p. 28)
59 *		states that all local symbols follow their file
60 *		symbol in the symbol table.  This allows us to relate
61 *		a function and its coverage array to the file that
62 *		contains it.
63 *
64 *		- For each symbol included in the profiling symbol
65 *		array, all corresponding symbol table information must
66 *		be present together with selected debug information.
67 *		Therefore, the correspondence between a symbol table
68 *		entry and a debug entry must be established.
69 *
70 *		- Although duplicate (static) function names may appear,
71 *		the names are unique within a given file.  Also, the
72 *		value (address) of each function is included in both
73 *		the symbol table information and the debug information.
74 *		This provides a verifable correspondence between these
75 *		information sets.
76 *
77 *	The algorithm used in this file is as follows:
78 */
79 
80 
81 
82 /*
83 * This is a discussion of the problem of multiple files with a single
84 * name.  (See also, the _err_exit call in the routine "add_function".)
85 *
86 * Currently, when the executable contains more than one file with
87 * a common name, we sometimes mix a set of functions with the wrong
88 * file.  Because the addresses don't match, add_profsymbol tends to
89 * fail (with _err_exit).  The problem is to consistently choose the
90 * correct file for the set of functions that are about to be processed.
91 * This aspect of the problem has been addressed by the code below,
92 * but there is another part to the story.
93 *
94 * In order to match the symbol table with the debug information, we
95 * have to strip the path (if any) off of the file name; that is,
96 * the function _CAleaf is used to find the name of the file.  This
97 * means that even if we make the match, we may still have trouble
98 * finding the file.  One solution might be to retain a pointer to
99 * the full name for use at the proper point (when lprof is trying
100 * to find the source file).  I have not traced this down completely;
101 * it may or may not work depending upon whether the full path is
102 * always included in the debug information.  If it is not possible
103 * to depend on the complete path, then there may be no way to completely
104 * solve the problem.  (Consider talking to the debugger people about
105 * this problem; they have to deal with it also.)
106 *
107 * Below I have included the code I used to solve the first part of
108 * the problem.  I have also included an explanation of what each part
109 * of the code does.  When the code is implemented this way, it does
110 * work for some cases, but I'm not sure that the assumptions it makes
111 * are valid.  In particular, it makes implicit assumptions about the
112 * ordering of names and pointers; you should check that these assumptions
113 * do not include that the values returned from malloc are monotone
114 * increasing (which I think they do).
115 *
116 * With the following change, add_profsymbol will scan to the first
117 * file entry of the given name that has not yet been processed.  It
118 * detects that a file has been processed by noting that sn_value_p
119 * has been set to zero; it accepts the first one whose value is not
120 * zero and calls dbfill_tag to "refill" the tag.  Warning: setting
121 * sn_value_p to zero is dangerous; in particular, you must avoid
122 * trying to use this value when it is zero.  Some cpus will produce
123 * a segmentation violation, but the 3b2 does not.
124 *
125 * add_profsymbol()
126 * {
127 * ...
128 * 	} else if (stchk_file(prsym_p)) {
129 * 		if (
130 * 			(sn_p + 1) < (dblist + dblist_cnt)
131 * 			&& strcmp(sn_p[0].sn_name_p, sn_p[1].sn_name_p) == 0
132 * 		) {
133 * 			_err_warn(
134 * 				"File name %s was used more than once.",
135 * 				sn_p->sn_name_p
136 * 			);
137 * 			while (
138 * 				sn_p->sn_value_p == 0
139 * 				&& sn_p < (dblist + dblist_cnt)
140 * 			) {
141 * 				sn_p++;
142 * 			}
143 * 			dbfill_tag(sn_p->sn_value_p, &tag);
144 * 		}
145 * 		sn_p->sn_value_p = 0;
146 * 		add_file(&tag);
147 * 	} else {
148 * ...
149 * }
150 *
151 * The change to sn_search is only to prepare for a call to sn_compare
152 * which has been changed to compare on both the name and the pointer
153 * value (instead of just the name).  (Here, we might be using the
154 * incorrect assumption that malloc is monotone increasing; this scheme
155 * should be carefully thought out.)  The change consists of setting
156 * the sn_value_p in the local tnode to zero; this allows sn_compare
157 * to ignore the value and compare only the name.
158 *
159 * sn_search()
160 * {
161 * ...
162 * 	tnode.sn_name_p = name_p;
163 * 	tnode.sn_value_p = 0;
164 * ...
165 * }
166 *
167 * This routine used to compare only the name; now it compares both
168 * the name and  the sn_value_p pointer (see note above sn_search).
169 * When the value pointer is zero, there is no use in comparing
170 * that part of the item.
171 *
172 * sn_compare()
173 * {
174 * 	register int i;
175 *
176 * 	if (i = strcmp(a_p->sn_name_p, b_p->sn_name_p)) {
177 * 		return(i);
178 *  	} else if (a_p->sn_value_p == 0 || b_p->sn_value_p == 0) {
179 *  		return(i);
180 *  	} else if (a_p->sn_value_p < b_p->sn_value_p) {
181 *  		return(-1);
182 *  	} else {
183 *  		return(1);
184 *  	}
185 * }
186 */
187 
188 
189 #include "string.h"
190 #include "symint.h"
191 #include "debug.h"
192 
193 /* search node */
194 typedef struct {
195 	char *sn_name_p;
196 	char *sn_value_p;
197 } SEARCH_NODE;
198 
199 
200 PROF_SYMBOL * _symintLoad();
201 
202 #if isLPROF
203 static int addcovset();
204 static SEARCH_NODE *build_stlist();
205 static int stscan();
206 static int stchk_focov();
207 static int stchk_filowog();
208 static int stchk_gowf();
209 static int stchk_func();
210 static int stchk_file();
211 static int stchk_cov();
212 static int stchk_match();
213 static void init_dblist();
214 static int dbscan_tag();
215 static void dbfill_tag();
216 static char * dbseek_att();
217 static int dbchk_stmnts();
218 static int dbchk_lowpc();
219 static int dbchk_highpc();
220 static int dbchk_filosub();
221 static PROF_SYMBOL * add_profsymbol();
222 static int add_function();
223 static void add_file();
224 static void check_capacity();
225 static char * debName();
226 static LEN4 bytesFor();
227 static SEARCH_NODE * sn_search();
228 static int sn_compare();
229 #ifdef DEBUG
230 static void sn_dump();
231 static void profsym_dump();
232 #endif
233 static LEN2 alignval2();
234 static LEN4 alignval4();
235 static void verify_match();
236 #endif
237 
238 
239 /* debug tag */
240 typedef struct {
241 	LEN4	tg_length;
242 	LEN2	tg_value;
243 	char	*tg_att_p;
244 	int	tg_attlen;
245 } DB_TAG;
246 
247 /*
248 *	Debug list used to connect a symbol table entry to a debug entry.
249 */
250 static SEARCH_NODE	*dblist;	/* array */
251 static int		dblist_cnt;	/* number of elements in array */
252 
253 /*
254 *	Global symbol table list used to connect coverage array entries
255 *	with their (global) owner functions.  This list contains all
256 *	global and weak functions.
257 */
258 static SEARCH_NODE	*gstlist;	/* array */
259 static int		gstlist_cnt;	/* number of elements in array */
260 
261 static PROF_FILE	*profPtr;
262 
263 #define ST_NAME(a)	&profPtr->pf_symstr_p[(a)->st_name]
264 #define PS_NAME(a)	&profPtr->pf_symstr_p[(a)->ps_sym.st_name]
265 #define DB_NAME(a)	(a)->ps_dbg.pd_name
266 #define DB_TAGLEN(ap)	alignval4(ap)
267 #define DB_STMNTOS(ap)	alignval4((ap) + sizeof(LEN2))
268 #define DB_PCVALUE(ap)	alignval4((ap) + sizeof(LEN2))
269 
270 /*
271 *	NOTE: When you change MATCH_STR, also change pcrt1.s.
272 *	(See notes on "verify_match" below.)
273 */
274 #ifdef __STDC__
275 #define	MATCH_NAME	_edata
276 #define	MATCH_STR	"_edata"
277 #else
278 #define	MATCH_NAME	edata
279 #define	MATCH_STR	"edata"
280 #endif
281 
282 static PROF_SYMBOL	*prsym_list_p = 0;	/* the list to return. */
283 static int		prsym_cnt = 0;	/* #entries in the list */
284 static int		prsym_cap = 0;	/* #entries capacity allocated */
285 
286 static int		prstsym_size;	/* size of a symbol table symbol */
287 
288 static int		add_profsym_search_fail; /* see add_profsymbol() */
289 
290 #if isLPROF
291 static int		prsym_size;	/* size of a PROF_SYMBOL */
292 
293 
294 /* * * * * *
295  * addr of line information, and of the PROF_DEBUGE,
296  * associated with the last file (symbol) seen.
297  *
298  * also, the DEBUGE for the file in effect Before the current one!
299  */
300 #define DBG_LINE_SIZE	(sizeof(LEN4) + sizeof(LEN2) + sizeof(LEN4))
301 static char		*curf_lp;
302 static LEN4		curf_lncnt;
303 static LEN4		curf_base;
304 static PROF_LINE	*curf_lns_p;
305 
306 static PROF_DEBUGE	*curf_dbp;
307 static PROF_DEBUGE	*priorFile_dbp;
308 
309 #endif
310 
311 /* * * * * *
312  * _symintLoad(proffilePtr)
313  * proffilePtr	- PROF_FILE pointer returned by _symintOpen().
314  *
315  * returns PROF_SYMBOL * - pointer to the malloc-ed array of
316  * 			   symbol information entries, or
317  * 			   NULL if fails.
318  *
319  *
320  * This routine builds the interface data structure from the data
321  * already loaded during _symintOpen().
322  *
323  * There are two different incarnations of this routine:
324  * one for Prof, and one for Lprof.
325  *
326  * Lprof:
327  *
328  * 	1. Pass through the symbol table and
329  * 	   populate an extended PROF_SYMBOL array.
330  *
331  * 	2. Include only certain symbols (see intro).
332  *
333  * 	3. Find and include the debug information
334  * 	   for each included symbol.
335  *
336  * Prof:
337  *
338  * 	1. Allocate a duplicate copy of the symbol table
339  * 	   data.  (For Prof, a PROF_SYMBOL is just
340  * 	   a structure containing an Elf32_Sym!)
341  *
342  * 	2. Set internal parameters to reflect this.
343  *
344  *
345  * Problems are dealt with by issuing an _err_exit().
346  *
347  */
348 PROF_SYMBOL *
349 _symintLoad(proffilePtr)
350 PROF_FILE	*proffilePtr;
351 {
352 	Elf_Data	*symdat_p;
353 	PROF_SYMBOL	*ps;
354 	int		symcount = 0;
355 #if isLPROF
356 	Elf32_Sym	*sym_p;
357 	Elf32_Sym	*sym_lim_p;
358 	Elf32_Sym	*next_p;
359 	Elf32_Sym	*tsym_p;
360 #endif
361 
362 	DEBUG_LOC("_symintLoad: top");
363 
364 	profPtr = proffilePtr;
365 
366 	/* * * * * *
367 	 * sanity checks.
368 	 */
369 	DEBUG_EXP(printf("profPtr = %x\n", profPtr));
370 	DEBUG_EXP(printf("profPtr->pf_symdat_p = %x\n", profPtr->pf_symdat_p));
371 	DEBUG_EXP(printf("profPtr->pf_nstsyms = %x\n", profPtr->pf_nstsyms));
372 
373 	assert( profPtr != 0 );
374 	assert( profPtr->pf_symdat_p != 0 );
375 	assert( profPtr->pf_nstsyms != 0 );
376 
377 	symdat_p = profPtr->pf_symdat_p;
378 	DEBUG_EXP(printf("symdat_p->d_size = %x\n", symdat_p->d_size));
379 
380 	prstsym_size = (symdat_p->d_size / profPtr->pf_nstsyms);
381 	DEBUG_EXP(printf("_symintLoad: prstsym_size = %d\n",prstsym_size));
382 
383 #if isLPROF
384 	prsym_size = prstsym_size + sizeof(PROF_DEBUGE);
385 	DEBUG_EXP(printf("_symintLoad: prsym_size = %d\n",prsym_size));
386 
387 	/* * * * * *
388 	 * Initialize structure parameters.  Updated by add_profsymbol().
389 	 */
390 	prsym_cnt = prsym_cap = 0;
391 
392 	init_dblist();
393 
394 	sym_lim_p = (Elf32_Sym *)
395 		(((char *) (symdat_p->d_buf)) + symdat_p->d_size);
396 
397 	tsym_p = NULL;
398 	gstlist = build_stlist(tsym_p, sym_lim_p, stchk_gowf, &gstlist_cnt);
399 
400 	verify_match();
401 
402 	next_p = NULL;
403 	(void) stscan(&next_p, sym_lim_p, stchk_file);
404 
405 	priorFile_dbp = 0;
406 
407 	sym_p = next_p;
408 	while (sym_p < sym_lim_p) {
409 		NO_DEBUG(printf("index for sym_p = %d\n",sym_p->st_name));
410 		NO_DEBUG(printf("name for sym_p = %s\n", ST_NAME(sym_p)));
411 
412 		(void) stscan(&next_p, sym_lim_p, stchk_filowog);
413 		tsym_p = sym_p;
414 		if (stscan(&tsym_p, next_p, stchk_cov)) {
415 			symcount += addcovset(sym_p, next_p, tsym_p);
416 		}
417 		if (!stchk_file(next_p)) {
418 			(void) stscan(&next_p, sym_lim_p, stchk_file);
419 		}
420 		sym_p = next_p;
421 	}
422 
423 	free(gstlist);
424 	profPtr->pf_nsyms = symcount;
425 
426 	DEBUG_EXP(printf("number of symbols constructed = %d\n", symcount));
427 #ifdef DEBUG
428 	printf("before profsym_dump\n");
429 	profsym_dump(prsym_list_p, symcount);
430 	printf("after profsym_dump\n");
431 #endif
432 
433 #else	/* isPROF */
434 
435 	/* * * * * *
436 	 * alloc a new copy of the array, and
437 	 *  do a bit-wise copy since the structures
438 	 *  ARE THE SAME SIZE & (effectively) HAVE THE SAME FIELDS!
439 	 *  Set the descriptive `parameters' accordingly.
440 	 *
441 	 * (We'll take a copy, to simplify the 'Drop'
442 	 *  logic.)
443 	 */
444 
445 	{
446 	int st_size;	/* size of symbol table data */
447 
448 	st_size = symdat_p->d_size;
449 
450 	NO_DEBUG_LOC("_symintLoad: before malloc for symbol list (PROF)");
451 	prsym_list_p = (PROF_SYMBOL *) _Malloc(st_size, 1);
452 	NO_DEBUG_LOC("_symintLoad: after malloc for symbol list (PROF)");
453 	prsym_cap = prsym_cnt = profPtr->pf_nstsyms;
454 
455 	NO_DEBUG_LOC("_symintLoad: before memcpy for symbol list (PROF)");
456 	memcpy((char *) &(prsym_list_p->ps_sym), symdat_p->d_buf, st_size);
457 
458 	profPtr->pf_nsyms = profPtr->pf_nstsyms;
459 	}
460 
461 #endif
462 	DEBUG_LOC("_symintLoad: bottom");
463 	return( prsym_list_p );
464 }
465 
466 
467 #ifdef  isLPROF
468 /*
469 *	addcovset: Add coverage array set to PROF_SYMBOL array.
470 *
471 *	The (local) symbols between the given file symbol and the
472 *	end contain at least one coverage array.  Sort all function
473 *	and coverage array symbols (by name) within the given bounds
474 *	and process each of the coverage array symbols by finding
475 *	its corresponding (local or global) function and adding entries
476 *	for both the coverage array and the function to the profile
477 *	symbol array.  Note that the file is also added to the profile
478 *	symbol array and that pointers are managed accordingly (the file
479 *	entries are linked and each of the non-file entries points
480 *	to its owner file).
481 *
482 *	- Add the file to the PROF_SYMBOL array.  If the file is not
483 *	found (i.e., the filename in the debug information does not
484 *	match the filename in the symbol table), then fail.
485 *	- Build (allocate) a sorted list of all function and coverage
486 *	array symbols within the given limits.
487 *	- Find the top of the coverage array subset of the pointer list.
488 *	- For each coverage array pointer:
489 *		- Find its function (look in local list, then global list).
490 *		- Add function and assoc coverage array to PROF_SYMBOL array.
491 *	- Free the sorted list.
492 *
493 *	Note: "k" is used to avoid having "cov_p" increment beyond
494 *	the last allocated search node and thereby (possibly) cause
495 *	a segmentation violation.
496 */
497 static int
498 addcovset(filsym_p, end_p, cov_p)
499 Elf32_Sym *filsym_p;
500 Elf32_Sym *end_p;
501 Elf32_Sym *cov_p;
502 {
503 	SEARCH_NODE	*stl_p;
504 	SEARCH_NODE	*sncov_p;
505 	SEARCH_NODE	*snfunc_p;
506 	PROF_SYMBOL	*ps_p;
507 	int		k, stlcount;
508 	char		*fname_p;
509 	int		symcount = 0;
510 
511 	DEBUG_LOC("addcovset: top");
512 	ps_p = add_profsymbol(filsym_p);
513 	if (add_profsym_search_fail) {
514 		_err_exit("Unable to locate file %s in debug information.\n",
515 			ST_NAME(filsym_p)
516 		);
517 	}
518 	ps_p->ps_dbg.pd_file_p = 0;
519 	symcount++;
520 	DEBUG_EXP(printf("debug name for ps_p = %s\n", DB_NAME(ps_p)));
521 
522 	curf_dbp = &(ps_p->ps_dbg);
523 	if (priorFile_dbp) {
524 		priorFile_dbp->pd_file_p = curf_dbp;
525 	}
526 	priorFile_dbp = curf_dbp;
527 
528 	stl_p = build_stlist(filsym_p, end_p, stchk_focov, &stlcount);
529 	sncov_p = sn_search(ST_NAME(cov_p), stl_p, stlcount);
530 	while (
531 		(sncov_p-1) >= stl_p
532 		&& strncmp(
533 			(sncov_p-1)->sn_name_p,
534 			COV_PREFIX,
535 			sizeof(COV_PREFIX)-1
536 		) == 0
537 	) {
538 		sncov_p--;
539 	}
540 
541 	k = stlcount;
542 	while (k-- > 0 && stchk_cov((Elf32_Sym *) (sncov_p->sn_value_p))) {
543 		fname_p = (char *) &(sncov_p->sn_name_p[sizeof(COV_PREFIX)-1]);
544 		if (
545 			(snfunc_p = sn_search(fname_p, stl_p, stlcount))
546 			|| (snfunc_p = sn_search(fname_p, gstlist, gstlist_cnt))
547 		) {
548 			ps_p = add_profsymbol(snfunc_p->sn_value_p);
549 			ps_p->ps_dbg.pd_file_p = curf_dbp;
550 			symcount++;
551 
552 			ps_p = add_profsymbol(sncov_p->sn_value_p);
553 			ps_p->ps_dbg.pd_file_p = curf_dbp;
554 			symcount++;
555 		}
556 		sncov_p++;
557 	}
558 
559 	free(stl_p);
560 	DEBUG_LOC("addcovset: bottom");
561 	return(symcount);
562 }
563 
564 
565 /*
566 *	build_stlist: Build a tailored list of symbol table entries.
567 */
568 static SEARCH_NODE *
569 build_stlist(begin_p, end_p, filter_p, count_p)
570 Elf32_Sym	*begin_p;
571 Elf32_Sym	*end_p;
572 int		(*filter_p)();
573 int		*count_p;
574 {
575 	Elf32_Sym	*tsym_p;
576 	SEARCH_NODE	*list_p;
577 	int		i, count;
578 
579 	DEBUG_LOC("build_stlist: top");
580 	DEBUG_EXP(printf("begin_p = 0x%lx,  end_p = 0x%lx\n", begin_p, end_p));
581 
582 	count = 0;
583 	tsym_p = begin_p;
584 	while (stscan(&tsym_p, end_p, filter_p)) {
585 		count++;
586 	}
587 	DEBUG_EXP(printf("count = %d\n",count));
588 
589 	list_p = (SEARCH_NODE *) _Malloc(count, sizeof(*list_p));
590 
591 	i = 0;
592 	tsym_p = begin_p;
593 	while (stscan(&tsym_p, end_p, filter_p)) {
594 		list_p[i].sn_name_p = ST_NAME(tsym_p);
595 		list_p[i].sn_value_p = (char *) tsym_p;
596 		i++;
597 	}
598 	DEBUG_EXP(sn_dump("symbol table (pre sort)", list_p, count));
599 
600 	qsort(list_p, count, sizeof(*list_p), sn_compare);
601 
602 	DEBUG_EXP(sn_dump("symbol table (post sort)", list_p, count));
603 
604 	DEBUG_LOC("build_stlist: bottom");
605 	*count_p = count;
606 	return(list_p);
607 }
608 
609 
610 /*
611 *	stscan - symbol table scan
612 *
613 *	Scan the symbol table until the given limit is reached or
614 *	the filter function returns true.  Neither the starting
615 *	symbol (**sym_pp) nor the limit symbol (*lim_p) are legal
616 *	return values.  Instead, if the starting pointer is NULL,
617 *	then the first item in the table is a valid return value.
618 *	This allows the routine to be used as a generator by
619 *	starting from where the last call stopped.
620 */
621 static int
622 stscan(sym_pp, lim_p, filter_p)
623 Elf32_Sym	**sym_pp;
624 Elf32_Sym	*lim_p;
625 int		(*filter_p)();
626 {
627 	if (*sym_pp == NULL) {
628 		*sym_pp = (Elf32_Sym *) (profPtr->pf_symdat_p->d_buf);
629 	} else {
630 		*sym_pp = (Elf32_Sym *) ((char *) (*sym_pp) + prstsym_size);
631 	}
632 
633 	while (*sym_pp < lim_p) {
634 		if ((*filter_p)(*sym_pp)) {
635 			return(1);
636 		}
637 		*sym_pp = (Elf32_Sym *) ((char *) (*sym_pp) + prstsym_size);
638 	}
639 	return(0);
640 }
641 
642 
643 /*
644 *	These routines check the type of a symbol table entry.
645 */
646 static int
647 stchk_focov(sym_p)	/* symbol is function or coverage array  */
648 Elf32_Sym *sym_p; {
649 	return(stchk_func(sym_p) || stchk_cov(sym_p));
650 }
651 static int
652 stchk_filowog(sym_p)	/* symbol is a file, a weak, or a global */
653 Elf32_Sym *sym_p; {
654 	return(
655 		stchk_file(sym_p)
656 		|| ELF32_ST_BIND(sym_p->st_info) == STB_GLOBAL
657 		|| ELF32_ST_BIND(sym_p->st_info) == STB_WEAK
658 	);
659 }
660 static int
661 stchk_gowf(sym_p)	/* symbol is global or weak function */
662 Elf32_Sym *sym_p; {
663 	return(
664 		(stchk_func(sym_p) || stchk_match(sym_p))
665 		&& (
666 			ELF32_ST_BIND(sym_p->st_info) == STB_GLOBAL
667 			|| ELF32_ST_BIND(sym_p->st_info) == STB_WEAK
668 		)
669 	);
670 }
671 static int
672 stchk_func(sym_p)	/* symbol is a function */
673 Elf32_Sym *sym_p; {
674 	return(ELF32_ST_TYPE(sym_p->st_info) == STT_FUNC);
675 }
676 static int
677 stchk_file(sym_p)	/* symbol is a file */
678 Elf32_Sym *sym_p; {
679 	return(ELF32_ST_TYPE(sym_p->st_info) == STT_FILE);
680 }
681 static int
682 stchk_cov(sym_p)	/* symbol is a coverage array */
683 Elf32_Sym *sym_p; {
684 	return(
685 		strncmp(ST_NAME(sym_p), COV_PREFIX, sizeof(COV_PREFIX)-1) == 0
686 	);
687 }
688 static int
689 stchk_match(sym_p)	/* symbol is the match symbol */
690 Elf32_Sym *sym_p; {
691 	return(
692 		strncmp(ST_NAME(sym_p), MATCH_STR, sizeof(MATCH_STR)-1) == 0
693 	);
694 }
695 
696 
697 /*
698 *	Initialize debug array (dblist).
699 *
700 *	This routine prepares the debug array for searching (see
701 *	also fillout_sym_dbinfo).
702 *
703 *	Initialization proceeds as follows:
704 *
705 *		- Count the debug entries that we care about.
706 *		- _Malloc space to contain the pointers.
707 *		- Extract pointers and fill in array.
708 *		- Sort entries alphabetically by name.
709 */
710 static void
711 init_dblist()
712 {
713 	DB_TAG		tag;
714 	char		*cur_p;
715 	char		*lim_p;
716 	Elf_Data	*dat_p;
717 	int		k;
718 	extern char	*_CAleaf();
719 
720 	DEBUG_LOC("init_dblist: top");
721 
722 	dat_p = profPtr->pf_debugdat_p;
723 
724 	DEBUG_EXP(printf("dat_p = 0x%lx, d_buf = 0x%x, d_size = %d\n",
725 		dat_p, dat_p->d_buf, dat_p->d_size
726 	));
727 
728 	lim_p = (char *) (dat_p->d_buf) + dat_p->d_size;
729 
730 	dblist_cnt = 0;
731 	cur_p = NULL;
732 	while (dbscan_tag(&cur_p, lim_p, &tag, dbchk_filosub)) {
733 		dblist_cnt++;
734 	}
735 
736 	dblist = (SEARCH_NODE *) _Malloc(dblist_cnt, sizeof(*dblist));
737 
738 	DEBUG_EXP(printf("dblist_cnt = %d\n",dblist_cnt));
739 	DEBUG_EXP(printf("dblist = 0x%lx\n", dblist));
740 
741 	k = 0;
742 	cur_p = NULL;
743 	while (dbscan_tag(&cur_p, lim_p, &tag, dbchk_filosub)) {
744 		dblist[k].sn_name_p =
745 			_CAleaf(debName(tag.tg_att_p, tag.tg_attlen));
746 		dblist[k].sn_value_p = cur_p;
747 		k++;
748 	}
749 
750 	DEBUG_EXP(sn_dump("debug info (pre sort)", dblist, dblist_cnt));
751 
752 	qsort(dblist, dblist_cnt, sizeof(*dblist), sn_compare);
753 
754 	DEBUG_EXP(sn_dump("debug info (post sort)", dblist, dblist_cnt));
755 
756 	DEBUG_LOC("init_dblist: bottom");
757 }
758 
759 
760 /*
761 *	Search for a given tag from the given starting point in
762 *	the debug information.  If found, fill in the tag at the
763 *	given pointer and return 1.  Otherwise, return 0.
764 */
765 static int
766 dbscan_tag(dbpos_pp, dblim_p, tag_p, filter_p)
767 char	**dbpos_pp;
768 char	*dblim_p;
769 DB_TAG	*tag_p;
770 int	(*filter_p)();
771 {
772 	NO_DEBUG_LOC("dbscan_tag: top");
773 
774 	if (*dbpos_pp == NULL) {
775 		*dbpos_pp = profPtr->pf_debugdat_p->d_buf;
776 	} else {
777 		*dbpos_pp += DB_TAGLEN(*dbpos_pp);
778 	}
779 
780 	while (*dbpos_pp < dblim_p) {
781 		dbfill_tag(*dbpos_pp, tag_p);
782 
783 		if ((*filter_p)(tag_p->tg_value)) {
784 			goto success;
785 		}
786 		*dbpos_pp += tag_p->tg_length;
787 	}
788 	return(0);
789 success:;
790 	return(1);
791 }
792 
793 static void
794 dbfill_tag(dbpos_p, tag_p)
795 char	*dbpos_p;
796 DB_TAG	*tag_p;
797 {
798 	tag_p->tg_length = DB_TAGLEN(dbpos_p);
799 	tag_p->tg_value = alignval2(dbpos_p + sizeof(LEN4));
800 	tag_p->tg_att_p = dbpos_p + sizeof(LEN4) + sizeof(LEN2);
801 	tag_p->tg_attlen = tag_p->tg_length - sizeof(LEN4) - sizeof(LEN2);
802 }
803 
804 
805 /*
806 *	Search the given tag for the given attribute(s).
807 *	Return a pointer to the attribute or NULL if not found.
808 */
809 static char *
810 dbseek_att(tag_p, filter_p)
811 DB_TAG	*tag_p;
812 int	(*filter_p)();
813 {
814 	int	size;
815 	char	*att_p;
816 
817 	NO_DEBUG_LOC("dbseek_att: top");
818 
819 	size = tag_p->tg_attlen;
820 	att_p = tag_p->tg_att_p;
821 	NO_DEBUG(printf("attribute size = %d\n",size));
822 	while (size > 0) {
823 		LEN4 length;
824 
825 		if ((*filter_p)(alignval2(att_p))) {
826 			return(att_p);
827 		}
828 
829 		length = bytesFor(att_p);
830 		NO_DEBUG(printf("bytesFor returns length = %d\n",length));
831 
832 		size  -= sizeof(LEN2) + length;
833 		att_p += sizeof(LEN2) + length;
834 	}
835 	return((char *) 0);
836 }
837 
838 
839 /*
840 *	dbchk...: Routines that check debug tags and attributes.
841 */
842 static int
843 dbchk_stmnts(value)	/* statement list (line section) */
844 LEN2 value;
845 {
846 	return(value == AT_stmt_list);
847 }
848 static int
849 dbchk_lowpc(value)	/* statement list (line section) */
850 LEN2 value;
851 {
852 	return(value == AT_low_pc);
853 }
854 static int
855 dbchk_highpc(value)	/* statement list (line section) */
856 LEN2 value;
857 {
858 	return(value == AT_high_pc);
859 }
860 static int
861 dbchk_filosub(value)	/* file or subroutine */
862 LEN2 value;
863 {
864 	switch(value) {
865 	case TAG_source_file:
866 	case TAG_subroutine:
867 	case TAG_global_subroutine:
868 	case TAG_inline_subroutine:
869 		return(1);
870 	default:
871 		return(0);
872 	}
873 }
874 
875 
876 
877 #define PS_BLKFACTOR	(64)	/* handle this many symbols at a time */
878 
879 /*
880 *	add_profsymbol: Add a new entry to the profsymbol array.
881 *
882 *	This routine allocates the space required (as needed) for
883 *	the PROF_SYMBOL array, extracts the required information
884 *	from the symbol table and from the debug information, if
885 *	available (none is recorded for the coverage structures).
886 *
887 *	- Check current capacity, assuming one new symbol is to be added.
888 *	- Copy all of the symbol table information.
889 *	- Search for the symbol in the debug list.  If this search fails,
890 *	then flag this failure with "add_profsym_search_fail".  This is used
891 *	by "addcovset()" for an error exit when a file is not found in the
892 *	debug information.  This applies only to files - other symbols
893 *	which are not found may still be valid.
894 *	- If the symbol is a function, it may be either global or local
895 *	and local functions are not unique.  Therefore we must compare the
896 *	address (value) in the symbol table with the address (low_pc)
897 *	given in the debug information to verify the match.
898 *	- If the symbol is a file, no verification is needed, but we
899 *	must change to a new statement list.
900 *	- If the symbol is a coverage structure, then we are finished with it.
901 */
902 static PROF_SYMBOL *
903 add_profsymbol(prsym_p)
904 Elf32_Sym *prsym_p;
905 {
906 	DB_TAG		tag;
907 	PROF_SYMBOL	*ps_p;
908 	char		*att_p;
909 	SEARCH_NODE	*sn_p;
910 
911 	DEBUG_LOC("add_profsymbol: top");
912 
913 	check_capacity();
914 
915 	ps_p = prsym_list_p + prsym_cnt - 1;
916 	memcpy((char *) &(ps_p->ps_sym), (char *) prsym_p, prstsym_size);
917 	memset((char *) &(ps_p->ps_dbg), '\0', sizeof(PROF_DEBUGE));
918 
919 	DEBUG_EXP(printf("symbol name = %s\n", ST_NAME(prsym_p)));
920 	ps_p->ps_dbg.pd_name = ST_NAME(prsym_p);
921 
922 	add_profsym_search_fail = 0;
923 	if (!(sn_p = sn_search(ST_NAME(prsym_p), dblist, dblist_cnt))) {
924 		add_profsym_search_fail = 1;
925 		goto theend;
926 	}
927 	DEBUG_EXP(printf("Post search: sn_p->sn_name_p = %s\n",sn_p->sn_name_p));
928 	dbfill_tag(sn_p->sn_value_p, &tag);
929 
930 	if (stchk_func(prsym_p)) {
931 		while (strcmp(ST_NAME(prsym_p), sn_p->sn_name_p) == 0) {
932 			if (add_function(ps_p, &tag)) {
933 				break;
934 			}
935 			sn_p++;
936 			dbfill_tag(sn_p->sn_value_p, &tag);
937 		}
938 	} else if (stchk_file(prsym_p)) {
939 		if (
940 			(sn_p + 1) < (dblist + dblist_cnt)
941 			&& strcmp(sn_p[0].sn_name_p, sn_p[1].sn_name_p) == 0
942 		) {
943 			_err_warn(
944 				"File name %s was used more than once.",
945 				sn_p->sn_name_p
946 			);
947 		}
948 		add_file(&tag);
949 	} else {
950 		goto theend;
951 	}
952 
953 	ps_p->ps_dbg.pd_symtag = tag.tg_value;
954 
955 theend:;
956 	DEBUG_LOC("add_profsymbol: bottom");
957 	return(ps_p);
958 }
959 
960 
961 static void
962 add_file(tag_p)
963 DB_TAG	*tag_p;
964 {
965 	int		i;
966 	char		*tp;
967 	PROF_LINE	*lnp;
968 	char		*att_p;
969 
970 	att_p = dbseek_att(tag_p, dbchk_stmnts);
971 
972 	curf_lp = ((char *) profPtr->pf_linedat_p->d_buf) + DB_STMNTOS(att_p);
973 	curf_lncnt = (alignval4(curf_lp) - 2*sizeof(LEN4)) / DBG_LINE_SIZE;
974 	curf_base = alignval4(curf_lp + sizeof(LEN4));
975 	curf_lp += sizeof(LEN4) + sizeof(LEN4);
976 
977 	curf_lns_p = (PROF_LINE *) _Malloc(curf_lncnt, sizeof(*curf_lns_p));
978 
979 	i = 0;
980 	tp = curf_lp;
981 	lnp = curf_lns_p;
982 	while (i++ < curf_lncnt) {
983 		*lnp++ = alignval4(tp);
984 		tp += DBG_LINE_SIZE;
985 	}
986 
987 #ifdef DEBUG
988 	printf("File Debug Line Information\n");
989 	printf("   DBG_LINE_SIZE = %d\n", DBG_LINE_SIZE);
990 	printf("   curf_lp = 0x%x\n", curf_lp);
991 	printf("   curf_lncnt = %d\n", curf_lncnt);
992 	printf("   curf_base = 0x%x\n", curf_base);
993 	printf("   curf_lns_p = 0x%x\n", curf_lns_p);
994 	printf("Dump of line numbers\n");
995 	for (i = 0, lnp = curf_lns_p; i < curf_lncnt; i++) {
996 		printf("   line %d = %d\n", i, lnp[i]);
997 	}
998 #endif
999 }
1000 
1001 
1002 
1003 /*
1004 * add_function -- add to function's PROF_DEBUGE, line# pointer info.
1005 *
1006 *	Warning: Because we are reading directly from memory, we
1007 *	cannot depend upon the form of the structures we are reading
1008 *	(e.g., pl_delta in PROF_LINE).   Thus, line_p is a "char *"
1009 *	and NOT a "PROF_LINE *".
1010 *
1011 *
1012 * 	Note from below(***):
1013 *
1014 * 	Note that this routine finds the range of .line section
1015 * 	entries that should be associated with this function, from
1016 * 	those which belong to this file.
1017 *
1018 * 	The FIRST line entry for a fcn is selected because
1019 * 	it is the first with a ``delta,'' or memory offset
1020 * 	from the file ``base address (curf_base),''
1021 * 	whose value is GREATER OR EQUAL to the effective offset
1022 * 	associated with this function (lo_delta).
1023 *
1024 * 	The LAST line entry is selected because it is
1025 * 	the LAST with a ``delta'' whose value is LESS THAN
1026 * 	the effective offset of the END of this function (hi_delta)
1027 * 	- i.e. it is the last line number associated with
1028 * 	code that is wholly included in this function!
1029 *
1030 * 	If no line number is found with a delta value that
1031 * 	exceeds hi_delta (i.e. is part of the next function),
1032 * 	then it is assumed that the last line number entry seen
1033 * 	should simply be accepted as part of this function's set
1034 * 	of line numbers; it simply has no ``bounding line entry.''
1035 *
1036 */
1037 
1038 static int
1039 add_function(ps_p, tag_p)
1040 PROF_SYMBOL	*ps_p;
1041 DB_TAG		*tag_p;
1042 {
1043 	char		*att_p;
1044 	LEN4		high_pc, hi_delta;
1045 	LEN4		low_pc, lo_delta;
1046 	char		*line_p;
1047 	int		first_found = 0;
1048 	PROF_LINE	*pl_p;
1049 	int		i;
1050 
1051 	DEBUG_LOC("add_function: top");
1052 
1053 	att_p = dbseek_att(tag_p, dbchk_lowpc);
1054 	low_pc = DB_PCVALUE(att_p);
1055 	if (ps_p->ps_sym.st_value != low_pc) {
1056 		DEBUG_LOC("add_function: returning - failed");
1057 		return(0);
1058 	}
1059 	att_p = dbseek_att(tag_p, dbchk_highpc);
1060 	high_pc = DB_PCVALUE(att_p);
1061 
1062 	hi_delta = high_pc - curf_base;
1063 	lo_delta = low_pc - curf_base;
1064 	DEBUG_EXP(printf("lo_delta = 0x%x\n", lo_delta));
1065 	DEBUG_EXP(printf("hi_delta = 0x%x\n", hi_delta));
1066 
1067 	line_p = curf_lp;
1068 	pl_p = curf_lns_p - 1;
1069 
1070 	DEBUG_EXP(printf("Building symbol: %s\n",SYMBOL_NAME(ps_p)));
1071 	i = 0;
1072 	while (i++ < curf_lncnt) {
1073 		LEN4	delad;
1074 
1075 		pl_p++;
1076 		delad = alignval4(line_p + sizeof(LEN4) + sizeof(LEN2));
1077 
1078 		NO_DEBUG(printf("delad = 0x%x\n", delad));
1079 		NO_DEBUG(printf("line_p = 0x%x\n", line_p));
1080 
1081 		if (!first_found && (delad >= lo_delta)) {
1082 			DEBUG_LOC("found first line");
1083 			first_found = 1;
1084 			ps_p->ps_dbg.pd_line_p = pl_p;
1085 		} else if (delad >= hi_delta) {
1086 			DEBUG_LOC("found last line");
1087 			ps_p->ps_dbg.pd_lali_p = pl_p-1;
1088 			break;
1089 		}
1090 
1091 		line_p += DBG_LINE_SIZE;
1092 	}
1093 
1094 	/*
1095 	*	If the first line is not found, then we have failed
1096 	*	and must return zero.  It is possible (e.g., sometimes
1097 	*	when the function is the last one in the file) for the
1098 	*	first line to be found, but the last not.  In this case,
1099 	*	we assume it simply the last possible line.
1100 	*/
1101 	if (ps_p->ps_dbg.pd_line_p == NULL) {
1102 		_err_exit(
1103 			"Unable to locate line information for function %s.",
1104 			SYMBOL_NAME(ps_p)
1105 		);
1106 	}
1107 	if (ps_p->ps_dbg.pd_lali_p == NULL) {
1108 		DEBUG_LOC("found last line (by default)");
1109 		ps_p->ps_dbg.pd_lali_p = pl_p;
1110 	}
1111 	DEBUG_EXP(printf("first line (pd_line_p) = 0x%x\n",ps_p->ps_dbg.pd_line_p));
1112 	DEBUG_EXP(printf("last line (pd_lali_p) = 0x%x\n",ps_p->ps_dbg.pd_lali_p));
1113 
1114 	DEBUG_LOC("add_function: bottom");
1115 	return(1);
1116 }
1117 
1118 
1119 /* * * * * *
1120  * If capacity will be exceeded with a new symbol, then
1121  * increase the capacity.
1122  */
1123 static void
1124 check_capacity()
1125 {
1126 	if ( ++prsym_cnt > prsym_cap ) {
1127 		if ( prsym_cap == 0 ) {
1128 			prsym_cap = PS_BLKFACTOR;
1129 			prsym_list_p = (PROF_SYMBOL *)
1130 				_Malloc( prsym_size, prsym_cap );
1131 		} else {
1132 			prsym_cap += PS_BLKFACTOR;
1133 			prsym_list_p = (PROF_SYMBOL *)
1134 				_Realloc( (char *) prsym_list_p,
1135 					prsym_size * prsym_cap );
1136 		}
1137 	}
1138 }
1139 
1140 
1141 
1142 /* * * * * *
1143  * debName -- return ptr to name value for name attr type:attr value pair.
1144  *
1145  * this routine is called by fillout_sym_dbinfo, to scan
1146  * through a list of debug attributes and return a ptr
1147  * to the name attrib value, when that type/value pair is found.
1148  */
1149 
1150 static
1151 char *
1152 debName( att_p, att_size )
1153 char	*att_p;		/* ptr to list of (attr_type,attr_value) pairs */
1154 int	att_size;	/* byte length attribute list */
1155 {
1156 	char *name_p = "";
1157 	/* * * * * *
1158 	 * loop through the entries.  when you find a name,
1159 	 * return the addr of the related data (a char string).
1160 	 */
1161 
1162 	NO_DEBUG_LOC("debName: top");
1163 	while ( att_size>0 ) {
1164 		LEN2 typea_one;
1165 		LEN4 lena_one;
1166 
1167 		NO_DEBUG(printf("att_size = %d\n",att_size));
1168 		typea_one = alignval2(att_p) ;
1169 		NO_DEBUG(printf("typea_one = 0x%x\n",typea_one));
1170 		lena_one  =  bytesFor(att_p) ;
1171 		NO_DEBUG(printf("lena_one = %d\n",lena_one));
1172 		NO_DEBUG(printf("att_p = 0x%x\n",att_p));
1173 
1174 		if( typea_one == AT_name ) {
1175 			name_p = att_p + sizeof(LEN2);
1176 			break;
1177 		}
1178 		att_size -= sizeof(LEN2) + lena_one;
1179 		att_p    += sizeof(LEN2) + lena_one;
1180 	}
1181 	NO_DEBUG(printf("name = %s\n",name_p));
1182 	NO_DEBUG_LOC("debName: bottom");
1183 	return( name_p );
1184 }
1185 
1186 
1187 /* * * * * *
1188  * bytesFor - indicate the number of bytes of attribute data
1189  * 		expected to be defined for an attribute type,
1190  * 		given a ptr to the attribute type:value pair.
1191  *
1192  * we don't particularly care about the specific attribute;
1193  * more, we are interested in the 'form' of the value
1194  * associated with this attribute type; hence the 'bit un-masking'.
1195  *
1196  * used by fillout1().
1197  */
1198 static LEN4
1199 bytesFor(attr_p)
1200 char	*attr_p;
1201 {
1202 	LEN4 len;
1203 	LEN2 form, type;
1204 	char *data_p = attr_p + sizeof(LEN2);	/* beginning of attr data */
1205 
1206 
1207 	NO_DEBUG_LOC("bytesFor: top");
1208 
1209 	type = alignval2(attr_p);
1210 	form = type & FORM_MASK ;
1211 	NO_DEBUG(printf("attribute: type = 0x%x",type));
1212 	NO_DEBUG(printf(", form = 0x%x\n",form));
1213 	switch( form )
1214 	{
1215 	case FORM_STRING:	/* NUL-terminated string */
1216 	/* * * * * *
1217 	 * len of string is #chars plus one for NULL.
1218 	 */
1219 		len = strlen(data_p) + 1;
1220 		break;
1221 
1222 	case FORM_DATA2:	/* 2 bytes */
1223 		len = 2;
1224 		break;
1225 
1226 	case FORM_ADDR:		/* relocated address */
1227 	case FORM_REF:		/* reference to another .debug entry */
1228 	case FORM_DATA4:	/* 4 bytes */
1229 		len = 4;
1230 		break;
1231 
1232 	case FORM_DATA8:	/* 8 bytes (two 4-byte values) */
1233 		len = 8;
1234 		break;
1235 
1236 	case FORM_BLOCK2:	/* block with 2-byte length, then data */
1237 		len = alignval2(data_p) + 2 ; /* + 2 -> len of length */
1238 		break;
1239 
1240 	case FORM_BLOCK4:	/* block with 4-byte length, then data */
1241 		len = alignval4(data_p) + 4 ; /* + 4 -> len of length */
1242 		break;
1243 
1244 	case FORM_NONE:		/* error */
1245 	default:
1246 		len = 0;
1247 		break;
1248 	}
1249 
1250 	if (len==0)
1251 		_err_exit("Invalid FORM_value %#x for attribute type %#x\n",
1252 			form , type);
1253 
1254 	NO_DEBUG_LOC("bytesFor: bottom");
1255 	return(len);
1256 }
1257 
1258 
1259 /*
1260 *	sn_search: Search sorted list of SEARCH_NODE for given name.
1261 *
1262 *	Search the list for the entry with the given name.  If there
1263 *	is no such entry, return 0.  Otherwise return a pointer to
1264 *	the *first* entry in the list that matches.
1265 */
1266 static SEARCH_NODE *
1267 sn_search(name_p, list_p, count)
1268 char		*name_p;
1269 SEARCH_NODE	*list_p;
1270 int		count;
1271 {
1272 	SEARCH_NODE	tnode;
1273 	SEARCH_NODE	*sn_p;
1274 	int		index;
1275 
1276 	tnode.sn_name_p = name_p;
1277 
1278 	sn_p = (SEARCH_NODE *) bsearch(
1279 		(char *) &tnode,
1280 		(char *) list_p,
1281 		count,
1282 		sizeof(*list_p),
1283 		sn_compare
1284 	);
1285 
1286 	if (sn_p == NULL) {
1287 		return(NULL);
1288 	}
1289 
1290 	index = sn_p - list_p;
1291 	while ((index > 0) && (sn_compare(&list_p[index-1], &tnode) == 0))
1292 		index--;
1293 
1294 	return(&list_p[index]);
1295 }
1296 
1297 static int
1298 sn_compare(a_p, b_p)
1299 SEARCH_NODE *a_p;
1300 SEARCH_NODE *b_p;
1301 {
1302 	return(strcmp(a_p->sn_name_p, b_p->sn_name_p));
1303 }
1304 
1305 #ifdef DEBUG
1306 static void
1307 sn_dump(title_p, snlist_p, sncount)
1308 char		*title_p;
1309 SEARCH_NODE	*snlist_p;
1310 int		sncount;
1311 {
1312 	int i;
1313 
1314 	printf("search list for %s: count = %d\n", title_p, sncount);
1315 	for (i = 0; i < sncount; i++) {
1316 		printf(
1317 			"   name = %s,	pointer = 0x%lx\n"
1318 			, snlist_p[i].sn_name_p
1319 			, snlist_p[i].sn_value_p
1320 		);
1321 	}
1322 }
1323 
1324 static void
1325 profsym_dump(list_p, count)
1326 PROF_SYMBOL	*list_p;
1327 int		count;
1328 {
1329 	int		i;
1330 	PROF_LINE	*p;
1331 
1332 	printf("Dump of %d prof symbols found.\n", count);
1333 	for (i = 0; i < count; i++, list_p++) {
1334 		printf("%d: location 0x%x\n", i, list_p);
1335 		printf("\tSymbol %s\n", ST_NAME(&(list_p->ps_sym)));
1336 		printf("\t   st_size = %d\n", list_p->ps_sym.st_size);
1337 		printf("\t   st_info = 0x%lx\n", list_p->ps_sym.st_info);
1338 		printf("\tDebug Information\n");
1339 		printf("\t   pd_name = %s\n", list_p->ps_dbg.pd_name);
1340 		printf("\t   pd_symtag = 0x%lx\n", list_p->ps_dbg.pd_symtag);
1341 		p = list_p->ps_dbg.pd_line_p;
1342 		printf("\t   *pd_line_p = %d\n", (p ? *p : 0));
1343 		p = list_p->ps_dbg.pd_lali_p;
1344 		printf("\t   *pd_lali_p = %d\n", (p ? *p : 0));
1345 		printf("\t   pd_file_p = 0x%lx\n", list_p->ps_dbg.pd_file_p);
1346 	}
1347 }
1348 #endif
1349 
1350 
1351 /*
1352 *	alignment routines
1353 *
1354 *	These routines are used to avoid the EMT trap that occurs
1355 *	when moving a unit of data (of 2 or more bytes) across a
1356 *	word boundry.
1357 */
1358 static LEN2
1359 alignval2(p)
1360 char *p;
1361 {
1362 	LEN2 tmp; char *tp = (char *) &tmp;
1363 
1364 	tp[0] = p[0]; tp[1] = p[1];
1365 	return(tmp);
1366 }
1367 
1368 static LEN4
1369 alignval4(p)
1370 char *p;
1371 {
1372 	LEN4 tmp; char *tp = (char *) &tmp;
1373 
1374 	tp[0] = p[0]; tp[1] = p[1]; tp[2] = p[2]; tp[3] = p[3];
1375 	return(tmp);
1376 }
1377 
1378 /*
1379 *	Disscussion of the argv[0] problem and solution.
1380 *
1381 *	If a process is run with a misleading first argument (argv[0]),
1382 *	the profiler will be confused when trying to read the file and
1383 *	match the information against that in memory.  As a confidence
1384 *	check, we compare the address of MATCH_STR as seen in the symbol
1385 *	table to the address of MATCH_STR as seen while running the code.
1386 *	If these are the same, it is *very* unlikely that the file
1387 *	does not correspond to the code in memory.
1388 *
1389 *	Because this code may be run from a shared object, we must
1390 *	insure that our reference to MATCH_STR is that of the main routine.
1391 *	We are depending on MATCH_NAME to not be defined by any shared object
1392 *	(including this one - libprof.so - when so built).
1393 *
1394 *	The search for MATCH_STR in the symbol table is done in _symintLoad
1395 *	because SymintLoad has an ordered version of selected entries from the
1396 *	symbol table which makes searching very efficient (O(log n)).
1397 *
1398 *	See also soqueue.c.
1399 */
1400 
1401 int	_prof_check_match;
1402 
1403 static void
1404 verify_match()
1405 {
1406 	SEARCH_NODE	*sn_p;
1407 	Elf32_Sym	*sym_p;
1408 	extern char	MATCH_NAME;
1409 
1410 	if (_prof_check_match) {
1411 		if (!(sn_p = sn_search(MATCH_STR, gstlist, gstlist_cnt))) {
1412 			_err_exit("Cannot find match name.");
1413 		}
1414 		sym_p = (Elf32_Sym *) sn_p->sn_value_p;
1415 		if (sym_p->st_value != (Elf32_Addr) &MATCH_NAME) {
1416 			_err_exit("Location of file for this process unknown.");
1417 		}
1418 	}
1419 }
1420 #endif
1421 
1422