Branch data Line data Source code
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
42 : 20 : arlib_init (void)
43 : : {
44 : : #define obstack_chunk_alloc xmalloc
45 : : #define obstack_chunk_free free
46 : 20 : obstack_init (&symtab.symsoffob);
47 : 20 : obstack_init (&symtab.symsnameob);
48 : 20 : 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 : 20 : 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 : 0 : int s = snprintf (tmpbuf, sizeof (tmpbuf), "%-*lld",
63 : : (int) sizeof (ar_hdr.ar_date),
64 [ + - ]: 20 : (arlib_deterministic_output ? 0
65 : 20 : : (long long int) time (NULL)));
66 : 20 : 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 : 20 : memcpy (ar_hdr.ar_uid, "0 ", sizeof (ar_hdr.ar_uid));
74 : 20 : memcpy (ar_hdr.ar_gid, "0 ", sizeof (ar_hdr.ar_gid));
75 : 20 : memcpy (ar_hdr.ar_mode, "0 ", sizeof (ar_hdr.ar_mode));
76 : 20 : memcpy (ar_hdr.ar_fmag, ARFMAG, sizeof (ar_hdr.ar_fmag));
77 : :
78 : : /* Add the archive header to the file content. */
79 [ - + ]: 20 : 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 [ - + ]: 20 : 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 : 20 : memcpy (ar_hdr.ar_name, "// ", sizeof (ar_hdr.ar_name));
91 : 20 : memcpy (ar_hdr.ar_date, " ", sizeof (ar_hdr.ar_date));
92 : 20 : memcpy (ar_hdr.ar_uid, " ", sizeof (ar_hdr.ar_uid));
93 : 20 : memcpy (ar_hdr.ar_gid, " ", sizeof (ar_hdr.ar_gid));
94 : 20 : 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 [ - + ]: 20 : obstack_grow (&symtab.longnamesob, &ar_hdr, sizeof (ar_hdr));
97 : :
98 : : /* All other members are zero. */
99 : 20 : symtab.symsofflen = 0;
100 : 20 : symtab.symsoff = NULL;
101 : 20 : symtab.symsnamelen = 0;
102 : 20 : symtab.symsname = NULL;
103 : 20 : }
104 : :
105 : :
106 : : /* Finalize ARLIB_SYMTAB content. */
107 : : void
108 : 20 : 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 : 20 : symtab.longnameslen = obstack_object_size (&symtab.longnamesob);
116 [ - + ]: 20 : if (symtab.longnameslen != sizeof (struct ar_hdr))
117 : : {
118 [ # # ]: 0 : if ((symtab.longnameslen & 1) != 0)
119 : : {
120 : : /* Add one more byte to make length even. */
121 [ # # ]: 0 : obstack_grow (&symtab.longnamesob, "\n", 1);
122 : 0 : ++symtab.longnameslen;
123 : : }
124 : :
125 [ # # # # ]: 0 : symtab.longnames = obstack_finish (&symtab.longnamesob);
126 : :
127 : 0 : int s = snprintf (tmpbuf, sizeof (tmpbuf), "%-*" PRIu32 "",
128 : : (int) sizeof (((struct ar_hdr *) NULL)->ar_size),
129 : 0 : (uint32_t) (symtab.longnameslen - sizeof (struct ar_hdr)));
130 : 0 : memcpy (&((struct ar_hdr *) symtab.longnames)->ar_size, tmpbuf, s);
131 : : }
132 : :
133 : 20 : symtab.symsofflen = obstack_object_size (&symtab.symsoffob);
134 [ - + ]: 20 : assert (symtab.symsofflen % sizeof (uint32_t) == 0);
135 [ + - ]: 20 : if (symtab.symsofflen != 0)
136 : : {
137 [ - + - + ]: 20 : symtab.symsoff = (uint32_t *) obstack_finish (&symtab.symsoffob);
138 : :
139 : : /* Fill in the number of offsets now. */
140 : 20 : symtab.symsoff[AR_HDR_WORDS] = le_bswap_32 ((symtab.symsofflen
141 : : - sizeof (struct ar_hdr))
142 : : / sizeof (uint32_t) - 1);
143 : : }
144 : :
145 : 20 : symtab.symsnamelen = obstack_object_size (&symtab.symsnameob);
146 [ + + ]: 20 : if ((symtab.symsnamelen & 1) != 0)
147 : : {
148 : : /* Add one more NUL byte to make length even. */
149 [ - + ]: 4 : obstack_grow (&symtab.symsnameob, "", 1);
150 : 4 : ++symtab.symsnamelen;
151 : : }
152 [ + + - + ]: 20 : symtab.symsname = obstack_finish (&symtab.symsnameob);
153 : :
154 : : /* Determine correction for the offsets in the symbol table. */
155 : 20 : off_t disp = 0;
156 [ + + ]: 20 : if (symtab.symsnamelen > 0)
157 : 6 : disp = symtab.symsofflen + symtab.symsnamelen;
158 [ - + ]: 20 : if (symtab.longnameslen > sizeof (struct ar_hdr))
159 : 0 : disp += symtab.longnameslen;
160 : :
161 [ + + + - ]: 20 : if (disp != 0 && symtab.symsoff != NULL)
162 : : {
163 : 6 : uint32_t nsyms = le_bswap_32 (symtab.symsoff[AR_HDR_WORDS]);
164 : :
165 [ + + ]: 1202 : for (uint32_t cnt = 1; cnt <= nsyms; ++cnt)
166 : : {
167 : 1196 : uint32_t val = le_bswap_32 (symtab.symsoff[AR_HDR_WORDS + cnt]);
168 : 1196 : val += disp;
169 : 1196 : symtab.symsoff[AR_HDR_WORDS + cnt] = le_bswap_32 (val);
170 : : }
171 : : }
172 : :
173 : : /* See comment for ar_date above. */
174 : 20 : memcpy (&((struct ar_hdr *) symtab.symsoff)->ar_size, tmpbuf,
175 : 20 : snprintf (tmpbuf, sizeof (tmpbuf), "%-*" PRIu32 "",
176 : : (int) sizeof (((struct ar_hdr *) NULL)->ar_size),
177 : 20 : (uint32_t) (symtab.symsofflen + symtab.symsnamelen
178 : : - sizeof (struct ar_hdr))));
179 : 20 : }
180 : :
181 : :
182 : : /* Free resources for ARLIB_SYMTAB. */
183 : : void
184 : 20 : arlib_fini (void)
185 : : {
186 [ - + - - ]: 20 : obstack_free (&symtab.symsoffob, NULL);
187 [ - + - - ]: 20 : obstack_free (&symtab.symsnameob, NULL);
188 [ - + - - ]: 20 : obstack_free (&symtab.longnamesob, NULL);
189 : 20 : }
190 : :
191 : :
192 : : /* Add name a file offset of a symbol. */
193 : : void
194 : 1196 : 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 [ - + ]: 1196 : obstack_int_grow (&symtab.symsoffob, (int) le_bswap_32 (symoff));
199 : :
200 : 1196 : size_t symname_len = strlen (symname) + 1;
201 [ + + ]: 1196 : obstack_grow (&symtab.symsnameob, symname, symname_len);
202 : 1196 : }
203 : :
204 : :
205 : : /* Add symbols from ELF with value OFFSET to the symbol table SYMTAB. */
206 : : void
207 : 78 : arlib_add_symbols (Elf *elf, const char *arfname, const char *membername,
208 : : off_t off)
209 : : {
210 [ - + ]: 78 : if (sizeof (off) > sizeof (uint32_t) && off > ~((uint32_t) 0))
211 : : /* The archive is too big. */
212 : 0 : 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 [ + + ]: 78 : if (elf_kind (elf) != ELF_K_ELF)
220 : 24 : return;
221 : :
222 : : GElf_Ehdr ehdr_mem;
223 : 54 : GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
224 [ - + ]: 54 : if (ehdr == NULL)
225 : 0 : error_exit (0, _("cannot read ELF header of %s(%s): %s"),
226 : : arfname, membername, elf_errmsg (-1));
227 : :
228 : : GElf_Word symtype;
229 [ + - ]: 54 : if (ehdr->e_type == ET_REL)
230 : 54 : symtype = SHT_SYMTAB;
231 [ # # # # ]: 0 : else if (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN)
232 : 0 : symtype = SHT_DYNSYM;
233 : : else
234 : : /* We do not handle that type. */
235 : 0 : return;
236 : :
237 : : /* Iterate over all sections. */
238 : 54 : Elf_Scn *scn = NULL;
239 [ + + ]: 3812 : while ((scn = elf_nextscn (elf, scn)) != NULL)
240 : : {
241 : : /* Get the section header. */
242 : : GElf_Shdr shdr_mem;
243 : 3758 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
244 [ - + ]: 3758 : if (shdr == NULL)
245 : 3704 : continue;
246 : :
247 [ + + ]: 3758 : if (shdr->sh_type != symtype)
248 : 3704 : continue;
249 : :
250 : 54 : Elf_Data *data = elf_getdata (scn, NULL);
251 [ - + ]: 54 : if (data == NULL)
252 : 0 : continue;
253 : :
254 [ - + ]: 54 : if (shdr->sh_entsize == 0)
255 : 0 : continue;
256 : :
257 : 54 : int nsyms = shdr->sh_size / shdr->sh_entsize;
258 [ + + ]: 3982 : for (int ndx = shdr->sh_info; ndx < nsyms; ++ndx)
259 : : {
260 : : GElf_Sym sym_mem;
261 : 3928 : GElf_Sym *sym = gelf_getsym (data, ndx, &sym_mem);
262 [ - + ]: 3928 : if (sym == NULL)
263 : 2732 : continue;
264 : :
265 : : /* Ignore undefined symbols. */
266 [ + + ]: 3928 : if (sym->st_shndx == SHN_UNDEF)
267 : 2732 : continue;
268 : :
269 : : /* Use this symbol. */
270 : 1196 : const char *symname = elf_strptr (elf, shdr->sh_link, sym->st_name);
271 [ + - ]: 1196 : if (symname != NULL)
272 : 1196 : arlib_add_symref (symname, off);
273 : : }
274 : :
275 : : /* Only relocatable files can have more than one symbol table. */
276 [ - + ]: 54 : if (ehdr->e_type != ET_REL)
277 : 0 : break;
278 : : }
279 : : }
|