dynamic.c revision 5088:26c540f30cd3
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_BUFSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
49
50/*
51 * Ensure that Conv_dyn_posflag1_buf_t is large enough:
52 *
53 * POSSZ is the real minimum size of the buffer required by conv_dyn_posflag1().
54 * However, Conv_dyn_posflag1_buf_t uses CONV_DYN_POSFLAG1_BUFSIZE to set the
55 * buffer size. We do things this way because the definition of POSSZ uses
56 * information that is not available in the environment of other programs
57 * that include the conv.h header file.
58 */
59#if CONV_DYN_POSFLAG1_BUFSIZE < POSSZ
60#error "CONV_DYN_POSFLAG1_BUFSIZE is not large enough"
61#endif
62
63const char *
64conv_dyn_posflag1(Xword flags, Conv_fmt_flags_t fmt_flags,
65    Conv_dyn_posflag1_buf_t *dyn_posflag1_buf)
66{
67	static Val_desc vda[] = {
68		{ DF_P1_LAZYLOAD,	MSG_ORIG(MSG_DFP_LAZYLOAD) },
69		{ DF_P1_GROUPPERM,	MSG_ORIG(MSG_DFP_GROUPPERM) },
70		{ 0,			0 }
71	};
72	static CONV_EXPN_FIELD_ARG conv_arg = {
73	    NULL, sizeof (dyn_posflag1_buf->buf), vda };
74	static Val_desc vda_alt[] = {
75		{ DF_P1_LAZYLOAD,	MSG_ORIG(MSG_DFP_LAZYLOAD_ALT) },
76		{ DF_P1_GROUPPERM,	MSG_ORIG(MSG_DFP_GROUPPERM) },
77		{ 0,			0 }
78	};
79	static CONV_EXPN_FIELD_ARG conv_arg_alt = {
80	    NULL, sizeof (dyn_posflag1_buf->buf), vda_alt, NULL, 0, 0,
81	    MSG_ORIG(MSG_STR_EMPTY), NULL, MSG_ORIG(MSG_STR_EMPTY) };
82
83	CONV_EXPN_FIELD_ARG *arg;
84
85	if (flags == 0)
86		return (MSG_ORIG(MSG_GBL_ZERO));
87
88	arg = (CONV_TYPE_FMT_ALT(fmt_flags) == CONV_FMT_ALT_DUMP) ?
89	    &conv_arg_alt : &conv_arg;
90	arg->buf = dyn_posflag1_buf->buf;
91	arg->oflags = arg->rflags = flags;
92	(void) conv_expn_field(arg, fmt_flags);
93
94	return ((const char *)dyn_posflag1_buf);
95}
96
97#define	FLAGSZ	CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \
98		MSG_DF_ORIGIN_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
99		MSG_DF_SYMBOLIC_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
100		MSG_DF_TEXTREL_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
101		MSG_DF_BIND_NOW_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
102		MSG_DF_STATIC_TLS_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
103		CONV_INV_BUFSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
104
105/*
106 * Ensure that Conv_dyn_flag_buf_t is large enough:
107 *
108 * FLAGSZ is the real minimum size of the buffer required by conv_dyn_flag().
109 * However, Conv_dyn_flag_buf_t uses CONV_DYN_FLAG_BUFSIZE to set the
110 * buffer size. We do things this way because the definition of FLAGSZ uses
111 * information that is not available in the environment of other programs
112 * that include the conv.h header file.
113 */
114#if CONV_DYN_FLAG_BUFSIZE < FLAGSZ
115#error "CONV_DYN_FLAG_BUFSIZE is not large enough"
116#endif
117
118const char *
119conv_dyn_flag(Xword flags, Conv_fmt_flags_t fmt_flags,
120    Conv_dyn_flag_buf_t *dyn_flag_buf)
121{
122	static Val_desc vda[] = {
123		{ DF_ORIGIN,		MSG_ORIG(MSG_DF_ORIGIN) },
124		{ DF_SYMBOLIC,		MSG_ORIG(MSG_DF_SYMBOLIC) },
125		{ DF_TEXTREL,		MSG_ORIG(MSG_DF_TEXTREL) },
126		{ DF_BIND_NOW,		MSG_ORIG(MSG_DF_BIND_NOW) },
127		{ DF_STATIC_TLS,	MSG_ORIG(MSG_DF_STATIC_TLS) },
128		{ 0,			0 }
129	};
130	static CONV_EXPN_FIELD_ARG conv_arg = {
131	    NULL, sizeof (dyn_flag_buf->buf), vda };
132
133	if (flags == 0)
134		return (MSG_ORIG(MSG_GBL_ZERO));
135
136	conv_arg.buf = dyn_flag_buf->buf;
137	conv_arg.oflags = conv_arg.rflags = flags;
138	if (CONV_TYPE_FMT_ALT(fmt_flags) == CONV_FMT_ALT_DUMP) {
139		conv_arg.prefix = conv_arg.suffix = MSG_ORIG(MSG_STR_EMPTY);
140	} else {
141		conv_arg.prefix = conv_arg.suffix = NULL;
142	}
143	(void) conv_expn_field(&conv_arg, fmt_flags);
144
145	return ((const char *)dyn_flag_buf->buf);
146}
147
148#define	FLAG1SZ	CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \
149		MSG_DF1_NOW_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
150		MSG_DF1_GLOBAL_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
151		MSG_DF1_GROUP_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
152		MSG_DF1_NODELETE_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
153		MSG_DF1_LOADFLTR_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
154		MSG_DF1_INITFIRST_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
155		MSG_DF1_NOOPEN_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
156		MSG_DF1_ORIGIN_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
157		MSG_DF1_DIRECT_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
158		MSG_DF1_TRANS_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
159		MSG_DF1_INTERPOSE_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
160		MSG_DF1_NODEFLIB_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
161		MSG_DF1_NODUMP_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
162		MSG_DF1_CONFALT_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
163		MSG_DF1_ENDFILTEE_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
164		MSG_DF1_DISPRELPND_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
165		MSG_DF1_DISPRELDNE_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
166		MSG_DF1_NODIRECT_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
167		MSG_DF1_IGNMULDEF_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
168		MSG_DF1_NOKSYMS_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
169		MSG_DF1_NOHDR_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
170		MSG_DF1_NORELOC_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
171		MSG_DF1_SYMINTPOSE_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
172		MSG_DF1_GLOBAUDIT_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
173		CONV_INV_BUFSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
174
175/*
176 * Ensure that Conv_dyn_flag1_buf_t is large enough:
177 *
178 * FLAG1SZ is the real minimum size of the buffer required by conv_dyn_flag1().
179 * However, Conv_dyn_flag1_buf_t uses CONV_DYN_FLAG1_BUFSIZE to set the
180 * buffer size. We do things this way because the definition of FLAG1SZ uses
181 * information that is not available in the environment of other programs
182 * that include the conv.h header file.
183 */
184#if CONV_DYN_FLAG1_BUFSIZE < FLAG1SZ
185#error "CONV_DYN_FLAG1_BUFSIZE is not large enough"
186#endif
187
188const char *
189conv_dyn_flag1(Xword flags, Conv_fmt_flags_t fmt_flags,
190    Conv_dyn_flag1_buf_t *dyn_flag1_buf)
191{
192	static Val_desc vda[] = {
193		{ DF_1_NOW,		MSG_ORIG(MSG_DF1_NOW) },
194		{ DF_1_GLOBAL,		MSG_ORIG(MSG_DF1_GLOBAL) },
195		{ DF_1_GROUP,		MSG_ORIG(MSG_DF1_GROUP) },
196		{ DF_1_NODELETE,	MSG_ORIG(MSG_DF1_NODELETE) },
197		{ DF_1_LOADFLTR,	MSG_ORIG(MSG_DF1_LOADFLTR) },
198		{ DF_1_INITFIRST,	MSG_ORIG(MSG_DF1_INITFIRST) },
199		{ DF_1_NOOPEN,		MSG_ORIG(MSG_DF1_NOOPEN) },
200		{ DF_1_ORIGIN,		MSG_ORIG(MSG_DF1_ORIGIN) },
201		{ DF_1_DIRECT,		MSG_ORIG(MSG_DF1_DIRECT) },
202		{ DF_1_TRANS,		MSG_ORIG(MSG_DF1_TRANS) },
203		{ DF_1_INTERPOSE,	MSG_ORIG(MSG_DF1_INTERPOSE) },
204		{ DF_1_NODEFLIB,	MSG_ORIG(MSG_DF1_NODEFLIB) },
205		{ DF_1_NODUMP,		MSG_ORIG(MSG_DF1_NODUMP) },
206		{ DF_1_CONFALT,		MSG_ORIG(MSG_DF1_CONFALT) },
207		{ DF_1_ENDFILTEE,	MSG_ORIG(MSG_DF1_ENDFILTEE) },
208		{ DF_1_DISPRELDNE,	MSG_ORIG(MSG_DF1_DISPRELDNE) },
209		{ DF_1_DISPRELPND,	MSG_ORIG(MSG_DF1_DISPRELPND) },
210		{ DF_1_NODIRECT,	MSG_ORIG(MSG_DF1_NODIRECT) },
211		{ DF_1_IGNMULDEF,	MSG_ORIG(MSG_DF1_IGNMULDEF) },
212		{ DF_1_NOKSYMS,		MSG_ORIG(MSG_DF1_NOKSYMS) },
213		{ DF_1_NOHDR,		MSG_ORIG(MSG_DF1_NOHDR) },
214		{ DF_1_EDITED,		MSG_ORIG(MSG_DF1_EDITED) },
215		{ DF_1_NORELOC,		MSG_ORIG(MSG_DF1_NORELOC) },
216		{ DF_1_SYMINTPOSE,	MSG_ORIG(MSG_DF1_SYMINTPOSE) },
217		{ DF_1_GLOBAUDIT,	MSG_ORIG(MSG_DF1_GLOBAUDIT) },
218		{ 0,			0 }
219	};
220	static CONV_EXPN_FIELD_ARG conv_arg = {
221	    NULL, sizeof (dyn_flag1_buf->buf), vda };
222
223	if (flags == 0)
224		return (MSG_ORIG(MSG_GBL_ZERO));
225
226	conv_arg.oflags = conv_arg.rflags = flags;
227	conv_arg.buf = dyn_flag1_buf->buf;
228	(void) conv_expn_field(&conv_arg, fmt_flags);
229
230	return ((const char *)dyn_flag1_buf->buf);
231}
232
233#define	FEATSZ	CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \
234		MSG_DTF_PARINIT_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
235		MSG_DTF_CONFEXP_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
236		CONV_INV_BUFSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
237
238/*
239 * Ensure that Conv_dyn_feature1_buf_t is large enough:
240 *
241 * FEATSZ is the real min size of the buffer required by conv_dyn_feature1().
242 * However, Conv_dyn_feature1_buf_t uses CONV_DYN_FEATURE1_BUFSIZE to set the
243 * buffer size. We do things this way because the definition of FEATSZ uses
244 * information that is not available in the environment of other programs
245 * that include the conv.h header file.
246 */
247#if CONV_DYN_FEATURE1_BUFSIZE < FEATSZ
248#error "CONV_DYN_FEATURE1_BUFSIZE is not large enough"
249#endif
250
251const char *
252conv_dyn_feature1(Xword flags, Conv_fmt_flags_t fmt_flags,
253    Conv_dyn_feature1_buf_t *dyn_feature1_buf)
254{
255	static Val_desc vda[] = {
256		{ DTF_1_PARINIT,	MSG_ORIG(MSG_DTF_PARINIT) },
257		{ DTF_1_CONFEXP,	MSG_ORIG(MSG_DTF_CONFEXP) },
258		{ 0,			0 }
259	};
260	static CONV_EXPN_FIELD_ARG conv_arg = {
261	    NULL, sizeof (dyn_feature1_buf->buf), vda };
262
263	if (flags == 0)
264		return (MSG_ORIG(MSG_GBL_ZERO));
265
266	conv_arg.buf = dyn_feature1_buf->buf;
267	conv_arg.oflags = conv_arg.rflags = flags;
268	if (CONV_TYPE_FMT_ALT(fmt_flags) == CONV_FMT_ALT_DUMP) {
269		conv_arg.prefix = conv_arg.suffix = MSG_ORIG(MSG_STR_EMPTY);
270	} else {
271		conv_arg.prefix = conv_arg.suffix = NULL;
272	}
273	(void) conv_expn_field(&conv_arg, fmt_flags);
274
275	return ((const char *)dyn_feature1_buf->buf);
276}
277
278const char *
279conv_dyn_tag(Xword tag, Half mach, Conv_fmt_flags_t fmt_flags,
280    Conv_inv_buf_t *inv_buf)
281{
282	/*
283	 * Dynamic tag values are sparse, cover a wide range, and have
284	 * holes. To handle this efficiently, we fall through a series
285	 * of tests below, in increasing tag order, returning at the first
286	 * match.
287	 *
288	 * If we fall all the way to the end, the tag is unknown,
289	 * and its numeric value is printed.
290	 */
291
292	/*
293	 * Most of the tag values are clustered in contiguous ranges.
294	 * Each contiguous range of defined values is handled with
295	 * an array that contains the message index corresponding to
296	 * each value in that range. The DYN_RANGE macro checks the
297	 * tag value against range of values starting at _start_tag.
298	 * If there is a match, the index of the appropriate name is
299	 * pulled from _array and returned to the caller.
300	 */
301#define	DYN_RANGE(_start_tag, _array) \
302	if ((tag >= _start_tag) && (tag < (_start_tag + ARRAY_NELTS(_array)))) \
303		return (MSG_ORIG(_array[tag - _start_tag]));
304
305
306	/*
307	 * Generic dynamic tags:
308	 *	- Note hole between DT_FLAGS and DT_PREINIT_ARRAY
309	 *	- The first range has alternative names for dump,
310	 *	  requiring a second array.
311	 */
312	static const Msg	tags_null[] = {
313		MSG_DYN_NULL,		MSG_DYN_NEEDED,
314		MSG_DYN_PLTRELSZ,	MSG_DYN_PLTGOT,
315		MSG_DYN_HASH,		MSG_DYN_STRTAB,
316		MSG_DYN_SYMTAB,		MSG_DYN_RELA,
317		MSG_DYN_RELASZ,		MSG_DYN_RELAENT,
318		MSG_DYN_STRSZ,		MSG_DYN_SYMENT,
319		MSG_DYN_INIT,		MSG_DYN_FINI,
320		MSG_DYN_SONAME,		MSG_DYN_RPATH,
321		MSG_DYN_SYMBOLIC,	MSG_DYN_REL,
322		MSG_DYN_RELSZ,		MSG_DYN_RELENT,
323		MSG_DYN_PLTREL,		MSG_DYN_DEBUG,
324		MSG_DYN_TEXTREL,	MSG_DYN_JMPREL,
325		MSG_DYN_BIND_NOW,	MSG_DYN_INIT_ARRAY,
326		MSG_DYN_FINI_ARRAY,	MSG_DYN_INIT_ARRAYSZ,
327		MSG_DYN_FINI_ARRAYSZ,	MSG_DYN_RUNPATH,
328		MSG_DYN_FLAGS
329	};
330	static const Msg	tags_null_alt[] = {
331		MSG_DYN_NULL,		MSG_DYN_NEEDED,
332		MSG_DYN_PLTRELSZ_ALT,	MSG_DYN_PLTGOT,
333		MSG_DYN_HASH,		MSG_DYN_STRTAB,
334		MSG_DYN_SYMTAB,		MSG_DYN_RELA,
335		MSG_DYN_RELASZ,		MSG_DYN_RELAENT,
336		MSG_DYN_STRSZ,		MSG_DYN_SYMENT,
337		MSG_DYN_INIT,		MSG_DYN_FINI,
338		MSG_DYN_SONAME,		MSG_DYN_RPATH,
339		MSG_DYN_SYMBOLIC_ALT,	MSG_DYN_REL,
340		MSG_DYN_RELSZ,		MSG_DYN_RELENT,
341		MSG_DYN_PLTREL,		MSG_DYN_DEBUG,
342		MSG_DYN_TEXTREL,	MSG_DYN_JMPREL,
343		MSG_DYN_BIND_NOW,	MSG_DYN_INIT_ARRAY,
344		MSG_DYN_FINI_ARRAY,	MSG_DYN_INIT_ARRAYSZ,
345		MSG_DYN_FINI_ARRAYSZ,	MSG_DYN_RUNPATH,
346		MSG_DYN_FLAGS
347	};
348	static const Msg	tags_preinit_array[] = {
349		MSG_DYN_PREINIT_ARRAY,	MSG_DYN_PREINIT_ARRAYSZ
350	};
351
352	/*
353	 * SUNW: DT_LOOS -> DT_HIOS range. Note hole between DT_SUNW_TLSSORTSZ
354	 * and DT_SUNW_STRPAD. We handle DT_SUNW_STRPAD as a single value below.
355	 */
356	static const Msg	tags_sunw_auxiliary[] = {
357		MSG_DYN_SUNW_AUXILIARY,	MSG_DYN_SUNW_RTLDINF,
358		MSG_DYN_SUNW_FILTER,	MSG_DYN_SUNW_CAP,
359		MSG_DYN_SUNW_SYMTAB,	MSG_DYN_SUNW_SYMSZ,
360		MSG_DYN_SUNW_SORTENT,	MSG_DYN_SUNW_SYMSORT,
361		MSG_DYN_SUNW_SYMSORTSZ,	MSG_DYN_SUNW_TLSSORT,
362		MSG_DYN_SUNW_TLSSORTSZ
363	};
364
365	/*
366	 * SUNW: DT_VALRNGLO - DT_VALRNGHI range.
367	 */
368	static const Msg	tags_checksum[] = {
369		MSG_DYN_CHECKSUM,	MSG_DYN_PLTPADSZ,
370		MSG_DYN_MOVEENT,	MSG_DYN_MOVESZ,
371		MSG_DYN_FEATURE_1,	MSG_DYN_POSFLAG_1,
372		MSG_DYN_SYMINSZ,	MSG_DYN_SYMINENT
373	};
374
375	/*
376	 * SUNW: DT_ADDRRNGLO - DT_ADDRRNGHI range.
377	 */
378	static const Msg	tags_config[] = {
379		MSG_DYN_CONFIG,		MSG_DYN_DEPAUDIT,
380		MSG_DYN_AUDIT,		MSG_DYN_PLTPAD,
381		MSG_DYN_MOVETAB,	MSG_DYN_SYMINFO
382	};
383
384	/*
385	 * SUNW: generic range. Note hole between DT_VERSYM and DT_RELACOUNT.
386	 * We handle DT_VERSYM as a single value below.
387	 */
388	static const Msg	tags_relacount[] = {
389		MSG_DYN_RELACOUNT,	MSG_DYN_RELCOUNT,
390		MSG_DYN_FLAGS_1,	MSG_DYN_VERDEF,
391		MSG_DYN_VERDEFNUM,	MSG_DYN_VERNEED,
392		MSG_DYN_VERNEEDNUM
393	};
394
395	/*
396	 * DT_LOPROC - DT_HIPROC range.
397	 */
398	static const Msg	tags_auxiliary[] = {
399		MSG_DYN_AUXILIARY,	MSG_DYN_USED,
400		MSG_DYN_FILTER
401	};
402
403
404
405
406	if (tag <= DT_FLAGS) {
407		/* use 'dump' style? */
408		if (CONV_TYPE_FMT_ALT(fmt_flags) == CONV_FMT_ALT_DUMP)
409			return (conv_map2str(inv_buf, tag, fmt_flags,
410			    ARRAY_NELTS(tags_null_alt), tags_null_alt));
411		/* Standard style */
412		return (conv_map2str(inv_buf, tag, fmt_flags,
413		    ARRAY_NELTS(tags_null), tags_null));
414	}
415	DYN_RANGE(DT_PREINIT_ARRAY, tags_preinit_array);
416	DYN_RANGE(DT_SUNW_AUXILIARY, tags_sunw_auxiliary);
417	if (tag == DT_SUNW_STRPAD)
418		return (MSG_ORIG(MSG_DYN_SUNW_STRPAD));
419	DYN_RANGE(DT_CHECKSUM, tags_checksum);
420	DYN_RANGE(DT_CONFIG, tags_config);
421	if (tag == DT_VERSYM)
422		return (MSG_ORIG(MSG_DYN_VERSYM));
423	DYN_RANGE(DT_RELACOUNT, tags_relacount);
424	DYN_RANGE(DT_AUXILIARY, tags_auxiliary);
425
426	/*
427	 * SUNW: machine specific range.
428	 */
429	if (((mach == EM_SPARC) || (mach == EM_SPARCV9) ||
430	    (mach == EM_SPARC32PLUS)) && (tag == DT_SPARC_REGISTER))
431		/* this is so x86 can display a sparc binary */
432		return (MSG_ORIG(MSG_DYN_REGISTER));
433
434	if (tag == DT_DEPRECATED_SPARC_REGISTER)
435		return (MSG_ORIG(MSG_DYN_REGISTER));
436
437	/* Unknown item */
438	return (conv_invalid_val(inv_buf, tag, fmt_flags));
439
440#undef DYN_RANGE
441}
442
443#define	BINDTSZ	CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \
444		MSG_BND_NEEDED_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
445		MSG_BND_REFER_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
446		MSG_BND_FILTER_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
447		CONV_INV_BUFSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
448
449/*
450 * Ensure that Conv_bnd_type_buf_t is large enough:
451 *
452 * BINDTSZ is the real minimum size of the buffer required by conv_bnd_type().
453 * However, Conv_bnd_type_buf_t uses CONV_BND_TYPE_BUFSIZE to set the
454 * buffer size. We do things this way because the definition of BINDTSZ uses
455 * information that is not available in the environment of other programs
456 * that include the conv.h header file.
457 */
458#if CONV_BND_TYPE_BUFSIZE < BINDTSZ
459#error "CONV_BND_TYPE_BUFSIZE is not large enough"
460#endif
461
462const char *
463conv_bnd_type(uint_t flags, Conv_bnd_type_buf_t *bnd_type_buf)
464{
465	static Val_desc vda[] = {
466		{ BND_NEEDED,		MSG_ORIG(MSG_BND_NEEDED) },
467		{ BND_REFER,		MSG_ORIG(MSG_BND_REFER) },
468		{ BND_FILTER,		MSG_ORIG(MSG_BND_FILTER) },
469		{ 0,			0 }
470	};
471	static CONV_EXPN_FIELD_ARG conv_arg = {
472	    NULL, sizeof (bnd_type_buf->buf), vda };
473
474	if (flags == 0)
475		return (MSG_ORIG(MSG_STR_EMPTY));
476
477	conv_arg.buf = bnd_type_buf->buf;
478	conv_arg.oflags = conv_arg.rflags = flags;
479	(void) conv_expn_field(&conv_arg, 0);
480
481	return ((const char *)bnd_type_buf->buf);
482}
483
484/*
485 * Note, conv_bnd_obj() is called with either:
486 *	LML_FLG_OBJADDED (possibly with LML_FLG_OBJREEVAL added), or
487 *	LML_FLG_OBJDELETED, or
488 *	LML_FLG_ATEXIT.
489 */
490#define	BINDOSZ	CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \
491		MSG_BND_ADDED_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
492		MSG_BND_REEVAL_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
493		CONV_INV_BUFSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
494
495/*
496 * Ensure that Conv_bnd_obj_buf_t is large enough:
497 *
498 * BINDOSZ is the real minimum size of the buffer required by conv_bnd_obj().
499 * However, Conv_bnd_obj_buf_t uses CONV_BND_OBJ_BUFSIZE to set the
500 * buffer size. We do things this way because the definition of BINDOSZ uses
501 * information that is not available in the environment of other programs
502 * that include the conv.h header file.
503 */
504#if CONV_BND_OBJ_BUFSIZE < BINDOSZ
505#error "CONV_BND_OBJ_BUFSIZE is not large enough"
506#endif
507
508const char *
509conv_bnd_obj(uint_t flags, Conv_bnd_obj_buf_t *bnd_obj_buf)
510{
511	static Val_desc vda[] = {
512		{ LML_FLG_OBJADDED,	MSG_ORIG(MSG_BND_ADDED) },
513		{ LML_FLG_OBJREEVAL,	MSG_ORIG(MSG_BND_REEVAL) },
514		{ LML_FLG_OBJDELETED,	MSG_ORIG(MSG_BND_DELETED) },
515		{ LML_FLG_ATEXIT,	MSG_ORIG(MSG_BND_ATEXIT) },
516		{ 0,			0 }
517	};
518	static CONV_EXPN_FIELD_ARG conv_arg = {
519	    NULL, sizeof (bnd_obj_buf->buf), vda };
520
521	if ((flags & (LML_FLG_OBJADDED | LML_FLG_OBJREEVAL |
522	    LML_FLG_OBJDELETED | LML_FLG_ATEXIT)) == 0)
523		return (MSG_ORIG(MSG_BND_REVISIT));
524
525	/*
526	 * Note, we're not worried about unknown flags for this family, only
527	 * the selected flags are of interest, so we leave conv_arg.rflags
528	 * set to 0.
529	 */
530	conv_arg.buf = bnd_obj_buf->buf;
531	conv_arg.oflags = flags;
532	(void) conv_expn_field(&conv_arg, 0);
533
534	return ((const char *)bnd_obj_buf->buf);
535}
536