1 /* Functions to handle creation of Linux archives.
2 Copyright (C) 2007-2012, 2016 Red Hat, Inc.
3 This file is part of elfutils.
4 Written by Ulrich Drepper <drepper@redhat.com>, 2007.
5
6 This file is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 elfutils is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
18
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 #include <assert.h>
24 #include <gelf.h>
25 #include <inttypes.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <time.h>
29
30 #include <libeu.h>
31
32 #include "system.h"
33 #include "arlib.h"
34
35
36 /* The one symbol table we hanble. */
37 struct arlib_symtab symtab;
38
39
40 /* Initialize ARLIB_SYMTAB structure. */
41 void
arlib_init(void)42 arlib_init (void)
43 {
44 #define obstack_chunk_alloc xmalloc
45 #define obstack_chunk_free free
46 obstack_init (&symtab.symsoffob);
47 obstack_init (&symtab.symsnameob);
48 obstack_init (&symtab.longnamesob);
49
50 /* We add the archive header here as well, that avoids allocating
51 another memory block. */
52 struct ar_hdr ar_hdr;
53 memcpy (ar_hdr.ar_name, "/ ", sizeof (ar_hdr.ar_name));
54 /* Using snprintf here has a problem: the call always wants to add a
55 NUL byte. We could use a trick whereby we specify the target
56 buffer size longer than it is and this would not actually fail,
57 since all the fields are consecutive and we fill them in
58 sequence (i.e., the NUL byte gets overwritten). But
59 _FORTIFY_SOURCE=2 would not let us play these games. Therefore
60 we play it safe. */
61 char tmpbuf[sizeof (ar_hdr.ar_date) + 1];
62 int s = snprintf (tmpbuf, sizeof (tmpbuf), "%-*lld",
63 (int) sizeof (ar_hdr.ar_date),
64 (arlib_deterministic_output ? 0
65 : (long long int) time (NULL)));
66 memcpy (ar_hdr.ar_date, tmpbuf, s);
67 assert ((sizeof (struct ar_hdr) % sizeof (uint32_t)) == 0);
68
69 /* Note the string for the ar_uid and ar_gid cases is longer than
70 necessary. This does not matter since we copy only as much as
71 necessary but it helps the compiler to use the same string for
72 the ar_mode case. */
73 memcpy (ar_hdr.ar_uid, "0 ", sizeof (ar_hdr.ar_uid));
74 memcpy (ar_hdr.ar_gid, "0 ", sizeof (ar_hdr.ar_gid));
75 memcpy (ar_hdr.ar_mode, "0 ", sizeof (ar_hdr.ar_mode));
76 memcpy (ar_hdr.ar_fmag, ARFMAG, sizeof (ar_hdr.ar_fmag));
77
78 /* Add the archive header to the file content. */
79 obstack_grow (&symtab.symsoffob, &ar_hdr, sizeof (ar_hdr));
80
81 /* The first word in the offset table specifies the size. Create
82 such an entry now. The real value will be filled-in later. For
83 all supported platforms the following is true. */
84 assert (sizeof (uint32_t) == sizeof (int));
85 obstack_int_grow (&symtab.symsoffob, 0);
86
87 /* The long name obstack also gets its archive header. As above,
88 some of the input strings are longer than required but we only
89 copy the necessary part. */
90 memcpy (ar_hdr.ar_name, "// ", sizeof (ar_hdr.ar_name));
91 memcpy (ar_hdr.ar_date, " ", sizeof (ar_hdr.ar_date));
92 memcpy (ar_hdr.ar_uid, " ", sizeof (ar_hdr.ar_uid));
93 memcpy (ar_hdr.ar_gid, " ", sizeof (ar_hdr.ar_gid));
94 memcpy (ar_hdr.ar_mode, " ", sizeof (ar_hdr.ar_mode));
95 /* The ar_size field will be filled in later and ar_fmag is already OK. */
96 obstack_grow (&symtab.longnamesob, &ar_hdr, sizeof (ar_hdr));
97
98 /* All other members are zero. */
99 symtab.symsofflen = 0;
100 symtab.symsoff = NULL;
101 symtab.symsnamelen = 0;
102 symtab.symsname = NULL;
103 }
104
105
106 /* Finalize ARLIB_SYMTAB content. */
107 void
arlib_finalize(void)108 arlib_finalize (void)
109 {
110 /* Note that the size is stored as decimal string in 10 chars,
111 without zero terminator (we add + 1 here only so snprintf can
112 put it at the end, we then don't use it when we memcpy it). */
113 char tmpbuf[sizeof (((struct ar_hdr *) NULL)->ar_size) + 1];
114
115 symtab.longnameslen = obstack_object_size (&symtab.longnamesob);
116 if (symtab.longnameslen != sizeof (struct ar_hdr))
117 {
118 if ((symtab.longnameslen & 1) != 0)
119 {
120 /* Add one more byte to make length even. */
121 obstack_grow (&symtab.longnamesob, "\n", 1);
122 ++symtab.longnameslen;
123 }
124
125 symtab.longnames = obstack_finish (&symtab.longnamesob);
126
127 int s = snprintf (tmpbuf, sizeof (tmpbuf), "%-*" PRIu32 "",
128 (int) sizeof (((struct ar_hdr *) NULL)->ar_size),
129 (uint32_t) (symtab.longnameslen - sizeof (struct ar_hdr)));
130 memcpy (&((struct ar_hdr *) symtab.longnames)->ar_size, tmpbuf, s);
131 }
132
133 symtab.symsofflen = obstack_object_size (&symtab.symsoffob);
134 assert (symtab.symsofflen % sizeof (uint32_t) == 0);
135 if (symtab.symsofflen != 0)
136 {
137 symtab.symsoff = (uint32_t *) obstack_finish (&symtab.symsoffob);
138
139 /* Fill in the number of offsets now. */
140 symtab.symsoff[AR_HDR_WORDS] = le_bswap_32 ((symtab.symsofflen
141 - sizeof (struct ar_hdr))
142 / sizeof (uint32_t) - 1);
143 }
144
145 symtab.symsnamelen = obstack_object_size (&symtab.symsnameob);
146 if ((symtab.symsnamelen & 1) != 0)
147 {
148 /* Add one more NUL byte to make length even. */
149 obstack_grow (&symtab.symsnameob, "", 1);
150 ++symtab.symsnamelen;
151 }
152 symtab.symsname = obstack_finish (&symtab.symsnameob);
153
154 /* Determine correction for the offsets in the symbol table. */
155 off_t disp = 0;
156 if (symtab.symsnamelen > 0)
157 disp = symtab.symsofflen + symtab.symsnamelen;
158 if (symtab.longnameslen > sizeof (struct ar_hdr))
159 disp += symtab.longnameslen;
160
161 if (disp != 0 && symtab.symsoff != NULL)
162 {
163 uint32_t nsyms = le_bswap_32 (symtab.symsoff[AR_HDR_WORDS]);
164
165 for (uint32_t cnt = 1; cnt <= nsyms; ++cnt)
166 {
167 uint32_t val = le_bswap_32 (symtab.symsoff[AR_HDR_WORDS + cnt]);
168 val += disp;
169 symtab.symsoff[AR_HDR_WORDS + cnt] = le_bswap_32 (val);
170 }
171 }
172
173 /* See comment for ar_date above. */
174 memcpy (&((struct ar_hdr *) symtab.symsoff)->ar_size, tmpbuf,
175 snprintf (tmpbuf, sizeof (tmpbuf), "%-*" PRIu32 "",
176 (int) sizeof (((struct ar_hdr *) NULL)->ar_size),
177 (uint32_t) (symtab.symsofflen + symtab.symsnamelen
178 - sizeof (struct ar_hdr))));
179 }
180
181
182 /* Free resources for ARLIB_SYMTAB. */
183 void
arlib_fini(void)184 arlib_fini (void)
185 {
186 obstack_free (&symtab.symsoffob, NULL);
187 obstack_free (&symtab.symsnameob, NULL);
188 obstack_free (&symtab.longnamesob, NULL);
189 }
190
191
192 /* Add name a file offset of a symbol. */
193 void
arlib_add_symref(const char * symname,off_t symoff)194 arlib_add_symref (const char *symname, off_t symoff)
195 {
196 /* For all supported platforms the following is true. */
197 assert (sizeof (uint32_t) == sizeof (int));
198 obstack_int_grow (&symtab.symsoffob, (int) le_bswap_32 (symoff));
199
200 size_t symname_len = strlen (symname) + 1;
201 obstack_grow (&symtab.symsnameob, symname, symname_len);
202 }
203
204
205 /* Add symbols from ELF with value OFFSET to the symbol table SYMTAB. */
206 void
arlib_add_symbols(Elf * elf,const char * arfname,const char * membername,off_t off)207 arlib_add_symbols (Elf *elf, const char *arfname, const char *membername,
208 off_t off)
209 {
210 if (sizeof (off) > sizeof (uint32_t) && off > ~((uint32_t) 0))
211 /* The archive is too big. */
212 error_exit (0, _("the archive '%s' is too large"),
213 arfname);
214
215 /* We only add symbol tables for ELF files. It makes not much sense
216 to add symbols from executables but we do so for compatibility.
217 For DSOs and executables we use the dynamic symbol table, for
218 relocatable files all the DT_SYMTAB tables. */
219 if (elf_kind (elf) != ELF_K_ELF)
220 return;
221
222 GElf_Ehdr ehdr_mem;
223 GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
224 if (ehdr == NULL)
225 error_exit (0, _("cannot read ELF header of %s(%s): %s"),
226 arfname, membername, elf_errmsg (-1));
227
228 GElf_Word symtype;
229 if (ehdr->e_type == ET_REL)
230 symtype = SHT_SYMTAB;
231 else if (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN)
232 symtype = SHT_DYNSYM;
233 else
234 /* We do not handle that type. */
235 return;
236
237 /* Iterate over all sections. */
238 Elf_Scn *scn = NULL;
239 while ((scn = elf_nextscn (elf, scn)) != NULL)
240 {
241 /* Get the section header. */
242 GElf_Shdr shdr_mem;
243 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
244 if (shdr == NULL)
245 continue;
246
247 if (shdr->sh_type != symtype)
248 continue;
249
250 Elf_Data *data = elf_getdata (scn, NULL);
251 if (data == NULL)
252 continue;
253
254 if (shdr->sh_entsize == 0)
255 continue;
256
257 int nsyms = shdr->sh_size / shdr->sh_entsize;
258 for (int ndx = shdr->sh_info; ndx < nsyms; ++ndx)
259 {
260 GElf_Sym sym_mem;
261 GElf_Sym *sym = gelf_getsym (data, ndx, &sym_mem);
262 if (sym == NULL)
263 continue;
264
265 /* Ignore undefined symbols. */
266 if (sym->st_shndx == SHN_UNDEF)
267 continue;
268
269 /* Use this symbol. */
270 const char *symname = elf_strptr (elf, shdr->sh_link, sym->st_name);
271 if (symname != NULL)
272 arlib_add_symref (symname, off);
273 }
274
275 /* Only relocatable files can have more than one symbol table. */
276 if (ehdr->e_type != ET_REL)
277 break;
278 }
279 }
280