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