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