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