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