Branch data Line data Source code
1 : : /* Combine stripped files with separate symbols and debug information.
2 : : Copyright (C) 2007-2012 Red Hat, Inc.
3 : : This file is part of elfutils.
4 : : Written by Roland McGrath <roland@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 : : /* TODO:
20 : :
21 : : * SHX_XINDEX
22 : :
23 : : * prelink vs .debug_* linked addresses
24 : :
25 : : */
26 : :
27 : : #ifdef HAVE_CONFIG_H
28 : : # include <config.h>
29 : : #endif
30 : :
31 : : #include <argp.h>
32 : : #include <assert.h>
33 : : #include <errno.h>
34 : : #include <error.h>
35 : : #include <fcntl.h>
36 : : #include <fnmatch.h>
37 : : #include <libintl.h>
38 : : #include <locale.h>
39 : : #include <mcheck.h>
40 : : #include <stdbool.h>
41 : : #include <stdio.h>
42 : : #include <stdio_ext.h>
43 : : #include <inttypes.h>
44 : : #include <stdlib.h>
45 : : #include <string.h>
46 : : #include <unistd.h>
47 : : #include <sys/stat.h>
48 : :
49 : : #include <gelf.h>
50 : : #include <libebl.h>
51 : : #include <libdwfl.h>
52 : : #include "system.h"
53 : :
54 : : #ifndef _
55 : : # define _(str) gettext (str)
56 : : #endif
57 : :
58 : : /* Name and version of program. */
59 : : static void print_version (FILE *stream, struct argp_state *state);
60 : : ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
61 : :
62 : : /* Bug report address. */
63 : : ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
64 : :
65 : : /* Definitions of arguments for argp functions. */
66 : : static const struct argp_option options[] =
67 : : {
68 : : /* Group 2 will follow group 1 from dwfl_standard_argp. */
69 : : { "match-file-names", 'f', NULL, 0,
70 : : N_("Match MODULE against file names, not module names"), 2 },
71 : : { "ignore-missing", 'i', NULL, 0, N_("Silently skip unfindable files"), 0 },
72 : :
73 : : { NULL, 0, NULL, 0, N_("Output options:"), 0 },
74 : : { "output", 'o', "FILE", 0, N_("Place output into FILE"), 0 },
75 : : { "output-directory", 'd', "DIRECTORY",
76 : : 0, N_("Create multiple output files under DIRECTORY"), 0 },
77 : : { "module-names", 'm', NULL, 0, N_("Use module rather than file names"), 0 },
78 : : { "all", 'a', NULL, 0,
79 : : N_("Create output for modules that have no separate debug information"),
80 : : 0 },
81 : : { "relocate", 'R', NULL, 0,
82 : : N_("Apply relocations to section contents in ET_REL files"), 0 },
83 : : { "list-only", 'n', NULL, 0,
84 : : N_("Only list module and file names, build IDs"), 0 },
85 : : { NULL, 0, NULL, 0, NULL, 0 }
86 : : };
87 : :
88 : : struct arg_info
89 : : {
90 : : const char *output_file;
91 : : const char *output_dir;
92 : : Dwfl *dwfl;
93 : : char **args;
94 : : bool list;
95 : : bool all;
96 : : bool ignore;
97 : : bool modnames;
98 : : bool match_files;
99 : : bool relocate;
100 : : };
101 : :
102 : : /* Handle program arguments. */
103 : : static error_t
104 : 64 : parse_opt (int key, char *arg, struct argp_state *state)
105 : : {
106 : 64 : struct arg_info *info = state->input;
107 : :
108 [ + + - - : 64 : switch (key)
- - - + -
+ + ]
109 : : {
110 : : case ARGP_KEY_INIT:
111 : 11 : state->child_inputs[0] = &info->dwfl;
112 : 11 : break;
113 : :
114 : : case 'o':
115 [ - + ]: 7 : if (info->output_file != NULL)
116 : : {
117 : 0 : argp_error (state, _("-o option specified twice"));
118 : 0 : return EINVAL;
119 : : }
120 : 7 : info->output_file = arg;
121 : 7 : break;
122 : :
123 : : case 'd':
124 [ # # ]: 0 : if (info->output_dir != NULL)
125 : : {
126 : 0 : argp_error (state, _("-d option specified twice"));
127 : 0 : return EINVAL;
128 : : }
129 : 0 : info->output_dir = arg;
130 : 0 : break;
131 : :
132 : : case 'm':
133 : 0 : info->modnames = true;
134 : 0 : break;
135 : : case 'f':
136 : 0 : info->match_files = true;
137 : 0 : break;
138 : : case 'a':
139 : 0 : info->all = true;
140 : 0 : break;
141 : : case 'i':
142 : 0 : info->ignore = true;
143 : 0 : break;
144 : : case 'n':
145 : 2 : info->list = true;
146 : 2 : break;
147 : : case 'R':
148 : 0 : info->relocate = true;
149 : 0 : break;
150 : :
151 : : case ARGP_KEY_ARGS:
152 : : case ARGP_KEY_NO_ARGS:
153 : : /* We "consume" all the arguments here. */
154 : 11 : info->args = &state->argv[state->next];
155 : :
156 [ + + ][ - + ]: 11 : if (info->output_file != NULL && info->output_dir != NULL)
157 : : {
158 : 0 : argp_error (state, _("only one of -o or -d allowed"));
159 : 0 : return EINVAL;
160 : : }
161 : :
162 [ + + ][ + - ]: 11 : if (info->list && (info->dwfl == NULL
163 [ + - ]: 2 : || info->output_dir != NULL
164 [ - + ]: 2 : || info->output_file != NULL))
165 : : {
166 : 0 : argp_error (state,
167 : 0 : _("-n cannot be used with explicit files or -o or -d"));
168 : 0 : return EINVAL;
169 : : }
170 : :
171 [ - + ]: 11 : if (info->output_dir != NULL)
172 : : {
173 : : struct stat64 st;
174 : 0 : error_t fail = 0;
175 [ # # ]: 0 : if (stat64 (info->output_dir, &st) < 0)
176 : 0 : fail = errno;
177 [ # # ]: 0 : else if (!S_ISDIR (st.st_mode))
178 : 0 : fail = ENOTDIR;
179 [ # # ]: 0 : if (fail)
180 : : {
181 : 0 : argp_failure (state, EXIT_FAILURE, fail,
182 : 0 : _("output directory '%s'"), info->output_dir);
183 : : return fail;
184 : : }
185 : : }
186 : :
187 [ + + ]: 11 : if (info->dwfl == NULL)
188 : : {
189 [ - + ]: 9 : if (state->next + 2 != state->argc)
190 : : {
191 : 0 : argp_error (state, _("exactly two file arguments are required"));
192 : 0 : return EINVAL;
193 : : }
194 : :
195 [ + - ][ + - ]: 9 : if (info->ignore || info->all || info->modnames || info->relocate)
[ + - ][ - + ]
196 : : {
197 : 0 : argp_error (state, _("\
198 : : -m, -a, -R, and -i options not allowed with explicit files"));
199 : 0 : return EINVAL;
200 : : }
201 : :
202 : : /* Bail out immediately to prevent dwfl_standard_argp's parser
203 : : from defaulting to "-e a.out". */
204 : : return ENOSYS;
205 : : }
206 [ + - ][ + - ]: 2 : else if (info->output_file == NULL && info->output_dir == NULL
207 [ - + ]: 2 : && !info->list)
208 : : {
209 : 0 : argp_error (state,
210 : 0 : _("-o or -d is required when using implicit files"));
211 : 64 : return EINVAL;
212 : : }
213 : : break;
214 : :
215 : : default:
216 : : return ARGP_ERR_UNKNOWN;
217 : : }
218 : : return 0;
219 : : }
220 : :
221 : : /* Print the version information. */
222 : : static void
223 : 0 : print_version (FILE *stream, struct argp_state *state __attribute__ ((unused)))
224 : : {
225 : 0 : fprintf (stream, "unstrip (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION);
226 : 0 : fprintf (stream, _("\
227 : : Copyright (C) %s Red Hat, Inc.\n\
228 : : This is free software; see the source for copying conditions. There is NO\n\
229 : : warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
230 : : "), "2012");
231 : 0 : fprintf (stream, gettext ("Written by %s.\n"), "Roland McGrath");
232 : 0 : }
233 : :
234 : : #define ELF_CHECK(call, msg) \
235 : : do \
236 : : { \
237 : : if (!(call)) \
238 : : error (EXIT_FAILURE, 0, msg, elf_errmsg (-1)); \
239 : : } while (0)
240 : :
241 : : /* Copy INELF to newly-created OUTELF, exit via error for any problems. */
242 : : static void
243 : 7 : copy_elf (Elf *outelf, Elf *inelf)
244 : : {
245 [ - + ]: 7 : ELF_CHECK (gelf_newehdr (outelf, gelf_getclass (inelf)),
246 : : _("cannot create ELF header: %s"));
247 : :
248 : : GElf_Ehdr ehdr_mem;
249 : 7 : GElf_Ehdr *ehdr = gelf_getehdr (inelf, &ehdr_mem);
250 [ - + ]: 7 : ELF_CHECK (gelf_update_ehdr (outelf, ehdr),
251 : : _("cannot copy ELF header: %s"));
252 : :
253 [ + + ]: 7 : if (ehdr->e_phnum > 0)
254 : : {
255 [ + - ]: 5 : ELF_CHECK (gelf_newphdr (outelf, ehdr->e_phnum),
256 : : _("cannot create program headers: %s"));
257 : :
258 : : GElf_Phdr phdr_mem;
259 [ + + ]: 35 : for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i)
260 [ - + ]: 28 : ELF_CHECK (gelf_update_phdr (outelf, i,
261 : : gelf_getphdr (inelf, i, &phdr_mem)),
262 : : _("cannot copy program header: %s"));
263 : : }
264 : :
265 : : Elf_Scn *scn = NULL;
266 [ + + ]: 217 : while ((scn = elf_nextscn (inelf, scn)) != NULL)
267 : : {
268 : 210 : Elf_Scn *newscn = elf_newscn (outelf);
269 : :
270 : : GElf_Shdr shdr_mem;
271 [ - + ]: 210 : ELF_CHECK (gelf_update_shdr (newscn, gelf_getshdr (scn, &shdr_mem)),
272 : : _("cannot copy section header: %s"));
273 : :
274 : 210 : Elf_Data *data = elf_getdata (scn, NULL);
275 [ - + ]: 210 : ELF_CHECK (data != NULL, _("cannot get section data: %s"));
276 : 210 : Elf_Data *newdata = elf_newdata (newscn);
277 [ - + ]: 210 : ELF_CHECK (newdata != NULL, _("cannot copy section data: %s"));
278 : 210 : *newdata = *data;
279 : 210 : elf_flagdata (newdata, ELF_C_SET, ELF_F_DIRTY);
280 : : }
281 : 7 : }
282 : :
283 : : /* Create directories containing PATH. */
284 : : static void
285 : 0 : make_directories (const char *path)
286 : : {
287 : 0 : const char *lastslash = strrchr (path, '/');
288 [ # # ]: 0 : if (lastslash == NULL)
289 : : return;
290 : :
291 [ # # ][ # # ]: 0 : while (lastslash > path && lastslash[-1] == '/')
292 : 0 : --lastslash;
293 [ # # ]: 0 : if (lastslash == path)
294 : : return;
295 : :
296 : 0 : char *dir = strndupa (path, lastslash - path);
297 [ # # ][ # # ]: 0 : while (mkdir (dir, 0777) < 0 && errno != EEXIST)
298 [ # # ]: 0 : if (errno == ENOENT)
299 : 0 : make_directories (dir);
300 : : else
301 : 0 : error (EXIT_FAILURE, errno, _("cannot create directory '%s'"), dir);
302 : : }
303 : :
304 : :
305 : : /* The binutils linker leaves gratuitous section symbols in .symtab
306 : : that strip has to remove. Older linkers likewise include a
307 : : symbol for every section, even unallocated ones, in .dynsym.
308 : : Because of this, the related sections can shrink in the stripped
309 : : file from their original size. Older versions of strip do not
310 : : adjust the sh_size field in the debuginfo file's SHT_NOBITS
311 : : version of the section header, so it can appear larger. */
312 : : static bool
313 : : section_can_shrink (const GElf_Shdr *shdr)
314 : : {
315 [ - + ]: 7 : switch (shdr->sh_type)
316 : : {
317 : : case SHT_SYMTAB:
318 : : case SHT_DYNSYM:
319 : : case SHT_HASH:
320 : : case SHT_GNU_versym:
321 : : return true;
322 : : }
323 : : return false;
324 : : }
325 : :
326 : : /* See if this symbol table has a leading section symbol for every single
327 : : section, in order. The binutils linker produces this. While we're here,
328 : : update each section symbol's st_value. */
329 : : static size_t
330 : 7 : symtab_count_leading_section_symbols (Elf *elf, Elf_Scn *scn, size_t shnum,
331 : : Elf_Data *newsymdata)
332 : : {
333 : 7 : Elf_Data *data = elf_getdata (scn, NULL);
334 : 7 : Elf_Data *shndxdata = NULL; /* XXX */
335 : :
336 [ + - ]: 80 : for (size_t i = 1; i < shnum; ++i)
337 : : {
338 : : GElf_Sym sym_mem;
339 : 73 : GElf_Word shndx = SHN_UNDEF;
340 : 73 : GElf_Sym *sym = gelf_getsymshndx (data, shndxdata, i, &sym_mem, &shndx);
341 [ - + ]: 73 : ELF_CHECK (sym != NULL, _("cannot get symbol table entry: %s"));
342 : :
343 : : GElf_Shdr shdr_mem;
344 : 73 : GElf_Shdr *shdr = gelf_getshdr (elf_getscn (elf, i), &shdr_mem);
345 [ - + ]: 73 : ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
346 : :
347 [ + - ]: 73 : if (sym->st_shndx != SHN_XINDEX)
348 : 73 : shndx = sym->st_shndx;
349 : :
350 [ + + ][ - + ]: 73 : if (shndx != i || GELF_ST_TYPE (sym->st_info) != STT_SECTION)
351 : : return i;
352 : :
353 : 66 : sym->st_value = shdr->sh_addr;
354 [ + - ]: 66 : if (sym->st_shndx != SHN_XINDEX)
355 : 66 : shndx = SHN_UNDEF;
356 [ - + ]: 66 : ELF_CHECK (gelf_update_symshndx (newsymdata, shndxdata, i, sym, shndx),
357 : : _("cannot update symbol table: %s"));
358 : : }
359 : :
360 : : return shnum;
361 : : }
362 : :
363 : : static void
364 : 319 : update_shdr (Elf_Scn *outscn, GElf_Shdr *newshdr)
365 : : {
366 [ - + ]: 319 : ELF_CHECK (gelf_update_shdr (outscn, newshdr),
367 : : _("cannot update section header: %s"));
368 : 319 : }
369 : :
370 : : /* We expanded the output section, so update its header. */
371 : : static void
372 : 6 : update_sh_size (Elf_Scn *outscn, const Elf_Data *data)
373 : : {
374 : : GElf_Shdr shdr_mem;
375 : 6 : GElf_Shdr *newshdr = gelf_getshdr (outscn, &shdr_mem);
376 [ - + ]: 6 : ELF_CHECK (newshdr != NULL, _("cannot get section header: %s"));
377 : :
378 : 6 : newshdr->sh_size = data->d_size;
379 : :
380 : 6 : update_shdr (outscn, newshdr);
381 : 6 : }
382 : :
383 : : /* Update relocation sections using the symbol table. */
384 : : static void
385 : 30 : adjust_relocs (Elf_Scn *outscn, Elf_Scn *inscn, const GElf_Shdr *shdr,
386 : : size_t map[], const GElf_Shdr *symshdr)
387 : : {
388 : 30 : Elf_Data *data = elf_getdata (outscn, NULL);
389 : :
390 : : inline void adjust_reloc (GElf_Xword *info)
391 : : {
392 : 2271 : size_t ndx = GELF_R_SYM (*info);
393 [ + - + + ]: 2271 : if (ndx != STN_UNDEF)
394 : 2265 : *info = GELF_R_INFO (map[ndx - 1], GELF_R_TYPE (*info));
395 : : }
396 : :
397 [ + + - + : 30 : switch (shdr->sh_type)
+ - ]
398 : : {
399 : : case SHT_REL:
400 [ + + ]: 2240 : for (size_t i = 0; i < shdr->sh_size / shdr->sh_entsize; ++i)
401 : : {
402 : : GElf_Rel rel_mem;
403 : 2229 : GElf_Rel *rel = gelf_getrel (data, i, &rel_mem);
404 : 2229 : adjust_reloc (&rel->r_info);
405 [ - + ]: 2229 : ELF_CHECK (gelf_update_rel (data, i, rel),
406 : : _("cannot update relocation: %s"));
407 : : }
408 : : break;
409 : :
410 : : case SHT_RELA:
411 [ + + ]: 55 : for (size_t i = 0; i < shdr->sh_size / shdr->sh_entsize; ++i)
412 : : {
413 : : GElf_Rela rela_mem;
414 : 42 : GElf_Rela *rela = gelf_getrela (data, i, &rela_mem);
415 : 42 : adjust_reloc (&rela->r_info);
416 [ - + ]: 42 : ELF_CHECK (gelf_update_rela (data, i, rela),
417 : : _("cannot update relocation: %s"));
418 : : }
419 : : break;
420 : :
421 : : case SHT_GROUP:
422 : : {
423 : : GElf_Shdr shdr_mem;
424 : 0 : GElf_Shdr *newshdr = gelf_getshdr (outscn, &shdr_mem);
425 [ # # ]: 0 : ELF_CHECK (newshdr != NULL, _("cannot get section header: %s"));
426 [ # # ]: 0 : if (newshdr->sh_info != STN_UNDEF)
427 : : {
428 : 0 : newshdr->sh_info = map[newshdr->sh_info - 1];
429 : 0 : update_shdr (outscn, newshdr);
430 : : }
431 : : break;
432 : : }
433 : :
434 : : case SHT_HASH:
435 : : /* We must expand the table and rejigger its contents. */
436 : : {
437 : 3 : const size_t nsym = symshdr->sh_size / symshdr->sh_entsize;
438 : 3 : const size_t onent = shdr->sh_size / shdr->sh_entsize;
439 [ - + ]: 3 : assert (data->d_size == shdr->sh_size);
440 : :
441 : : #define CONVERT_HASH(Hash_Word) \
442 : : { \
443 : : const Hash_Word *const old_hash = data->d_buf; \
444 : : const size_t nbucket = old_hash[0]; \
445 : : const size_t nchain = old_hash[1]; \
446 : : const Hash_Word *const old_bucket = &old_hash[2]; \
447 : : const Hash_Word *const old_chain = &old_bucket[nbucket]; \
448 : : assert (onent == 2 + nbucket + nchain); \
449 : : \
450 : : const size_t nent = 2 + nbucket + nsym; \
451 : : Hash_Word *const new_hash = xcalloc (nent, sizeof new_hash[0]); \
452 : : Hash_Word *const new_bucket = &new_hash[2]; \
453 : : Hash_Word *const new_chain = &new_bucket[nbucket]; \
454 : : \
455 : : new_hash[0] = nbucket; \
456 : : new_hash[1] = nsym; \
457 : : for (size_t i = 0; i < nbucket; ++i) \
458 : : if (old_bucket[i] != STN_UNDEF) \
459 : : new_bucket[i] = map[old_bucket[i] - 1]; \
460 : : \
461 : : for (size_t i = 1; i < nchain; ++i) \
462 : : if (old_chain[i] != STN_UNDEF) \
463 : : new_chain[map[i - 1]] = map[old_chain[i] - 1]; \
464 : : \
465 : : data->d_buf = new_hash; \
466 : : data->d_size = nent * sizeof new_hash[0]; \
467 : : }
468 : :
469 [ + - - ]: 3 : switch (shdr->sh_entsize)
470 : : {
471 : : case 4:
472 [ - + ][ + + ]: 216 : CONVERT_HASH (Elf32_Word);
[ + + ][ + + ]
[ + + ]
473 : : break;
474 : : case 8:
475 [ # # ][ # # ]: 0 : CONVERT_HASH (Elf64_Xword);
[ # # ][ # # ]
[ # # ]
476 : : break;
477 : : default:
478 : 0 : abort ();
479 : : }
480 : :
481 : 3 : elf_flagdata (data, ELF_C_SET, ELF_F_DIRTY);
482 : 3 : update_sh_size (outscn, data);
483 : :
484 : : #undef CONVERT_HASH
485 : : }
486 : : break;
487 : :
488 : : case SHT_GNU_versym:
489 : : /* We must expand the table and move its elements around. */
490 : : {
491 : 3 : const size_t nent = symshdr->sh_size / symshdr->sh_entsize;
492 : 3 : const size_t onent = shdr->sh_size / shdr->sh_entsize;
493 [ - + ]: 3 : assert (nent >= onent);
494 : :
495 : : /* We don't bother using gelf_update_versym because there is
496 : : really no conversion to be done. */
497 : : assert (sizeof (Elf32_Versym) == sizeof (GElf_Versym));
498 : : assert (sizeof (Elf64_Versym) == sizeof (GElf_Versym));
499 : 3 : GElf_Versym *versym = xcalloc (nent, sizeof versym[0]);
500 : :
501 [ + + ]: 105 : for (size_t i = 1; i < onent; ++i)
502 : : {
503 : 102 : GElf_Versym *v = gelf_getversym (data, i, &versym[map[i - 1]]);
504 [ - + ]: 102 : ELF_CHECK (v != NULL, _("cannot get symbol version: %s"));
505 : : }
506 : :
507 : 3 : data->d_buf = versym;
508 : 3 : data->d_size = nent * shdr->sh_entsize;
509 : 3 : elf_flagdata (data, ELF_C_SET, ELF_F_DIRTY);
510 : 3 : update_sh_size (outscn, data);
511 : : }
512 : : break;
513 : :
514 : : default:
515 : 0 : error (EXIT_FAILURE, 0,
516 : 0 : _("unexpected section type in [%Zu] with sh_link to symtab"),
517 : : elf_ndxscn (inscn));
518 : : }
519 : 30 : }
520 : :
521 : : /* Adjust all the relocation sections in the file. */
522 : : static void
523 : 5 : adjust_all_relocs (Elf *elf, Elf_Scn *symtab, const GElf_Shdr *symshdr,
524 : : size_t map[])
525 : : {
526 : 5 : size_t new_sh_link = elf_ndxscn (symtab);
527 : 5 : Elf_Scn *scn = NULL;
528 [ + + ]: 152 : while ((scn = elf_nextscn (elf, scn)) != NULL)
529 [ + + ]: 147 : if (scn != symtab)
530 : : {
531 : : GElf_Shdr shdr_mem;
532 : 142 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
533 [ - + ]: 142 : ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
534 [ + + ][ + + ]: 142 : if (shdr->sh_type != SHT_NOBITS && shdr->sh_link == new_sh_link)
535 : 147 : adjust_relocs (scn, scn, shdr, map, symshdr);
536 : : }
537 : 5 : }
538 : :
539 : : /* The original file probably had section symbols for all of its
540 : : sections, even the unallocated ones. To match it as closely as
541 : : possible, add in section symbols for the added sections. */
542 : : static Elf_Data *
543 : 3 : add_new_section_symbols (Elf_Scn *old_symscn, size_t old_shnum,
544 : : Elf *elf, bool rel, Elf_Scn *symscn, size_t shnum)
545 : : {
546 : 3 : const size_t added = shnum - old_shnum;
547 : :
548 : : GElf_Shdr shdr_mem;
549 : 3 : GElf_Shdr *shdr = gelf_getshdr (symscn, &shdr_mem);
550 [ - + ]: 3 : ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
551 : :
552 : 3 : const size_t nsym = shdr->sh_size / shdr->sh_entsize;
553 : 3 : size_t symndx_map[nsym - 1];
554 : :
555 : 3 : shdr->sh_info += added;
556 : 3 : shdr->sh_size += added * shdr->sh_entsize;
557 : 3 : update_shdr (symscn, shdr);
558 : :
559 : 3 : Elf_Data *symdata = elf_getdata (symscn, NULL);
560 : 3 : Elf_Data *shndxdata = NULL; /* XXX */
561 : :
562 : 3 : symdata->d_size = shdr->sh_size;
563 : 3 : symdata->d_buf = xmalloc (symdata->d_size);
564 : :
565 : : /* Copy the existing section symbols. */
566 : 3 : Elf_Data *old_symdata = elf_getdata (old_symscn, NULL);
567 [ + + ]: 72 : for (size_t i = 0; i < old_shnum; ++i)
568 : : {
569 : : GElf_Sym sym_mem;
570 : 69 : GElf_Word shndx = SHN_UNDEF;
571 : 69 : GElf_Sym *sym = gelf_getsymshndx (old_symdata, shndxdata,
572 : : i, &sym_mem, &shndx);
573 [ - + ]: 69 : ELF_CHECK (gelf_update_symshndx (symdata, shndxdata, i,
574 : : sym, shndx),
575 : : _("cannot update symbol table: %s"));
576 : :
577 [ + + ]: 69 : if (i > 0)
578 : 66 : symndx_map[i - 1] = i;
579 : : }
580 : :
581 : : /* Add in the new section symbols. */
582 [ + + ]: 27 : for (size_t i = old_shnum; i < shnum; ++i)
583 : : {
584 : : GElf_Shdr i_shdr_mem;
585 : 24 : GElf_Shdr *i_shdr = gelf_getshdr (elf_getscn (elf, i), &i_shdr_mem);
586 [ - + ]: 24 : ELF_CHECK (i_shdr != NULL, _("cannot get section header: %s"));
587 [ + - ]: 24 : GElf_Sym sym =
588 : : {
589 [ + - ]: 24 : .st_value = rel ? 0 : i_shdr->sh_addr,
590 : : .st_info = GELF_ST_INFO (STB_LOCAL, STT_SECTION),
591 : : .st_shndx = i < SHN_LORESERVE ? i : SHN_XINDEX
592 : : };
593 [ - + ]: 24 : GElf_Word shndx = i < SHN_LORESERVE ? SHN_UNDEF : i;
594 [ - + ]: 24 : ELF_CHECK (gelf_update_symshndx (symdata, shndxdata, i,
595 : : &sym, shndx),
596 : : _("cannot update symbol table: %s"));
597 : : }
598 : :
599 : : /* Now copy the rest of the existing symbols. */
600 [ + + ]: 39 : for (size_t i = old_shnum; i < nsym; ++i)
601 : : {
602 : : GElf_Sym sym_mem;
603 : 36 : GElf_Word shndx = SHN_UNDEF;
604 : 36 : GElf_Sym *sym = gelf_getsymshndx (old_symdata, shndxdata,
605 : : i, &sym_mem, &shndx);
606 [ - + ]: 36 : ELF_CHECK (gelf_update_symshndx (symdata, shndxdata,
607 : : i + added, sym, shndx),
608 : : _("cannot update symbol table: %s"));
609 : :
610 : 36 : symndx_map[i - 1] = i + added;
611 : : }
612 : :
613 : : /* Adjust any relocations referring to the old symbol table. */
614 : 3 : adjust_all_relocs (elf, symscn, shdr, symndx_map);
615 : :
616 : 3 : return symdata;
617 : : }
618 : :
619 : : /* This has the side effect of updating STT_SECTION symbols' values,
620 : : in case of prelink adjustments. */
621 : : static Elf_Data *
622 : 7 : check_symtab_section_symbols (Elf *elf, bool rel, Elf_Scn *scn,
623 : : size_t shnum, size_t shstrndx,
624 : : Elf_Scn *oscn, size_t oshnum, size_t oshstrndx,
625 : : size_t debuglink)
626 : : {
627 : 7 : size_t n = symtab_count_leading_section_symbols (elf, oscn, oshnum,
628 : : elf_getdata (scn, NULL));
629 : :
630 [ - + ]: 7 : if (n == oshnum)
631 : 0 : return add_new_section_symbols (oscn, n, elf, rel, scn, shnum);
632 : :
633 [ + - ][ + + ]: 7 : if (n == oshstrndx || (n == debuglink && n == oshstrndx - 1))
[ + - ]
634 : 7 : return add_new_section_symbols (oscn, n, elf, rel, scn, shstrndx);
635 : :
636 : : return NULL;
637 : : }
638 : :
639 : : struct section
640 : : {
641 : : Elf_Scn *scn;
642 : : const char *name;
643 : : Elf_Scn *outscn;
644 : : struct Ebl_Strent *strent;
645 : : GElf_Shdr shdr;
646 : : };
647 : :
648 : : static int
649 : 351 : compare_alloc_sections (const struct section *s1, const struct section *s2,
650 : : bool rel)
651 : : {
652 [ + + ]: 351 : if (!rel)
653 : : {
654 : : /* Sort by address. */
655 [ + + ]: 337 : if (s1->shdr.sh_addr < s2->shdr.sh_addr)
656 : : return -1;
657 [ + - ]: 1 : if (s1->shdr.sh_addr > s2->shdr.sh_addr)
658 : : return 1;
659 : : }
660 : :
661 : : /* At the same address, preserve original section order. */
662 : 351 : return (ssize_t) elf_ndxscn (s1->scn) - (ssize_t) elf_ndxscn (s2->scn);
663 : : }
664 : :
665 : : static int
666 : 311 : compare_unalloc_sections (const GElf_Shdr *shdr1, const GElf_Shdr *shdr2,
667 : : const char *name1, const char *name2)
668 : : {
669 : : /* Sort by sh_flags as an arbitrary ordering. */
670 [ + - ]: 311 : if (shdr1->sh_flags < shdr2->sh_flags)
671 : : return -1;
672 [ + + ]: 311 : if (shdr1->sh_flags > shdr2->sh_flags)
673 : : return 1;
674 : :
675 : : /* Sort by name as last resort. */
676 : 311 : return strcmp (name1, name2);
677 : : }
678 : :
679 : : static int
680 : 434 : compare_sections (const void *a, const void *b, bool rel)
681 : : {
682 : 434 : const struct section *s1 = a;
683 : 434 : const struct section *s2 = b;
684 : :
685 : : /* Sort all non-allocated sections last. */
686 [ + + ]: 434 : if ((s1->shdr.sh_flags ^ s2->shdr.sh_flags) & SHF_ALLOC)
687 [ + + ]: 36 : return (s1->shdr.sh_flags & SHF_ALLOC) ? -1 : 1;
688 : :
689 : 434 : return ((s1->shdr.sh_flags & SHF_ALLOC)
690 : 351 : ? compare_alloc_sections (s1, s2, rel)
691 [ + + ]: 398 : : compare_unalloc_sections (&s1->shdr, &s2->shdr,
692 : : s1->name, s2->name));
693 : : }
694 : :
695 : : static int
696 : 55 : compare_sections_rel (const void *a, const void *b)
697 : : {
698 : 55 : return compare_sections (a, b, true);
699 : : }
700 : :
701 : : static int
702 : 379 : compare_sections_nonrel (const void *a, const void *b)
703 : : {
704 : 379 : return compare_sections (a, b, false);
705 : : }
706 : :
707 : :
708 : : struct symbol
709 : : {
710 : : size_t *map;
711 : :
712 : : union
713 : : {
714 : : const char *name;
715 : : struct Ebl_Strent *strent;
716 : : };
717 : : union
718 : : {
719 : : struct
720 : : {
721 : : GElf_Addr value;
722 : : GElf_Xword size;
723 : : GElf_Word shndx;
724 : : union
725 : : {
726 : : struct
727 : : {
728 : : uint8_t info;
729 : : uint8_t other;
730 : : } info;
731 : : int16_t compare;
732 : : };
733 : : };
734 : :
735 : : /* For a symbol discarded after first sort, this matches its better's
736 : : map pointer. */
737 : : size_t *duplicate;
738 : : };
739 : : };
740 : :
741 : : /* Collect input symbols into our internal form. */
742 : : static void
743 : 4 : collect_symbols (Elf *outelf, bool rel, Elf_Scn *symscn, Elf_Scn *strscn,
744 : : const size_t nent, const GElf_Addr bias,
745 : : const size_t scnmap[], struct symbol *table, size_t *map,
746 : : struct section *split_bss)
747 : : {
748 : 4 : Elf_Data *symdata = elf_getdata (symscn, NULL);
749 : 4 : Elf_Data *strdata = elf_getdata (strscn, NULL);
750 : 4 : Elf_Data *shndxdata = NULL; /* XXX */
751 : :
752 [ + + ]: 210 : for (size_t i = 1; i < nent; ++i)
753 : : {
754 : : GElf_Sym sym_mem;
755 : 206 : GElf_Word shndx = SHN_UNDEF;
756 : 206 : GElf_Sym *sym = gelf_getsymshndx (symdata, shndxdata, i,
757 : : &sym_mem, &shndx);
758 [ - + ]: 206 : ELF_CHECK (sym != NULL, _("cannot get symbol table entry: %s"));
759 [ + - ]: 206 : if (sym->st_shndx != SHN_XINDEX)
760 : 206 : shndx = sym->st_shndx;
761 : :
762 [ - + ]: 206 : if (sym->st_name >= strdata->d_size)
763 : : error (EXIT_FAILURE, 0,
764 : 0 : _("invalid string offset in symbol [%Zu]"), i);
765 : :
766 : 206 : struct symbol *s = &table[i - 1];
767 : 206 : s->map = &map[i - 1];
768 : 206 : s->name = strdata->d_buf + sym->st_name;
769 : 206 : s->value = sym->st_value + bias;
770 : 206 : s->size = sym->st_size;
771 : 206 : s->shndx = shndx;
772 : 206 : s->info.info = sym->st_info;
773 : 206 : s->info.other = sym->st_other;
774 : :
775 [ + + ][ + + ]: 206 : if (scnmap != NULL && shndx != SHN_UNDEF && shndx < SHN_LORESERVE)
[ + + ]
776 : 29 : s->shndx = scnmap[shndx - 1];
777 : :
778 [ + + ][ - + ]: 206 : if (GELF_ST_TYPE (s->info.info) == STT_SECTION && !rel)
779 : 0 : {
780 : : /* Update the value to match the output section. */
781 : : GElf_Shdr shdr_mem;
782 : 0 : GElf_Shdr *shdr = gelf_getshdr (elf_getscn (outelf, s->shndx),
783 : : &shdr_mem);
784 [ # # ]: 0 : ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
785 : 0 : s->value = shdr->sh_addr;
786 : : }
787 [ - + ]: 206 : else if (split_bss != NULL
788 [ # # ]: 0 : && s->value < split_bss->shdr.sh_addr
789 [ # # ]: 0 : && s->value >= split_bss[-1].shdr.sh_addr
790 [ # # ]: 0 : && shndx == elf_ndxscn (split_bss->outscn))
791 : : /* This symbol was in .bss and was split into .dynbss. */
792 : 0 : s->shndx = elf_ndxscn (split_bss[-1].outscn);
793 : : }
794 : 4 : }
795 : :
796 : :
797 : : #define CMP(value) \
798 : : if (s1->value < s2->value) \
799 : : return -1; \
800 : : if (s1->value > s2->value) \
801 : : return 1
802 : :
803 : : /* Compare symbols with a consistent ordering,
804 : : but one only meaningful for equality. */
805 : : static int
806 : 1321 : compare_symbols (const void *a, const void *b)
807 : : {
808 : 1321 : const struct symbol *s1 = a;
809 : 1321 : const struct symbol *s2 = b;
810 : :
811 [ + + ][ + + ]: 1321 : CMP (value);
812 [ + + ][ + + ]: 1204 : CMP (size);
813 [ + + ][ + + ]: 1135 : CMP (shndx);
814 : :
815 [ + + ]: 1321 : return (s1->compare - s2->compare) ?: strcmp (s1->name, s2->name);
816 : : }
817 : :
818 : : /* Compare symbols for output order after slots have been assigned. */
819 : : static int
820 : 1199 : compare_symbols_output (const void *a, const void *b)
821 : : {
822 : 1199 : const struct symbol *s1 = a;
823 : 1199 : const struct symbol *s2 = b;
824 : : int cmp;
825 : :
826 : : /* Sort discarded symbols last. */
827 : 1199 : cmp = (s1->name == NULL) - (s2->name == NULL);
828 : :
829 [ + + ]: 1199 : if (cmp == 0)
830 : : /* Local symbols must come first. */
831 : 952 : cmp = ((GELF_ST_BIND (s2->info.info) == STB_LOCAL)
832 : 952 : - (GELF_ST_BIND (s1->info.info) == STB_LOCAL));
833 : :
834 [ + + ]: 1199 : if (cmp == 0)
835 : : /* binutils always puts section symbols first. */
836 : 808 : cmp = ((GELF_ST_TYPE (s2->info.info) == STT_SECTION)
837 : 808 : - (GELF_ST_TYPE (s1->info.info) == STT_SECTION));
838 : :
839 [ + + ]: 1199 : if (cmp == 0)
840 : : {
841 [ + + ]: 774 : if (GELF_ST_TYPE (s1->info.info) == STT_SECTION)
842 : : {
843 : : /* binutils always puts section symbols in section index order. */
844 [ - + ][ # # ]: 70 : CMP (shndx);
845 : : else
846 [ # # ]: 0 : assert (s1 == s2);
847 : : }
848 : :
849 : : /* Nothing really matters, so preserve the original order. */
850 [ + + ][ - + ]: 704 : CMP (map);
851 : : else
852 [ # # ]: 1199 : assert (s1 == s2);
853 : : }
854 : :
855 : : return cmp;
856 : : }
857 : :
858 : : #undef CMP
859 : :
860 : : /* Return true iff the flags, size, and name match. */
861 : : static bool
862 : 159 : sections_match (const struct section *sections, size_t i,
863 : : const GElf_Shdr *shdr, const char *name)
864 : : {
865 : 159 : return (sections[i].shdr.sh_flags == shdr->sh_flags
866 [ + + ]: 158 : && (sections[i].shdr.sh_size == shdr->sh_size
867 [ + - ]: 7 : || (sections[i].shdr.sh_size < shdr->sh_size
868 [ + - ]: 7 : && section_can_shrink (§ions[i].shdr)))
869 [ + + ][ - + ]: 317 : && !strcmp (sections[i].name, name));
870 : : }
871 : :
872 : : /* Locate a matching allocated section in SECTIONS. */
873 : : static struct section *
874 : 148 : find_alloc_section (const GElf_Shdr *shdr, GElf_Addr bias, const char *name,
875 : : struct section sections[], size_t nalloc)
876 : : {
877 : 148 : const GElf_Addr addr = shdr->sh_addr + bias;
878 : 148 : size_t l = 0, u = nalloc;
879 [ + - ]: 707 : while (l < u)
880 : : {
881 : 559 : size_t i = (l + u) / 2;
882 [ + + ]: 559 : if (addr < sections[i].shdr.sh_addr)
883 : : u = i;
884 [ + + ]: 322 : else if (addr > sections[i].shdr.sh_addr)
885 : 174 : l = i + 1;
886 : : else
887 : : {
888 : : /* We've found allocated sections with this address.
889 : : Find one with matching size, flags, and name. */
890 [ + + ][ + + ]: 150 : while (i > 0 && sections[i - 1].shdr.sh_addr == addr)
891 : 2 : --i;
892 [ + - ][ + - ]: 560 : for (; i < nalloc && sections[i].shdr.sh_addr == addr;
893 : 1 : ++i)
894 [ + + ]: 149 : if (sections_match (sections, i, shdr, name))
895 : : return §ions[i];
896 : : break;
897 : : }
898 : : }
899 : : return NULL;
900 : : }
901 : :
902 : : static inline const char *
903 : 263 : get_section_name (size_t ndx, const GElf_Shdr *shdr, const Elf_Data *shstrtab)
904 : : {
905 [ - + ]: 263 : if (shdr->sh_name >= shstrtab->d_size)
906 : 0 : error (EXIT_FAILURE, 0, _("cannot read section [%Zu] name: %s"),
907 : : ndx, elf_errmsg (-1));
908 : 263 : return shstrtab->d_buf + shdr->sh_name;
909 : : }
910 : :
911 : : /* Fix things up when prelink has moved some allocated sections around
912 : : and the debuginfo file's section headers no longer match up.
913 : : This fills in SECTIONS[0..NALLOC-1].outscn or exits.
914 : : If there was a .bss section that was split into two sections
915 : : with the new one preceding it in sh_addr, we return that pointer. */
916 : : static struct section *
917 : 0 : find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
918 : : Elf *main, const GElf_Ehdr *main_ehdr,
919 : : Elf_Data *main_shstrtab, GElf_Addr bias,
920 : : struct section *sections,
921 : : size_t nalloc, size_t nsections)
922 : : {
923 : : /* Clear assignments that might have been bogus. */
924 [ # # ]: 0 : for (size_t i = 0; i < nalloc; ++i)
925 : 0 : sections[i].outscn = NULL;
926 : :
927 : : Elf_Scn *undo = NULL;
928 [ # # ]: 0 : for (size_t i = nalloc; i < nsections; ++i)
929 : : {
930 : 0 : const struct section *sec = §ions[i];
931 [ # # ]: 0 : if (sec->shdr.sh_type == SHT_PROGBITS
932 [ # # ]: 0 : && !(sec->shdr.sh_flags & SHF_ALLOC)
933 [ # # ]: 0 : && !strcmp (sec->name, ".gnu.prelink_undo"))
934 : : {
935 : 0 : undo = sec->scn;
936 : : break;
937 : : }
938 : : }
939 : :
940 : : /* Find the original allocated sections before prelinking. */
941 : 0 : struct section *undo_sections = NULL;
942 : 0 : size_t undo_nalloc = 0;
943 [ # # ]: 0 : if (undo != NULL)
944 : : {
945 : 0 : Elf_Data *undodata = elf_rawdata (undo, NULL);
946 [ # # ]: 0 : ELF_CHECK (undodata != NULL,
947 : : _("cannot read '.gnu.prelink_undo' section: %s"));
948 : :
949 : : union
950 : : {
951 : : Elf32_Ehdr e32;
952 : : Elf64_Ehdr e64;
953 : : } ehdr;
954 : 0 : Elf_Data dst =
955 : : {
956 : : .d_buf = &ehdr,
957 : : .d_size = sizeof ehdr,
958 : : .d_type = ELF_T_EHDR,
959 : : .d_version = EV_CURRENT
960 : : };
961 : 0 : Elf_Data src = *undodata;
962 : 0 : src.d_size = gelf_fsize (main, ELF_T_EHDR, 1, EV_CURRENT);
963 : 0 : src.d_type = ELF_T_EHDR;
964 [ # # ]: 0 : ELF_CHECK (gelf_xlatetom (main, &dst, &src,
965 : : main_ehdr->e_ident[EI_DATA]) != NULL,
966 : : _("cannot read '.gnu.prelink_undo' section: %s"));
967 : :
968 : : uint_fast16_t phnum;
969 : : uint_fast16_t shnum;
970 [ # # ]: 0 : if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
971 : : {
972 : 0 : phnum = ehdr.e32.e_phnum;
973 : 0 : shnum = ehdr.e32.e_shnum;
974 : : }
975 : : else
976 : : {
977 : 0 : phnum = ehdr.e64.e_phnum;
978 : 0 : shnum = ehdr.e64.e_shnum;
979 : : }
980 : :
981 : 0 : size_t phsize = gelf_fsize (main, ELF_T_PHDR, phnum, EV_CURRENT);
982 : 0 : src.d_buf += src.d_size + phsize;
983 : 0 : src.d_size = gelf_fsize (main, ELF_T_SHDR, shnum - 1, EV_CURRENT);
984 : 0 : src.d_type = ELF_T_SHDR;
985 [ # # ]: 0 : if ((size_t) (src.d_buf - undodata->d_buf) > undodata->d_size
986 [ # # ]: 0 : || undodata->d_size - (src.d_buf - undodata->d_buf) != src.d_size)
987 : 0 : error (EXIT_FAILURE, 0, _("invalid contents in '%s' section"),
988 : : ".gnu.prelink_undo");
989 : :
990 : 0 : union
991 : : {
992 : 0 : Elf32_Shdr s32[shnum - 1];
993 : 0 : Elf64_Shdr s64[shnum - 1];
994 : 0 : } shdr;
995 : 0 : dst.d_buf = &shdr;
996 : 0 : dst.d_size = sizeof shdr;
997 [ # # ]: 0 : ELF_CHECK (gelf_xlatetom (main, &dst, &src,
998 : : main_ehdr->e_ident[EI_DATA]) != NULL,
999 : : _("cannot read '.gnu.prelink_undo' section: %s"));
1000 : :
1001 : 0 : undo_sections = xmalloc ((shnum - 1) * sizeof undo_sections[0]);
1002 [ # # ]: 0 : for (size_t i = 0; i < shnum - 1; ++i)
1003 : : {
1004 : 0 : struct section *sec = &undo_sections[undo_nalloc];
1005 [ # # ]: 0 : if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
1006 : : {
1007 : : #define COPY(field) sec->shdr.field = shdr.s32[i].field
1008 : 0 : COPY (sh_name);
1009 : 0 : COPY (sh_type);
1010 : 0 : COPY (sh_flags);
1011 : 0 : COPY (sh_addr);
1012 : 0 : COPY (sh_offset);
1013 : 0 : COPY (sh_size);
1014 : 0 : COPY (sh_link);
1015 : 0 : COPY (sh_info);
1016 : 0 : COPY (sh_addralign);
1017 : 0 : COPY (sh_entsize);
1018 : : #undef COPY
1019 : : }
1020 : : else
1021 : 0 : sec->shdr = shdr.s64[i];
1022 [ # # ]: 0 : if (sec->shdr.sh_flags & SHF_ALLOC)
1023 : : {
1024 : 0 : sec->shdr.sh_addr += bias;
1025 : 0 : sec->name = get_section_name (i + 1, &sec->shdr, main_shstrtab);
1026 : 0 : sec->scn = elf_getscn (main, i + 1); /* Really just for ndx. */
1027 : 0 : sec->outscn = NULL;
1028 : 0 : sec->strent = NULL;
1029 : 0 : ++undo_nalloc;
1030 : : }
1031 : : }
1032 : 0 : qsort (undo_sections, undo_nalloc,
1033 : : sizeof undo_sections[0], compare_sections_nonrel);
1034 : : }
1035 : :
1036 : 0 : bool fail = false;
1037 : 0 : inline void check_match (bool match, Elf_Scn *scn, const char *name)
1038 : : {
1039 [ # # ]: 0 : if (!match)
1040 : : {
1041 : 0 : fail = true;
1042 : 0 : error (0, 0, _("cannot find matching section for [%Zu] '%s'"),
1043 : : elf_ndxscn (scn), name);
1044 : : }
1045 : 0 : }
1046 : :
1047 : 0 : Elf_Scn *scn = NULL;
1048 [ # # ]: 0 : while ((scn = elf_nextscn (debug, scn)) != NULL)
1049 : : {
1050 : : GElf_Shdr shdr_mem;
1051 : 0 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1052 [ # # ]: 0 : ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
1053 : :
1054 [ # # ]: 0 : if (!(shdr->sh_flags & SHF_ALLOC))
1055 : 0 : continue;
1056 : :
1057 : 0 : const char *name = get_section_name (elf_ndxscn (scn), shdr,
1058 : : debug_shstrtab);
1059 : :
1060 [ # # ]: 0 : if (undo_sections != NULL)
1061 : : {
1062 : 0 : struct section *sec = find_alloc_section (shdr, 0, name,
1063 : : undo_sections,
1064 : : undo_nalloc);
1065 [ # # ]: 0 : if (sec != NULL)
1066 : : {
1067 : 0 : sec->outscn = scn;
1068 : 0 : continue;
1069 : : }
1070 : : }
1071 : :
1072 : : /* If there is no prelink info, we are just here to find
1073 : : the sections to give error messages about. */
1074 [ # # ]: 0 : for (size_t i = 0; shdr != NULL && i < nalloc; ++i)
1075 [ # # ]: 0 : if (sections[i].outscn == scn)
1076 : 0 : shdr = NULL;
1077 : 0 : check_match (shdr == NULL, scn, name);
1078 : : }
1079 : :
1080 [ # # ]: 0 : if (fail)
1081 : 0 : exit (EXIT_FAILURE);
1082 : :
1083 : : /* Now we have lined up output sections for each of the original sections
1084 : : before prelinking. Translate those to the prelinked sections.
1085 : : This matches what prelink's undo_sections does. */
1086 : : struct section *split_bss = NULL;
1087 [ # # ]: 0 : for (size_t i = 0; i < undo_nalloc; ++i)
1088 : : {
1089 : 0 : const struct section *undo_sec = &undo_sections[i];
1090 : :
1091 : 0 : const char *name = undo_sec->name;
1092 : 0 : scn = undo_sec->scn; /* This is just for elf_ndxscn. */
1093 : :
1094 [ # # ]: 0 : for (size_t j = 0; j < nalloc; ++j)
1095 : : {
1096 : 0 : struct section *sec = §ions[j];
1097 : : #define RELA_SCALED(field) \
1098 : : (2 * sec->shdr.field == 3 * undo_sec->shdr.field)
1099 [ # # ]: 0 : if (sec->outscn == NULL
1100 [ # # ]: 0 : && sec->shdr.sh_name == undo_sec->shdr.sh_name
1101 [ # # ]: 0 : && sec->shdr.sh_flags == undo_sec->shdr.sh_flags
1102 [ # # ]: 0 : && sec->shdr.sh_addralign == undo_sec->shdr.sh_addralign
1103 [ # # ]: 0 : && (((sec->shdr.sh_type == undo_sec->shdr.sh_type
1104 [ # # ]: 0 : && sec->shdr.sh_entsize == undo_sec->shdr.sh_entsize
1105 [ # # ]: 0 : && (sec->shdr.sh_size == undo_sec->shdr.sh_size
1106 [ # # ]: 0 : || (sec->shdr.sh_size > undo_sec->shdr.sh_size
1107 [ # # ]: 0 : && main_ehdr->e_type == ET_EXEC
1108 [ # # ]: 0 : && !strcmp (sec->name, ".dynstr"))))
1109 [ # # ]: 0 : || (sec->shdr.sh_size == undo_sec->shdr.sh_size
1110 [ # # ]: 0 : && ((sec->shdr.sh_entsize == undo_sec->shdr.sh_entsize
1111 [ # # ]: 0 : && undo_sec->shdr.sh_type == SHT_NOBITS)
1112 [ # # ]: 0 : || undo_sec->shdr.sh_type == SHT_PROGBITS)
1113 [ # # ]: 0 : && !strcmp (sec->name, ".plt")))
1114 [ # # ]: 0 : || (sec->shdr.sh_type == SHT_RELA
1115 [ # # ]: 0 : && undo_sec->shdr.sh_type == SHT_REL
1116 [ # # ][ # # ]: 0 : && RELA_SCALED (sh_entsize) && RELA_SCALED (sh_size))
1117 [ # # ]: 0 : || (sec->shdr.sh_entsize == undo_sec->shdr.sh_entsize
1118 [ # # ]: 0 : && (sec->shdr.sh_type == undo_sec->shdr.sh_type
1119 [ # # ]: 0 : || (sec->shdr.sh_type == SHT_PROGBITS
1120 [ # # ]: 0 : && undo_sec->shdr.sh_type == SHT_NOBITS))
1121 [ # # ]: 0 : && sec->shdr.sh_size < undo_sec->shdr.sh_size
1122 [ # # ]: 0 : && (!strcmp (sec->name, ".bss")
1123 [ # # ]: 0 : || !strcmp (sec->name, ".sbss"))
1124 [ # # ]: 0 : && (split_bss = sec) > sections)))
1125 : : {
1126 : 0 : sec->outscn = undo_sec->outscn;
1127 : 0 : undo_sec = NULL;
1128 : : break;
1129 : : }
1130 : : }
1131 : :
1132 : 0 : check_match (undo_sec == NULL, scn, name);
1133 : : }
1134 : :
1135 : 0 : free (undo_sections);
1136 : :
1137 [ # # ]: 0 : if (fail)
1138 : 0 : exit (EXIT_FAILURE);
1139 : :
1140 : 0 : return split_bss;
1141 : : }
1142 : :
1143 : : /* Create new .shstrtab contents, subroutine of copy_elided_sections.
1144 : : This can't be open coded there and still use variable-length auto arrays,
1145 : : since the end of our block would free other VLAs too. */
1146 : : static Elf_Data *
1147 : 9 : new_shstrtab (Elf *unstripped, size_t unstripped_shnum,
1148 : : Elf_Data *shstrtab, size_t unstripped_shstrndx,
1149 : : struct section *sections, size_t stripped_shnum,
1150 : : struct Ebl_Strtab *strtab)
1151 : : {
1152 [ - + ]: 9 : if (strtab == NULL)
1153 : : return NULL;
1154 : :
1155 : 0 : struct Ebl_Strent *unstripped_strent[unstripped_shnum - 1];
1156 : 0 : memset (unstripped_strent, 0, sizeof unstripped_strent);
1157 [ # # ]: 0 : for (struct section *sec = sections;
1158 : 0 : sec < §ions[stripped_shnum - 1];
1159 : 0 : ++sec)
1160 [ # # ]: 0 : if (sec->outscn != NULL)
1161 : : {
1162 [ # # ]: 0 : if (sec->strent == NULL)
1163 : : {
1164 : 0 : sec->strent = ebl_strtabadd (strtab, sec->name, 0);
1165 [ # # ]: 0 : ELF_CHECK (sec->strent != NULL,
1166 : : _("cannot add section name to string table: %s"));
1167 : : }
1168 : 0 : unstripped_strent[elf_ndxscn (sec->outscn) - 1] = sec->strent;
1169 : : }
1170 : :
1171 : : /* Add names of sections we aren't touching. */
1172 [ # # ]: 0 : for (size_t i = 0; i < unstripped_shnum - 1; ++i)
1173 [ # # ]: 0 : if (unstripped_strent[i] == NULL)
1174 : : {
1175 : 0 : Elf_Scn *scn = elf_getscn (unstripped, i + 1);
1176 : : GElf_Shdr shdr_mem;
1177 : 0 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1178 : 0 : const char *name = get_section_name (i + 1, shdr, shstrtab);
1179 : 0 : unstripped_strent[i] = ebl_strtabadd (strtab, name, 0);
1180 [ # # ]: 0 : ELF_CHECK (unstripped_strent[i] != NULL,
1181 : : _("cannot add section name to string table: %s"));
1182 : : }
1183 : : else
1184 : 0 : unstripped_strent[i] = NULL;
1185 : :
1186 : : /* Now finalize the string table so we can get offsets. */
1187 : 0 : Elf_Data *strtab_data = elf_getdata (elf_getscn (unstripped,
1188 : : unstripped_shstrndx), NULL);
1189 [ # # ]: 0 : ELF_CHECK (elf_flagdata (strtab_data, ELF_C_SET, ELF_F_DIRTY),
1190 : : _("cannot update section header string table data: %s"));
1191 : 0 : ebl_strtabfinalize (strtab, strtab_data);
1192 : :
1193 : : /* Update the sh_name fields of sections we aren't modifying later. */
1194 [ # # ]: 9 : for (size_t i = 0; i < unstripped_shnum - 1; ++i)
1195 [ # # ]: 0 : if (unstripped_strent[i] != NULL)
1196 : : {
1197 : 0 : Elf_Scn *scn = elf_getscn (unstripped, i + 1);
1198 : : GElf_Shdr shdr_mem;
1199 : 0 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1200 : 0 : shdr->sh_name = ebl_strtaboffset (unstripped_strent[i]);
1201 [ # # ]: 0 : if (i + 1 == unstripped_shstrndx)
1202 : 0 : shdr->sh_size = strtab_data->d_size;
1203 : 0 : update_shdr (scn, shdr);
1204 : : }
1205 : :
1206 : : return strtab_data;
1207 : : }
1208 : :
1209 : : /* Fill in any SHT_NOBITS sections in UNSTRIPPED by
1210 : : copying their contents and sh_type from STRIPPED. */
1211 : : static void
1212 : 9 : copy_elided_sections (Elf *unstripped, Elf *stripped,
1213 : : const GElf_Ehdr *stripped_ehdr, GElf_Addr bias)
1214 : : {
1215 : : size_t unstripped_shstrndx;
1216 [ - + ]: 9 : ELF_CHECK (elf_getshdrstrndx (unstripped, &unstripped_shstrndx) == 0,
1217 : : _("cannot get section header string table section index: %s"));
1218 : :
1219 : : size_t stripped_shstrndx;
1220 [ - + ]: 9 : ELF_CHECK (elf_getshdrstrndx (stripped, &stripped_shstrndx) == 0,
1221 : : _("cannot get section header string table section index: %s"));
1222 : :
1223 : : size_t unstripped_shnum;
1224 [ - + ]: 9 : ELF_CHECK (elf_getshdrnum (unstripped, &unstripped_shnum) == 0,
1225 : : _("cannot get section count: %s"));
1226 : :
1227 : : size_t stripped_shnum;
1228 [ - + ]: 9 : ELF_CHECK (elf_getshdrnum (stripped, &stripped_shnum) == 0,
1229 : : _("cannot get section count: %s"));
1230 : :
1231 [ - + ]: 9 : if (unlikely (stripped_shnum > unstripped_shnum))
1232 : 0 : error (EXIT_FAILURE, 0, _("\
1233 : : more sections in stripped file than debug file -- arguments reversed?"));
1234 : :
1235 : : /* Cache the stripped file's section details. */
1236 : 9 : struct section sections[stripped_shnum - 1];
1237 : 9 : Elf_Scn *scn = NULL;
1238 [ + + ]: 204 : while ((scn = elf_nextscn (stripped, scn)) != NULL)
1239 : : {
1240 : 195 : size_t i = elf_ndxscn (scn) - 1;
1241 : 195 : GElf_Shdr *shdr = gelf_getshdr (scn, §ions[i].shdr);
1242 [ - + ]: 195 : ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
1243 : 195 : sections[i].name = elf_strptr (stripped, stripped_shstrndx,
1244 : 195 : shdr->sh_name);
1245 [ - + ]: 195 : if (sections[i].name == NULL)
1246 : 0 : error (EXIT_FAILURE, 0, _("cannot read section [%Zu] name: %s"),
1247 : : elf_ndxscn (scn), elf_errmsg (-1));
1248 : 195 : sections[i].scn = scn;
1249 : 195 : sections[i].outscn = NULL;
1250 : 195 : sections[i].strent = NULL;
1251 : : }
1252 : :
1253 : 9 : const struct section *stripped_symtab = NULL;
1254 : :
1255 : : /* Sort the sections, allocated by address and others after. */
1256 [ + + ]: 9 : qsort (sections, stripped_shnum - 1, sizeof sections[0],
1257 : 9 : stripped_ehdr->e_type == ET_REL
1258 : : ? compare_sections_rel : compare_sections_nonrel);
1259 : 9 : size_t nalloc = stripped_shnum - 1;
1260 [ + - ][ + + ]: 46 : while (nalloc > 0 && !(sections[nalloc - 1].shdr.sh_flags & SHF_ALLOC))
1261 : : {
1262 : 37 : --nalloc;
1263 [ + + ]: 37 : if (sections[nalloc].shdr.sh_type == SHT_SYMTAB)
1264 : 37 : stripped_symtab = §ions[nalloc];
1265 : : }
1266 : :
1267 : : /* Locate a matching unallocated section in SECTIONS. */
1268 : 105 : inline struct section *find_unalloc_section (const GElf_Shdr *shdr,
1269 : : const char *name)
1270 : : {
1271 : 105 : size_t l = nalloc, u = stripped_shnum - 1;
1272 [ + + ]: 369 : while (l < u)
1273 : : {
1274 : 264 : size_t i = (l + u) / 2;
1275 : 264 : struct section *sec = §ions[i];
1276 : 264 : int cmp = compare_unalloc_sections (shdr, &sec->shdr,
1277 : : name, sec->name);
1278 [ + + ]: 264 : if (cmp < 0)
1279 : : u = i;
1280 [ + + ]: 126 : else if (cmp > 0)
1281 : 247 : l = i + 1;
1282 : : else
1283 : : return sec;
1284 : : }
1285 : : return NULL;
1286 : : }
1287 : :
1288 : 9 : Elf_Data *shstrtab = elf_getdata (elf_getscn (unstripped,
1289 : : unstripped_shstrndx), NULL);
1290 [ + - ]: 9 : ELF_CHECK (shstrtab != NULL,
1291 : : _("cannot read section header string table: %s"));
1292 : :
1293 : : /* Match each debuginfo section with its corresponding stripped section. */
1294 : : bool check_prelink = false;
1295 : : Elf_Scn *unstripped_symtab = NULL;
1296 : : size_t alloc_avail = 0;
1297 : : scn = NULL;
1298 [ + + ]: 290 : while ((scn = elf_nextscn (unstripped, scn)) != NULL)
1299 : : {
1300 : : GElf_Shdr shdr_mem;
1301 : 281 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1302 [ - + ]: 281 : ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
1303 : :
1304 [ + + ]: 281 : if (shdr->sh_type == SHT_SYMTAB)
1305 : : {
1306 : 9 : unstripped_symtab = scn;
1307 : 9 : continue;
1308 : : }
1309 : :
1310 : 272 : const size_t ndx = elf_ndxscn (scn);
1311 [ + + ]: 272 : if (ndx == unstripped_shstrndx)
1312 : 9 : continue;
1313 : :
1314 : 263 : const char *name = get_section_name (ndx, shdr, shstrtab);
1315 : :
1316 : 263 : struct section *sec = NULL;
1317 [ + + ]: 263 : if (shdr->sh_flags & SHF_ALLOC)
1318 : : {
1319 [ + + ]: 158 : if (stripped_ehdr->e_type != ET_REL)
1320 : : {
1321 : : /* Look for the section that matches. */
1322 : 148 : sec = find_alloc_section (shdr, bias, name, sections, nalloc);
1323 [ - + ]: 148 : if (sec == NULL)
1324 : : {
1325 : : /* We couldn't figure it out. It may be a prelink issue. */
1326 : 0 : check_prelink = true;
1327 : 0 : continue;
1328 : : }
1329 : : }
1330 : : else
1331 : : {
1332 : : /* The sh_addr of allocated sections does not help us,
1333 : : but the order usually matches. */
1334 [ + - ]: 10 : if (likely (sections_match (sections, alloc_avail, shdr, name)))
1335 : 10 : sec = §ions[alloc_avail++];
1336 : : else
1337 [ # # ]: 0 : for (size_t i = alloc_avail + 1; i < nalloc; ++i)
1338 [ # # ]: 0 : if (sections_match (sections, i, shdr, name))
1339 : : {
1340 : 0 : sec = §ions[i];
1341 : 0 : break;
1342 : : }
1343 : : }
1344 : : }
1345 : : else
1346 : : {
1347 : : /* Look for the section that matches. */
1348 : 105 : sec = find_unalloc_section (shdr, name);
1349 [ + + ]: 105 : if (sec == NULL)
1350 : : {
1351 : : /* An additional unallocated section is fine if not SHT_NOBITS.
1352 : : We looked it up anyway in case it's an unallocated section
1353 : : copied in both files (e.g. SHT_NOTE), and don't keep both. */
1354 [ + - ]: 88 : if (shdr->sh_type != SHT_NOBITS)
1355 : 88 : continue;
1356 : :
1357 : : /* Somehow some old .debug files wound up with SHT_NOBITS
1358 : : .comment sections, so let those pass. */
1359 [ # # ]: 0 : if (!strcmp (name, ".comment"))
1360 : 0 : continue;
1361 : : }
1362 : : }
1363 : :
1364 [ - + ]: 175 : if (sec == NULL)
1365 : 0 : error (EXIT_FAILURE, 0,
1366 : 0 : _("cannot find matching section for [%Zu] '%s'"),
1367 : : elf_ndxscn (scn), name);
1368 : :
1369 : 281 : sec->outscn = scn;
1370 : : }
1371 : :
1372 : : /* If that failed due to changes made by prelink, we take another tack.
1373 : : We keep track of a .bss section that was partly split into .dynbss
1374 : : so that collect_symbols can update symbols' st_shndx fields. */
1375 : 9 : struct section *split_bss = NULL;
1376 [ - + ]: 9 : if (check_prelink)
1377 : : {
1378 : 0 : Elf_Data *data = elf_getdata (elf_getscn (stripped, stripped_shstrndx),
1379 : : NULL);
1380 [ # # ]: 0 : ELF_CHECK (data != NULL,
1381 : : _("cannot read section header string table: %s"));
1382 : 0 : split_bss = find_alloc_sections_prelink (unstripped, shstrtab,
1383 : : stripped, stripped_ehdr,
1384 : 0 : data, bias, sections,
1385 : : nalloc, stripped_shnum - 1);
1386 : : }
1387 : :
1388 : : /* Make sure each main file section has a place to go. */
1389 : 9 : const struct section *stripped_dynsym = NULL;
1390 : 9 : size_t debuglink = SHN_UNDEF;
1391 : 9 : size_t ndx_section[stripped_shnum - 1];
1392 : 9 : struct Ebl_Strtab *strtab = NULL;
1393 [ + + ]: 204 : for (struct section *sec = sections;
1394 : 204 : sec < §ions[stripped_shnum - 1];
1395 : 195 : ++sec)
1396 : : {
1397 : 195 : size_t secndx = elf_ndxscn (sec->scn);
1398 : :
1399 [ + + ]: 195 : if (sec->outscn == NULL)
1400 : : {
1401 : : /* We didn't find any corresponding section for this. */
1402 : :
1403 [ + + ]: 20 : if (secndx == stripped_shstrndx)
1404 : : {
1405 : : /* We only need one .shstrtab. */
1406 : 9 : ndx_section[secndx - 1] = unstripped_shstrndx;
1407 : 9 : continue;
1408 : : }
1409 : :
1410 [ + + ]: 11 : if (unstripped_symtab != NULL && sec == stripped_symtab)
1411 : : {
1412 : : /* We don't need a second symbol table. */
1413 : 2 : ndx_section[secndx - 1] = elf_ndxscn (unstripped_symtab);
1414 : 2 : continue;
1415 : : }
1416 : :
1417 [ + + ]: 9 : if (unstripped_symtab != NULL && stripped_symtab != NULL
1418 [ - + ]: 2 : && secndx == stripped_symtab->shdr.sh_link)
1419 : : {
1420 : : /* ... nor its string table. */
1421 : : GElf_Shdr shdr_mem;
1422 : 0 : GElf_Shdr *shdr = gelf_getshdr (unstripped_symtab, &shdr_mem);
1423 [ # # ]: 0 : ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
1424 : 0 : ndx_section[secndx - 1] = shdr->sh_link;
1425 : 0 : continue;
1426 : : }
1427 : :
1428 [ + - ]: 9 : if (!(sec->shdr.sh_flags & SHF_ALLOC)
1429 [ + - ]: 9 : && !strcmp (sec->name, ".gnu_debuglink"))
1430 : : {
1431 : : /* This was created by stripping. We don't want it. */
1432 : 9 : debuglink = secndx;
1433 : 9 : ndx_section[secndx - 1] = SHN_UNDEF;
1434 : 9 : continue;
1435 : : }
1436 : :
1437 : 0 : sec->outscn = elf_newscn (unstripped);
1438 : 0 : Elf_Data *newdata = elf_newdata (sec->outscn);
1439 [ # # ][ # # ]: 0 : ELF_CHECK (newdata != NULL && gelf_update_shdr (sec->outscn,
1440 : : &sec->shdr),
1441 : : _("cannot add new section: %s"));
1442 : :
1443 [ # # ]: 0 : if (strtab == NULL)
1444 : 0 : strtab = ebl_strtabinit (true);
1445 : 0 : sec->strent = ebl_strtabadd (strtab, sec->name, 0);
1446 [ # # ]: 0 : ELF_CHECK (sec->strent != NULL,
1447 : : _("cannot add section name to string table: %s"));
1448 : : }
1449 : :
1450 : : /* Cache the mapping of original section indices to output sections. */
1451 : 175 : ndx_section[secndx - 1] = elf_ndxscn (sec->outscn);
1452 : : }
1453 : :
1454 : : /* We added some sections, so we need a new shstrtab. */
1455 : 9 : Elf_Data *strtab_data = new_shstrtab (unstripped, unstripped_shnum,
1456 : : shstrtab, unstripped_shstrndx,
1457 : 9 : sections, stripped_shnum,
1458 : : strtab);
1459 : :
1460 : : /* Get the updated section count. */
1461 [ - + ]: 9 : ELF_CHECK (elf_getshdrnum (unstripped, &unstripped_shnum) == 0,
1462 : : _("cannot get section count: %s"));
1463 : :
1464 : 9 : bool placed[unstripped_shnum - 1];
1465 : 9 : memset (placed, 0, sizeof placed);
1466 : :
1467 : : /* Now update the output sections and copy in their data. */
1468 : 9 : GElf_Off offset = 0;
1469 [ + + ]: 204 : for (const struct section *sec = sections;
1470 : 204 : sec < §ions[stripped_shnum - 1];
1471 : 195 : ++sec)
1472 [ + + ]: 195 : if (sec->outscn != NULL)
1473 : : {
1474 : : GElf_Shdr shdr_mem;
1475 : 175 : GElf_Shdr *shdr = gelf_getshdr (sec->outscn, &shdr_mem);
1476 [ - + ]: 175 : ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
1477 : :
1478 : : /* In an ET_REL file under --relocate, the sh_addr of SHF_ALLOC
1479 : : sections will have been set nonzero by relocation. This
1480 : : touched the shdrs of whichever file had the symtab. sh_addr
1481 : : is still zero in the corresponding shdr. The relocated
1482 : : address is what we want to use. */
1483 [ + + ]: 175 : if (stripped_ehdr->e_type != ET_REL
1484 [ + + ]: 18 : || !(shdr_mem.sh_flags & SHF_ALLOC)
1485 [ + - ]: 10 : || shdr_mem.sh_addr == 0)
1486 : 175 : shdr_mem.sh_addr = sec->shdr.sh_addr;
1487 : :
1488 : 175 : shdr_mem.sh_type = sec->shdr.sh_type;
1489 : 175 : shdr_mem.sh_size = sec->shdr.sh_size;
1490 : 175 : shdr_mem.sh_info = sec->shdr.sh_info;
1491 : 175 : shdr_mem.sh_link = sec->shdr.sh_link;
1492 [ + + ]: 175 : if (sec->shdr.sh_link != SHN_UNDEF)
1493 : 52 : shdr_mem.sh_link = ndx_section[sec->shdr.sh_link - 1];
1494 [ - + ]: 175 : if (shdr_mem.sh_flags & SHF_INFO_LINK)
1495 : 0 : shdr_mem.sh_info = ndx_section[sec->shdr.sh_info - 1];
1496 : :
1497 [ - + ]: 175 : if (strtab != NULL)
1498 : 0 : shdr_mem.sh_name = ebl_strtaboffset (sec->strent);
1499 : :
1500 : 175 : Elf_Data *indata = elf_getdata (sec->scn, NULL);
1501 [ - + ]: 175 : ELF_CHECK (indata != NULL, _("cannot get section data: %s"));
1502 : 175 : Elf_Data *outdata = elf_getdata (sec->outscn, NULL);
1503 [ - + ]: 175 : ELF_CHECK (outdata != NULL, _("cannot copy section data: %s"));
1504 : 175 : *outdata = *indata;
1505 : 175 : elf_flagdata (outdata, ELF_C_SET, ELF_F_DIRTY);
1506 : :
1507 : : /* Preserve the file layout of the allocated sections. */
1508 [ + + ][ + + ]: 175 : if (stripped_ehdr->e_type != ET_REL && (shdr_mem.sh_flags & SHF_ALLOC))
1509 : : {
1510 : 148 : shdr_mem.sh_offset = sec->shdr.sh_offset;
1511 : 148 : placed[elf_ndxscn (sec->outscn) - 1] = true;
1512 : :
1513 : 296 : const GElf_Off end_offset = (shdr_mem.sh_offset
1514 : 148 : + (shdr_mem.sh_type == SHT_NOBITS
1515 [ + + ]: 148 : ? 0 : shdr_mem.sh_size));
1516 [ + + ]: 148 : if (end_offset > offset)
1517 : 144 : offset = end_offset;
1518 : : }
1519 : :
1520 : 175 : update_shdr (sec->outscn, &shdr_mem);
1521 : :
1522 [ + + ]: 175 : if (shdr_mem.sh_type == SHT_SYMTAB || shdr_mem.sh_type == SHT_DYNSYM)
1523 : : {
1524 : : /* We must adjust all the section indices in the symbol table. */
1525 : :
1526 : : Elf_Data *shndxdata = NULL; /* XXX */
1527 : :
1528 [ + + ]: 204 : for (size_t i = 1; i < shdr_mem.sh_size / shdr_mem.sh_entsize; ++i)
1529 : : {
1530 : : GElf_Sym sym_mem;
1531 : 197 : GElf_Word shndx = SHN_UNDEF;
1532 : 197 : GElf_Sym *sym = gelf_getsymshndx (outdata, shndxdata,
1533 : : i, &sym_mem, &shndx);
1534 [ - + ]: 197 : ELF_CHECK (sym != NULL,
1535 : : _("cannot get symbol table entry: %s"));
1536 [ + - ]: 197 : if (sym->st_shndx != SHN_XINDEX)
1537 : 197 : shndx = sym->st_shndx;
1538 : :
1539 [ + + ]: 197 : if (shndx != SHN_UNDEF && shndx < SHN_LORESERVE)
1540 : : {
1541 [ - + ]: 115 : if (shndx >= stripped_shnum)
1542 : : error (EXIT_FAILURE, 0,
1543 : 0 : _("symbol [%Zu] has invalid section index"), i);
1544 : :
1545 : 115 : shndx = ndx_section[shndx - 1];
1546 [ + - ]: 115 : if (shndx < SHN_LORESERVE)
1547 : : {
1548 : 115 : sym->st_shndx = shndx;
1549 : 115 : shndx = SHN_UNDEF;
1550 : : }
1551 : : else
1552 : 0 : sym->st_shndx = SHN_XINDEX;
1553 : :
1554 [ - + ]: 115 : ELF_CHECK (gelf_update_symshndx (outdata, shndxdata,
1555 : : i, sym, shndx),
1556 : : _("cannot update symbol table: %s"));
1557 : : }
1558 : : }
1559 : :
1560 [ - + ]: 7 : if (shdr_mem.sh_type == SHT_SYMTAB)
1561 : 0 : stripped_symtab = sec;
1562 [ + - ]: 7 : if (shdr_mem.sh_type == SHT_DYNSYM)
1563 : 175 : stripped_dynsym = sec;
1564 : : }
1565 : : }
1566 : :
1567 : : /* We may need to update the symbol table. */
1568 : 9 : Elf_Data *symdata = NULL;
1569 : 9 : struct Ebl_Strtab *symstrtab = NULL;
1570 : 9 : Elf_Data *symstrdata = NULL;
1571 [ + - ][ + + ]: 9 : if (unstripped_symtab != NULL && (stripped_symtab != NULL
1572 : 9 : || check_prelink /* Section adjustments. */
1573 [ + - ]: 7 : || (stripped_ehdr->e_type != ET_REL
1574 [ - + ]: 7 : && bias != 0)))
1575 : 2 : {
1576 : : /* Merge the stripped file's symbol table into the unstripped one. */
1577 : 2 : const size_t stripped_nsym = (stripped_symtab == NULL ? 1
1578 [ + - ]: 2 : : (stripped_symtab->shdr.sh_size
1579 : 2 : / stripped_symtab->shdr.sh_entsize));
1580 : :
1581 : : GElf_Shdr shdr_mem;
1582 : 2 : GElf_Shdr *shdr = gelf_getshdr (unstripped_symtab, &shdr_mem);
1583 [ - + ]: 2 : ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
1584 : 2 : const size_t unstripped_nsym = shdr->sh_size / shdr->sh_entsize;
1585 : :
1586 : : /* First collect all the symbols from both tables. */
1587 : :
1588 : 2 : const size_t total_syms = stripped_nsym - 1 + unstripped_nsym - 1;
1589 : 2 : struct symbol symbols[total_syms];
1590 : 2 : size_t symndx_map[total_syms];
1591 : :
1592 [ + - ]: 2 : if (stripped_symtab != NULL)
1593 : 2 : collect_symbols (unstripped, stripped_ehdr->e_type == ET_REL,
1594 : : stripped_symtab->scn,
1595 : 2 : elf_getscn (stripped, stripped_symtab->shdr.sh_link),
1596 : 2 : stripped_nsym, 0, ndx_section,
1597 : 2 : symbols, symndx_map, NULL);
1598 : :
1599 : 2 : Elf_Scn *unstripped_strtab = elf_getscn (unstripped, shdr->sh_link);
1600 [ - + ]: 2 : collect_symbols (unstripped, stripped_ehdr->e_type == ET_REL,
1601 : : unstripped_symtab, unstripped_strtab, unstripped_nsym,
1602 : 2 : stripped_ehdr->e_type == ET_REL ? 0 : bias, NULL,
1603 : : &symbols[stripped_nsym - 1],
1604 : 2 : &symndx_map[stripped_nsym - 1], split_bss);
1605 : :
1606 : : /* Next, sort our array of all symbols. */
1607 : 2 : qsort (symbols, total_syms, sizeof symbols[0], compare_symbols);
1608 : :
1609 : : /* Now we can weed out the duplicates. Assign remaining symbols
1610 : : new slots, collecting a map from old indices to new. */
1611 : 2 : size_t nsym = 0;
1612 [ + + ]: 115 : for (struct symbol *s = symbols; s < &symbols[total_syms]; ++s)
1613 : : {
1614 : : /* Skip a section symbol for a removed section. */
1615 [ + + ]: 113 : if (s->shndx == SHN_UNDEF
1616 [ - + ]: 62 : && GELF_ST_TYPE (s->info.info) == STT_SECTION)
1617 : : {
1618 : 0 : s->name = NULL; /* Mark as discarded. */
1619 : 0 : *s->map = STN_UNDEF;
1620 : 0 : s->duplicate = NULL;
1621 : 113 : continue;
1622 : : }
1623 : :
1624 : : struct symbol *n = s;
1625 [ + + ][ + + ]: 206 : while (n + 1 < &symbols[total_syms] && !compare_symbols (s, n + 1))
1626 : : ++n;
1627 : :
1628 [ + + ]: 206 : while (s < n)
1629 : : {
1630 : : /* This is a duplicate. Its twin will get the next slot. */
1631 : 93 : s->name = NULL; /* Mark as discarded. */
1632 : 93 : s->duplicate = n->map;
1633 : 93 : ++s;
1634 : : }
1635 : :
1636 : : /* Allocate the next slot. */
1637 : 113 : *s->map = ++nsym;
1638 : : }
1639 : :
1640 : : /* Now we sort again, to determine the order in the output. */
1641 : 2 : qsort (symbols, total_syms, sizeof symbols[0], compare_symbols_output);
1642 : :
1643 [ + - ]: 2 : if (nsym < total_syms)
1644 : : /* The discarded symbols are now at the end of the table. */
1645 [ - + ]: 2 : assert (symbols[nsym].name == NULL);
1646 : :
1647 : : /* Now a final pass updates the map with the final order,
1648 : : and builds up the new string table. */
1649 : 2 : symstrtab = ebl_strtabinit (true);
1650 [ + + ]: 115 : for (size_t i = 0; i < nsym; ++i)
1651 : : {
1652 [ - + ]: 113 : assert (symbols[i].name != NULL);
1653 [ - + ]: 113 : assert (*symbols[i].map != 0);
1654 : 113 : *symbols[i].map = 1 + i;
1655 : 113 : symbols[i].strent = ebl_strtabadd (symstrtab, symbols[i].name, 0);
1656 : : }
1657 : :
1658 : : /* Scan the discarded symbols too, just to update their slots
1659 : : in SYMNDX_MAP to refer to their live duplicates. */
1660 [ + + ]: 95 : for (size_t i = nsym; i < total_syms; ++i)
1661 : : {
1662 [ - + ]: 93 : assert (symbols[i].name == NULL);
1663 [ - + ]: 93 : if (symbols[i].duplicate == NULL)
1664 [ # # ]: 0 : assert (*symbols[i].map == STN_UNDEF);
1665 : : else
1666 : : {
1667 [ - + ]: 93 : assert (*symbols[i].duplicate != STN_UNDEF);
1668 : 93 : *symbols[i].map = *symbols[i].duplicate;
1669 : : }
1670 : : }
1671 : :
1672 : : /* Now we are ready to write the new symbol table. */
1673 : 2 : symdata = elf_getdata (unstripped_symtab, NULL);
1674 : 2 : symstrdata = elf_getdata (unstripped_strtab, NULL);
1675 : 2 : Elf_Data *shndxdata = NULL; /* XXX */
1676 : :
1677 : 2 : ebl_strtabfinalize (symstrtab, symstrdata);
1678 : 2 : elf_flagdata (symstrdata, ELF_C_SET, ELF_F_DIRTY);
1679 : :
1680 : 2 : shdr->sh_size = symdata->d_size = (1 + nsym) * shdr->sh_entsize;
1681 : 2 : symdata->d_buf = xmalloc (symdata->d_size);
1682 : :
1683 : : GElf_Sym sym;
1684 : 2 : memset (&sym, 0, sizeof sym);
1685 [ - + ]: 2 : ELF_CHECK (gelf_update_symshndx (symdata, shndxdata, 0, &sym, SHN_UNDEF),
1686 : : _("cannot update symbol table: %s"));
1687 : :
1688 : 2 : shdr->sh_info = 1;
1689 [ + + ]: 115 : for (size_t i = 0; i < nsym; ++i)
1690 : : {
1691 : 113 : struct symbol *s = &symbols[i];
1692 : :
1693 : : /* Fill in the symbol details. */
1694 : 113 : sym.st_name = ebl_strtaboffset (s->strent);
1695 : 113 : sym.st_value = s->value; /* Already biased to output address. */
1696 : 113 : sym.st_size = s->size;
1697 : 113 : sym.st_shndx = s->shndx; /* Already mapped to output index. */
1698 : 113 : sym.st_info = s->info.info;
1699 : 113 : sym.st_other = s->info.other;
1700 : :
1701 : : /* Keep track of the number of leading local symbols. */
1702 [ + + ]: 113 : if (GELF_ST_BIND (sym.st_info) == STB_LOCAL)
1703 : : {
1704 [ - + ]: 48 : assert (shdr->sh_info == 1 + i);
1705 : 48 : shdr->sh_info = 1 + i + 1;
1706 : : }
1707 : :
1708 [ - + ]: 113 : ELF_CHECK (gelf_update_symshndx (symdata, shndxdata, 1 + i,
1709 : : &sym, SHN_UNDEF),
1710 : : _("cannot update symbol table: %s"));
1711 : :
1712 : : }
1713 : 2 : elf_flagdata (symdata, ELF_C_SET, ELF_F_DIRTY);
1714 : 2 : update_shdr (unstripped_symtab, shdr);
1715 : :
1716 [ + - ]: 2 : if (stripped_symtab != NULL)
1717 : : {
1718 : : /* Adjust any relocations referring to the old symbol table. */
1719 : 2 : const size_t old_sh_link = elf_ndxscn (stripped_symtab->scn);
1720 [ + + ]: 26 : for (const struct section *sec = sections;
1721 : 26 : sec < §ions[stripped_shnum - 1];
1722 : 24 : ++sec)
1723 [ + + ][ + + ]: 24 : if (sec->outscn != NULL && sec->shdr.sh_link == old_sh_link)
1724 : 4 : adjust_relocs (sec->outscn, sec->scn, &sec->shdr,
1725 : 4 : symndx_map, shdr);
1726 : : }
1727 : :
1728 : : /* Also adjust references to the other old symbol table. */
1729 : 2 : adjust_all_relocs (unstripped, unstripped_symtab, shdr,
1730 : : &symndx_map[stripped_nsym - 1]);
1731 : : }
1732 [ - + ][ # # ]: 7 : else if (stripped_symtab != NULL && stripped_shnum != unstripped_shnum)
1733 : 0 : check_symtab_section_symbols (unstripped,
1734 : 0 : stripped_ehdr->e_type == ET_REL,
1735 : : stripped_symtab->scn,
1736 : : unstripped_shnum, unstripped_shstrndx,
1737 : : stripped_symtab->outscn,
1738 : : stripped_shnum, stripped_shstrndx,
1739 : : debuglink);
1740 : :
1741 [ + + ]: 9 : if (stripped_dynsym != NULL)
1742 : 7 : (void) check_symtab_section_symbols (unstripped,
1743 : 7 : stripped_ehdr->e_type == ET_REL,
1744 : : stripped_dynsym->outscn,
1745 : : unstripped_shnum,
1746 : : unstripped_shstrndx,
1747 : : stripped_dynsym->scn, stripped_shnum,
1748 : : stripped_shstrndx, debuglink);
1749 : :
1750 : : /* We need to preserve the layout of the stripped file so the
1751 : : phdrs will match up. This requires us to do our own layout of
1752 : : the added sections. We do manual layout even for ET_REL just
1753 : : so we can try to match what the original probably had. */
1754 : :
1755 : 9 : elf_flagelf (unstripped, ELF_C_SET, ELF_F_LAYOUT);
1756 : :
1757 [ + + ]: 9 : if (offset == 0)
1758 : : /* For ET_REL we are starting the layout from scratch. */
1759 : 9 : offset = gelf_fsize (unstripped, ELF_T_EHDR, 1, EV_CURRENT);
1760 : :
1761 : : bool skip_reloc = false;
1762 : : do
1763 : : {
1764 : 18 : skip_reloc = !skip_reloc;
1765 [ + + ]: 580 : for (size_t i = 0; i < unstripped_shnum - 1; ++i)
1766 [ + + ]: 562 : if (!placed[i])
1767 : : {
1768 : 147 : scn = elf_getscn (unstripped, 1 + i);
1769 : :
1770 : : GElf_Shdr shdr_mem;
1771 : 147 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1772 [ - + ]: 147 : ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
1773 : :
1774 : : /* We must make sure we have read in the data of all sections
1775 : : beforehand and marked them to be written out. When we're
1776 : : modifying the existing file in place, we might overwrite
1777 : : this part of the file before we get to handling the section. */
1778 : :
1779 [ - + ]: 147 : ELF_CHECK (elf_flagdata (elf_getdata (scn, NULL),
1780 : : ELF_C_SET, ELF_F_DIRTY),
1781 : : _("cannot read section data: %s"));
1782 : :
1783 [ + + ]: 147 : if (skip_reloc
1784 [ + + ]: 133 : && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA))
1785 : 14 : continue;
1786 : :
1787 [ + - ]: 133 : GElf_Off align = shdr->sh_addralign ?: 1;
1788 : 133 : offset = (offset + align - 1) & -align;
1789 : 133 : shdr->sh_offset = offset;
1790 [ + + ]: 133 : if (shdr->sh_type != SHT_NOBITS)
1791 : 131 : offset += shdr->sh_size;
1792 : :
1793 : 133 : update_shdr (scn, shdr);
1794 : :
1795 [ + + ]: 133 : if (unstripped_shstrndx == 1 + i)
1796 : : {
1797 : : /* Place the section headers immediately after
1798 : : .shstrtab, and update the ELF header. */
1799 : :
1800 : : GElf_Ehdr ehdr_mem;
1801 : 9 : GElf_Ehdr *ehdr = gelf_getehdr (unstripped, &ehdr_mem);
1802 [ - + ]: 9 : ELF_CHECK (ehdr != NULL, _("cannot get ELF header: %s"));
1803 : :
1804 : 9 : GElf_Off sh_align = gelf_getclass (unstripped) * 4;
1805 : 9 : offset = (offset + sh_align - 1) & -sh_align;
1806 : 9 : ehdr->e_shnum = unstripped_shnum;
1807 : 9 : ehdr->e_shoff = offset;
1808 : 9 : offset += unstripped_shnum * ehdr->e_shentsize;
1809 [ - + ]: 9 : ELF_CHECK (gelf_update_ehdr (unstripped, ehdr),
1810 : : _("cannot update ELF header: %s"));
1811 : : }
1812 : :
1813 : 133 : placed[i] = true;
1814 : : }
1815 : : }
1816 [ + + ]: 18 : while (skip_reloc);
1817 : :
1818 [ + + ]: 9 : if (stripped_ehdr->e_phnum > 0)
1819 [ + - ]: 9 : ELF_CHECK (gelf_newphdr (unstripped, stripped_ehdr->e_phnum),
1820 : : _("cannot create program headers: %s"));
1821 : :
1822 : : /* Copy each program header from the stripped file. */
1823 [ + + ]: 49 : for (uint_fast16_t i = 0; i < stripped_ehdr->e_phnum; ++i)
1824 : : {
1825 : : GElf_Phdr phdr_mem;
1826 : 40 : GElf_Phdr *phdr = gelf_getphdr (stripped, i, &phdr_mem);
1827 [ - + ]: 40 : ELF_CHECK (phdr != NULL, _("cannot get program header: %s"));
1828 : :
1829 [ - + ]: 40 : ELF_CHECK (gelf_update_phdr (unstripped, i, phdr),
1830 : : _("cannot update program header: %s"));
1831 : : }
1832 : :
1833 : : /* Finally, write out the file. */
1834 [ - + ]: 9 : ELF_CHECK (elf_update (unstripped, ELF_C_WRITE) > 0,
1835 : : _("cannot write output file: %s"));
1836 : :
1837 [ - + ]: 9 : if (strtab != NULL)
1838 : : {
1839 : 0 : ebl_strtabfree (strtab);
1840 : 0 : free (strtab_data->d_buf);
1841 : : }
1842 : :
1843 [ + + ]: 9 : if (symdata != NULL)
1844 : 2 : free (symdata->d_buf);
1845 [ + + ]: 9 : if (symstrtab != NULL)
1846 : : {
1847 : 2 : ebl_strtabfree (symstrtab);
1848 : 2 : free (symstrdata->d_buf);
1849 : : }
1850 : 9 : }
1851 : :
1852 : : /* Process one pair of files, already opened. */
1853 : : static void
1854 : 9 : handle_file (const char *output_file, bool create_dirs,
1855 : : Elf *stripped, const GElf_Ehdr *stripped_ehdr,
1856 : : Elf *unstripped)
1857 : : {
1858 : : /* Determine the address bias between the debuginfo file and the main
1859 : : file, which may have been modified by prelinking. */
1860 : 9 : GElf_Addr bias = 0;
1861 [ + - ]: 9 : if (unstripped != NULL)
1862 [ + + ]: 15 : for (uint_fast16_t i = 0; i < stripped_ehdr->e_phnum; ++i)
1863 : : {
1864 : : GElf_Phdr phdr_mem;
1865 : 13 : GElf_Phdr *phdr = gelf_getphdr (stripped, i, &phdr_mem);
1866 [ - + ]: 13 : ELF_CHECK (phdr != NULL, _("cannot get program header: %s"));
1867 [ + + ]: 13 : if (phdr->p_type == PT_LOAD)
1868 : : {
1869 : : GElf_Phdr unstripped_phdr_mem;
1870 : 7 : GElf_Phdr *unstripped_phdr = gelf_getphdr (unstripped, i,
1871 : : &unstripped_phdr_mem);
1872 [ - + ]: 7 : ELF_CHECK (unstripped_phdr != NULL,
1873 : : _("cannot get program header: %s"));
1874 : 7 : bias = phdr->p_vaddr - unstripped_phdr->p_vaddr;
1875 : : break;
1876 : : }
1877 : : }
1878 : :
1879 : : /* One day we could adjust all the DWARF data (like prelink itself does). */
1880 [ - + ]: 9 : if (bias != 0)
1881 : : {
1882 [ # # ]: 0 : if (output_file == NULL)
1883 : 0 : error (0, 0, _("\
1884 : : DWARF data not adjusted for prelinking bias; consider prelink -u"));
1885 : : else
1886 : 0 : error (0, 0, _("\
1887 : : DWARF data in '%s' not adjusted for prelinking bias; consider prelink -u"),
1888 : : output_file);
1889 : : }
1890 : :
1891 [ + + ]: 9 : if (output_file == NULL)
1892 : : /* Modify the unstripped file in place. */
1893 : 2 : copy_elided_sections (unstripped, stripped, stripped_ehdr, bias);
1894 : : else
1895 : : {
1896 [ - + ]: 7 : if (create_dirs)
1897 : 0 : make_directories (output_file);
1898 : :
1899 : : /* Copy the unstripped file and then modify it. */
1900 [ + + ]: 7 : int outfd = open64 (output_file, O_RDWR | O_CREAT,
1901 : 7 : stripped_ehdr->e_type == ET_REL ? 0666 : 0777);
1902 [ - + ]: 7 : if (outfd < 0)
1903 : 0 : error (EXIT_FAILURE, errno, _("cannot open '%s'"), output_file);
1904 : 7 : Elf *outelf = elf_begin (outfd, ELF_C_WRITE, NULL);
1905 [ - + ]: 7 : ELF_CHECK (outelf != NULL, _("cannot create ELF descriptor: %s"));
1906 : :
1907 [ - + ]: 7 : if (unstripped == NULL)
1908 : : {
1909 : : /* Actually, we are just copying out the main file as it is. */
1910 : 0 : copy_elf (outelf, stripped);
1911 [ # # ]: 0 : if (stripped_ehdr->e_type != ET_REL)
1912 : 0 : elf_flagelf (outelf, ELF_C_SET, ELF_F_LAYOUT);
1913 [ # # ]: 0 : ELF_CHECK (elf_update (outelf, ELF_C_WRITE) > 0,
1914 : : _("cannot write output file: %s"));
1915 : : }
1916 : : else
1917 : : {
1918 : 7 : copy_elf (outelf, unstripped);
1919 : 7 : copy_elided_sections (outelf, stripped, stripped_ehdr, bias);
1920 : : }
1921 : :
1922 : 7 : elf_end (outelf);
1923 : 7 : close (outfd);
1924 : : }
1925 : 9 : }
1926 : :
1927 : : static int
1928 : 18 : open_file (const char *file, bool writable)
1929 : : {
1930 [ + + ]: 18 : int fd = open64 (file, writable ? O_RDWR : O_RDONLY);
1931 [ - + ]: 18 : if (fd < 0)
1932 : 0 : error (EXIT_FAILURE, errno, _("cannot open '%s'"), file);
1933 : 18 : return fd;
1934 : : }
1935 : :
1936 : : /* Handle a pair of files we need to open by name. */
1937 : : static void
1938 : 9 : handle_explicit_files (const char *output_file, bool create_dirs,
1939 : : const char *stripped_file, const char *unstripped_file)
1940 : : {
1941 : 9 : int stripped_fd = open_file (stripped_file, false);
1942 : 9 : Elf *stripped = elf_begin (stripped_fd, ELF_C_READ, NULL);
1943 : : GElf_Ehdr stripped_ehdr;
1944 [ - + ]: 9 : ELF_CHECK (gelf_getehdr (stripped, &stripped_ehdr),
1945 : : _("cannot create ELF descriptor: %s"));
1946 : :
1947 : 9 : int unstripped_fd = -1;
1948 : 9 : Elf *unstripped = NULL;
1949 [ + - ]: 9 : if (unstripped_file != NULL)
1950 : : {
1951 : 9 : unstripped_fd = open_file (unstripped_file, output_file == NULL);
1952 [ + + ]: 9 : unstripped = elf_begin (unstripped_fd,
1953 : : (output_file == NULL ? ELF_C_RDWR : ELF_C_READ),
1954 : : NULL);
1955 : : GElf_Ehdr unstripped_ehdr;
1956 [ - + ]: 9 : ELF_CHECK (gelf_getehdr (unstripped, &unstripped_ehdr),
1957 : : _("cannot create ELF descriptor: %s"));
1958 : :
1959 [ + - ]: 9 : if (memcmp (stripped_ehdr.e_ident, unstripped_ehdr.e_ident, EI_NIDENT)
1960 : : || stripped_ehdr.e_type != unstripped_ehdr.e_type
1961 [ + - ]: 9 : || stripped_ehdr.e_machine != unstripped_ehdr.e_machine
1962 [ - + ]: 9 : || stripped_ehdr.e_phnum != unstripped_ehdr.e_phnum)
1963 : 0 : error (EXIT_FAILURE, 0, _("'%s' and '%s' do not seem to match"),
1964 : : stripped_file, unstripped_file);
1965 : : }
1966 : :
1967 : 9 : handle_file (output_file, create_dirs, stripped, &stripped_ehdr, unstripped);
1968 : :
1969 : 9 : elf_end (stripped);
1970 : 9 : close (stripped_fd);
1971 : :
1972 : 9 : elf_end (unstripped);
1973 : 9 : close (unstripped_fd);
1974 : 9 : }
1975 : :
1976 : :
1977 : : /* Handle a pair of files opened implicitly by libdwfl for one module. */
1978 : : static void
1979 : 0 : handle_dwfl_module (const char *output_file, bool create_dirs,
1980 : : Dwfl_Module *mod, bool all, bool ignore, bool relocate)
1981 : : {
1982 : : GElf_Addr bias;
1983 : 0 : Elf *stripped = dwfl_module_getelf (mod, &bias);
1984 [ # # ]: 0 : if (stripped == NULL)
1985 : : {
1986 [ # # ]: 0 : if (ignore)
1987 : : return;
1988 : :
1989 : : const char *file;
1990 : 0 : const char *modname = dwfl_module_info (mod, NULL, NULL, NULL,
1991 : : NULL, NULL, &file, NULL);
1992 [ # # ]: 0 : if (file == NULL)
1993 : 0 : error (EXIT_FAILURE, 0,
1994 : 0 : _("cannot find stripped file for module '%s': %s"),
1995 : : modname, dwfl_errmsg (-1));
1996 : : else
1997 : 0 : error (EXIT_FAILURE, 0,
1998 : 0 : _("cannot open stripped file '%s' for module '%s': %s"),
1999 : : modname, file, dwfl_errmsg (-1));
2000 : : }
2001 : :
2002 : 0 : Elf *debug = dwarf_getelf (dwfl_module_getdwarf (mod, &bias));
2003 [ # # ]: 0 : if (debug == NULL && !all)
2004 : : {
2005 [ # # ]: 0 : if (ignore)
2006 : : return;
2007 : :
2008 : : const char *file;
2009 : 0 : const char *modname = dwfl_module_info (mod, NULL, NULL, NULL,
2010 : : NULL, NULL, NULL, &file);
2011 [ # # ]: 0 : if (file == NULL)
2012 : 0 : error (EXIT_FAILURE, 0,
2013 : 0 : _("cannot find debug file for module '%s': %s"),
2014 : : modname, dwfl_errmsg (-1));
2015 : : else
2016 : 0 : error (EXIT_FAILURE, 0,
2017 : 0 : _("cannot open debug file '%s' for module '%s': %s"),
2018 : : modname, file, dwfl_errmsg (-1));
2019 : : }
2020 : :
2021 [ # # ]: 0 : if (debug == stripped)
2022 : : {
2023 [ # # ]: 0 : if (all)
2024 : : debug = NULL;
2025 : : else
2026 : : {
2027 : : const char *file;
2028 : 0 : const char *modname = dwfl_module_info (mod, NULL, NULL, NULL,
2029 : : NULL, NULL, &file, NULL);
2030 : 0 : error (EXIT_FAILURE, 0, _("module '%s' file '%s' is not stripped"),
2031 : : modname, file);
2032 : : }
2033 : : }
2034 : :
2035 : : GElf_Ehdr stripped_ehdr;
2036 [ # # ]: 0 : ELF_CHECK (gelf_getehdr (stripped, &stripped_ehdr),
2037 : : _("cannot create ELF descriptor: %s"));
2038 : :
2039 [ # # ]: 0 : if (stripped_ehdr.e_type == ET_REL)
2040 : : {
2041 [ # # ]: 0 : if (!relocate)
2042 : : {
2043 : : /* We can't use the Elf handles already open,
2044 : : because the DWARF sections have been relocated. */
2045 : :
2046 : 0 : const char *stripped_file = NULL;
2047 : 0 : const char *unstripped_file = NULL;
2048 : 0 : (void) dwfl_module_info (mod, NULL, NULL, NULL, NULL, NULL,
2049 : : &stripped_file, &unstripped_file);
2050 : :
2051 : 0 : handle_explicit_files (output_file, create_dirs,
2052 : : stripped_file, unstripped_file);
2053 : : return;
2054 : : }
2055 : :
2056 : : /* Relocation is what we want! This ensures that all sections that can
2057 : : get sh_addr values assigned have them, even ones not used in DWARF.
2058 : : They might still be used in the symbol table. */
2059 [ # # ]: 0 : if (dwfl_module_relocations (mod) < 0)
2060 : 0 : error (EXIT_FAILURE, 0,
2061 : 0 : _("cannot cache section addresses for module '%s': %s"),
2062 : : dwfl_module_info (mod, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
2063 : : dwfl_errmsg (-1));
2064 : : }
2065 : :
2066 : 0 : handle_file (output_file, create_dirs, stripped, &stripped_ehdr, debug);
2067 : : }
2068 : :
2069 : : /* Handle one module being written to the output directory. */
2070 : : static void
2071 : 0 : handle_output_dir_module (const char *output_dir, Dwfl_Module *mod,
2072 : : bool all, bool ignore, bool modnames, bool relocate)
2073 : : {
2074 [ # # ]: 0 : if (! modnames)
2075 : : {
2076 : : /* Make sure we've searched for the ELF file. */
2077 : : GElf_Addr bias;
2078 : 0 : (void) dwfl_module_getelf (mod, &bias);
2079 : : }
2080 : :
2081 : : const char *file;
2082 : 0 : const char *name = dwfl_module_info (mod, NULL, NULL, NULL,
2083 : : NULL, NULL, &file, NULL);
2084 : :
2085 [ # # ][ # # ]: 0 : if (file == NULL && ignore)
2086 : 0 : return;
2087 : :
2088 : : char *output_file;
2089 [ # # ][ # # ]: 0 : if (asprintf (&output_file, "%s/%s", output_dir, modnames ? name : file) < 0)
2090 : 0 : error (EXIT_FAILURE, 0, _("memory exhausted"));
2091 : :
2092 : 0 : handle_dwfl_module (output_file, true, mod, all, ignore, relocate);
2093 : : }
2094 : :
2095 : :
2096 : : static void
2097 : 12 : list_module (Dwfl_Module *mod)
2098 : : {
2099 : : /* Make sure we have searched for the files. */
2100 : : GElf_Addr bias;
2101 : 12 : bool have_elf = dwfl_module_getelf (mod, &bias) != NULL;
2102 : 12 : bool have_dwarf = dwfl_module_getdwarf (mod, &bias) != NULL;
2103 : :
2104 : : const char *file;
2105 : : const char *debug;
2106 : : Dwarf_Addr start;
2107 : : Dwarf_Addr end;
2108 : 12 : const char *name = dwfl_module_info (mod, NULL, &start, &end,
2109 : : NULL, NULL, &file, &debug);
2110 [ + + ][ - + ]: 12 : if (file != NULL && debug != NULL && (debug == file || !strcmp (debug, file)))
[ # # ][ # # ]
2111 : 0 : debug = ".";
2112 : :
2113 : : const unsigned char *id;
2114 : : GElf_Addr id_vaddr;
2115 : 12 : int id_len = dwfl_module_build_id (mod, &id, &id_vaddr);
2116 : :
2117 : 12 : printf ("%#" PRIx64 "+%#" PRIx64 " ", start, end - start);
2118 : :
2119 [ + - ]: 12 : if (id_len > 0)
2120 : : {
2121 : : do
2122 : 240 : printf ("%02" PRIx8, *id++);
2123 [ + + ]: 240 : while (--id_len > 0);
2124 [ + - ]: 12 : if (id_vaddr != 0)
2125 : 12 : printf ("@%#" PRIx64, id_vaddr);
2126 : : }
2127 : : else
2128 : : putchar ('-');
2129 : :
2130 [ + - ][ + - ]: 12 : printf (" %s %s %s\n",
[ + + ][ - + ]
2131 : 12 : file ?: have_elf ? "." : "-",
2132 : 12 : debug ?: have_dwarf ? "." : "-",
2133 : : name);
2134 : 12 : }
2135 : :
2136 : :
2137 : : struct match_module_info
2138 : : {
2139 : : char **patterns;
2140 : : Dwfl_Module *found;
2141 : : bool match_files;
2142 : : };
2143 : :
2144 : : static int
2145 : 12 : match_module (Dwfl_Module *mod,
2146 : : void **userdata __attribute__ ((unused)),
2147 : : const char *name,
2148 : : Dwarf_Addr start __attribute__ ((unused)),
2149 : : void *arg)
2150 : : {
2151 : 12 : struct match_module_info *info = arg;
2152 : :
2153 [ + - ]: 12 : if (info->patterns[0] == NULL) /* Match all. */
2154 : : {
2155 : : match:
2156 : 12 : info->found = mod;
2157 : 12 : return DWARF_CB_ABORT;
2158 : : }
2159 : :
2160 [ # # ]: 0 : if (info->match_files)
2161 : : {
2162 : : /* Make sure we've searched for the ELF file. */
2163 : : GElf_Addr bias;
2164 : 0 : (void) dwfl_module_getelf (mod, &bias);
2165 : :
2166 : : const char *file;
2167 : 0 : const char *check = dwfl_module_info (mod, NULL, NULL, NULL,
2168 : : NULL, NULL, &file, NULL);
2169 [ # # ]: 0 : assert (check == name);
2170 [ # # ]: 0 : if (file == NULL)
2171 : : return DWARF_CB_OK;
2172 : :
2173 : 0 : name = file;
2174 : : }
2175 : :
2176 [ # # ]: 12 : for (char **p = info->patterns; *p != NULL; ++p)
2177 [ # # ]: 0 : if (fnmatch (*p, name, 0) == 0)
2178 : : goto match;
2179 : :
2180 : : return DWARF_CB_OK;
2181 : : }
2182 : :
2183 : : /* Handle files opened implicitly via libdwfl. */
2184 : : static void
2185 : 2 : handle_implicit_modules (const struct arg_info *info)
2186 : : {
2187 : 2 : struct match_module_info mmi = { info->args, NULL, info->match_files };
2188 : 14 : inline ptrdiff_t next (ptrdiff_t offset)
2189 : : {
2190 : 14 : return dwfl_getmodules (info->dwfl, &match_module, &mmi, offset);
2191 : : }
2192 : 2 : ptrdiff_t offset = next (0);
2193 [ - + ]: 2 : if (offset == 0)
2194 : 0 : error (EXIT_FAILURE, 0, _("no matching modules found"));
2195 : :
2196 [ + - ]: 2 : if (info->list)
2197 : : do
2198 : 12 : list_module (mmi.found);
2199 [ + + ]: 12 : while ((offset = next (offset)) > 0);
2200 [ # # ]: 0 : else if (info->output_dir == NULL)
2201 : : {
2202 [ # # ]: 0 : if (next (offset) != 0)
2203 : 0 : error (EXIT_FAILURE, 0, _("matched more than one module"));
2204 : 0 : handle_dwfl_module (info->output_file, false, mmi.found,
2205 : 0 : info->all, info->ignore, info->relocate);
2206 : : }
2207 : : else
2208 : : do
2209 : 0 : handle_output_dir_module (info->output_dir, mmi.found,
2210 : 0 : info->all, info->ignore,
2211 : 0 : info->modnames, info->relocate);
2212 [ # # ]: 0 : while ((offset = next (offset)) > 0);
2213 : 2 : }
2214 : :
2215 : : int
2216 : 11 : main (int argc, char **argv)
2217 : : {
2218 : : /* Make memory leak detection possible. */
2219 : 11 : mtrace ();
2220 : :
2221 : : /* We use no threads here which can interfere with handling a stream. */
2222 : 11 : __fsetlocking (stdin, FSETLOCKING_BYCALLER);
2223 : 11 : __fsetlocking (stdout, FSETLOCKING_BYCALLER);
2224 : 11 : __fsetlocking (stderr, FSETLOCKING_BYCALLER);
2225 : :
2226 : : /* Set locale. */
2227 : 11 : setlocale (LC_ALL, "");
2228 : :
2229 : : /* Make sure the message catalog can be found. */
2230 : 11 : bindtextdomain (PACKAGE_TARNAME, LOCALEDIR);
2231 : :
2232 : : /* Initialize the message catalog. */
2233 : 11 : textdomain (PACKAGE_TARNAME);
2234 : :
2235 : : /* Parse and process arguments. */
2236 : 22 : const struct argp_child argp_children[] =
2237 : : {
2238 : : {
2239 : 11 : .argp = dwfl_standard_argp (),
2240 : : .header = N_("Input selection options:"),
2241 : : .group = 1,
2242 : : },
2243 : : { .argp = NULL },
2244 : : };
2245 : 11 : const struct argp argp =
2246 : : {
2247 : : .options = options,
2248 : : .parser = parse_opt,
2249 : : .children = argp_children,
2250 : : .args_doc = N_("STRIPPED-FILE DEBUG-FILE\n[MODULE...]"),
2251 : : .doc = N_("\
2252 : : Combine stripped files with separate symbols and debug information.\v\
2253 : : The first form puts the result in DEBUG-FILE if -o was not given.\n\
2254 : : \n\
2255 : : MODULE arguments give file name patterns matching modules to process.\n\
2256 : : With -f these match the file name of the main (stripped) file \
2257 : : (slashes are never special), otherwise they match the simple module names. \
2258 : : With no arguments, process all modules found.\n\
2259 : : \n\
2260 : : Multiple modules are written to files under OUTPUT-DIRECTORY, \
2261 : : creating subdirectories as needed. \
2262 : : With -m these files have simple module names, otherwise they have the \
2263 : : name of the main file complete with directory underneath OUTPUT-DIRECTORY.\n\
2264 : : \n\
2265 : : With -n no files are written, but one line to standard output for each module:\
2266 : : \n\tSTART+SIZE BUILDID FILE DEBUGFILE MODULENAME\n\
2267 : : START and SIZE are hexadecimal giving the address bounds of the module. \
2268 : : BUILDID is hexadecimal for the build ID bits, or - if no ID is known; \
2269 : : the hexadecimal may be followed by @0xADDR giving the address where the \
2270 : : ID resides if that is known. \
2271 : : FILE is the file name found for the module, or - if none was found, \
2272 : : or . if an ELF image is available but not from any named file. \
2273 : : DEBUGFILE is the separate debuginfo file name, \
2274 : : or - if no debuginfo was found, or . if FILE contains the debug information.\
2275 : : ")
2276 : : };
2277 : :
2278 : : int remaining;
2279 : 11 : struct arg_info info = { .args = NULL };
2280 : 11 : error_t result = argp_parse (&argp, argc, argv, 0, &remaining, &info);
2281 [ + + ]: 11 : if (result == ENOSYS)
2282 [ - + ]: 9 : assert (info.dwfl == NULL);
2283 [ + - ]: 2 : else if (result)
2284 : : return EXIT_FAILURE;
2285 [ - + ]: 11 : assert (info.args != NULL);
2286 : :
2287 : : /* Tell the library which version we are expecting. */
2288 : 11 : elf_version (EV_CURRENT);
2289 : :
2290 [ + + ]: 11 : if (info.dwfl == NULL)
2291 : : {
2292 [ - + ]: 9 : assert (result == ENOSYS);
2293 : :
2294 [ - + ]: 9 : if (info.output_dir != NULL)
2295 : : {
2296 : : char *file;
2297 [ # # ]: 0 : if (asprintf (&file, "%s/%s", info.output_dir, info.args[0]) < 0)
2298 : 0 : error (EXIT_FAILURE, 0, _("memory exhausted"));
2299 : 0 : handle_explicit_files (file, true, info.args[0], info.args[1]);
2300 : 0 : free (file);
2301 : : }
2302 : : else
2303 : 9 : handle_explicit_files (info.output_file, false,
2304 : 9 : info.args[0], info.args[1]);
2305 : : }
2306 : : else
2307 : : {
2308 : : /* parse_opt checked this. */
2309 [ + - ][ + - ]: 2 : assert (info.output_file != NULL || info.output_dir != NULL || info.list);
[ - + ]
2310 : :
2311 : 2 : handle_implicit_modules (&info);
2312 : :
2313 : 11 : dwfl_end (info.dwfl);
2314 : : }
2315 : :
2316 : : return 0;
2317 : : }
2318 : :
2319 : :
2320 : 2751 : #include "debugpred.h"
|