xref: /titanic_41/usr/src/cmd/sgs/libconv/common/dynamic.c (revision 5ce5f3670f7934e376808da0d1309924ecf8f9e5)
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 #define	POSSZ	CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \
39 		MSG_DFP_LAZYLOAD_ALT_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
40 		MSG_DFP_GROUPPERM_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
41 		CONV_INV_STRSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
42 
43 const char *
44 conv_dyn_posflag1(Xword flags, int fmt_flags)
45 {
46 	static char	string[POSSZ];
47 	static Val_desc vda[] = {
48 		{ DF_P1_LAZYLOAD,	MSG_ORIG(MSG_DFP_LAZYLOAD) },
49 		{ DF_P1_GROUPPERM,	MSG_ORIG(MSG_DFP_GROUPPERM) },
50 		{ 0,			0 }
51 	};
52 	static CONV_EXPN_FIELD_ARG conv_arg = { string, sizeof (string), vda };
53 	static Val_desc vda_alt[] = {
54 		{ DF_P1_LAZYLOAD,	MSG_ORIG(MSG_DFP_LAZYLOAD_ALT) },
55 		{ DF_P1_GROUPPERM,	MSG_ORIG(MSG_DFP_GROUPPERM) },
56 		{ 0,			0 }
57 	};
58 	static CONV_EXPN_FIELD_ARG conv_arg_alt = { string, sizeof (string),
59 		vda_alt, NULL, 0, 0, MSG_ORIG(MSG_STR_EMPTY), NULL,
60 		MSG_ORIG(MSG_STR_EMPTY) };
61 
62 	CONV_EXPN_FIELD_ARG *arg;
63 
64 	if (flags == 0)
65 		return (MSG_ORIG(MSG_GBL_ZERO));
66 
67 	arg = (fmt_flags & CONV_FMT_ALTDUMP) ? &conv_arg_alt : &conv_arg;
68 	arg->oflags = arg->rflags = flags;
69 	(void) conv_expn_field(arg);
70 
71 	return ((const char *)string);
72 }
73 
74 #define	FLAGSZ	CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \
75 		MSG_DF_ORIGIN_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
76 		MSG_DF_SYMBOLIC_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
77 		MSG_DF_TEXTREL_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
78 		MSG_DF_BIND_NOW_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
79 		MSG_DF_STATIC_TLS_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
80 		CONV_INV_STRSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
81 
82 const char *
83 conv_dyn_flag(Xword flags, int fmt_flags)
84 {
85 	static char	string[FLAGSZ];
86 	static Val_desc vda[] = {
87 		{ DF_ORIGIN,		MSG_ORIG(MSG_DF_ORIGIN) },
88 		{ DF_SYMBOLIC,		MSG_ORIG(MSG_DF_SYMBOLIC) },
89 		{ DF_TEXTREL,		MSG_ORIG(MSG_DF_TEXTREL) },
90 		{ DF_BIND_NOW,		MSG_ORIG(MSG_DF_BIND_NOW) },
91 		{ DF_STATIC_TLS,	MSG_ORIG(MSG_DF_STATIC_TLS) },
92 		{ 0,			0 }
93 	};
94 	static CONV_EXPN_FIELD_ARG conv_arg = { string, sizeof (string), vda };
95 
96 	if (flags == 0)
97 		return (MSG_ORIG(MSG_GBL_ZERO));
98 
99 	conv_arg.oflags = conv_arg.rflags = flags;
100 	if (fmt_flags & CONV_FMT_ALTDUMP) {
101 		conv_arg.prefix = conv_arg.suffix = MSG_ORIG(MSG_STR_EMPTY);
102 	} else {
103 		conv_arg.prefix = conv_arg.suffix = NULL;
104 	}
105 	(void) conv_expn_field(&conv_arg);
106 
107 	return ((const char *)string);
108 }
109 
110 #define	FLAG1SZ	CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \
111 		MSG_DF1_NOW_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
112 		MSG_DF1_GLOBAL_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
113 		MSG_DF1_GROUP_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
114 		MSG_DF1_NODELETE_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
115 		MSG_DF1_LOADFLTR_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
116 		MSG_DF1_INITFIRST_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
117 		MSG_DF1_NOOPEN_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
118 		MSG_DF1_ORIGIN_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
119 		MSG_DF1_DIRECT_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
120 		MSG_DF1_TRANS_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
121 		MSG_DF1_INTERPOSE_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
122 		MSG_DF1_NODEFLIB_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
123 		MSG_DF1_NODUMP_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
124 		MSG_DF1_CONFALT_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
125 		MSG_DF1_ENDFILTEE_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
126 		MSG_DF1_DISPRELPND_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
127 		MSG_DF1_DISPRELDNE_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
128 		MSG_DF1_NODIRECT_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
129 		MSG_DF1_IGNMULDEF_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
130 		MSG_DF1_NOKSYMS_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
131 		MSG_DF1_NOHDR_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
132 		MSG_DF1_NORELOC_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
133 		MSG_DF1_SYMINTPOSE_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
134 		CONV_INV_STRSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
135 
136 const char *
137 conv_dyn_flag1(Xword flags)
138 {
139 	static char	string[FLAG1SZ];
140 	static Val_desc vda[] = {
141 		{ DF_1_NOW,		MSG_ORIG(MSG_DF1_NOW) },
142 		{ DF_1_GLOBAL,		MSG_ORIG(MSG_DF1_GLOBAL) },
143 		{ DF_1_GROUP,		MSG_ORIG(MSG_DF1_GROUP) },
144 		{ DF_1_NODELETE,	MSG_ORIG(MSG_DF1_NODELETE) },
145 		{ DF_1_LOADFLTR,	MSG_ORIG(MSG_DF1_LOADFLTR) },
146 		{ DF_1_INITFIRST,	MSG_ORIG(MSG_DF1_INITFIRST) },
147 		{ DF_1_NOOPEN,		MSG_ORIG(MSG_DF1_NOOPEN) },
148 		{ DF_1_ORIGIN,		MSG_ORIG(MSG_DF1_ORIGIN) },
149 		{ DF_1_DIRECT,		MSG_ORIG(MSG_DF1_DIRECT) },
150 		{ DF_1_TRANS,		MSG_ORIG(MSG_DF1_TRANS) },
151 		{ DF_1_INTERPOSE,	MSG_ORIG(MSG_DF1_INTERPOSE) },
152 		{ DF_1_NODEFLIB,	MSG_ORIG(MSG_DF1_NODEFLIB) },
153 		{ DF_1_NODUMP,		MSG_ORIG(MSG_DF1_NODUMP) },
154 		{ DF_1_CONFALT,		MSG_ORIG(MSG_DF1_CONFALT) },
155 		{ DF_1_ENDFILTEE,	MSG_ORIG(MSG_DF1_ENDFILTEE) },
156 		{ DF_1_DISPRELPND,	MSG_ORIG(MSG_DF1_DISPRELPND) },
157 		{ DF_1_DISPRELDNE,	MSG_ORIG(MSG_DF1_DISPRELDNE) },
158 		{ DF_1_NODIRECT,	MSG_ORIG(MSG_DF1_NODIRECT) },
159 		{ DF_1_IGNMULDEF,	MSG_ORIG(MSG_DF1_IGNMULDEF) },
160 		{ DF_1_NOKSYMS,		MSG_ORIG(MSG_DF1_NOKSYMS) },
161 		{ DF_1_NOHDR,		MSG_ORIG(MSG_DF1_NOHDR) },
162 		{ DF_1_NORELOC,		MSG_ORIG(MSG_DF1_NORELOC) },
163 		{ DF_1_SYMINTPOSE,	MSG_ORIG(MSG_DF1_SYMINTPOSE) },
164 		{ 0,			0 }
165 	};
166 	static CONV_EXPN_FIELD_ARG conv_arg = { string, sizeof (string), vda };
167 
168 	if (flags == 0)
169 		return (MSG_ORIG(MSG_GBL_ZERO));
170 
171 	conv_arg.oflags = conv_arg.rflags = flags;
172 	(void) conv_expn_field(&conv_arg);
173 
174 	return ((const char *)string);
175 }
176 
177 #define	FEATSZ	CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \
178 		MSG_DTF_PARINIT_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
179 		MSG_DTF_CONFEXP_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
180 		CONV_INV_STRSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
181 
182 const char *
183 conv_dyn_feature1(Xword flags, int fmt_flags)
184 {
185 	static char	string[FEATSZ];
186 	static Val_desc vda[] = {
187 		{ DTF_1_PARINIT,	MSG_ORIG(MSG_DTF_PARINIT) },
188 		{ DTF_1_CONFEXP,	MSG_ORIG(MSG_DTF_CONFEXP) },
189 		{ 0,			0 }
190 	};
191 	static CONV_EXPN_FIELD_ARG conv_arg = { string, sizeof (string), vda };
192 
193 	if (flags == 0)
194 		return (MSG_ORIG(MSG_GBL_ZERO));
195 
196 	conv_arg.oflags = conv_arg.rflags = flags;
197 	if (fmt_flags & CONV_FMT_ALTDUMP) {
198 		conv_arg.prefix = conv_arg.suffix = MSG_ORIG(MSG_STR_EMPTY);
199 	} else {
200 		conv_arg.prefix = conv_arg.suffix = NULL;
201 	}
202 	(void) conv_expn_field(&conv_arg);
203 
204 	return ((const char *)string);
205 }
206 
207 const char *
208 conv_dyn_tag(Xword tag, Half mach, int fmt_flags)
209 {
210 	static Conv_inv_buf_t	string;
211 	static const Msg	tags[DT_MAXPOSTAGS] = {
212 		MSG_DYN_NULL,		MSG_DYN_NEEDED,
213 		MSG_DYN_PLTRELSZ,	MSG_DYN_PLTGOT,
214 		MSG_DYN_HASH,		MSG_DYN_STRTAB,
215 		MSG_DYN_SYMTAB,		MSG_DYN_RELA,
216 		MSG_DYN_RELASZ,		MSG_DYN_RELAENT,
217 		MSG_DYN_STRSZ,		MSG_DYN_SYMENT,
218 		MSG_DYN_INIT,		MSG_DYN_FINI,
219 		MSG_DYN_SONAME,		MSG_DYN_RPATH,
220 		MSG_DYN_SYMBOLIC,	MSG_DYN_REL,
221 		MSG_DYN_RELSZ,		MSG_DYN_RELENT,
222 		MSG_DYN_PLTREL,		MSG_DYN_DEBUG,
223 		MSG_DYN_TEXTREL,	MSG_DYN_JMPREL,
224 		MSG_DYN_BIND_NOW,	MSG_DYN_INIT_ARRAY,
225 		MSG_DYN_FINI_ARRAY,	MSG_DYN_INIT_ARRAYSZ,
226 		MSG_DYN_FINI_ARRAYSZ,	MSG_DYN_RUNPATH,
227 		MSG_DYN_FLAGS,		MSG_DYN_NULL,
228 		MSG_DYN_PREINIT_ARRAY,	MSG_DYN_PREINIT_ARRAYSZ
229 	};
230 	static const Msg	tags_alt[DT_MAXPOSTAGS] = {
231 		MSG_DYN_NULL,		MSG_DYN_NEEDED,
232 		MSG_DYN_PLTRELSZ_ALT,	MSG_DYN_PLTGOT,
233 		MSG_DYN_HASH,		MSG_DYN_STRTAB,
234 		MSG_DYN_SYMTAB,		MSG_DYN_RELA,
235 		MSG_DYN_RELASZ,		MSG_DYN_RELAENT,
236 		MSG_DYN_STRSZ,		MSG_DYN_SYMENT,
237 		MSG_DYN_INIT,		MSG_DYN_FINI,
238 		MSG_DYN_SONAME,		MSG_DYN_RPATH,
239 		MSG_DYN_SYMBOLIC_ALT,	MSG_DYN_REL,
240 		MSG_DYN_RELSZ,		MSG_DYN_RELENT,
241 		MSG_DYN_PLTREL,		MSG_DYN_DEBUG,
242 		MSG_DYN_TEXTREL,	MSG_DYN_JMPREL,
243 		MSG_DYN_BIND_NOW,	MSG_DYN_INIT_ARRAY,
244 		MSG_DYN_FINI_ARRAY,	MSG_DYN_INIT_ARRAYSZ,
245 		MSG_DYN_FINI_ARRAYSZ,	MSG_DYN_RUNPATH,
246 		MSG_DYN_FLAGS,		MSG_DYN_NULL,
247 		MSG_DYN_PREINIT_ARRAY,	MSG_DYN_PREINIT_ARRAYSZ
248 	};
249 
250 	if (tag < DT_MAXPOSTAGS) {
251 		/*
252 		 * Generic dynamic tags.
253 		 */
254 		return ((fmt_flags & CONV_FMTALTMASK)
255 			? MSG_ORIG(tags_alt[tag]) : MSG_ORIG(tags[tag]));
256 	} else {
257 		/*
258 		 * SUNW: DT_LOOS -> DT_HIOS range.
259 		 */
260 		if (tag == DT_SUNW_AUXILIARY)
261 			return (MSG_ORIG(MSG_DYN_SUNW_AUXILIARY));
262 		else if (tag == DT_SUNW_RTLDINF)
263 			return (MSG_ORIG(MSG_DYN_SUNW_RTLDINF));
264 		else if (tag == DT_SUNW_FILTER)
265 			return (MSG_ORIG(MSG_DYN_SUNW_FILTER));
266 		else if (tag == DT_SUNW_CAP)
267 			return (MSG_ORIG(MSG_DYN_SUNW_CAP));
268 		else if (tag == DT_SUNW_SYMTAB)
269 			return (MSG_ORIG(MSG_DYN_SUNW_SYMTAB));
270 		else if (tag == DT_SUNW_SYMSZ)
271 			return (MSG_ORIG(MSG_DYN_SUNW_SYMSZ));
272 
273 		/*
274 		 * SUNW: DT_VALRNGLO - DT_VALRNGHI range.
275 		 */
276 		else if (tag == DT_CHECKSUM)
277 			return (MSG_ORIG(MSG_DYN_CHECKSUM));
278 		else if (tag == DT_PLTPADSZ)
279 			return (MSG_ORIG(MSG_DYN_PLTPADSZ));
280 		else if (tag == DT_MOVEENT)
281 			return (MSG_ORIG(MSG_DYN_MOVEENT));
282 		else if (tag == DT_MOVESZ)
283 			return (MSG_ORIG(MSG_DYN_MOVESZ));
284 		else if (tag == DT_FEATURE_1)
285 			return (MSG_ORIG(MSG_DYN_FEATURE_1));
286 		else if (tag == DT_POSFLAG_1)
287 			return (MSG_ORIG(MSG_DYN_POSFLAG_1));
288 		else if (tag == DT_SYMINSZ)
289 			return (MSG_ORIG(MSG_DYN_SYMINSZ));
290 		else if (tag == DT_SYMINENT)
291 			return (MSG_ORIG(MSG_DYN_SYMINENT));
292 
293 		/*
294 		 * SUNW: DT_ADDRRNGLO - DT_ADDRRNGHI range.
295 		 */
296 		else if (tag == DT_CONFIG)
297 			return (MSG_ORIG(MSG_DYN_CONFIG));
298 		else if (tag == DT_DEPAUDIT)
299 			return (MSG_ORIG(MSG_DYN_DEPAUDIT));
300 		else if (tag == DT_AUDIT)
301 			return (MSG_ORIG(MSG_DYN_AUDIT));
302 		else if (tag == DT_PLTPAD)
303 			return (MSG_ORIG(MSG_DYN_PLTPAD));
304 		else if (tag == DT_MOVETAB)
305 			return (MSG_ORIG(MSG_DYN_MOVETAB));
306 		else if (tag == DT_SYMINFO)
307 			return (MSG_ORIG(MSG_DYN_SYMINFO));
308 
309 		/*
310 		 * SUNW: generic range.
311 		 */
312 		else if (tag == DT_VERSYM)
313 			return (MSG_ORIG(MSG_DYN_VERSYM));
314 		else if (tag == DT_RELACOUNT)
315 			return (MSG_ORIG(MSG_DYN_RELACOUNT));
316 		else if (tag == DT_RELCOUNT)
317 			return (MSG_ORIG(MSG_DYN_RELCOUNT));
318 		else if (tag == DT_FLAGS_1)
319 			return (MSG_ORIG(MSG_DYN_FLAGS_1));
320 		else if (tag == DT_VERDEF)
321 			return (MSG_ORIG(MSG_DYN_VERDEF));
322 		else if (tag == DT_VERDEFNUM)
323 			return (MSG_ORIG(MSG_DYN_VERDEFNUM));
324 		else if (tag == DT_VERNEED)
325 			return (MSG_ORIG(MSG_DYN_VERNEED));
326 		else if (tag == DT_VERNEEDNUM)
327 			return (MSG_ORIG(MSG_DYN_VERNEEDNUM));
328 		else if (tag == DT_AUXILIARY)
329 			return (MSG_ORIG(MSG_DYN_AUXILIARY));
330 		else if (tag == DT_USED)
331 			return (MSG_ORIG(MSG_DYN_USED));
332 		else if (tag == DT_FILTER)
333 			return (MSG_ORIG(MSG_DYN_FILTER));
334 
335 		/*
336 		 * SUNW: machine specific range.
337 		 */
338 		else if (((mach == EM_SPARC) || (mach == EM_SPARCV9) ||
339 		    (mach == EM_SPARC32PLUS)) && (tag == DT_SPARC_REGISTER))
340 			/* this is so x86 can display a sparc binary */
341 			return (MSG_ORIG(MSG_DYN_REGISTER));
342 		else if (tag == DT_DEPRECATED_SPARC_REGISTER)
343 			return (MSG_ORIG(MSG_DYN_REGISTER));
344 		else
345 			return (conv_invalid_val(string, CONV_INV_STRSIZE,
346 			    tag, fmt_flags));
347 	}
348 }
349 
350 #define	BINDTSZ	CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \
351 		MSG_BND_NEEDED_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
352 		MSG_BND_REFER_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
353 		MSG_BND_FILTER_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
354 		CONV_INV_STRSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
355 
356 const char *
357 conv_bnd_type(uint_t flags)
358 {
359 	static char	string[BINDTSZ];
360 	static Val_desc vda[] = {
361 		{ BND_NEEDED,		MSG_ORIG(MSG_BND_NEEDED) },
362 		{ BND_REFER,		MSG_ORIG(MSG_BND_REFER) },
363 		{ BND_FILTER,		MSG_ORIG(MSG_BND_FILTER) },
364 		{ 0,			0 }
365 	};
366 	static CONV_EXPN_FIELD_ARG conv_arg = { string, sizeof (string), vda };
367 
368 	if (flags == 0)
369 		return (MSG_ORIG(MSG_STR_EMPTY));
370 
371 	conv_arg.oflags = conv_arg.rflags = flags;
372 	(void) conv_expn_field(&conv_arg);
373 
374 	return ((const char *)string);
375 }
376 
377 /*
378  * Note, conv_bnd_obj() is called with either:
379  *	LML_FLG_OBJADDED (possibly with LML_FLG_OBJREEVAL added), or
380  *	LML_FLG_OBJDELETED, or
381  *	LML_FLG_ATEXIT.
382  */
383 #define	BINDOSZ	CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \
384 		MSG_BND_ADDED_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
385 		MSG_BND_REEVAL_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
386 		CONV_INV_STRSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
387 
388 const char *
389 conv_bnd_obj(uint_t flags)
390 {
391 	static char	string[BINDOSZ];
392 	static Val_desc vda[] = {
393 		{ LML_FLG_OBJADDED,	MSG_ORIG(MSG_BND_ADDED) },
394 		{ LML_FLG_OBJREEVAL,	MSG_ORIG(MSG_BND_REEVAL) },
395 		{ LML_FLG_OBJDELETED,	MSG_ORIG(MSG_BND_DELETED) },
396 		{ LML_FLG_ATEXIT,	MSG_ORIG(MSG_BND_ATEXIT) },
397 		{ 0,			0 }
398 	};
399 	static CONV_EXPN_FIELD_ARG conv_arg = { string, sizeof (string), vda };
400 
401 	if ((flags & (LML_FLG_OBJADDED | LML_FLG_OBJREEVAL |
402 	    LML_FLG_OBJDELETED | LML_FLG_ATEXIT)) == 0)
403 		return (MSG_ORIG(MSG_BND_REVISIT));
404 
405 	/*
406 	 * Note, we're not worried about unknown flags for this family, only
407 	 * the selected flags are of interest, so we leave conv_arg.rflags
408 	 * set to 0.
409 	 */
410 	conv_arg.oflags = flags;
411 	(void) conv_expn_field(&conv_arg);
412 
413 	return ((const char *)string);
414 }
415