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 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * Copyright 2018 OmniOS Community Edition (OmniOSce) Association. 26 */ 27 28 /* 29 * ELFCLASS specific code for elfedit, built once for each class 30 */ 31 #include <stdlib.h> 32 #include <stdio.h> 33 #include <unistd.h> 34 #include <_machelf.h> 35 #include <libelf.h> 36 #include <strings.h> 37 #include <sgs.h> 38 #include "msg.h" 39 #include "_elfedit.h" 40 41 42 43 /* 44 * Look up the elfedit_symtab_t that corresponds to the symbol table 45 * referenced by the sh_link field of the given auxiliary section. 46 * 47 * entry: 48 * obj_state - Partially constructed object state from 49 * elfedit_init_obj_state(). 50 * auxsec - Section that is associated with the symbol table section 51 * 52 * exit: 53 * Returns the pointer to the elfedit_symtab_t entry that is 54 * referenced by the auxiliary section. If not found, 55 * outputs a debug message, and returns NULL. 56 */ 57 static elfedit_symtab_t * 58 get_symtab(elfedit_obj_state_t *obj_state, elfedit_section_t *auxsec) 59 { 60 elfedit_symtab_t *symtab = obj_state->os_symtab; 61 Word sh_link = auxsec->sec_shdr->sh_link; 62 Word i; 63 64 for (i = 0; i < obj_state->os_symtabnum; i++, symtab++) 65 if (symtab->symt_shndx == sh_link) 66 return (symtab); 67 68 /* 69 * If we don't return above, it doesn't reference a valid 70 * symbol table. Issue warning. 71 */ 72 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_AUX_LINK), 73 EC_WORD(auxsec->sec_shndx), auxsec->sec_name, 74 EC_WORD(sh_link)); 75 76 return (NULL); 77 } 78 79 80 /* 81 * Fill in state.elf.obj_state with a a dynamically allocated 82 * elfedit_obj_state_t struct of the appropriate ELFCLASS. 83 * This pre-chewed form is fed to each command, reducing the amount 84 * of ELF boilerplate code each command needs to contain. 85 * 86 * entry: 87 * file - Name of file to process 88 * fd - Descriptor of open file which has been successfully 89 * processed by elf_begin(). 90 * elf - Elf handle returned by elf_begin 91 * 92 * exit: 93 * An elfedit_obj_state_t struct of the appropriate ELFCLASS has 94 * been dynamically allocated, and state.elf.obj_state references it. 95 * On failure, this routine does not return to the caller. 96 * 97 * note: The resulting elfedit_obj_state_t is allocated from a single 98 * piece of memory, such that a single call to free() suffices 99 * to release it as well as any memory it references. 100 */ 101 #ifdef _ELF64 102 void 103 elfedit64_init_obj_state(const char *file, int fd, Elf *elf) 104 #else 105 void 106 elfedit32_init_obj_state(const char *file, int fd, Elf *elf) 107 #endif 108 { 109 #define INITIAL_SYMTABNDX_ALLOC 5 110 111 /* 112 * These macros are used to call functions from libelf. 113 * 114 * LIBELF_FAIL encapsulates the common way in which we handle 115 * all of these errors: libelf_fail_name is set and execution 116 * jumps to the libelf_failure label for handling. 117 * 118 * LIBELF is used for the common case in which the function returns 119 * NULL for failure and something else for success. 120 */ 121 #define LIBELF_FAIL(_name) { libelf_fail_name = _name; goto libelf_failure; } 122 #define LIBELF(_libelf_expr, _name) \ 123 if ((_libelf_expr) == NULL) \ 124 LIBELF_FAIL(_name) 125 126 const char *libelf_fail_name; /* Used for LIBELF errors */ 127 128 Elf_Scn *scn; 129 Elf_Data *data; 130 uint_t ndx; 131 size_t len, os_size, secarr_size; 132 char *names = 0; 133 size_t names_len; 134 elfedit_section_t *_cache; 135 elfedit_obj_state_t tstate; 136 elfedit_obj_state_t *obj_state = NULL; 137 Word *symtabndx = NULL; 138 Word symtabndx_size = 0; 139 elfedit_symtab_t *symtab; 140 141 tstate.os_file = file; 142 tstate.os_fd = fd; 143 tstate.os_elf = elf; 144 tstate.os_dynndx = SHN_UNDEF; 145 tstate.os_symtabnum = 0; 146 147 LIBELF(tstate.os_ehdr = elf_getehdr(tstate.os_elf), 148 MSG_ORIG(MSG_ELF_GETEHDR)) 149 150 /* Program header array count and address */ 151 if (elf_getphdrnum(tstate.os_elf, &tstate.os_phnum) == -1) 152 LIBELF_FAIL(MSG_ORIG(MSG_ELF_GETPHDRNUM)) 153 if (tstate.os_phnum > 0) { 154 LIBELF((tstate.os_phdr = elf_getphdr(tstate.os_elf)), 155 MSG_ORIG(MSG_ELF_GETPHDR)) 156 } else { 157 tstate.os_phdr = NULL; 158 } 159 160 if (elf_getshdrnum(tstate.os_elf, &tstate.os_shnum) == -1) 161 LIBELF_FAIL(MSG_ORIG(MSG_ELF_GETSHDRNUM)) 162 163 /* 164 * Obtain the .shstrtab data buffer to provide the required section 165 * name strings. 166 */ 167 if (elf_getshdrstrndx(tstate.os_elf, &tstate.os_shstrndx) == -1) 168 LIBELF_FAIL(MSG_ORIG(MSG_ELF_GETSHDRSTRNDX)) 169 LIBELF((scn = elf_getscn(tstate.os_elf, tstate.os_shstrndx)), 170 MSG_ORIG(MSG_ELF_GETSCN)) 171 LIBELF((data = elf_getdata(scn, NULL)), MSG_ORIG(MSG_ELF_GETDATA)) 172 names = data->d_buf; 173 names_len = (names == NULL) ? 0 : data->d_size; 174 175 /* 176 * Count the number of symbol tables and capture their indexes. 177 * Find the dynamic section. 178 */ 179 for (ndx = 1, scn = NULL; 180 (scn = elf_nextscn(tstate.os_elf, scn)) != NULL; ndx++) { 181 Shdr *shdr; 182 183 LIBELF(shdr = elf_getshdr(scn), MSG_ORIG(MSG_ELF_GETSHDR)); 184 185 switch (shdr->sh_type) { 186 case SHT_DYNAMIC: 187 /* Save index of dynamic section for use below */ 188 tstate.os_dynndx = ndx; 189 break; 190 191 case SHT_SYMTAB: 192 case SHT_DYNSYM: 193 case SHT_SUNW_LDYNSYM: 194 if (symtabndx_size <= tstate.os_symtabnum) { 195 symtabndx_size = (symtabndx_size == 0) ? 196 INITIAL_SYMTABNDX_ALLOC : 197 (symtabndx_size * 2); 198 symtabndx = elfedit_realloc( 199 MSG_INTL(MSG_ALLOC_SYMTABOS), symtabndx, 200 symtabndx_size * sizeof (symtabndx[0])); 201 } 202 symtabndx[tstate.os_symtabnum++] = ndx; 203 break; 204 } 205 } 206 207 /* 208 * Allocate space to hold the state. We allocate space for everything 209 * in one chunk to make releasing it easy: 210 * (1) elfedit_obj_state_t struct 211 * (2) The array of elfedit_section_t items referenced from 212 * the elfedit_obj_state_t struct. 213 * (3) The array of elfedit_symtab_t items referenced from 214 * the elfedit_obj_state_t struct. 215 * (4) The file name. 216 * 217 * Note that we round up the size of (1) and (2) to a double boundary 218 * to ensure proper alignment of (2) and (3). (4) can align on any 219 * boundary. 220 */ 221 os_size = S_DROUND(sizeof (tstate)); 222 secarr_size = (tstate.os_shnum * sizeof (elfedit_section_t)); 223 secarr_size = S_DROUND(secarr_size); 224 len = strlen(tstate.os_file) + 1; 225 obj_state = elfedit_malloc(MSG_INTL(MSG_ALLOC_OBJSTATE), 226 os_size + secarr_size + 227 (tstate.os_symtabnum * sizeof (elfedit_symtab_t)) + len); 228 *obj_state = tstate; 229 230 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 231 obj_state->os_secarr = (elfedit_section_t *) 232 ((char *)obj_state + os_size); 233 if (obj_state->os_symtabnum == 0) { 234 obj_state->os_symtab = NULL; 235 } else { 236 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 237 obj_state->os_symtab = (elfedit_symtab_t *) 238 ((char *)obj_state->os_secarr + secarr_size); 239 obj_state->os_file = 240 (char *)(obj_state->os_symtab + tstate.os_symtabnum); 241 (void) strncpy((char *)obj_state->os_file, tstate.os_file, len); 242 } 243 244 /* 245 * Fill in obj_state->os_secarr with information for each section. 246 * At the same time, fill in obj_state->os_symtab with the symbol 247 * table related data. 248 */ 249 bzero(obj_state->os_secarr, sizeof (obj_state->os_secarr[0])); 250 _cache = obj_state->os_secarr; 251 LIBELF(scn = elf_getscn(tstate.os_elf, 0), 252 MSG_ORIG(MSG_ELF_GETSCN)); 253 _cache->sec_scn = scn; 254 LIBELF(_cache->sec_shdr = elf_getshdr(scn), MSG_ORIG(MSG_ELF_GETSHDR)); 255 _cache->sec_name = (_cache->sec_shdr->sh_name < names_len) ? 256 (names + _cache->sec_shdr->sh_name) : MSG_INTL(MSG_UNKNOWNSECNAM); 257 _cache++; 258 259 if (obj_state->os_symtab != NULL) { 260 bzero(obj_state->os_symtab, 261 sizeof (obj_state->os_symtab[0]) * obj_state->os_symtabnum); 262 for (ndx = 0; ndx < obj_state->os_symtabnum; ndx++) 263 obj_state->os_symtab[ndx].symt_shndx = symtabndx[ndx]; 264 free(symtabndx); 265 } 266 267 for (ndx = 1, scn = NULL; 268 (scn = elf_nextscn(tstate.os_elf, scn)) != NULL; ndx++, _cache++) { 269 _cache->sec_shndx = ndx; 270 _cache->sec_scn = scn; 271 LIBELF(_cache->sec_shdr = elf_getshdr(scn), 272 MSG_ORIG(MSG_ELF_GETSHDR)) 273 _cache->sec_data = elf_getdata(scn, NULL); 274 _cache->sec_name = (_cache->sec_shdr->sh_name < names_len) ? 275 (names + _cache->sec_shdr->sh_name) : 276 MSG_INTL(MSG_UNKNOWNSECNAM); 277 278 switch (_cache->sec_shdr->sh_type) { 279 case SHT_SYMTAB_SHNDX: 280 symtab = get_symtab(obj_state, _cache); 281 symtab->symt_xshndx = ndx; 282 break; 283 284 case SHT_SUNW_syminfo: 285 symtab = get_symtab(obj_state, _cache); 286 symtab->symt_syminfo = ndx; 287 break; 288 289 case SHT_SUNW_versym: 290 symtab = get_symtab(obj_state, _cache); 291 symtab->symt_versym = ndx; 292 break; 293 } 294 } 295 296 /* 297 * Sanity check the symbol tables, and discard any auxiliary 298 * sections without enough elements. 299 */ 300 symtab = obj_state->os_symtab; 301 for (ndx = 0; ndx < obj_state->os_symtabnum; ndx++, symtab++) { 302 elfedit_section_t *symsec; 303 Word symsec_cnt, aux_cnt; 304 305 symsec = &obj_state->os_secarr[symtab->symt_shndx]; 306 symsec_cnt = symsec->sec_shdr->sh_size / sizeof (Sym); 307 308 /* Extended section indexes */ 309 if (symtab->symt_xshndx != SHN_UNDEF) { 310 _cache = &obj_state->os_secarr[symtab->symt_xshndx]; 311 aux_cnt = _cache->sec_shdr->sh_size / sizeof (Word); 312 if (symsec_cnt > aux_cnt) 313 elfedit_msg(ELFEDIT_MSG_DEBUG, 314 MSG_INTL(MSG_DEBUG_AUX_SIZE), 315 EC_WORD(ndx), _cache->sec_name, 316 EC_WORD(aux_cnt), 317 EC_WORD(symsec->sec_shndx), 318 symsec->sec_name, EC_WORD(aux_cnt)); 319 } 320 321 /* Syminfo */ 322 if (symtab->symt_syminfo != SHN_UNDEF) { 323 _cache = &obj_state->os_secarr[symtab->symt_syminfo]; 324 aux_cnt = _cache->sec_shdr->sh_size / sizeof (Syminfo); 325 if (symsec_cnt > aux_cnt) 326 elfedit_msg(ELFEDIT_MSG_DEBUG, 327 MSG_INTL(MSG_DEBUG_AUX_SIZE), 328 EC_WORD(ndx), _cache->sec_name, 329 EC_WORD(aux_cnt), 330 EC_WORD(symsec->sec_shndx), 331 symsec->sec_name, EC_WORD(aux_cnt)); 332 } 333 334 /* Versym */ 335 if (symtab->symt_versym != SHN_UNDEF) { 336 _cache = &obj_state->os_secarr[symtab->symt_versym]; 337 aux_cnt = _cache->sec_shdr->sh_size / sizeof (Versym); 338 if (symsec_cnt > aux_cnt) 339 elfedit_msg(ELFEDIT_MSG_DEBUG, 340 MSG_INTL(MSG_DEBUG_AUX_SIZE), 341 EC_WORD(ndx), _cache->sec_name, 342 EC_WORD(aux_cnt), 343 EC_WORD(symsec->sec_shndx), 344 symsec->sec_name, EC_WORD(aux_cnt)); 345 } 346 } 347 348 /* 349 * If this object has a dynsym section with a FLAGS_1 field, 350 * then set the DF_1_EDITED bit. elfedit allows changes that 351 * can break the resulting program, so knowing that a file was 352 * edited can be helpful when encountering a core file or other 353 * unexpected failure in the field. A single bit can't tell you 354 * what was changed, but it will alert you to the possibility that 355 * some additional questions might be in order. 356 */ 357 if (obj_state->os_dynndx != SHN_UNDEF) { 358 Word i; 359 Word numdyn; 360 elfedit_section_t *dynsec; 361 elfedit_dyn_elt_t flags_1_elt; 362 elfedit_dyn_elt_t null_elt; 363 Dyn *dyn; 364 365 dynsec = &obj_state->os_secarr[obj_state->os_dynndx]; 366 dyn = (Dyn *) dynsec->sec_data->d_buf; 367 numdyn = dynsec->sec_shdr->sh_size / 368 dynsec->sec_shdr->sh_entsize; 369 elfedit_dyn_elt_init(&flags_1_elt); 370 elfedit_dyn_elt_init(&null_elt); 371 for (i = 0; i < numdyn; i++) { 372 373 switch (dyn[i].d_tag) { 374 case DT_NULL: 375 /* 376 * Remember state of the first DT_NULL. If there 377 * are more than one (i.e. the first one is not 378 * in the final spot), and there is no flags1, 379 * then we will turn the first one into a 380 * DT_FLAGS_1. 381 */ 382 if (!null_elt.dn_seen) 383 elfedit_dyn_elt_save(&null_elt, i, 384 &dyn[i]); 385 break; 386 387 case DT_FLAGS_1: 388 elfedit_dyn_elt_save(&flags_1_elt, i, &dyn[i]); 389 break; 390 } 391 } 392 /* If don't have a flags1 field, can we make one from a NULL? */ 393 if (!flags_1_elt.dn_seen && null_elt.dn_seen && 394 (null_elt.dn_ndx < (numdyn - 1))) { 395 elfedit_msg(ELFEDIT_MSG_DEBUG, 396 MSG_INTL(MSG_DEBUG_NULL2DYNFL1), 397 EC_WORD(obj_state->os_dynndx), 398 dynsec->sec_name, EC_WORD(null_elt.dn_ndx)); 399 flags_1_elt.dn_seen = 1; 400 flags_1_elt.dn_ndx = null_elt.dn_ndx; 401 flags_1_elt.dn_dyn.d_tag = DT_FLAGS_1; 402 flags_1_elt.dn_dyn.d_un.d_val = 0; 403 } 404 /* 405 * If there is a flags 1 field, add the edit flag if 406 * it is not present, and report it's presence otherwise. 407 */ 408 if (flags_1_elt.dn_seen) { 409 if (flags_1_elt.dn_dyn.d_un.d_val & DF_1_EDITED) { 410 elfedit_msg(ELFEDIT_MSG_DEBUG, 411 MSG_INTL(MSG_DEBUG_SEEDYNFLG), 412 EC_WORD(obj_state->os_dynndx), 413 dynsec->sec_name, 414 EC_WORD(flags_1_elt.dn_ndx)); 415 } else { 416 elfedit_msg(ELFEDIT_MSG_DEBUG, 417 MSG_INTL(MSG_DEBUG_ADDDYNFLG), 418 EC_WORD(obj_state->os_dynndx), 419 dynsec->sec_name, 420 EC_WORD(flags_1_elt.dn_ndx)); 421 flags_1_elt.dn_dyn.d_un.d_val |= DF_1_EDITED; 422 dyn[flags_1_elt.dn_ndx] = flags_1_elt.dn_dyn; 423 elfedit_modified_data(dynsec); 424 } 425 } 426 } 427 428 #ifdef _ELF64 429 state.elf.obj_state.s64 = obj_state; 430 #else 431 state.elf.obj_state.s32 = obj_state; 432 #endif 433 return; 434 435 libelf_failure: 436 /* 437 * Control comes here if there is an error with LIBELF. 438 * 439 * entry: 440 * libelf_fail_name - Name of failing libelf function 441 * tstate.os_file - Name of ELF file being processed 442 * tstate.os_fd - Descriptor of open ELF file 443 * 444 * exit: 445 * - dynamic memory is released if necessary 446 * - The error issued 447 */ 448 if (obj_state != NULL) 449 free(obj_state); 450 (void) close(tstate.os_fd); 451 elfedit_elferr(tstate.os_file, libelf_fail_name); 452 #undef INITIAL_SYMTABNDX_ALLOC 453 #undef LIBELF_FAIL 454 #undef LIBELF 455 } 456