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 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 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 } 301 302 /* 303 * Allocate/Fill an atoui array for the specified constant. 304 */ 305 static void 306 libconv_fill(sym_table_ent_t *sym, conv_iter_osabi_t osabi, Half mach) 307 { 308 libconv_fill_state_t fill_state; 309 310 /* How many descriptors will we need? */ 311 fill_state.cnt = 1; /* Extra for NULL termination */ 312 libconv_fill_iter(sym, osabi, mach, libconv_count_cb, &fill_state.cnt); 313 314 /* 315 * If there is an existing allocation, and it is not large enough, 316 * release it. 317 */ 318 if ((sym->ste_alloc != NULL) && (fill_state.cnt > sym->ste_nelts)) { 319 free(sym->ste_alloc); 320 sym->ste_alloc = NULL; 321 sym->ste_nelts = 0; 322 } 323 324 /* Allocate memory if don't already have an allocation */ 325 if (sym->ste_alloc == NULL) { 326 sym->ste_alloc = elfedit_malloc(MSG_INTL(MSG_ALLOC_ELFCONDESC), 327 fill_state.cnt * sizeof (*fill_state.desc)); 328 sym->ste_nelts = fill_state.cnt; 329 } 330 331 /* Fill the array */ 332 fill_state.desc = sym->ste_alloc; 333 fill_state.cur = 0; 334 libconv_fill_iter(sym, osabi, mach, libconv_fill_cb, &fill_state); 335 336 /* Add null termination */ 337 fill_state.desc[fill_state.cur].sym_name = NULL; 338 fill_state.desc[fill_state.cur].sym_value = 0; 339 340 /* atoui array for this item is now available */ 341 sym->ste_arr = fill_state.desc; 342 } 343 344 /* 345 * Should be called on first call to elfedit_const_to_atoui(). Does the 346 * runtime initialization of sym_table. 347 */ 348 static void 349 init_libconv_strings(conv_iter_osabi_t *osabi, Half *mach) 350 { 351 /* 352 * It is critical that the ste_type and ste_conv_func values 353 * agree. Since the libconv iteration function signatures can 354 * change (gain or lose an osabi or mach argument), we want to 355 * ensure that the compiler will catch such changes. 356 * 357 * The compiler will catch an attempt to assign a function of 358 * the wrong type to ste_conv_func. Using these macros, we ensure 359 * that the ste_type and function assignment happen as a unit. 360 */ 361 #define LC(_ndx, _func) sym_table[_ndx].ste_type = STE_LC; \ 362 sym_table[_ndx].ste_conv_func.simple = _func; 363 #define LC_OS(_ndx, _func) sym_table[_ndx].ste_type = STE_LC_OS; \ 364 sym_table[_ndx].ste_conv_func.osabi = _func; 365 #define LC_MACH(_ndx, _func) sym_table[_ndx].ste_type = STE_LC_MACH; \ 366 sym_table[_ndx].ste_conv_func.mach = _func; 367 #define LC_OS_MACH(_ndx, _func) sym_table[_ndx].ste_type = STE_LC_OS_MACH; \ 368 sym_table[_ndx].ste_conv_func.osabi_mach = _func; 369 370 371 if (!state.file.present) { 372 /* 373 * No input file: Supply the maximal set of strings for 374 * all osabi and mach values understood by libconv. 375 */ 376 *osabi = CONV_OSABI_ALL; 377 *mach = CONV_MACH_ALL; 378 } else if (state.elf.elfclass == ELFCLASS32) { 379 *osabi = state.elf.obj_state.s32->os_ehdr->e_ident[EI_OSABI]; 380 *mach = state.elf.obj_state.s32->os_ehdr->e_machine; 381 } else { 382 *osabi = state.elf.obj_state.s64->os_ehdr->e_ident[EI_OSABI]; 383 *mach = state.elf.obj_state.s64->os_ehdr->e_machine; 384 } 385 386 /* Set up non- STE_STATIC libconv fill functions */ 387 LC_OS_MACH(ELFEDIT_CONST_SHN, conv_iter_sym_shndx); 388 LC_OS_MACH(ELFEDIT_CONST_SHT, conv_iter_sec_type); 389 LC_OS(ELFEDIT_CONST_SHT_ALLSYMTAB, conv_iter_sec_symtab); 390 LC_OS_MACH(ELFEDIT_CONST_DT, conv_iter_dyn_tag); 391 LC(ELFEDIT_CONST_DF, conv_iter_dyn_flag); 392 LC(ELFEDIT_CONST_DF_P1, conv_iter_dyn_posflag1); 393 LC(ELFEDIT_CONST_DF_1, conv_iter_dyn_flag1); 394 LC(ELFEDIT_CONST_DTF_1, conv_iter_dyn_feature1); 395 LC(ELFEDIT_CONST_EI, conv_iter_ehdr_eident); 396 LC_OS(ELFEDIT_CONST_ET, conv_iter_ehdr_type); 397 LC(ELFEDIT_CONST_ELFCLASS, conv_iter_ehdr_class); 398 LC(ELFEDIT_CONST_ELFDATA, conv_iter_ehdr_data); 399 LC_MACH(ELFEDIT_CONST_EF, conv_iter_ehdr_flags); 400 LC(ELFEDIT_CONST_EV, conv_iter_ehdr_vers); 401 LC(ELFEDIT_CONST_EM, conv_iter_ehdr_mach); 402 LC(ELFEDIT_CONST_ELFOSABI, conv_iter_ehdr_osabi); 403 LC_OS(ELFEDIT_CONST_EAV, conv_iter_ehdr_abivers); 404 LC_OS(ELFEDIT_CONST_PT, conv_iter_phdr_type); 405 LC_OS(ELFEDIT_CONST_PF, conv_iter_phdr_flags); 406 LC_OS_MACH(ELFEDIT_CONST_SHF, conv_iter_sec_flags); 407 LC(ELFEDIT_CONST_STB, conv_iter_sym_info_bind); 408 LC_MACH(ELFEDIT_CONST_STT, conv_iter_sym_info_type); 409 LC(ELFEDIT_CONST_STV, conv_iter_sym_other_vis); 410 LC(ELFEDIT_CONST_SYMINFO_BT, conv_iter_syminfo_boundto); 411 LC(ELFEDIT_CONST_SYMINFO_FLG, conv_iter_syminfo_flags); 412 LC(ELFEDIT_CONST_CA, conv_iter_cap_tags); 413 LC_MACH(ELFEDIT_CONST_HW1_SUNW, conv_iter_cap_val_hw1); 414 LC(ELFEDIT_CONST_SF1_SUNW, conv_iter_cap_val_sf1); 415 LC_MACH(ELFEDIT_CONST_HW2_SUNW, conv_iter_cap_val_hw2); 416 LC_MACH(ELFEDIT_CONST_HW3_SUNW, conv_iter_cap_val_hw3); 417 418 #undef LC 419 #undef LC_OS 420 #undef LC_MACH 421 #undef LC_OS_MACH 422 } 423 424 /* 425 * If the user has changed the osabi or machine type of the object, 426 * then we need to discard the strings we've loaded from libconv 427 * that are dependent on these values. 428 */ 429 static void 430 invalidate_libconv_strings(conv_iter_osabi_t *osabi, Half *mach) 431 { 432 uchar_t cur_osabi; 433 Half cur_mach; 434 sym_table_ent_t *sym; 435 int osabi_change, mach_change; 436 int i; 437 438 439 /* Reset the ELF header change notification */ 440 state.elf.elfconst_ehdr_change = 0; 441 442 if (state.elf.elfclass == ELFCLASS32) { 443 cur_osabi = state.elf.obj_state.s32->os_ehdr->e_ident[EI_OSABI]; 444 cur_mach = state.elf.obj_state.s32->os_ehdr->e_machine; 445 } else { 446 cur_osabi = state.elf.obj_state.s64->os_ehdr->e_ident[EI_OSABI]; 447 cur_mach = state.elf.obj_state.s64->os_ehdr->e_machine; 448 } 449 450 /* What has changed? */ 451 mach_change = *mach != cur_mach; 452 osabi_change = *osabi != cur_osabi; 453 if (!(mach_change || osabi_change)) 454 return; 455 456 /* 457 * Set the ste_arr pointer to NULL for any items that 458 * depend on the things that have changed. Note that we 459 * do not release the allocated memory --- it may turn 460 * out to be large enough to hold the new strings, so we 461 * keep the allocation and leave that decision to the fill 462 * routine, which will run the next time those strings are 463 * needed. 464 */ 465 for (i = 0, sym = sym_table; 466 i < (sizeof (sym_table) / sizeof (sym_table[0])); i++, sym++) { 467 if (sym->ste_arr == NULL) 468 continue; 469 470 switch (sym->ste_type) { 471 case STE_LC_OS: 472 if (osabi_change) 473 sym->ste_arr = NULL; 474 break; 475 476 case STE_LC_MACH: 477 if (mach_change) 478 sym->ste_arr = NULL; 479 break; 480 481 case STE_LC_OS_MACH: 482 if (osabi_change || mach_change) 483 sym->ste_arr = NULL; 484 break; 485 } 486 } 487 488 *mach = cur_mach; 489 *osabi = cur_osabi; 490 } 491 492 493 494 /* 495 * Given an elfedit_const_t value, return the array of elfedit_atoui_sym_t 496 * entries that it represents. 497 */ 498 elfedit_atoui_sym_t * 499 elfedit_const_to_atoui(elfedit_const_t const_type) 500 { 501 static int first = 1; 502 static conv_iter_osabi_t osabi; 503 static Half mach; 504 505 sym_table_ent_t *sym; 506 507 if (first) { 508 init_libconv_strings(&osabi, &mach); 509 first = 0; 510 } 511 512 if ((const_type < 0) || 513 (const_type >= (sizeof (sym_table) / sizeof (sym_table[0])))) 514 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_BADCONST)); 515 sym = &sym_table[const_type]; 516 517 /* 518 * If the constant is not STE_STATIC, then we may need to fetch 519 * the strings from libconv. 520 */ 521 if (sym->ste_type != STE_STATIC) { 522 /* 523 * If the ELF header has changed since the last 524 * time we were called, then we need to invalidate any 525 * strings previously pulled from libconv that have 526 * an osabi or machine dependency. 527 */ 528 if (state.elf.elfconst_ehdr_change) 529 invalidate_libconv_strings(&osabi, &mach); 530 531 /* If we don't already have the strings, get them */ 532 if (sym->ste_arr == NULL) 533 libconv_fill(sym, osabi, mach); 534 } 535 536 return (sym->ste_arr); 537 } 538