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 *
get_symtab(elfedit_obj_state_t * obj_state,elfedit_section_t * auxsec)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
elfedit64_init_obj_state(const char * file,int fd,Elf * elf)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