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