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