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