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