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 2008 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 * 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 * This macro is used to call functions from libelf, all of which 113 * return NULL for failure and something else for success. On error, 114 * libelf_fail_name is set and execution jumps to the libelf_failure 115 * label for handling. Otherwise, the results of the call are ready 116 * for use by the caller. 117 */ 118 #define LIBELF(_libelf_expr, _name) \ 119 if ((_libelf_expr) == NULL) { \ 120 libelf_fail_name = _name; \ 121 goto libelf_failure; \ 122 } 123 124 const char *libelf_fail_name; /* Used for LIBELF errors */ 125 126 Elf_Scn *scn; 127 Elf_Data *data; 128 uint_t ndx; 129 size_t len, os_size, secarr_size; 130 char *names = 0; 131 size_t names_len; 132 elfedit_section_t *_cache; 133 elfedit_obj_state_t tstate; 134 elfedit_obj_state_t *obj_state = NULL; 135 Word *symtabndx = NULL; 136 Word symtabndx_size = 0; 137 elfedit_symtab_t *symtab; 138 139 tstate.os_file = file; 140 tstate.os_fd = fd; 141 tstate.os_elf = elf; 142 tstate.os_dynndx = SHN_UNDEF; 143 tstate.os_symtabnum = 0; 144 145 LIBELF(tstate.os_ehdr = elf_getehdr(tstate.os_elf), 146 MSG_ORIG(MSG_ELF_GETEHDR)) 147 148 /* Program header array count and address */ 149 LIBELF(elf_getphnum(tstate.os_elf, &tstate.os_phnum), 150 MSG_ORIG(MSG_ELF_GETPHNUM)) 151 if (tstate.os_phnum > 0) { 152 LIBELF((tstate.os_phdr = elf_getphdr(tstate.os_elf)), 153 MSG_ORIG(MSG_ELF_GETPHDR)) 154 } else { 155 tstate.os_phdr = NULL; 156 } 157 158 159 LIBELF(elf_getshnum(tstate.os_elf, &tstate.os_shnum), 160 MSG_ORIG(MSG_ELF_GETSHNUM)) 161 162 163 /* 164 * Obtain the .shstrtab data buffer to provide the required section 165 * name strings. 166 */ 167 LIBELF(elf_getshstrndx(tstate.os_elf, &tstate.os_shstrndx), 168 MSG_ORIG(MSG_ELF_GETSHSTRNDX)) 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; scn = elf_nextscn(tstate.os_elf, scn); 180 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 * Fill in obj_state->os_secarr with information for each section. 245 * At the same time, fill in obj_state->os_symtab with the symbol 246 * table related data. 247 */ 248 bzero(obj_state->os_secarr, sizeof (obj_state->os_secarr[0])); 249 _cache = obj_state->os_secarr; 250 LIBELF(scn = elf_getscn(tstate.os_elf, 0), 251 MSG_ORIG(MSG_ELF_GETSCN)); 252 _cache->sec_scn = scn; 253 LIBELF(_cache->sec_shdr = elf_getshdr(scn), MSG_ORIG(MSG_ELF_GETSHDR)); 254 _cache->sec_name = (_cache->sec_shdr->sh_name < names_len) ? 255 (names + _cache->sec_shdr->sh_name) : MSG_INTL(MSG_UNKNOWNSECNAM); 256 _cache++; 257 258 if (obj_state->os_symtab != NULL) { 259 bzero(obj_state->os_symtab, 260 sizeof (obj_state->os_symtab[0]) * obj_state->os_symtabnum); 261 for (ndx = 0; ndx < obj_state->os_symtabnum; ndx++) 262 obj_state->os_symtab[ndx].symt_shndx = symtabndx[ndx]; 263 free(symtabndx); 264 } 265 266 for (ndx = 1, scn = NULL; scn = elf_nextscn(tstate.os_elf, scn); 267 ndx++, _cache++) { 268 _cache->sec_shndx = ndx; 269 _cache->sec_scn = scn; 270 LIBELF(_cache->sec_shdr = elf_getshdr(scn), 271 MSG_ORIG(MSG_ELF_GETSHDR)) 272 _cache->sec_data = elf_getdata(scn, NULL); 273 _cache->sec_name = (_cache->sec_shdr->sh_name < names_len) ? 274 (names + _cache->sec_shdr->sh_name) : 275 MSG_INTL(MSG_UNKNOWNSECNAM); 276 277 switch (_cache->sec_shdr->sh_type) { 278 case SHT_SYMTAB_SHNDX: 279 symtab = get_symtab(obj_state, _cache); 280 symtab->symt_xshndx = ndx; 281 break; 282 283 case SHT_SUNW_syminfo: 284 symtab = get_symtab(obj_state, _cache); 285 symtab->symt_syminfo = ndx; 286 break; 287 288 case SHT_SUNW_versym: 289 symtab = get_symtab(obj_state, _cache); 290 symtab->symt_versym = ndx; 291 break; 292 } 293 } 294 295 /* 296 * Sanity check the symbol tables, and discard any auxiliary 297 * sections without enough elements. 298 */ 299 symtab = obj_state->os_symtab; 300 for (ndx = 0; ndx < obj_state->os_symtabnum; ndx++, symtab++) { 301 elfedit_section_t *symsec; 302 Word symsec_cnt, aux_cnt; 303 304 symsec = &obj_state->os_secarr[symtab->symt_shndx]; 305 symsec_cnt = symsec->sec_shdr->sh_size / sizeof (Sym); 306 307 /* Extended section indexes */ 308 if (symtab->symt_xshndx != SHN_UNDEF) { 309 _cache = &obj_state->os_secarr[symtab->symt_xshndx]; 310 aux_cnt = _cache->sec_shdr->sh_size / sizeof (Word); 311 if (symsec_cnt > aux_cnt) 312 elfedit_msg(ELFEDIT_MSG_DEBUG, 313 MSG_INTL(MSG_DEBUG_AUX_SIZE), 314 EC_WORD(ndx), _cache->sec_name, 315 EC_WORD(aux_cnt), 316 EC_WORD(symsec->sec_shndx), 317 symsec->sec_name, EC_WORD(aux_cnt)); 318 } 319 320 /* Syminfo */ 321 if (symtab->symt_syminfo != SHN_UNDEF) { 322 _cache = &obj_state->os_secarr[symtab->symt_syminfo]; 323 aux_cnt = _cache->sec_shdr->sh_size / sizeof (Syminfo); 324 if (symsec_cnt > aux_cnt) 325 elfedit_msg(ELFEDIT_MSG_DEBUG, 326 MSG_INTL(MSG_DEBUG_AUX_SIZE), 327 EC_WORD(ndx), _cache->sec_name, 328 EC_WORD(aux_cnt), 329 EC_WORD(symsec->sec_shndx), 330 symsec->sec_name, EC_WORD(aux_cnt)); 331 } 332 333 /* Versym */ 334 if (symtab->symt_versym != SHN_UNDEF) { 335 _cache = &obj_state->os_secarr[symtab->symt_versym]; 336 aux_cnt = _cache->sec_shdr->sh_size / sizeof (Versym); 337 if (symsec_cnt > aux_cnt) 338 elfedit_msg(ELFEDIT_MSG_DEBUG, 339 MSG_INTL(MSG_DEBUG_AUX_SIZE), 340 EC_WORD(ndx), _cache->sec_name, 341 EC_WORD(aux_cnt), 342 EC_WORD(symsec->sec_shndx), 343 symsec->sec_name, EC_WORD(aux_cnt)); 344 } 345 } 346 347 /* 348 * If this object has a dynsym section with a FLAGS_1 field, 349 * then set the DF_1_EDITED bit. elfedit allows changes that 350 * can break the resulting program, so knowing that a file was 351 * edited can be helpful when encountering a core file or other 352 * unexpected failure in the field. A single bit can't tell you 353 * what was changed, but it will alert you to the possibility that 354 * some additional questions might be in order. 355 */ 356 if (obj_state->os_dynndx != SHN_UNDEF) { 357 Word i; 358 Word numdyn; 359 elfedit_section_t *dynsec; 360 elfedit_dyn_elt_t flags_1_elt; 361 elfedit_dyn_elt_t null_elt; 362 Dyn *dyn; 363 364 dynsec = &obj_state->os_secarr[obj_state->os_dynndx]; 365 dyn = (Dyn *) dynsec->sec_data->d_buf; 366 numdyn = dynsec->sec_shdr->sh_size / 367 dynsec->sec_shdr->sh_entsize; 368 elfedit_dyn_elt_init(&flags_1_elt); 369 elfedit_dyn_elt_init(&null_elt); 370 for (i = 0; i < numdyn; i++) { 371 372 switch (dyn[i].d_tag) { 373 case DT_NULL: 374 /* 375 * Remember state of the first DT_NULL. If there 376 * are more than one (i.e. the first one is not 377 * in the final spot), and there is no flags1, 378 * then we will turn the first one into a 379 * DT_FLAGS_1. 380 */ 381 if (!null_elt.dn_seen) 382 elfedit_dyn_elt_save(&null_elt, i, 383 &dyn[i]); 384 break; 385 386 case DT_FLAGS_1: 387 elfedit_dyn_elt_save(&flags_1_elt, i, &dyn[i]); 388 break; 389 } 390 } 391 /* If don't have a flags1 field, can we make one from a NULL? */ 392 if (!flags_1_elt.dn_seen && null_elt.dn_seen && 393 (null_elt.dn_ndx < (numdyn - 1))) { 394 elfedit_msg(ELFEDIT_MSG_DEBUG, 395 MSG_INTL(MSG_DEBUG_NULL2DYNFL1), 396 EC_WORD(obj_state->os_dynndx), 397 dynsec->sec_name, EC_WORD(null_elt.dn_ndx)); 398 flags_1_elt.dn_seen = 1; 399 flags_1_elt.dn_ndx = null_elt.dn_ndx; 400 flags_1_elt.dn_dyn.d_tag = DT_FLAGS_1; 401 flags_1_elt.dn_dyn.d_un.d_val = 0; 402 } 403 /* 404 * If there is a flags 1 field, add the edit flag if 405 * it is not present, and report it's presence otherwise. 406 */ 407 if (flags_1_elt.dn_seen) { 408 if (flags_1_elt.dn_dyn.d_un.d_val & DF_1_EDITED) { 409 elfedit_msg(ELFEDIT_MSG_DEBUG, 410 MSG_INTL(MSG_DEBUG_SEEDYNFLG), 411 EC_WORD(obj_state->os_dynndx), 412 dynsec->sec_name, 413 EC_WORD(flags_1_elt.dn_ndx)); 414 } else { 415 elfedit_msg(ELFEDIT_MSG_DEBUG, 416 MSG_INTL(MSG_DEBUG_ADDDYNFLG), 417 EC_WORD(obj_state->os_dynndx), 418 dynsec->sec_name, 419 EC_WORD(flags_1_elt.dn_ndx)); 420 flags_1_elt.dn_dyn.d_un.d_val |= DF_1_EDITED; 421 dyn[flags_1_elt.dn_ndx] = flags_1_elt.dn_dyn; 422 elfedit_modified_data(dynsec); 423 } 424 } 425 } 426 427 #ifdef _ELF64 428 state.elf.obj_state.s64 = obj_state; 429 #else 430 state.elf.obj_state.s32 = obj_state; 431 #endif 432 return; 433 434 libelf_failure: 435 /* 436 * Control comes here if there is an error with LIBELF. 437 * 438 * entry: 439 * libelf_fail_name - Name of failing libelf function 440 * tstate.os_file - Name of ELF file being processed 441 * tstate.os_fd - Descriptor of open ELF file 442 * 443 * exit: 444 * - dynamic memory is released if necessary 445 * - The error issued 446 */ 447 if (obj_state != NULL) 448 free(obj_state); 449 (void) close(tstate.os_fd); 450 elfedit_elferr(tstate.os_file, libelf_fail_name); 451 #undef LIBELF_FAILURE 452 #undef INITIAL_SYMTABNDX_ALLOC 453 } 454