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