xref: /illumos-gate/usr/src/cmd/sgs/libconv/common/dynamic.c (revision cf74e62b28857cc7cf88dd0a34d34df9a7e26fe8)
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_STRSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
49 
50 const char *
51 conv_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 
89 const char *
90 conv_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 		MSG_DF1_GLOBAUDIT_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
142 		CONV_INV_STRSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
143 
144 const char *
145 conv_dyn_flag1(Xword flags)
146 {
147 	static char	string[FLAG1SZ];
148 	static Val_desc vda[] = {
149 		{ DF_1_NOW,		MSG_ORIG(MSG_DF1_NOW) },
150 		{ DF_1_GLOBAL,		MSG_ORIG(MSG_DF1_GLOBAL) },
151 		{ DF_1_GROUP,		MSG_ORIG(MSG_DF1_GROUP) },
152 		{ DF_1_NODELETE,	MSG_ORIG(MSG_DF1_NODELETE) },
153 		{ DF_1_LOADFLTR,	MSG_ORIG(MSG_DF1_LOADFLTR) },
154 		{ DF_1_INITFIRST,	MSG_ORIG(MSG_DF1_INITFIRST) },
155 		{ DF_1_NOOPEN,		MSG_ORIG(MSG_DF1_NOOPEN) },
156 		{ DF_1_ORIGIN,		MSG_ORIG(MSG_DF1_ORIGIN) },
157 		{ DF_1_DIRECT,		MSG_ORIG(MSG_DF1_DIRECT) },
158 		{ DF_1_TRANS,		MSG_ORIG(MSG_DF1_TRANS) },
159 		{ DF_1_INTERPOSE,	MSG_ORIG(MSG_DF1_INTERPOSE) },
160 		{ DF_1_NODEFLIB,	MSG_ORIG(MSG_DF1_NODEFLIB) },
161 		{ DF_1_NODUMP,		MSG_ORIG(MSG_DF1_NODUMP) },
162 		{ DF_1_CONFALT,		MSG_ORIG(MSG_DF1_CONFALT) },
163 		{ DF_1_ENDFILTEE,	MSG_ORIG(MSG_DF1_ENDFILTEE) },
164 		{ DF_1_DISPRELDNE,	MSG_ORIG(MSG_DF1_DISPRELDNE) },
165 		{ DF_1_DISPRELPND,	MSG_ORIG(MSG_DF1_DISPRELPND) },
166 		{ DF_1_NODIRECT,	MSG_ORIG(MSG_DF1_NODIRECT) },
167 		{ DF_1_IGNMULDEF,	MSG_ORIG(MSG_DF1_IGNMULDEF) },
168 		{ DF_1_NOKSYMS,		MSG_ORIG(MSG_DF1_NOKSYMS) },
169 		{ DF_1_NOHDR,		MSG_ORIG(MSG_DF1_NOHDR) },
170 		{ DF_1_EDITED,		MSG_ORIG(MSG_DF1_EDITED) },
171 		{ DF_1_NORELOC,		MSG_ORIG(MSG_DF1_NORELOC) },
172 		{ DF_1_SYMINTPOSE,	MSG_ORIG(MSG_DF1_SYMINTPOSE) },
173 		{ DF_1_GLOBAUDIT,	MSG_ORIG(MSG_DF1_GLOBAUDIT) },
174 		{ 0,			0 }
175 	};
176 	static CONV_EXPN_FIELD_ARG conv_arg = { string, sizeof (string), vda };
177 
178 	if (flags == 0)
179 		return (MSG_ORIG(MSG_GBL_ZERO));
180 
181 	conv_arg.oflags = conv_arg.rflags = flags;
182 	(void) conv_expn_field(&conv_arg);
183 
184 	return ((const char *)string);
185 }
186 
187 #define	FEATSZ	CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \
188 		MSG_DTF_PARINIT_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
189 		MSG_DTF_CONFEXP_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
190 		CONV_INV_STRSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
191 
192 const char *
193 conv_dyn_feature1(Xword flags, int fmt_flags)
194 {
195 	static char	string[FEATSZ];
196 	static Val_desc vda[] = {
197 		{ DTF_1_PARINIT,	MSG_ORIG(MSG_DTF_PARINIT) },
198 		{ DTF_1_CONFEXP,	MSG_ORIG(MSG_DTF_CONFEXP) },
199 		{ 0,			0 }
200 	};
201 	static CONV_EXPN_FIELD_ARG conv_arg = { string, sizeof (string), vda };
202 
203 	if (flags == 0)
204 		return (MSG_ORIG(MSG_GBL_ZERO));
205 
206 	conv_arg.oflags = conv_arg.rflags = flags;
207 	if (fmt_flags & CONV_FMT_ALTDUMP) {
208 		conv_arg.prefix = conv_arg.suffix = MSG_ORIG(MSG_STR_EMPTY);
209 	} else {
210 		conv_arg.prefix = conv_arg.suffix = NULL;
211 	}
212 	(void) conv_expn_field(&conv_arg);
213 
214 	return ((const char *)string);
215 }
216 
217 const char *
218 conv_dyn_tag(Xword tag, Half mach, int fmt_flags)
219 {
220 	static Conv_inv_buf_t	string;
221 
222 	/*
223 	 * Dynamic tag values are sparse, cover a wide range, and have
224 	 * holes. To handle this efficiently, we fall through a series
225 	 * of tests below, in increasing tag order, returning at the first
226 	 * match.
227 	 *
228 	 * If we fall all the way to the end, the tag is unknown,
229 	 * and its numeric value is printed.
230 	 */
231 
232 	/*
233 	 * Most of the tag values are clustered in contiguous ranges.
234 	 * Each contiguous range of defined values is handled with
235 	 * an array that contains the message index corresponding to
236 	 * each value in that range. The DYN_RANGE macro checks the
237 	 * tag value against range of values starting at _start_tag.
238 	 * If there is a match, the index of the appropriate name is
239 	 * pulled from _array and returned to the caller.
240 	 */
241 #define	DYN_RANGE(_start_tag, _array) \
242 	if ((tag >= _start_tag) && (tag < (_start_tag + ARRAY_NELTS(_array)))) \
243 		return (MSG_ORIG(_array[tag - _start_tag]));
244 
245 
246 	/*
247 	 * Generic dynamic tags:
248 	 *	- Note hole between DT_FLAGS and DT_PREINIT_ARRAY
249 	 *	- The first range has alternative names for dump,
250 	 *	  requiring a second array.
251 	 */
252 	static const Msg	tags_null[] = {
253 		MSG_DYN_NULL,		MSG_DYN_NEEDED,
254 		MSG_DYN_PLTRELSZ,	MSG_DYN_PLTGOT,
255 		MSG_DYN_HASH,		MSG_DYN_STRTAB,
256 		MSG_DYN_SYMTAB,		MSG_DYN_RELA,
257 		MSG_DYN_RELASZ,		MSG_DYN_RELAENT,
258 		MSG_DYN_STRSZ,		MSG_DYN_SYMENT,
259 		MSG_DYN_INIT,		MSG_DYN_FINI,
260 		MSG_DYN_SONAME,		MSG_DYN_RPATH,
261 		MSG_DYN_SYMBOLIC,	MSG_DYN_REL,
262 		MSG_DYN_RELSZ,		MSG_DYN_RELENT,
263 		MSG_DYN_PLTREL,		MSG_DYN_DEBUG,
264 		MSG_DYN_TEXTREL,	MSG_DYN_JMPREL,
265 		MSG_DYN_BIND_NOW,	MSG_DYN_INIT_ARRAY,
266 		MSG_DYN_FINI_ARRAY,	MSG_DYN_INIT_ARRAYSZ,
267 		MSG_DYN_FINI_ARRAYSZ,	MSG_DYN_RUNPATH,
268 		MSG_DYN_FLAGS
269 	};
270 	static const Msg	tags_null_alt[] = {
271 		MSG_DYN_NULL,		MSG_DYN_NEEDED,
272 		MSG_DYN_PLTRELSZ_ALT,	MSG_DYN_PLTGOT,
273 		MSG_DYN_HASH,		MSG_DYN_STRTAB,
274 		MSG_DYN_SYMTAB,		MSG_DYN_RELA,
275 		MSG_DYN_RELASZ,		MSG_DYN_RELAENT,
276 		MSG_DYN_STRSZ,		MSG_DYN_SYMENT,
277 		MSG_DYN_INIT,		MSG_DYN_FINI,
278 		MSG_DYN_SONAME,		MSG_DYN_RPATH,
279 		MSG_DYN_SYMBOLIC_ALT,	MSG_DYN_REL,
280 		MSG_DYN_RELSZ,		MSG_DYN_RELENT,
281 		MSG_DYN_PLTREL,		MSG_DYN_DEBUG,
282 		MSG_DYN_TEXTREL,	MSG_DYN_JMPREL,
283 		MSG_DYN_BIND_NOW,	MSG_DYN_INIT_ARRAY,
284 		MSG_DYN_FINI_ARRAY,	MSG_DYN_INIT_ARRAYSZ,
285 		MSG_DYN_FINI_ARRAYSZ,	MSG_DYN_RUNPATH,
286 		MSG_DYN_FLAGS
287 	};
288 	static const Msg	tags_preinit_array[] = {
289 		MSG_DYN_PREINIT_ARRAY,	MSG_DYN_PREINIT_ARRAYSZ
290 	};
291 
292 	/*
293 	 * SUNW: DT_LOOS -> DT_HIOS range. Note hole between DT_SUNW_TLSSORTSZ
294 	 * and DT_SUNW_STRPAD. We handle DT_SUNW_STRPAD as a single value below.
295 	 */
296 	static const Msg	tags_sunw_auxiliary[] = {
297 		MSG_DYN_SUNW_AUXILIARY,	MSG_DYN_SUNW_RTLDINF,
298 		MSG_DYN_SUNW_FILTER,	MSG_DYN_SUNW_CAP,
299 		MSG_DYN_SUNW_SYMTAB,	MSG_DYN_SUNW_SYMSZ,
300 		MSG_DYN_SUNW_SORTENT,	MSG_DYN_SUNW_SYMSORT,
301 		MSG_DYN_SUNW_SYMSORTSZ,	MSG_DYN_SUNW_TLSSORT,
302 		MSG_DYN_SUNW_TLSSORTSZ
303 	};
304 
305 	/*
306 	 * SUNW: DT_VALRNGLO - DT_VALRNGHI range.
307 	 */
308 	static const Msg	tags_checksum[] = {
309 		MSG_DYN_CHECKSUM,	MSG_DYN_PLTPADSZ,
310 		MSG_DYN_MOVEENT,	MSG_DYN_MOVESZ,
311 		MSG_DYN_FEATURE_1,	MSG_DYN_POSFLAG_1,
312 		MSG_DYN_SYMINSZ,	MSG_DYN_SYMINENT
313 	};
314 
315 	/*
316 	 * SUNW: DT_ADDRRNGLO - DT_ADDRRNGHI range.
317 	 */
318 	static const Msg	tags_config[] = {
319 		MSG_DYN_CONFIG,		MSG_DYN_DEPAUDIT,
320 		MSG_DYN_AUDIT,		MSG_DYN_PLTPAD,
321 		MSG_DYN_MOVETAB,	MSG_DYN_SYMINFO
322 	};
323 
324 	/*
325 	 * SUNW: generic range. Note hole between DT_VERSYM and DT_RELACOUNT.
326 	 * We handle DT_VERSYM as a single value below.
327 	 */
328 	static const Msg	tags_relacount[] = {
329 		MSG_DYN_RELACOUNT,	MSG_DYN_RELCOUNT,
330 		MSG_DYN_FLAGS_1,	MSG_DYN_VERDEF,
331 		MSG_DYN_VERDEFNUM,	MSG_DYN_VERNEED,
332 		MSG_DYN_VERNEEDNUM
333 	};
334 
335 	/*
336 	 * DT_LOPROC - DT_HIPROC range.
337 	 */
338 	static const Msg	tags_auxiliary[] = {
339 		MSG_DYN_AUXILIARY,	MSG_DYN_USED,
340 		MSG_DYN_FILTER
341 	};
342 
343 
344 
345 
346 	if (tag <= DT_FLAGS)
347 		return (conv_map2str(string, sizeof (string), tag,
348 		    fmt_flags, ARRAY_NELTS(tags_null), tags_null,
349 		    tags_null_alt, NULL));
350 	DYN_RANGE(DT_PREINIT_ARRAY, tags_preinit_array);
351 	DYN_RANGE(DT_SUNW_AUXILIARY, tags_sunw_auxiliary);
352 	if (tag == DT_SUNW_STRPAD)
353 		return (MSG_ORIG(MSG_DYN_SUNW_STRPAD));
354 	DYN_RANGE(DT_CHECKSUM, tags_checksum);
355 	DYN_RANGE(DT_CONFIG, tags_config);
356 	if (tag == DT_VERSYM)
357 		return (MSG_ORIG(MSG_DYN_VERSYM));
358 	DYN_RANGE(DT_RELACOUNT, tags_relacount);
359 	DYN_RANGE(DT_AUXILIARY, tags_auxiliary);
360 
361 	/*
362 	 * SUNW: machine specific range.
363 	 */
364 	if (((mach == EM_SPARC) || (mach == EM_SPARCV9) ||
365 	    (mach == EM_SPARC32PLUS)) && (tag == DT_SPARC_REGISTER))
366 		/* this is so x86 can display a sparc binary */
367 		return (MSG_ORIG(MSG_DYN_REGISTER));
368 
369 	if (tag == DT_DEPRECATED_SPARC_REGISTER)
370 		return (MSG_ORIG(MSG_DYN_REGISTER));
371 
372 	/* Unknown item */
373 	return (conv_invalid_val(string, CONV_INV_STRSIZE, tag, fmt_flags));
374 
375 #undef DYN_RANGE
376 }
377 
378 #define	BINDTSZ	CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \
379 		MSG_BND_NEEDED_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
380 		MSG_BND_REFER_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
381 		MSG_BND_FILTER_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
382 		CONV_INV_STRSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
383 
384 const char *
385 conv_bnd_type(uint_t flags)
386 {
387 	static char	string[BINDTSZ];
388 	static Val_desc vda[] = {
389 		{ BND_NEEDED,		MSG_ORIG(MSG_BND_NEEDED) },
390 		{ BND_REFER,		MSG_ORIG(MSG_BND_REFER) },
391 		{ BND_FILTER,		MSG_ORIG(MSG_BND_FILTER) },
392 		{ 0,			0 }
393 	};
394 	static CONV_EXPN_FIELD_ARG conv_arg = { string, sizeof (string), vda };
395 
396 	if (flags == 0)
397 		return (MSG_ORIG(MSG_STR_EMPTY));
398 
399 	conv_arg.oflags = conv_arg.rflags = flags;
400 	(void) conv_expn_field(&conv_arg);
401 
402 	return ((const char *)string);
403 }
404 
405 /*
406  * Note, conv_bnd_obj() is called with either:
407  *	LML_FLG_OBJADDED (possibly with LML_FLG_OBJREEVAL added), or
408  *	LML_FLG_OBJDELETED, or
409  *	LML_FLG_ATEXIT.
410  */
411 #define	BINDOSZ	CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \
412 		MSG_BND_ADDED_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
413 		MSG_BND_REEVAL_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
414 		CONV_INV_STRSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
415 
416 const char *
417 conv_bnd_obj(uint_t flags)
418 {
419 	static char	string[BINDOSZ];
420 	static Val_desc vda[] = {
421 		{ LML_FLG_OBJADDED,	MSG_ORIG(MSG_BND_ADDED) },
422 		{ LML_FLG_OBJREEVAL,	MSG_ORIG(MSG_BND_REEVAL) },
423 		{ LML_FLG_OBJDELETED,	MSG_ORIG(MSG_BND_DELETED) },
424 		{ LML_FLG_ATEXIT,	MSG_ORIG(MSG_BND_ATEXIT) },
425 		{ 0,			0 }
426 	};
427 	static CONV_EXPN_FIELD_ARG conv_arg = { string, sizeof (string), vda };
428 
429 	if ((flags & (LML_FLG_OBJADDED | LML_FLG_OBJREEVAL |
430 	    LML_FLG_OBJDELETED | LML_FLG_ATEXIT)) == 0)
431 		return (MSG_ORIG(MSG_BND_REVISIT));
432 
433 	/*
434 	 * Note, we're not worried about unknown flags for this family, only
435 	 * the selected flags are of interest, so we leave conv_arg.rflags
436 	 * set to 0.
437 	 */
438 	conv_arg.oflags = flags;
439 	(void) conv_expn_field(&conv_arg);
440 
441 	return ((const char *)string);
442 }
443