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 2010 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright 2022 Oxide Computer Company
27  */
28 
29 #include	<stdlib.h>
30 #include	<stdio.h>
31 #include	<_elfedit.h>
32 #include	<conv.h>
33 #include	<msg.h>
34 
35 
36 
37 /*
38  * This file contains support for mapping well known ELF constants
39  * to their numeric values. It is a layer on top of the elfedit_atoui()
40  * routines defined in util.c. The idea is that centralizing all the
41  * support for such constants will improve consistency between modules,
42  * allow for sharing of commonly needed items, and make the modules
43  * simpler.
44  */
45 
46 
47 
48 
49 /*
50  * elfedit output style, with and without leading -o
51  */
52 static elfedit_atoui_sym_t sym_outstyle[] = {
53 	{ MSG_ORIG(MSG_STR_DEFAULT),		ELFEDIT_OUTSTYLE_DEFAULT },
54 	{ MSG_ORIG(MSG_STR_SIMPLE),		ELFEDIT_OUTSTYLE_SIMPLE },
55 	{ MSG_ORIG(MSG_STR_NUM),		ELFEDIT_OUTSTYLE_NUM },
56 	{ NULL }
57 };
58 static elfedit_atoui_sym_t sym_minus_o_outstyle[] = {
59 	{ MSG_ORIG(MSG_STR_MINUS_O_DEFAULT),	ELFEDIT_OUTSTYLE_DEFAULT },
60 	{ MSG_ORIG(MSG_STR_MINUS_O_SIMPLE),	ELFEDIT_OUTSTYLE_SIMPLE },
61 	{ MSG_ORIG(MSG_STR_MINUS_O_NUM),	ELFEDIT_OUTSTYLE_NUM },
62 	{ NULL }
63 };
64 
65 
66 /*
67  * Booleans
68  */
69 static elfedit_atoui_sym_t sym_bool[] = {
70 	{ MSG_ORIG(MSG_STR_T),			1 },
71 	{ MSG_ORIG(MSG_STR_F),			0 },
72 	{ MSG_ORIG(MSG_STR_TRUE),		1 },
73 	{ MSG_ORIG(MSG_STR_FALSE),		0 },
74 	{ MSG_ORIG(MSG_STR_ON),			1 },
75 	{ MSG_ORIG(MSG_STR_OFF),		0 },
76 	{ MSG_ORIG(MSG_STR_YES),		1 },
77 	{ MSG_ORIG(MSG_STR_NO),			0 },
78 	{ MSG_ORIG(MSG_STR_Y),			1 },
79 	{ MSG_ORIG(MSG_STR_N),			0 },
80 	{ NULL }
81 };
82 
83 /*
84  * ELF strings for SHT_STRTAB
85  */
86 static elfedit_atoui_sym_t sym_sht_strtab[] = {
87 	{ MSG_ORIG(MSG_SHT_STRTAB),		SHT_STRTAB },
88 	{ MSG_ORIG(MSG_SHT_STRTAB_ALT1),	SHT_STRTAB },
89 
90 	{ NULL }
91 };
92 
93 
94 /*
95  * Strings for SHT_SYMTAB
96  */
97 static elfedit_atoui_sym_t sym_sht_symtab[] = {
98 	{ MSG_ORIG(MSG_SHT_SYMTAB),		SHT_SYMTAB },
99 	{ MSG_ORIG(MSG_SHT_SYMTAB_ALT1),	SHT_SYMTAB },
100 
101 	{ NULL }
102 };
103 
104 /*
105  * Strings for SHT_DYNSYM
106  */
107 static elfedit_atoui_sym_t sym_sht_dynsym[] = {
108 	{ MSG_ORIG(MSG_SHT_DYNSYM),		SHT_DYNSYM },
109 	{ MSG_ORIG(MSG_SHT_DYNSYM_ALT1),	SHT_DYNSYM },
110 
111 	{ NULL }
112 };
113 
114 /*
115  * Strings for SHT_SUNW_LDYNSYM
116  */
117 static elfedit_atoui_sym_t sym_sht_ldynsym[] = {
118 	{ MSG_ORIG(MSG_SHT_SUNW_LDYNSYM),	SHT_SUNW_LDYNSYM },
119 	{ MSG_ORIG(MSG_SHT_SUNW_LDYNSYM_ALT1),	SHT_SUNW_LDYNSYM },
120 
121 	{ NULL }
122 };
123 
124 
125 
126 /*
127  * Types of items found in sym_table[]. All items other than STE_STATIC
128  * pulls strings from libconv, differing in the interface required by
129  * the libconv iteration function used.
130  */
131 typedef enum {
132 	STE_STATIC =		0,	/* Constants are statically defined */
133 	STE_LC =		1,	/* Libconv, pull once */
134 	STE_LC_OS =		2,	/* From libconv, osabi dependency */
135 	STE_LC_MACH =		3,	/* From libconv, mach dependency */
136 	STE_LC_OS_MACH =	4	/* From libconv, osabi/mach dep. */
137 } ste_type_t;
138 
139 /*
140  * Interface of functions called to fill strings from libconv
141  */
142 typedef conv_iter_ret_t	(* libconv_iter_func_simple_t)(
143 			    Conv_fmt_flags_t, conv_iter_cb_t, void *);
144 typedef conv_iter_ret_t	(* libconv_iter_func_os_t)(conv_iter_osabi_t,
145 			    Conv_fmt_flags_t, conv_iter_cb_t, void *);
146 typedef conv_iter_ret_t	(* libconv_iter_func_mach_t)(Half,
147 			    Conv_fmt_flags_t, conv_iter_cb_t, void *);
148 typedef conv_iter_ret_t	(* libconv_iter_func_os_mach_t)(conv_iter_osabi_t, Half,
149 			    Conv_fmt_flags_t, conv_iter_cb_t, void *);
150 typedef union {
151 	libconv_iter_func_simple_t	simple;
152 	libconv_iter_func_os_t		osabi;
153 	libconv_iter_func_mach_t	mach;
154 	libconv_iter_func_os_mach_t	osabi_mach;
155 } libconv_iter_func_t;
156 
157 /*
158  * State for each type of constant
159  */
160 typedef struct {
161 	ste_type_t		ste_type;	/* Type of entry */
162 	elfedit_atoui_sym_t	*ste_arr;	/* NULL, or atoui array */
163 	void			*ste_alloc;	/* Current memory allocation */
164 	size_t			ste_nelts;	/* # items in ste_alloc */
165 	libconv_iter_func_t	ste_conv_func;	/* libconv fill function */
166 } sym_table_ent_t;
167 
168 
169 /*
170  * Array of state for each constant type, including the array of atoui
171  * pointers, for each constant type, indexed by elfedit_const_t value.
172  * The number and order of entries in this table must agree with the
173  * definition of elfedit_const_t in elfedit.h.
174  *
175  * note:
176  * -	STE_STATIC items must supply a statically allocated buffer here.
177  * -	The non-STE_STATIC items use libconv strings. These items are
178  *	initialized by init_libconv_strings() at runtime, and are represented
179  *	by a simple { 0 } here. The memory used for these arrays is dynamic,
180  *	and can be released and rebuilt at runtime as necessary to keep up
181  *	with changes in osabi or machine type.
182  */
183 static sym_table_ent_t sym_table[ELFEDIT_CONST_NUM] = {
184 						/* #: ELFEDIT_CONST_xxx */
185 	{ STE_STATIC, sym_outstyle },		/* 0: OUTSTYLE */
186 	{ STE_STATIC, sym_minus_o_outstyle },	/* 1: OUTSTYLE_MO */
187 	{ STE_STATIC, sym_bool },		/* 2: BOOL */
188 	{ STE_STATIC, sym_sht_strtab },		/* 3: SHT_STRTAB */
189 	{ STE_STATIC, sym_sht_symtab },		/* 4: SHT_SYMTAB */
190 	{ STE_STATIC, sym_sht_dynsym },		/* 5: SHT_DYNSYM */
191 	{ STE_STATIC, sym_sht_ldynsym },	/* 6: SHT_LDYNSYM */
192 	{ 0 },					/* 7: SHN */
193 	{ 0 },					/* 8: SHT */
194 	{ 0 },					/* 9: SHT_ALLSYMTAB */
195 	{ 0 },					/* 10: DT */
196 	{ 0 },					/* 11: DF */
197 	{ 0 },					/* 12: DF_P1 */
198 	{ 0 },					/* 13: DF_1 */
199 	{ 0 },					/* 14: DTF_1 */
200 	{ 0 },					/* 15: EI */
201 	{ 0 },					/* 16: ET */
202 	{ 0 },					/* 17: ELFCLASS */
203 	{ 0 },					/* 18: ELFDATA */
204 	{ 0 },					/* 19: EF */
205 	{ 0 },					/* 20: EV */
206 	{ 0 },					/* 21: EM */
207 	{ 0 },					/* 22: ELFOSABI */
208 	{ 0 },					/* 23: EAV osabi version */
209 	{ 0 },					/* 24: PT */
210 	{ 0 },					/* 25: PF */
211 	{ 0 },					/* 26: SHF */
212 	{ 0 },					/* 27: STB */
213 	{ 0 },					/* 28: STT */
214 	{ 0 },					/* 29: STV */
215 	{ 0 },					/* 30: SYMINFO_BT */
216 	{ 0 },					/* 31: SYMINFO_FLG */
217 	{ 0 },					/* 32: CA */
218 	{ 0 },					/* 33: AV */
219 	{ 0 },					/* 34: SF1_SUNW */
220 };
221 #if ELFEDIT_CONST_NUM != (ELFEDIT_CONST_SF1_SUNW)
222 error "ELFEDIT_CONST_NUM has grown. Update sym_table[]"
223 #endif
224 
225 
226 
227 
228 /*
229  * Used to count the number of descriptors that will be needed to hold
230  * strings from libconv.
231  */
232 /*ARGSUSED*/
233 static conv_iter_ret_t
234 libconv_count_cb(const char *str, Conv_elfvalue_t value, void *uvalue)
235 {
236 	size_t *cnt = (size_t *)uvalue;
237 
238 	(*cnt)++;
239 	return (CONV_ITER_CONT);
240 }
241 
242 /*
243  * Used to fill in the descriptors with strings from libconv.
244  */
245 typedef struct {
246 	size_t			cur;	/* Index of next descriptor */
247 	size_t			cnt;	/* # of descriptors */
248 	elfedit_atoui_sym_t	*desc;	/* descriptors */
249 } libconv_fill_state_t;
250 
251 static conv_iter_ret_t
libconv_fill_cb(const char * str,Conv_elfvalue_t value,void * uvalue)252 libconv_fill_cb(const char *str, Conv_elfvalue_t value, void *uvalue)
253 {
254 	libconv_fill_state_t	*fill_state = (libconv_fill_state_t *)uvalue;
255 	elfedit_atoui_sym_t	*sym = &fill_state->desc[fill_state->cur++];
256 
257 	sym->sym_name = str;
258 	sym->sym_value = value;
259 	return (CONV_ITER_CONT);
260 }
261 
262 
263 /*
264  * Call the iteration function using the correct calling sequence for
265  * the libconv routine.
266  */
267 static void
libconv_fill_iter(sym_table_ent_t * sym,conv_iter_osabi_t osabi,Half mach,conv_iter_cb_t func,void * uvalue)268 libconv_fill_iter(sym_table_ent_t *sym, conv_iter_osabi_t osabi, Half mach,
269     conv_iter_cb_t func, void *uvalue)
270 {
271 	switch (sym->ste_type) {
272 	case STE_LC:
273 		(void) (* sym->ste_conv_func.simple)(
274 		    CONV_FMT_ALT_CF, func, uvalue);
275 		(void) (* sym->ste_conv_func.simple)(
276 		    CONV_FMT_ALT_NF, func, uvalue);
277 		break;
278 
279 	case STE_LC_OS:
280 		(void) (* sym->ste_conv_func.osabi)(osabi,
281 		    CONV_FMT_ALT_CF, func, uvalue);
282 		(void) (* sym->ste_conv_func.osabi)(osabi,
283 		    CONV_FMT_ALT_NF, func, uvalue);
284 		break;
285 
286 	case STE_LC_MACH:
287 		(void) (* sym->ste_conv_func.mach)(mach,
288 		    CONV_FMT_ALT_CF, func, uvalue);
289 		(void) (* sym->ste_conv_func.mach)(mach,
290 		    CONV_FMT_ALT_NF, func, uvalue);
291 		break;
292 
293 	case STE_LC_OS_MACH:
294 		(void) (* sym->ste_conv_func.osabi_mach)(osabi, mach,
295 		    CONV_FMT_ALT_CF, func, uvalue);
296 		(void) (* sym->ste_conv_func.osabi_mach)(osabi, mach,
297 		    CONV_FMT_ALT_NF, func, uvalue);
298 		break;
299 
300 	case STE_STATIC:
301 		break;
302 	}
303 }
304 
305 /*
306  * Allocate/Fill an atoui array for the specified constant.
307  */
308 static void
libconv_fill(sym_table_ent_t * sym,conv_iter_osabi_t osabi,Half mach)309 libconv_fill(sym_table_ent_t *sym, conv_iter_osabi_t osabi, Half mach)
310 {
311 	libconv_fill_state_t	fill_state;
312 
313 	/* How many descriptors will we need? */
314 	fill_state.cnt = 1;		/* Extra for NULL termination */
315 	libconv_fill_iter(sym, osabi, mach, libconv_count_cb, &fill_state.cnt);
316 
317 	/*
318 	 * If there is an existing allocation, and it is not large enough,
319 	 * release it.
320 	 */
321 	if ((sym->ste_alloc != NULL) && (fill_state.cnt > sym->ste_nelts)) {
322 		free(sym->ste_alloc);
323 		sym->ste_alloc = NULL;
324 		sym->ste_nelts = 0;
325 	}
326 
327 	/* Allocate memory if don't already have an allocation */
328 	if (sym->ste_alloc == NULL) {
329 		sym->ste_alloc = elfedit_malloc(MSG_INTL(MSG_ALLOC_ELFCONDESC),
330 		    fill_state.cnt * sizeof (*fill_state.desc));
331 		sym->ste_nelts = fill_state.cnt;
332 	}
333 
334 	/* Fill the array */
335 	fill_state.desc = sym->ste_alloc;
336 	fill_state.cur = 0;
337 	libconv_fill_iter(sym, osabi, mach, libconv_fill_cb, &fill_state);
338 
339 	/* Add null termination */
340 	fill_state.desc[fill_state.cur].sym_name = NULL;
341 	fill_state.desc[fill_state.cur].sym_value = 0;
342 
343 	/* atoui array for this item is now available */
344 	sym->ste_arr = fill_state.desc;
345 }
346 
347 /*
348  * Should be called on first call to elfedit_const_to_atoui(). Does the
349  * runtime initialization of sym_table.
350  */
351 static void
init_libconv_strings(conv_iter_osabi_t * osabi,Half * mach)352 init_libconv_strings(conv_iter_osabi_t *osabi, Half *mach)
353 {
354 	/*
355 	 * It is critical that the ste_type and ste_conv_func values
356 	 * agree. Since the libconv iteration function signatures can
357 	 * change (gain or lose an osabi or mach argument), we want to
358 	 * ensure that the compiler will catch such changes.
359 	 *
360 	 * The compiler will catch an attempt to assign a function of
361 	 * the wrong type to ste_conv_func. Using these macros, we ensure
362 	 * that the ste_type and function assignment happen as a unit.
363 	 */
364 #define	LC(_ndx, _func) sym_table[_ndx].ste_type = STE_LC; \
365 	sym_table[_ndx].ste_conv_func.simple = _func;
366 #define	LC_OS(_ndx, _func) sym_table[_ndx].ste_type = STE_LC_OS; \
367 	sym_table[_ndx].ste_conv_func.osabi = _func;
368 #define	LC_MACH(_ndx, _func) sym_table[_ndx].ste_type = STE_LC_MACH; \
369 	sym_table[_ndx].ste_conv_func.mach = _func;
370 #define	LC_OS_MACH(_ndx, _func) sym_table[_ndx].ste_type = STE_LC_OS_MACH; \
371 	sym_table[_ndx].ste_conv_func.osabi_mach = _func;
372 
373 
374 	if (!state.file.present) {
375 		/*
376 		 * No input file: Supply the maximal set of strings for
377 		 * all osabi and mach values understood by libconv.
378 		 */
379 		*osabi = CONV_OSABI_ALL;
380 		*mach = CONV_MACH_ALL;
381 	} else if (state.elf.elfclass == ELFCLASS32) {
382 		*osabi = state.elf.obj_state.s32->os_ehdr->e_ident[EI_OSABI];
383 		*mach = state.elf.obj_state.s32->os_ehdr->e_machine;
384 	} else {
385 		*osabi = state.elf.obj_state.s64->os_ehdr->e_ident[EI_OSABI];
386 		*mach = state.elf.obj_state.s64->os_ehdr->e_machine;
387 	}
388 
389 	/* Set up non- STE_STATIC libconv fill functions */
390 	LC_OS_MACH(ELFEDIT_CONST_SHN,		conv_iter_sym_shndx);
391 	LC_OS_MACH(ELFEDIT_CONST_SHT,		conv_iter_sec_type);
392 	LC_OS(ELFEDIT_CONST_SHT_ALLSYMTAB,	conv_iter_sec_symtab);
393 	LC_OS_MACH(ELFEDIT_CONST_DT,		conv_iter_dyn_tag);
394 	LC(ELFEDIT_CONST_DF,			conv_iter_dyn_flag);
395 	LC(ELFEDIT_CONST_DF_P1,			conv_iter_dyn_posflag1);
396 	LC(ELFEDIT_CONST_DF_1,			conv_iter_dyn_flag1);
397 	LC(ELFEDIT_CONST_DTF_1,			conv_iter_dyn_feature1);
398 	LC(ELFEDIT_CONST_EI,			conv_iter_ehdr_eident);
399 	LC_OS(ELFEDIT_CONST_ET,			conv_iter_ehdr_type);
400 	LC(ELFEDIT_CONST_ELFCLASS,		conv_iter_ehdr_class);
401 	LC(ELFEDIT_CONST_ELFDATA,		conv_iter_ehdr_data);
402 	LC_MACH(ELFEDIT_CONST_EF,		conv_iter_ehdr_flags);
403 	LC(ELFEDIT_CONST_EV,			conv_iter_ehdr_vers);
404 	LC(ELFEDIT_CONST_EM,			conv_iter_ehdr_mach);
405 	LC(ELFEDIT_CONST_ELFOSABI,		conv_iter_ehdr_osabi);
406 	LC_OS(ELFEDIT_CONST_EAV,		conv_iter_ehdr_abivers);
407 	LC_OS(ELFEDIT_CONST_PT,			conv_iter_phdr_type);
408 	LC_OS(ELFEDIT_CONST_PF,			conv_iter_phdr_flags);
409 	LC_OS_MACH(ELFEDIT_CONST_SHF,		conv_iter_sec_flags);
410 	LC(ELFEDIT_CONST_STB,			conv_iter_sym_info_bind);
411 	LC_MACH(ELFEDIT_CONST_STT,		conv_iter_sym_info_type);
412 	LC(ELFEDIT_CONST_STV,			conv_iter_sym_other_vis);
413 	LC(ELFEDIT_CONST_SYMINFO_BT,		conv_iter_syminfo_boundto);
414 	LC(ELFEDIT_CONST_SYMINFO_FLG,		conv_iter_syminfo_flags);
415 	LC(ELFEDIT_CONST_CA,			conv_iter_cap_tags);
416 	LC_MACH(ELFEDIT_CONST_HW1_SUNW,		conv_iter_cap_val_hw1);
417 	LC(ELFEDIT_CONST_SF1_SUNW,		conv_iter_cap_val_sf1);
418 	LC_MACH(ELFEDIT_CONST_HW2_SUNW,		conv_iter_cap_val_hw2);
419 	LC_MACH(ELFEDIT_CONST_HW3_SUNW,		conv_iter_cap_val_hw3);
420 
421 #undef LC
422 #undef LC_OS
423 #undef LC_MACH
424 #undef LC_OS_MACH
425 }
426 
427 /*
428  * If the user has changed the osabi or machine type of the object,
429  * then we need to discard the strings we've loaded from libconv
430  * that are dependent on these values.
431  */
432 static void
invalidate_libconv_strings(conv_iter_osabi_t * osabi,Half * mach)433 invalidate_libconv_strings(conv_iter_osabi_t *osabi, Half *mach)
434 {
435 	uchar_t		cur_osabi;
436 	Half		cur_mach;
437 	sym_table_ent_t	*sym;
438 	int		osabi_change, mach_change;
439 	int		i;
440 
441 
442 	/* Reset the ELF header change notification */
443 	state.elf.elfconst_ehdr_change = 0;
444 
445 	if (state.elf.elfclass == ELFCLASS32) {
446 		cur_osabi = state.elf.obj_state.s32->os_ehdr->e_ident[EI_OSABI];
447 		cur_mach = state.elf.obj_state.s32->os_ehdr->e_machine;
448 	} else {
449 		cur_osabi = state.elf.obj_state.s64->os_ehdr->e_ident[EI_OSABI];
450 		cur_mach = state.elf.obj_state.s64->os_ehdr->e_machine;
451 	}
452 
453 	/* What has changed? */
454 	mach_change = *mach != cur_mach;
455 	osabi_change = *osabi != cur_osabi;
456 	if (!(mach_change || osabi_change))
457 		return;
458 
459 	/*
460 	 * Set the ste_arr pointer to NULL for any items that
461 	 * depend on the things that have changed. Note that we
462 	 * do not release the allocated memory --- it may turn
463 	 * out to be large enough to hold the new strings, so we
464 	 * keep the allocation and leave that decision to the fill
465 	 * routine, which will run the next time those strings are
466 	 * needed.
467 	 */
468 	for (i = 0, sym = sym_table;
469 	    i < (sizeof (sym_table) / sizeof (sym_table[0])); i++, sym++) {
470 		if (sym->ste_arr == NULL)
471 			continue;
472 
473 		switch (sym->ste_type) {
474 		case STE_STATIC:
475 		case STE_LC:
476 			break;
477 
478 		case STE_LC_OS:
479 			if (osabi_change)
480 				sym->ste_arr = NULL;
481 			break;
482 
483 		case STE_LC_MACH:
484 			if (mach_change)
485 				sym->ste_arr = NULL;
486 			break;
487 
488 		case STE_LC_OS_MACH:
489 			if (osabi_change || mach_change)
490 				sym->ste_arr = NULL;
491 			break;
492 		}
493 	}
494 
495 	*mach = cur_mach;
496 	*osabi = cur_osabi;
497 }
498 
499 
500 
501 /*
502  * Given an elfedit_const_t value, return the array of elfedit_atoui_sym_t
503  * entries that it represents.
504  */
505 elfedit_atoui_sym_t *
elfedit_const_to_atoui(elfedit_const_t const_type)506 elfedit_const_to_atoui(elfedit_const_t const_type)
507 {
508 	static int			first = 1;
509 	static conv_iter_osabi_t	osabi;
510 	static Half			mach;
511 
512 	sym_table_ent_t	*sym;
513 
514 	if (first) {
515 		init_libconv_strings(&osabi, &mach);
516 		first = 0;
517 	}
518 
519 	if ((const_type < 0) ||
520 	    (const_type >= (sizeof (sym_table) / sizeof (sym_table[0]))))
521 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_BADCONST));
522 	sym = &sym_table[const_type];
523 
524 	/*
525 	 * If the constant is not STE_STATIC, then we may need to fetch
526 	 * the strings from libconv.
527 	 */
528 	if (sym->ste_type != STE_STATIC) {
529 		/*
530 		 * If the ELF header has changed since the last
531 		 * time we were called, then we need to invalidate any
532 		 * strings previously pulled from libconv that have
533 		 * an osabi or machine dependency.
534 		 */
535 		if (state.elf.elfconst_ehdr_change)
536 			invalidate_libconv_strings(&osabi, &mach);
537 
538 		/* If we don't already have the strings, get them */
539 		if (sym->ste_arr == NULL)
540 			libconv_fill(sym, osabi, mach);
541 	}
542 
543 	return (sym->ste_arr);
544 }
545