pahole: Describe expected use of 'default' in the man page
[dwarves.git] / elfcreator.c
blob8e775c553ea7266102839e753be75099a3f9adcc
1 /*
2 * SPDX-License-Identifier: GPL-2.0-only
4 * Copyright 2009 Red Hat, Inc.
6 * Author: Peter Jones <pjones@redhat.com>
7 */
8 #include <dlfcn.h>
9 #include <gelf.h>
10 #include <stdio.h>
11 #include <strings.h>
12 #include <string.h>
13 #include <fcntl.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <assert.h>
18 #include "elfcreator.h"
20 struct elf_creator {
21 const char *path;
22 int fd;
24 Elf *elf;
25 GElf_Ehdr *ehdr, ehdr_mem;
27 Elf *oldelf;
28 /* just because we have to look this up /so/ often... */
29 Elf_Scn *dynscn;
30 GElf_Shdr *dynshdr, dynshdr_mem;
31 Elf_Data *dyndata;
34 static void clear(ElfCreator *ctor, int do_unlink)
36 if (do_unlink) {
37 if (ctor->elf)
38 elf_end(ctor->elf);
39 if (ctor->fd >= 0)
40 close(ctor->fd);
41 if (ctor->path)
42 unlink(ctor->path);
43 } else {
44 if (ctor->elf) {
45 elf_update(ctor->elf, ELF_C_WRITE_MMAP);
46 elf_end(ctor->elf);
48 if (ctor->fd >= 0)
49 close(ctor->fd);
51 memset(ctor, '\0', sizeof(*ctor));
54 ElfCreator *elfcreator_begin(char *path, Elf *elf) {
55 ElfCreator *ctor = NULL;
56 GElf_Ehdr ehdr_mem, *ehdr;
58 if (!(ctor = calloc(1, sizeof(*ctor))))
59 return NULL;
61 clear(ctor, 0);
63 ctor->path = path;
64 ctor->oldelf = elf;
66 ehdr = gelf_getehdr(elf, &ehdr_mem);
68 if ((ctor->fd = open(path, O_RDWR|O_CREAT|O_TRUNC, 0755)) < 0) {
69 err:
70 clear(ctor, 1);
71 free(ctor);
72 return NULL;
75 if (!(ctor->elf = elf_begin(ctor->fd, ELF_C_WRITE_MMAP, elf)))
76 goto err;
78 gelf_newehdr(ctor->elf, gelf_getclass(elf));
79 gelf_update_ehdr(ctor->elf, ehdr);
81 if (!(ctor->ehdr = gelf_getehdr(ctor->elf, &ctor->ehdr_mem)))
82 goto err;
84 return ctor;
87 static Elf_Scn *get_scn_by_type(ElfCreator *ctor, Elf64_Word sh_type)
89 Elf_Scn *scn = NULL;
91 while ((scn = elf_nextscn(ctor->elf, scn)) != NULL) {
92 GElf_Shdr *shdr, shdr_mem;
94 shdr = gelf_getshdr(scn, &shdr_mem);
95 if (shdr->sh_type == sh_type)
96 return scn;
98 return NULL;
101 static void update_dyn_cache(ElfCreator *ctor)
103 ctor->dynscn = get_scn_by_type(ctor, SHT_DYNAMIC);
104 if (ctor->dynscn == NULL)
105 return;
107 ctor->dynshdr = gelf_getshdr(ctor->dynscn, &ctor->dynshdr_mem);
108 ctor->dyndata = elf_getdata(ctor->dynscn, NULL);
111 void elfcreator_copy_scn(ElfCreator *ctor, Elf_Scn *scn)
113 Elf_Scn *newscn;
114 Elf_Data *indata, *outdata;
115 GElf_Shdr *oldshdr, oldshdr_mem;
116 GElf_Shdr *newshdr, newshdr_mem;
118 newscn = elf_newscn(ctor->elf);
119 newshdr = gelf_getshdr(newscn, &newshdr_mem);
121 oldshdr = gelf_getshdr(scn, &oldshdr_mem);
123 memmove(newshdr, oldshdr, sizeof(*newshdr));
124 gelf_update_shdr(newscn, newshdr);
126 indata = NULL;
127 while ((indata = elf_getdata(scn, indata)) != NULL) {
128 outdata = elf_newdata(newscn);
129 *outdata = *indata;
131 if (newshdr->sh_type == SHT_DYNAMIC)
132 update_dyn_cache(ctor);
135 static GElf_Dyn *get_dyn_by_tag(ElfCreator *ctor, Elf64_Sxword d_tag,
136 GElf_Dyn *mem, size_t *idx)
138 size_t cnt;
140 if (!ctor->dyndata)
141 return NULL;
143 for (cnt = 1; cnt < ctor->dynshdr->sh_size / ctor->dynshdr->sh_entsize;
144 cnt++) {
145 GElf_Dyn *dyn;
147 if ((dyn = gelf_getdyn(ctor->dyndata, cnt, mem)) == NULL)
148 break;
150 if (dyn->d_tag == d_tag) {
151 *idx = cnt;
152 return dyn;
155 return NULL;
158 static void remove_dyn(ElfCreator *ctor, size_t idx)
160 size_t cnt;
162 for (cnt = idx; cnt < ctor->dynshdr->sh_size/ctor->dynshdr->sh_entsize;
163 cnt++) {
164 GElf_Dyn *dyn, dyn_mem;
166 if (cnt+1 == ctor->dynshdr->sh_size/ctor->dynshdr->sh_entsize) {
167 memset(&dyn_mem, '\0', sizeof(dyn_mem));
168 gelf_update_dyn(ctor->dyndata, cnt, &dyn_mem);
169 break;
172 dyn = gelf_getdyn(ctor->dyndata, cnt+1, &dyn_mem);
173 gelf_update_dyn(ctor->dyndata, cnt, dyn);
175 ctor->dynshdr->sh_size--;
176 gelf_update_shdr(ctor->dynscn, ctor->dynshdr);
177 update_dyn_cache(ctor);
180 typedef void (*dyn_fixup_fn)(ElfCreator *ctor, Elf64_Sxword d_tag, Elf_Scn *scn);
182 static void generic_dyn_fixup_fn(ElfCreator *ctor, Elf64_Sxword d_tag, Elf_Scn *scn)
184 GElf_Shdr *shdr, shdr_mem;
185 GElf_Dyn *dyn, dyn_mem;
186 size_t idx = 0;
188 dyn = get_dyn_by_tag(ctor, d_tag, &dyn_mem, &idx);
189 shdr = gelf_getshdr(scn, &shdr_mem);
190 if (shdr) {
191 dyn->d_un.d_ptr = shdr->sh_addr;
192 gelf_update_dyn(ctor->dyndata, idx, dyn);
193 } else {
194 remove_dyn(ctor, idx);
198 static void rela_dyn_fixup_fn(ElfCreator *ctor, Elf64_Sxword d_tag, Elf_Scn *scn)
200 GElf_Shdr *shdr, shdr_mem;
201 GElf_Dyn *dyn, dyn_mem;
202 size_t idx = 0;
204 dyn = get_dyn_by_tag(ctor, d_tag, &dyn_mem, &idx);
205 shdr = gelf_getshdr(scn, &shdr_mem);
206 if (shdr) {
207 dyn->d_un.d_ptr = shdr->sh_addr;
208 gelf_update_dyn(ctor->dyndata, idx, dyn);
209 } else {
210 remove_dyn(ctor, idx);
211 dyn = get_dyn_by_tag(ctor, DT_RELASZ, &dyn_mem, &idx);
212 if (dyn) {
213 dyn->d_un.d_val = 0;
214 gelf_update_dyn(ctor->dyndata, idx, dyn);
219 static void rel_dyn_fixup_fn(ElfCreator *ctor, Elf64_Sxword d_tag, Elf_Scn *scn)
221 GElf_Shdr *shdr, shdr_mem;
222 GElf_Dyn *dyn, dyn_mem;
223 size_t idx = 0;
225 dyn = get_dyn_by_tag(ctor, d_tag, &dyn_mem, &idx);
226 shdr = gelf_getshdr(scn, &shdr_mem);
227 if (shdr) {
228 dyn->d_un.d_ptr = shdr->sh_addr;
229 gelf_update_dyn(ctor->dyndata, idx, dyn);
230 } else {
231 remove_dyn(ctor, idx);
232 dyn = get_dyn_by_tag(ctor, DT_RELSZ, &dyn_mem, &idx);
233 if (dyn) {
234 dyn->d_un.d_val = 0;
235 gelf_update_dyn(ctor->dyndata, idx, dyn);
240 static void fixup_dynamic(ElfCreator *ctor)
242 struct {
243 Elf64_Sxword d_tag;
244 Elf64_Word sh_type;
245 dyn_fixup_fn fn;
246 } fixups[] = {
247 { DT_HASH, SHT_HASH, NULL },
248 { DT_STRTAB, SHT_STRTAB, NULL },
249 { DT_SYMTAB, SHT_SYMTAB, NULL },
250 { DT_RELA, SHT_RELA, rela_dyn_fixup_fn},
251 { DT_REL, SHT_REL, rel_dyn_fixup_fn},
252 { DT_GNU_HASH, SHT_GNU_HASH, NULL },
253 { DT_NULL, SHT_NULL, NULL }
255 int i;
257 for (i = 0; fixups[i].d_tag != DT_NULL; i++) {
258 Elf_Scn *scn;
260 scn = get_scn_by_type(ctor, fixups[i].sh_type);
261 if (fixups[i].fn)
262 fixups[i].fn(ctor, fixups[i].d_tag, scn);
263 else
264 generic_dyn_fixup_fn(ctor, fixups[i].d_tag, scn);
268 void elfcreator_end(ElfCreator *ctor)
270 GElf_Phdr phdr_mem, *phdr;
271 int m,n;
273 for (m = 0; (phdr = gelf_getphdr(ctor->oldelf, m, &phdr_mem)) != NULL; m++)
274 /* XXX this should check if an entry is needed */;
276 gelf_newphdr(ctor->elf, m);
277 elf_update(ctor->elf, ELF_C_NULL);
278 update_dyn_cache(ctor);
280 for (n = 0; n < m; n++) {
281 /* XXX this should check if an entry is needed */
282 phdr = gelf_getphdr(ctor->oldelf, n, &phdr_mem);
283 if (ctor->dynshdr && phdr->p_type == PT_DYNAMIC)
284 phdr->p_offset = ctor->dynshdr->sh_offset;
286 gelf_update_phdr(ctor->elf, n, phdr);
289 fixup_dynamic(ctor);
291 clear(ctor, 0);
292 free(ctor);