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