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.
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.
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]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
29 * ELFCLASS specific code for elfedit, built once for each class
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.
48 * obj_state - Partially constructed object state from
49 * elfedit_init_obj_state().
50 * auxsec - Section that is associated with the symbol table section
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.
57 static elfedit_symtab_t
*
58 get_symtab(elfedit_obj_state_t
*obj_state
, elfedit_section_t
*auxsec
)
60 elfedit_symtab_t
*symtab
= obj_state
->os_symtab
;
61 Word sh_link
= auxsec
->sec_shdr
->sh_link
;
64 for (i
= 0; i
< obj_state
->os_symtabnum
; i
++, symtab
++)
65 if (symtab
->symt_shndx
== sh_link
)
69 * If we don't return above, it doesn't reference a valid
70 * symbol table. Issue warning.
72 elfedit_msg(ELFEDIT_MSG_DEBUG
, MSG_INTL(MSG_DEBUG_AUX_LINK
),
73 EC_WORD(auxsec
->sec_shndx
), auxsec
->sec_name
,
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.
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
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.
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.
103 elfedit64_init_obj_state(const char *file
, int fd
, Elf
*elf
)
106 elfedit32_init_obj_state(const char *file
, int fd
, Elf
*elf
)
109 #define INITIAL_SYMTABNDX_ALLOC 5
112 * These macros are used to call functions from libelf.
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.
118 * LIBELF is used for the common case in which the function returns
119 * NULL for failure and something else for success.
121 #define LIBELF_FAIL(_name) { libelf_fail_name = _name; goto libelf_failure; }
122 #define LIBELF(_libelf_expr, _name) \
123 if ((_libelf_expr) == NULL) \
126 const char *libelf_fail_name
; /* Used for LIBELF errors */
131 size_t len
, os_size
, secarr_size
;
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
;
141 tstate
.os_file
= file
;
144 tstate
.os_dynndx
= SHN_UNDEF
;
145 tstate
.os_symtabnum
= 0;
147 LIBELF(tstate
.os_ehdr
= elf_getehdr(tstate
.os_elf
),
148 MSG_ORIG(MSG_ELF_GETEHDR
))
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
))
157 tstate
.os_phdr
= NULL
;
160 if (elf_getshdrnum(tstate
.os_elf
, &tstate
.os_shnum
) == -1)
161 LIBELF_FAIL(MSG_ORIG(MSG_ELF_GETSHDRNUM
))
164 * Obtain the .shstrtab data buffer to provide the required section
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
))
173 names_len
= (names
== NULL
) ? 0 : data
->d_size
;
176 * Count the number of symbol tables and capture their indexes.
177 * Find the dynamic section.
179 for (ndx
= 1, scn
= NULL
; scn
= elf_nextscn(tstate
.os_elf
, scn
);
183 LIBELF(shdr
= elf_getshdr(scn
), MSG_ORIG(MSG_ELF_GETSHDR
));
185 switch (shdr
->sh_type
) {
187 /* Save index of dynamic section for use below */
188 tstate
.os_dynndx
= ndx
;
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]));
202 symtabndx
[tstate
.os_symtabnum
++] = ndx
;
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.
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
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
);
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
;
236 /*LINTED E_BAD_PTR_CAST_ALIGN*/
237 obj_state
->os_symtab
= (elfedit_symtab_t
*)
238 ((char *)obj_state
->os_secarr
+ secarr_size
);
240 (char *)(obj_state
->os_symtab
+ tstate
.os_symtabnum
);
241 (void) strncpy((char *)obj_state
->os_file
, tstate
.os_file
, len
);
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.
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
);
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
];
267 for (ndx
= 1, scn
= NULL
; scn
= elf_nextscn(tstate
.os_elf
, scn
);
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
);
278 switch (_cache
->sec_shdr
->sh_type
) {
279 case SHT_SYMTAB_SHNDX
:
280 symtab
= get_symtab(obj_state
, _cache
);
281 symtab
->symt_xshndx
= ndx
;
284 case SHT_SUNW_syminfo
:
285 symtab
= get_symtab(obj_state
, _cache
);
286 symtab
->symt_syminfo
= ndx
;
289 case SHT_SUNW_versym
:
290 symtab
= get_symtab(obj_state
, _cache
);
291 symtab
->symt_versym
= ndx
;
297 * Sanity check the symbol tables, and discard any auxiliary
298 * sections without enough elements.
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
;
305 symsec
= &obj_state
->os_secarr
[symtab
->symt_shndx
];
306 symsec_cnt
= symsec
->sec_shdr
->sh_size
/ sizeof (Sym
);
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
,
317 EC_WORD(symsec
->sec_shndx
),
318 symsec
->sec_name
, EC_WORD(aux_cnt
));
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
,
330 EC_WORD(symsec
->sec_shndx
),
331 symsec
->sec_name
, EC_WORD(aux_cnt
));
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
,
343 EC_WORD(symsec
->sec_shndx
),
344 symsec
->sec_name
, EC_WORD(aux_cnt
));
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.
357 if (obj_state
->os_dynndx
!= SHN_UNDEF
) {
360 elfedit_section_t
*dynsec
;
361 elfedit_dyn_elt_t flags_1_elt
;
362 elfedit_dyn_elt_t null_elt
;
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
++) {
373 switch (dyn
[i
].d_tag
) {
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
382 if (!null_elt
.dn_seen
)
383 elfedit_dyn_elt_save(&null_elt
, i
,
388 elfedit_dyn_elt_save(&flags_1_elt
, i
, &dyn
[i
]);
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;
405 * If there is a flags 1 field, add the edit flag if
406 * it is not present, and report it's presence otherwise.
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
),
414 EC_WORD(flags_1_elt
.dn_ndx
));
416 elfedit_msg(ELFEDIT_MSG_DEBUG
,
417 MSG_INTL(MSG_DEBUG_ADDDYNFLG
),
418 EC_WORD(obj_state
->os_dynndx
),
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
);
429 state
.elf
.obj_state
.s64
= obj_state
;
431 state
.elf
.obj_state
.s32
= obj_state
;
437 * Control comes here if there is an error with LIBELF.
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
445 * - dynamic memory is released if necessary
449 (void) close(tstate
.os_fd
);
450 elfedit_elferr(tstate
.os_file
, libelf_fail_name
);
451 #undef INITIAL_SYMTABNDX_ALLOC