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 : 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 : 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 : : (long long int) time (NULL)));
67 12 : 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 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 12 : 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 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 12 : 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 : 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 12 : 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 6 : 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 6 : uint32_t nsyms = le_bswap_32 (symtab.symsoff[AR_HDR_WORDS]);
165 :
166 66 : for (uint32_t cnt = 1; cnt <= nsyms; ++cnt)
167 : {
168 126 : uint32_t val = le_bswap_32 (symtab.symsoff[AR_HDR_WORDS + cnt]);
169 63 : val += disp;
170 126 : symtab.symsoff[AR_HDR_WORDS + cnt] = le_bswap_32 (val);
171 : }
172 : }
173 :
174 : /* See comment for ar_date above. */
175 12 : memcpy (&((struct ar_hdr *) symtab.symsoff)->ar_size, tmpbuf,
176 12 : 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 63 : 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 126 : obstack_int_grow (&symtab.symsoffob, (int) le_bswap_32 (symoff));
200 :
201 63 : size_t symname_len = strlen (symname) + 1;
202 126 : obstack_grow (&symtab.symsnameob, symname, symname_len);
203 63 : }
204 :
205 :
206 : /* Add symbols from ELF with value OFFSET to the symbol table SYMTAB. */
207 : void
208 29 : arlib_add_symbols (Elf *elf, const char *arfname, const char *membername,
209 : off_t off)
210 : {
211 29 : if (sizeof (off) > sizeof (uint32_t) && off > ~((uint32_t) 0))
212 : /* The archive is too big. */
213 0 : 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 29 : if (elf_kind (elf) != ELF_K_ELF)
221 4 : return;
222 :
223 : GElf_Ehdr ehdr_mem;
224 25 : GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
225 25 : if (ehdr == NULL)
226 0 : 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 25 : 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 25 : Elf_Scn *scn = NULL;
240 858 : while ((scn = elf_nextscn (elf, scn)) != NULL)
241 : {
242 : /* Get the section header. */
243 : GElf_Shdr shdr_mem;
244 808 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
245 808 : if (shdr == NULL)
246 783 : continue;
247 :
248 808 : if (shdr->sh_type != symtype)
249 783 : continue;
250 :
251 25 : Elf_Data *data = elf_getdata (scn, NULL);
252 25 : if (data == NULL)
253 0 : continue;
254 :
255 25 : if (shdr->sh_entsize == 0)
256 0 : continue;
257 :
258 25 : int nsyms = shdr->sh_size / shdr->sh_entsize;
259 1307 : for (int ndx = shdr->sh_info; ndx < nsyms; ++ndx)
260 : {
261 : GElf_Sym sym_mem;
262 1282 : GElf_Sym *sym = gelf_getsym (data, ndx, &sym_mem);
263 1282 : if (sym == NULL)
264 1219 : continue;
265 :
266 : /* Ignore undefined symbols. */
267 1282 : if (sym->st_shndx == SHN_UNDEF)
268 1219 : continue;
269 :
270 : /* Use this symbol. */
271 63 : const char *symname = elf_strptr (elf, shdr->sh_link, sym->st_name);
272 63 : if (symname != NULL)
273 63 : arlib_add_symref (symname, off);
274 : }
275 :
276 : /* Only relocatable files can have more than one symbol table. */
277 25 : if (ehdr->e_type != ET_REL)
278 : break;
279 : }
280 : }
|