dynamic.c revision 3492:cd4326c9ab0e
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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26#pragma ident	"%Z%%M%	%I%	%E% SMI"
27
28/*
29 * String conversion routine for .dynamic tag entries.
30 */
31#include	<stdio.h>
32#include	<string.h>
33#include	<sys/elf_SPARC.h>
34#include	"rtld.h"
35#include	"_conv.h"
36#include	"dynamic_msg.h"
37
38
39
40/* Instantiate a local copy of conv_map2str() from _conv.h */
41DEFINE_conv_map2str
42
43
44
45#define	POSSZ	CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \
46		MSG_DFP_LAZYLOAD_ALT_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
47		MSG_DFP_GROUPPERM_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
48		CONV_INV_STRSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
49
50const char *
51conv_dyn_posflag1(Xword flags, int fmt_flags)
52{
53	static char	string[POSSZ];
54	static Val_desc vda[] = {
55		{ DF_P1_LAZYLOAD,	MSG_ORIG(MSG_DFP_LAZYLOAD) },
56		{ DF_P1_GROUPPERM,	MSG_ORIG(MSG_DFP_GROUPPERM) },
57		{ 0,			0 }
58	};
59	static CONV_EXPN_FIELD_ARG conv_arg = { string, sizeof (string), vda };
60	static Val_desc vda_alt[] = {
61		{ DF_P1_LAZYLOAD,	MSG_ORIG(MSG_DFP_LAZYLOAD_ALT) },
62		{ DF_P1_GROUPPERM,	MSG_ORIG(MSG_DFP_GROUPPERM) },
63		{ 0,			0 }
64	};
65	static CONV_EXPN_FIELD_ARG conv_arg_alt = { string, sizeof (string),
66		vda_alt, NULL, 0, 0, MSG_ORIG(MSG_STR_EMPTY), NULL,
67		MSG_ORIG(MSG_STR_EMPTY) };
68
69	CONV_EXPN_FIELD_ARG *arg;
70
71	if (flags == 0)
72		return (MSG_ORIG(MSG_GBL_ZERO));
73
74	arg = (fmt_flags & CONV_FMT_ALTDUMP) ? &conv_arg_alt : &conv_arg;
75	arg->oflags = arg->rflags = flags;
76	(void) conv_expn_field(arg);
77
78	return ((const char *)string);
79}
80
81#define	FLAGSZ	CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \
82		MSG_DF_ORIGIN_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
83		MSG_DF_SYMBOLIC_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
84		MSG_DF_TEXTREL_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
85		MSG_DF_BIND_NOW_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
86		MSG_DF_STATIC_TLS_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
87		CONV_INV_STRSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
88
89const char *
90conv_dyn_flag(Xword flags, int fmt_flags)
91{
92	static char	string[FLAGSZ];
93	static Val_desc vda[] = {
94		{ DF_ORIGIN,		MSG_ORIG(MSG_DF_ORIGIN) },
95		{ DF_SYMBOLIC,		MSG_ORIG(MSG_DF_SYMBOLIC) },
96		{ DF_TEXTREL,		MSG_ORIG(MSG_DF_TEXTREL) },
97		{ DF_BIND_NOW,		MSG_ORIG(MSG_DF_BIND_NOW) },
98		{ DF_STATIC_TLS,	MSG_ORIG(MSG_DF_STATIC_TLS) },
99		{ 0,			0 }
100	};
101	static CONV_EXPN_FIELD_ARG conv_arg = { string, sizeof (string), vda };
102
103	if (flags == 0)
104		return (MSG_ORIG(MSG_GBL_ZERO));
105
106	conv_arg.oflags = conv_arg.rflags = flags;
107	if (fmt_flags & CONV_FMT_ALTDUMP) {
108		conv_arg.prefix = conv_arg.suffix = MSG_ORIG(MSG_STR_EMPTY);
109	} else {
110		conv_arg.prefix = conv_arg.suffix = NULL;
111	}
112	(void) conv_expn_field(&conv_arg);
113
114	return ((const char *)string);
115}
116
117#define	FLAG1SZ	CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \
118		MSG_DF1_NOW_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
119		MSG_DF1_GLOBAL_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
120		MSG_DF1_GROUP_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
121		MSG_DF1_NODELETE_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
122		MSG_DF1_LOADFLTR_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
123		MSG_DF1_INITFIRST_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
124		MSG_DF1_NOOPEN_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
125		MSG_DF1_ORIGIN_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
126		MSG_DF1_DIRECT_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
127		MSG_DF1_TRANS_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
128		MSG_DF1_INTERPOSE_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
129		MSG_DF1_NODEFLIB_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
130		MSG_DF1_NODUMP_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
131		MSG_DF1_CONFALT_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
132		MSG_DF1_ENDFILTEE_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
133		MSG_DF1_DISPRELPND_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
134		MSG_DF1_DISPRELDNE_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
135		MSG_DF1_NODIRECT_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
136		MSG_DF1_IGNMULDEF_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
137		MSG_DF1_NOKSYMS_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
138		MSG_DF1_NOHDR_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
139		MSG_DF1_NORELOC_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
140		MSG_DF1_SYMINTPOSE_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
141		CONV_INV_STRSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
142
143const char *
144conv_dyn_flag1(Xword flags)
145{
146	static char	string[FLAG1SZ];
147	static Val_desc vda[] = {
148		{ DF_1_NOW,		MSG_ORIG(MSG_DF1_NOW) },
149		{ DF_1_GLOBAL,		MSG_ORIG(MSG_DF1_GLOBAL) },
150		{ DF_1_GROUP,		MSG_ORIG(MSG_DF1_GROUP) },
151		{ DF_1_NODELETE,	MSG_ORIG(MSG_DF1_NODELETE) },
152		{ DF_1_LOADFLTR,	MSG_ORIG(MSG_DF1_LOADFLTR) },
153		{ DF_1_INITFIRST,	MSG_ORIG(MSG_DF1_INITFIRST) },
154		{ DF_1_NOOPEN,		MSG_ORIG(MSG_DF1_NOOPEN) },
155		{ DF_1_ORIGIN,		MSG_ORIG(MSG_DF1_ORIGIN) },
156		{ DF_1_DIRECT,		MSG_ORIG(MSG_DF1_DIRECT) },
157		{ DF_1_TRANS,		MSG_ORIG(MSG_DF1_TRANS) },
158		{ DF_1_INTERPOSE,	MSG_ORIG(MSG_DF1_INTERPOSE) },
159		{ DF_1_NODEFLIB,	MSG_ORIG(MSG_DF1_NODEFLIB) },
160		{ DF_1_NODUMP,		MSG_ORIG(MSG_DF1_NODUMP) },
161		{ DF_1_CONFALT,		MSG_ORIG(MSG_DF1_CONFALT) },
162		{ DF_1_ENDFILTEE,	MSG_ORIG(MSG_DF1_ENDFILTEE) },
163		{ DF_1_DISPRELPND,	MSG_ORIG(MSG_DF1_DISPRELPND) },
164		{ DF_1_DISPRELDNE,	MSG_ORIG(MSG_DF1_DISPRELDNE) },
165		{ DF_1_NODIRECT,	MSG_ORIG(MSG_DF1_NODIRECT) },
166		{ DF_1_IGNMULDEF,	MSG_ORIG(MSG_DF1_IGNMULDEF) },
167		{ DF_1_NOKSYMS,		MSG_ORIG(MSG_DF1_NOKSYMS) },
168		{ DF_1_NOHDR,		MSG_ORIG(MSG_DF1_NOHDR) },
169		{ DF_1_NORELOC,		MSG_ORIG(MSG_DF1_NORELOC) },
170		{ DF_1_SYMINTPOSE,	MSG_ORIG(MSG_DF1_SYMINTPOSE) },
171		{ 0,			0 }
172	};
173	static CONV_EXPN_FIELD_ARG conv_arg = { string, sizeof (string), vda };
174
175	if (flags == 0)
176		return (MSG_ORIG(MSG_GBL_ZERO));
177
178	conv_arg.oflags = conv_arg.rflags = flags;
179	(void) conv_expn_field(&conv_arg);
180
181	return ((const char *)string);
182}
183
184#define	FEATSZ	CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \
185		MSG_DTF_PARINIT_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
186		MSG_DTF_CONFEXP_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
187		CONV_INV_STRSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
188
189const char *
190conv_dyn_feature1(Xword flags, int fmt_flags)
191{
192	static char	string[FEATSZ];
193	static Val_desc vda[] = {
194		{ DTF_1_PARINIT,	MSG_ORIG(MSG_DTF_PARINIT) },
195		{ DTF_1_CONFEXP,	MSG_ORIG(MSG_DTF_CONFEXP) },
196		{ 0,			0 }
197	};
198	static CONV_EXPN_FIELD_ARG conv_arg = { string, sizeof (string), vda };
199
200	if (flags == 0)
201		return (MSG_ORIG(MSG_GBL_ZERO));
202
203	conv_arg.oflags = conv_arg.rflags = flags;
204	if (fmt_flags & CONV_FMT_ALTDUMP) {
205		conv_arg.prefix = conv_arg.suffix = MSG_ORIG(MSG_STR_EMPTY);
206	} else {
207		conv_arg.prefix = conv_arg.suffix = NULL;
208	}
209	(void) conv_expn_field(&conv_arg);
210
211	return ((const char *)string);
212}
213
214const char *
215conv_dyn_tag(Xword tag, Half mach, int fmt_flags)
216{
217	static Conv_inv_buf_t	string;
218
219	/*
220	 * Dynamic tag values are sparse, cover a wide range, and have
221	 * holes. To handle this efficiently, we fall through a series
222	 * of tests below, in increasing tag order, returning at the first
223	 * match.
224	 *
225	 * If we fall all the way to the end, the tag is unknown,
226	 * and its numeric value is printed.
227	 */
228
229	/*
230	 * Most of the tag values are clustered in contiguous ranges.
231	 * Each contiguous range of defined values is handled with
232	 * an array that contains the message index corresponding to
233	 * each value in that range. The DYN_RANGE macro checks the
234	 * tag value against range of values starting at _start_tag.
235	 * If there is a match, the index of the appropriate name is
236	 * pulled from _array and returned to the caller.
237	 */
238#define	DYN_RANGE(_start_tag, _array) \
239	if ((tag >= _start_tag) && (tag < (_start_tag + ARRAY_NELTS(_array)))) \
240		return (MSG_ORIG(_array[tag - _start_tag]));
241
242
243	/*
244	 * Generic dynamic tags:
245	 *	- Note hole between DT_FLAGS and DT_PREINIT_ARRAY
246	 *	- The first range has alternative names for dump,
247	 *	  requiring a second array.
248	 */
249	static const Msg	tags_null[] = {
250		MSG_DYN_NULL,		MSG_DYN_NEEDED,
251		MSG_DYN_PLTRELSZ,	MSG_DYN_PLTGOT,
252		MSG_DYN_HASH,		MSG_DYN_STRTAB,
253		MSG_DYN_SYMTAB,		MSG_DYN_RELA,
254		MSG_DYN_RELASZ,		MSG_DYN_RELAENT,
255		MSG_DYN_STRSZ,		MSG_DYN_SYMENT,
256		MSG_DYN_INIT,		MSG_DYN_FINI,
257		MSG_DYN_SONAME,		MSG_DYN_RPATH,
258		MSG_DYN_SYMBOLIC,	MSG_DYN_REL,
259		MSG_DYN_RELSZ,		MSG_DYN_RELENT,
260		MSG_DYN_PLTREL,		MSG_DYN_DEBUG,
261		MSG_DYN_TEXTREL,	MSG_DYN_JMPREL,
262		MSG_DYN_BIND_NOW,	MSG_DYN_INIT_ARRAY,
263		MSG_DYN_FINI_ARRAY,	MSG_DYN_INIT_ARRAYSZ,
264		MSG_DYN_FINI_ARRAYSZ,	MSG_DYN_RUNPATH,
265		MSG_DYN_FLAGS
266	};
267	static const Msg	tags_null_alt[] = {
268		MSG_DYN_NULL,		MSG_DYN_NEEDED,
269		MSG_DYN_PLTRELSZ_ALT,	MSG_DYN_PLTGOT,
270		MSG_DYN_HASH,		MSG_DYN_STRTAB,
271		MSG_DYN_SYMTAB,		MSG_DYN_RELA,
272		MSG_DYN_RELASZ,		MSG_DYN_RELAENT,
273		MSG_DYN_STRSZ,		MSG_DYN_SYMENT,
274		MSG_DYN_INIT,		MSG_DYN_FINI,
275		MSG_DYN_SONAME,		MSG_DYN_RPATH,
276		MSG_DYN_SYMBOLIC_ALT,	MSG_DYN_REL,
277		MSG_DYN_RELSZ,		MSG_DYN_RELENT,
278		MSG_DYN_PLTREL,		MSG_DYN_DEBUG,
279		MSG_DYN_TEXTREL,	MSG_DYN_JMPREL,
280		MSG_DYN_BIND_NOW,	MSG_DYN_INIT_ARRAY,
281		MSG_DYN_FINI_ARRAY,	MSG_DYN_INIT_ARRAYSZ,
282		MSG_DYN_FINI_ARRAYSZ,	MSG_DYN_RUNPATH,
283		MSG_DYN_FLAGS
284	};
285	static const Msg	tags_preinit_array[] = {
286		MSG_DYN_PREINIT_ARRAY,	MSG_DYN_PREINIT_ARRAYSZ
287	};
288
289	/*
290	 * SUNW: DT_LOOS -> DT_HIOS range.
291	 */
292	static const Msg	tags_sunw_auxiliary[] = {
293		MSG_DYN_SUNW_AUXILIARY,	MSG_DYN_SUNW_RTLDINF,
294		MSG_DYN_SUNW_FILTER,	MSG_DYN_SUNW_CAP,
295		MSG_DYN_SUNW_SYMTAB,	MSG_DYN_SUNW_SYMSZ,
296		MSG_DYN_SUNW_SORTENT,	MSG_DYN_SUNW_SYMSORTSZ,
297		MSG_DYN_SUNW_TLSSORT,	MSG_DYN_SUNW_TLSSORTSZ
298	};
299
300	/*
301	 * SUNW: DT_VALRNGLO - DT_VALRNGHI range.
302	 */
303	static const Msg	tags_checksum[] = {
304		MSG_DYN_CHECKSUM,	MSG_DYN_PLTPADSZ,
305		MSG_DYN_MOVEENT,	MSG_DYN_MOVESZ,
306		MSG_DYN_FEATURE_1,	MSG_DYN_POSFLAG_1,
307		MSG_DYN_SYMINSZ,	MSG_DYN_SYMINENT
308	};
309
310	/*
311	 * SUNW: DT_ADDRRNGLO - DT_ADDRRNGHI range.
312	 */
313	static const Msg	tags_config[] = {
314		MSG_DYN_CONFIG,		MSG_DYN_DEPAUDIT,
315		MSG_DYN_AUDIT,		MSG_DYN_PLTPAD,
316		MSG_DYN_MOVETAB,	MSG_DYN_SYMINFO
317	};
318
319	/*
320	 * SUNW: generic range. Note hole between DT_VERSYM and DT_RELACOUNT.
321	 * We handle DT_VERSYM as a single value below.
322	 */
323	static const Msg	tags_relacount[] = {
324		MSG_DYN_RELACOUNT,	MSG_DYN_RELCOUNT,
325		MSG_DYN_FLAGS_1,	MSG_DYN_VERDEF,
326		MSG_DYN_VERDEFNUM,	MSG_DYN_VERNEED,
327		MSG_DYN_VERNEEDNUM
328	};
329
330	/*
331	 * DT_LOPROC - DT_HIPROC range.
332	 */
333	static const Msg	tags_auxiliary[] = {
334		MSG_DYN_AUXILIARY,	MSG_DYN_USED,
335		MSG_DYN_FILTER
336	};
337
338
339
340
341	if (tag <= DT_FLAGS)
342		return (conv_map2str(string, sizeof (string), tag,
343			fmt_flags, ARRAY_NELTS(tags_null), tags_null,
344			tags_null_alt, NULL));
345	DYN_RANGE(DT_PREINIT_ARRAY, tags_preinit_array);
346	DYN_RANGE(DT_SUNW_AUXILIARY, tags_sunw_auxiliary);
347	DYN_RANGE(DT_CHECKSUM, tags_checksum);
348	DYN_RANGE(DT_CONFIG, tags_config);
349	if (tag == DT_VERSYM)
350		return (MSG_ORIG(MSG_DYN_VERSYM));
351	DYN_RANGE(DT_RELACOUNT, tags_relacount);
352	DYN_RANGE(DT_AUXILIARY, tags_auxiliary);
353
354	/*
355	 * SUNW: machine specific range.
356	 */
357	if (((mach == EM_SPARC) || (mach == EM_SPARCV9) ||
358	    (mach == EM_SPARC32PLUS)) && (tag == DT_SPARC_REGISTER))
359		/* this is so x86 can display a sparc binary */
360		return (MSG_ORIG(MSG_DYN_REGISTER));
361
362	if (tag == DT_DEPRECATED_SPARC_REGISTER)
363		return (MSG_ORIG(MSG_DYN_REGISTER));
364
365	/* Unknown item */
366	return (conv_invalid_val(string, CONV_INV_STRSIZE, tag, fmt_flags));
367
368#undef DYN_RANGE
369}
370
371#define	BINDTSZ	CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \
372		MSG_BND_NEEDED_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
373		MSG_BND_REFER_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
374		MSG_BND_FILTER_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
375		CONV_INV_STRSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
376
377const char *
378conv_bnd_type(uint_t flags)
379{
380	static char	string[BINDTSZ];
381	static Val_desc vda[] = {
382		{ BND_NEEDED,		MSG_ORIG(MSG_BND_NEEDED) },
383		{ BND_REFER,		MSG_ORIG(MSG_BND_REFER) },
384		{ BND_FILTER,		MSG_ORIG(MSG_BND_FILTER) },
385		{ 0,			0 }
386	};
387	static CONV_EXPN_FIELD_ARG conv_arg = { string, sizeof (string), vda };
388
389	if (flags == 0)
390		return (MSG_ORIG(MSG_STR_EMPTY));
391
392	conv_arg.oflags = conv_arg.rflags = flags;
393	(void) conv_expn_field(&conv_arg);
394
395	return ((const char *)string);
396}
397
398/*
399 * Note, conv_bnd_obj() is called with either:
400 *	LML_FLG_OBJADDED (possibly with LML_FLG_OBJREEVAL added), or
401 *	LML_FLG_OBJDELETED, or
402 *	LML_FLG_ATEXIT.
403 */
404#define	BINDOSZ	CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \
405		MSG_BND_ADDED_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
406		MSG_BND_REEVAL_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
407		CONV_INV_STRSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
408
409const char *
410conv_bnd_obj(uint_t flags)
411{
412	static char	string[BINDOSZ];
413	static Val_desc vda[] = {
414		{ LML_FLG_OBJADDED,	MSG_ORIG(MSG_BND_ADDED) },
415		{ LML_FLG_OBJREEVAL,	MSG_ORIG(MSG_BND_REEVAL) },
416		{ LML_FLG_OBJDELETED,	MSG_ORIG(MSG_BND_DELETED) },
417		{ LML_FLG_ATEXIT,	MSG_ORIG(MSG_BND_ATEXIT) },
418		{ 0,			0 }
419	};
420	static CONV_EXPN_FIELD_ARG conv_arg = { string, sizeof (string), vda };
421
422	if ((flags & (LML_FLG_OBJADDED | LML_FLG_OBJREEVAL |
423	    LML_FLG_OBJDELETED | LML_FLG_ATEXIT)) == 0)
424		return (MSG_ORIG(MSG_BND_REVISIT));
425
426	/*
427	 * Note, we're not worried about unknown flags for this family, only
428	 * the selected flags are of interest, so we leave conv_arg.rflags
429	 * set to 0.
430	 */
431	conv_arg.oflags = flags;
432	(void) conv_expn_field(&conv_arg);
433
434	return ((const char *)string);
435}
436