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