summaryrefslogtreecommitdiffstats
path: root/trunk/src/dso-readonly.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/dso-readonly.c')
-rw-r--r--trunk/src/dso-readonly.c1897
1 files changed, 0 insertions, 1897 deletions
diff --git a/trunk/src/dso-readonly.c b/trunk/src/dso-readonly.c
deleted file mode 100644
index 3cfe838..0000000
--- a/trunk/src/dso-readonly.c
+++ /dev/null
@@ -1,1897 +0,0 @@
-/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2010 Red Hat, Inc.
- Written by Jakub Jelinek <jakub@redhat.com>, 2001.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-#include <config.h>
-#include <assert.h>
-#include <errno.h>
-#include <error.h>
-#include <fcntl.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <time.h>
-#include <unistd.h>
-#include <utime.h>
-#include "prelink.h"
-
-#if defined HAVE_LIBSELINUX && defined HAVE_SELINUX_SELINUX_H
-#include <selinux/selinux.h>
-#define USE_SELINUX
-#endif
-
-#define RELOCATE_SCN(shf) \
- ((shf) & (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR))
-
-#ifndef ELF_F_PERMISSIVE
-# define ELF_F_PERMISSIVE 0
-#endif
-
-void
-read_dynamic (DSO *dso)
-{
- int i;
-
- memset (dso->info, 0, sizeof(dso->info));
- dso->info_set_mask = 0;
- for (i = 0; i < dso->ehdr.e_shnum; i++)
- if (dso->shdr[i].sh_type == SHT_DYNAMIC)
- {
- Elf_Data *data = NULL;
- Elf_Scn *scn = dso->scn[i];
- GElf_Dyn dyn;
-
- dso->dynamic = i;
- while ((data = elf_getdata (scn, data)) != NULL)
- {
- int ndx, maxndx;
-
- maxndx = data->d_size / dso->shdr[i].sh_entsize;
- for (ndx = 0; ndx < maxndx; ++ndx)
- {
- gelfx_getdyn (dso->elf, data, ndx, &dyn);
- if (dyn.d_tag == DT_NULL)
- break;
- else if ((GElf_Xword) dyn.d_tag < DT_NUM)
- {
- dso->info[dyn.d_tag] = dyn.d_un.d_val;
- if (dyn.d_tag < 50)
- dso->info_set_mask |= (1ULL << dyn.d_tag);
- }
- else if (dyn.d_tag == DT_CHECKSUM)
- {
- dso->info_DT_CHECKSUM = dyn.d_un.d_val;
- dso->info_set_mask |= (1ULL << DT_CHECKSUM_BIT);
- }
- else if (dyn.d_tag == DT_GNU_PRELINKED)
- {
- dso->info_DT_GNU_PRELINKED = dyn.d_un.d_val;
- dso->info_set_mask |= (1ULL << DT_GNU_PRELINKED_BIT);
- }
- else if (dyn.d_tag == DT_VERDEF)
- {
- dso->info_DT_VERDEF = dyn.d_un.d_val;
- dso->info_set_mask |= (1ULL << DT_VERDEF_BIT);
- }
- else if (dyn.d_tag == DT_VERNEED)
- {
- dso->info_DT_VERNEED = dyn.d_un.d_val;
- dso->info_set_mask |= (1ULL << DT_VERNEED_BIT);
- }
- else if (dyn.d_tag == DT_VERSYM)
- {
- dso->info_DT_VERSYM = dyn.d_un.d_val;
- dso->info_set_mask |= (1ULL << DT_VERSYM_BIT);
- }
- else if (dyn.d_tag == DT_FILTER)
- dso->info_set_mask |= (1ULL << DT_FILTER_BIT);
- else if (dyn.d_tag == DT_AUXILIARY)
- dso->info_set_mask |= (1ULL << DT_AUXILIARY_BIT);
- else if (dyn.d_tag == DT_LOPROC)
- dso->info_set_mask |= (1ULL << DT_LOPROC_BIT);
- else if (dyn.d_tag == DT_GNU_HASH)
- {
- dso->info_DT_GNU_HASH = dyn.d_un.d_val;
- dso->info_set_mask |= (1ULL << DT_GNU_HASH_BIT);
- }
- if (dso->ehdr.e_machine == EM_MIPS)
- {
- if (dyn.d_tag == DT_MIPS_LOCAL_GOTNO)
- dso->info_DT_MIPS_LOCAL_GOTNO = dyn.d_un.d_val;
- else if (dyn.d_tag == DT_MIPS_GOTSYM)
- dso->info_DT_MIPS_GOTSYM = dyn.d_un.d_val;
- else if (dyn.d_tag == DT_MIPS_SYMTABNO)
- dso->info_DT_MIPS_SYMTABNO = dyn.d_un.d_val;
- else if (dyn.d_tag == DT_MIPS_PLTGOT)
- dso->info_DT_MIPS_PLTGOT = dyn.d_un.d_val;
- }
- }
- if (ndx < maxndx)
- break;
- }
- }
-}
-
-int
-set_dynamic (DSO *dso, GElf_Word tag, GElf_Addr value, int fatal)
-{
- Elf_Data *data;
- Elf_Scn *scn;
- GElf_Dyn dyn;
- int ndx, maxndx;
- uint64_t mask = dso->info_set_mask;
-
- assert (dso->shdr[dso->dynamic].sh_type == SHT_DYNAMIC);
-
- scn = dso->scn[dso->dynamic];
-
- data = elf_getdata (scn, NULL);
- assert (elf_getdata (scn, data) == NULL);
-
- switch (tag)
- {
- case DT_CHECKSUM:
- mask |= (1ULL << DT_CHECKSUM_BIT); break;
- case DT_GNU_PRELINKED:
- mask |= (1ULL << DT_GNU_PRELINKED_BIT); break;
- case DT_VERDEF:
- mask |= (1ULL << DT_VERDEF_BIT); break;
- case DT_VERNEED:
- mask |= (1ULL << DT_VERNEED_BIT); break;
- case DT_VERSYM:
- mask |= (1ULL << DT_VERSYM_BIT); break;
- default:
- if (tag < DT_NUM && tag < 50)
- mask |= (1ULL << tag);
- break;
- }
-
- maxndx = data->d_size / dso->shdr[dso->dynamic].sh_entsize;
- for (ndx = 0; ndx < maxndx; ndx++)
- {
- gelfx_getdyn (dso->elf, data, ndx, &dyn);
- if (dyn.d_tag == DT_NULL)
- break;
- else if (dyn.d_tag == tag)
- {
- if (dyn.d_un.d_ptr != value)
- {
- dyn.d_un.d_ptr = value;
- gelfx_update_dyn (dso->elf, data, ndx, &dyn);
- elf_flagscn (scn, ELF_C_SET, ELF_F_DIRTY);
- }
-
- return 0;
- }
- }
- assert (ndx < maxndx);
-
- if (ndx + 1 < maxndx)
- {
- /* DT_NULL is not the last dynamic entry. */
- gelfx_update_dyn (dso->elf, data, ndx + 1, &dyn);
- dyn.d_tag = tag;
- dyn.d_un.d_ptr = value;
- gelfx_update_dyn (dso->elf, data, ndx, &dyn);
- dso->info_set_mask = mask;
- elf_flagscn (scn, ELF_C_SET, ELF_F_DIRTY);
- return 0;
- }
-
- if (fatal)
- error (0, 0, "%s: Not enough room to add .dynamic entry",
- dso->filename);
- return 1;
-}
-
-int
-check_dso (DSO *dso)
-{
- int i, last = 1;
-
- /* FIXME: Several routines in prelink and in libelf-0.7.0 too
- rely on sh_offset's monotonically increasing. */
- for (i = 2; i < dso->ehdr.e_shnum; ++i)
- {
- if (dso->shdr[last].sh_offset
- + (dso->shdr[last].sh_type == SHT_NOBITS
- ? 0 : dso->shdr[last].sh_size) > dso->shdr[i].sh_offset)
- {
- if (!dso->permissive
- || RELOCATE_SCN (dso->shdr[last].sh_flags)
- || RELOCATE_SCN (dso->shdr[i].sh_flags))
- {
- error (0, 0, "%s: section file offsets not monotonically increasing",
- dso->filename);
- return 1;
- }
- }
- if (!dso->permissive
- || (dso->shdr[i].sh_type != SHT_NOBITS && dso->shdr[i].sh_size != 0))
- last = i;
- }
- return 0;
-}
-
-DSO *
-open_dso (const char *name)
-{
- int fd;
-
- fd = wrap_open (name, O_RDONLY);
- if (fd == -1)
- {
- error (0, errno, "cannot open \"%s\"", name);
- return NULL;
- }
- return fdopen_dso (fd, name);
-}
-
-/* WARNING: If prelink is ever multi-threaded, this will not work
- Other alternatives are:
- 1) make section_cmp nested function - trampolines
- vs. non-exec stack needs to be resolved for it though
- 2) make the variable __thread
- 3) use locking around the qsort
- */
-static DSO *section_cmp_dso;
-
-static int
-section_cmp (const void *A, const void *B)
-{
- int *a = (int *) A;
- int *b = (int *) B;
- DSO *dso = section_cmp_dso;
-
- if (dso->shdr[*a].sh_offset < dso->shdr[*b].sh_offset)
- return -1;
- if (dso->shdr[*a].sh_offset > dso->shdr[*b].sh_offset)
- return 1;
- if (*a < *b)
- return -1;
- return *a > *b;
-}
-
-DSO *
-fdopen_dso (int fd, const char *name)
-{
- Elf *elf = NULL;
- GElf_Ehdr ehdr;
- GElf_Addr last_off;
- int i, j, k, last, *sections, *invsections;
- DSO *dso = NULL;
-#if 0
- struct PLArch *plarch;
- extern struct PLArch __start_pl_arch[], __stop_pl_arch[];
-#endif
-
- elf = elf_begin (fd, ELF_C_READ, NULL);
- if (elf == NULL)
- {
- error (0, 0, "cannot open ELF file: %s (dso_readonly)", elf_errmsg (-1));
- goto error_out;
- }
-
- if (elf_kind (elf) != ELF_K_ELF)
- {
- error (0, 0, "\"%s\" is not an ELF file", name);
- goto error_out;
- }
-
- if (gelf_getehdr (elf, &ehdr) == NULL)
- {
- error (0, 0, "cannot get the ELF header: %s",
- elf_errmsg (-1));
- goto error_out;
- }
-
- if (ehdr.e_type != ET_DYN && ehdr.e_type != ET_EXEC)
- {
- error (0, 0, "\"%s\" is not a shared library", name);
- goto error_out;
- }
-
- if (ehdr.e_shnum == 0)
- {
- GElf_Phdr phdr;
-
- /* Check for UPX compressed executables. */
- if (ehdr.e_type == ET_EXEC
- && ehdr.e_phnum > 0
- && (gelf_getphdr (elf, 0, &phdr), phdr.p_type == PT_LOAD)
- && phdr.p_filesz >= 256
- && phdr.p_filesz <= 4096
- && phdr.p_offset == 0
- && ehdr.e_phoff + ehdr.e_phnum * ehdr.e_phentsize < phdr.p_filesz)
- {
- char *buf = alloca (phdr.p_filesz);
- size_t start = ehdr.e_phoff + ehdr.e_phnum * ehdr.e_phentsize;
-
- if (pread (fd, buf, phdr.p_filesz, 0) == phdr.p_filesz
- && memmem (buf + start, phdr.p_filesz - start,
- "UPX!", 4) != NULL)
- {
- error (0, 0, "\"%s\" is UPX compressed executable", name);
- goto error_out;
- }
- }
- error (0, 0, "\"%s\" has no section headers", name);
- goto error_out;
- }
-
- /* Allocate DSO structure. Leave place for additional 20 new section
- headers. */
- dso = (DSO *)
- malloc (sizeof(DSO) + (ehdr.e_shnum + 20) * sizeof(GElf_Shdr)
- + (ehdr.e_phnum + 1) * sizeof(GElf_Phdr)
- + (ehdr.e_shnum + 20) * sizeof(Elf_Scn *));
- if (!dso)
- {
- error (0, ENOMEM, "Could not open DSO");
- goto error_out;
- }
-
- elf_flagelf (elf, ELF_C_SET, ELF_F_LAYOUT | ELF_F_PERMISSIVE);
-
- memset (dso, 0, sizeof(DSO));
- dso->elf = elf;
- dso->ehdr = ehdr;
- dso->phdr = (GElf_Phdr *) &dso->shdr[ehdr.e_shnum + 20];
- dso->scn = (Elf_Scn **) &dso->phdr[ehdr.e_phnum + 1];
- switch (ehdr.e_ident[EI_CLASS])
- {
- case ELFCLASS32:
- dso->mask = 0xffffffff; break;
- case ELFCLASS64:
- dso->mask = 0xffffffffffffffffULL; break;
- }
- for (i = 0; i < ehdr.e_phnum; ++i)
- gelf_getphdr (elf, i, dso->phdr + i);
- dso->fd = fd;
-
- for (i = 0, j = 0; i < ehdr.e_shnum; ++i)
- {
- dso->scn[i] = elf_getscn (elf, i);
- gelfx_getshdr (elf, dso->scn[i], dso->shdr + i);
- if ((dso->shdr[i].sh_flags & SHF_ALLOC) && dso->shdr[i].sh_type != SHT_NOBITS)
- j = 1;
- }
- if (j == 0)
- {
- /* If all ALLOC sections are SHT_NOBITS, then this is a
- stripped-to-file debuginfo. Skip it silently. */
- goto error_out;
- }
-
- sections = (int *) alloca (dso->ehdr.e_shnum * sizeof (int) * 2);
- sections[0] = 0;
- for (i = 1, j = 1, k = dso->ehdr.e_shnum, last = -1;
- i < dso->ehdr.e_shnum; ++i)
- if (RELOCATE_SCN (dso->shdr[i].sh_flags))
- {
- last = i;
- sections[j++] = i;
- }
- else
- sections[--k] = i;
- assert (j == k);
-
- section_cmp_dso = dso;
- qsort (sections + k, dso->ehdr.e_shnum - k, sizeof (*sections), section_cmp);
- invsections = sections + dso->ehdr.e_shnum;
- invsections[0] = 0;
- for (i = 1, j = 0; i < ehdr.e_shnum; ++i)
- {
- if (i != sections[i])
- {
- j = 1;
- dso->scn[i] = elf_getscn (elf, sections[i]);
- gelfx_getshdr (elf, dso->scn[i], dso->shdr + i);
- }
- invsections[sections[i]] = i;
- }
-
-#if 0
- if (j)
- {
- dso->move = init_section_move (dso);
- if (dso->move == NULL)
- goto error_out;
- memcpy (dso->move->old_to_new, invsections, dso->ehdr.e_shnum * sizeof (int));
- memcpy (dso->move->new_to_old, sections, dso->ehdr.e_shnum * sizeof (int));
- }
-#endif
-
- last_off = 0;
- for (i = 1; i < ehdr.e_shnum; ++i)
- {
- if (dso->shdr[i].sh_link >= ehdr.e_shnum)
- {
- error (0, 0, "%s: bogus sh_link value %d", name,
- dso->shdr[i].sh_link);
- goto error_out;
- }
- dso->shdr[i].sh_link = invsections[dso->shdr[i].sh_link];
- if (dso->shdr[i].sh_type == SHT_REL
- || dso->shdr[i].sh_type == SHT_RELA
- || (dso->shdr[i].sh_flags & SHF_INFO_LINK))
- {
- if (dso->shdr[i].sh_info >= ehdr.e_shnum)
- {
- error (0, 0, "%s: bogus sh_info value %d", name,
- dso->shdr[i].sh_info);
- goto error_out;
- }
- dso->shdr[i].sh_info = invsections[dso->shdr[i].sh_info];
- }
-
- /* Some linkers mess up sh_offset fields for empty or nobits
- sections. */
- if (RELOCATE_SCN (dso->shdr[i].sh_flags)
- && (dso->shdr[i].sh_size == 0
- || dso->shdr[i].sh_type == SHT_NOBITS))
- {
- for (j = i + 1; j < ehdr.e_shnum; ++j)
- if (! RELOCATE_SCN (dso->shdr[j].sh_flags))
- break;
- else if (dso->shdr[j].sh_size != 0
- && dso->shdr[j].sh_type != SHT_NOBITS)
- break;
- dso->shdr[i].sh_offset = (last_off + dso->shdr[i].sh_addralign - 1)
- & ~(dso->shdr[i].sh_addralign - 1);
- if (j < ehdr.e_shnum
- && dso->shdr[i].sh_offset > dso->shdr[j].sh_offset)
- {
- GElf_Addr k;
-
- for (k = dso->shdr[i].sh_addralign - 1; k; )
- {
- k >>= 1;
- dso->shdr[i].sh_offset = (last_off + k) & ~k;
- if (dso->shdr[i].sh_offset <= dso->shdr[j].sh_offset)
- break;
- }
- }
- last_off = dso->shdr[i].sh_offset;
- }
- else
- last_off = dso->shdr[i].sh_offset + dso->shdr[i].sh_size;
- }
- dso->ehdr.e_shstrndx = invsections[dso->ehdr.e_shstrndx];
-
-#if 0
- for (plarch = __start_pl_arch; plarch < __stop_pl_arch; plarch++)
- if (plarch->class == ehdr.e_ident[EI_CLASS]
- && (plarch->machine == ehdr.e_machine
- || plarch->alternate_machine[0] == ehdr.e_machine
- || plarch->alternate_machine[1] == ehdr.e_machine
- || plarch->alternate_machine[2] == ehdr.e_machine))
- break;
-
- if (plarch == __stop_pl_arch || ehdr.e_machine == EM_NONE)
- {
- error (0, 0, "\"%s\"'s architecture is not supported", name);
- goto error_out;
- }
-
- dso->arch = plarch;
-#else
- dso->arch = NULL;
-#endif
-
- dso->base = ~(GElf_Addr) 0;
- dso->align = 0;
- dso->end = 0;
- for (i = 0; i < dso->ehdr.e_phnum; i++)
- if (dso->phdr[i].p_type == PT_LOAD)
- {
- GElf_Addr base, end;
-
- if (dso->phdr[i].p_align > dso->align)
- dso->align = dso->phdr[i].p_align;
- base = dso->phdr[i].p_vaddr & ~(dso->phdr[i].p_align - 1);
- end = dso->phdr[i].p_vaddr + dso->phdr[i].p_memsz;
- if (base < dso->base)
- dso->base = base;
- if (end > dso->end)
- dso->end = end;
- }
-
- if (dso->base == ~(GElf_Addr) 0)
- {
- error (0, 0, "%s: cannot find loadable segment", name);
- goto error_out;
- }
-
- read_dynamic (dso);
-
- dso->filename = (const char *) strdup (name);
- dso->soname = dso->filename;
- if (dso->info[DT_STRTAB] && dso->info[DT_SONAME])
- {
- const char *soname;
-
- soname = get_data (dso, dso->info[DT_STRTAB] + dso->info[DT_SONAME],
- NULL, NULL);
- if (soname && soname[0] != '\0')
- dso->soname = (const char *) strdup (soname);
- }
-
-#if 0
- if (dso->arch->machine == EM_ALPHA
- || dso->arch->machine == EM_MIPS)
- for (i = 1; i < ehdr.e_shnum; ++i)
- {
- if ((dso->shdr[i].sh_type == SHT_ALPHA_DEBUG
- && dso->arch->machine == EM_ALPHA)
- || (dso->shdr[i].sh_type == SHT_MIPS_DEBUG
- && dso->arch->machine == EM_MIPS))
- {
- const char *name
- = strptr (dso, dso->ehdr.e_shstrndx, dso->shdr[i].sh_name);
- if (! strcmp (name, ".mdebug"))
- dso->mdebug_orig_offset = dso->shdr[i].sh_offset;
- break;
- }
- }
-#endif
-
- return dso;
-
-error_out:
- if (dso)
- {
- free (dso->move);
- if (dso->soname != dso->filename)
- free ((char *) dso->soname);
- free ((char *) dso->filename);
- free (dso);
- }
- if (elf)
- elf_end (elf);
- if (fd != -1)
- {
- fsync (fd);
- close (fd);
- }
- return NULL;
-}
-
-#if 0
-
-static int
-adjust_symtab_section_indices (DSO *dso, int n, int old_shnum, int *old_to_new)
-{
- Elf_Data *data = NULL;
- Elf_Scn *scn = dso->scn[n];
- GElf_Sym sym;
- int changed = 0, ndx, maxndx;
-
- while ((data = elf_getdata (scn, data)) != NULL)
- {
- maxndx = data->d_size / dso->shdr[n].sh_entsize;
- for (ndx = 0; ndx < maxndx; ++ndx)
- {
- gelfx_getsym (dso->elf, data, ndx, &sym);
- if (sym.st_shndx > SHN_UNDEF && sym.st_shndx < SHN_LORESERVE)
- {
- if (sym.st_shndx >= old_shnum
- || old_to_new[sym.st_shndx] == -1)
- {
- if (! sym.st_size &&
- sym.st_info == ELF32_ST_INFO (STB_LOCAL, STT_SECTION))
- {
- sym.st_value = 0;
- sym.st_shndx = SHN_UNDEF;
- gelfx_update_sym (dso->elf, data, ndx, &sym);
- changed = 1;
- continue;
- }
- else
- {
- if (sym.st_shndx >= old_shnum)
- {
- error (0, 0, "%s: Symbol section index outside of section numbers",
- dso->filename);
- return 1;
- }
- error (0, 0, "%s: Section symbol points into has been removed",
- dso->filename);
- return 1;
- }
- }
- if (old_to_new[sym.st_shndx] != sym.st_shndx)
- {
- changed = 1;
- sym.st_shndx = old_to_new[sym.st_shndx];
- gelfx_update_sym (dso->elf, data, ndx, &sym);
- }
- }
- }
- }
-
- if (changed)
- elf_flagscn (scn, ELF_C_SET, ELF_F_DIRTY);
-
- return 0;
-}
-
-static int
-set_stt_section_values (DSO *dso, int n)
-{
- Elf_Data *data;
- Elf_Scn *scn = dso->scn[n];
- GElf_Sym sym;
- int ndx, maxndx, sec;
- char seen[dso->ehdr.e_shnum];
-
- memset (seen, 0, dso->ehdr.e_shnum);
- data = elf_getdata (scn, NULL);
- assert (data != NULL);
- assert (elf_getdata (scn, data) == NULL);
- assert (data->d_off == 0);
-
- maxndx = data->d_size / dso->shdr[n].sh_entsize;
- gelfx_getsym (dso->elf, data, 0, &sym);
- if (sym.st_info != ELF32_ST_INFO (STB_LOCAL, STT_NOTYPE)
- || sym.st_size != 0 || sym.st_other != 0
- || sym.st_value != 0 || sym.st_shndx != SHN_UNDEF
- || sym.st_name != 0)
- return 0;
-
- for (ndx = 1; ndx < maxndx; ++ndx)
- {
- gelfx_getsym (dso->elf, data, ndx, &sym);
- if (sym.st_info == ELF32_ST_INFO (STB_LOCAL, STT_SECTION)
- && sym.st_size == 0 && sym.st_other == 0
- && sym.st_name == 0)
- {
- if (sym.st_shndx > SHN_UNDEF && sym.st_shndx < SHN_LORESERVE)
- {
- seen[sym.st_shndx] = 1;
- sym.st_value = dso->shdr[sym.st_shndx].sh_addr;
- gelfx_update_sym (dso->elf, data, ndx, &sym);
- }
- }
- else
- break;
- }
-
- for (ndx = 1, sec = 1; ndx < maxndx; ++ndx)
- {
- gelfx_getsym (dso->elf, data, ndx, &sym);
- if (sym.st_info == ELF32_ST_INFO (STB_LOCAL, STT_SECTION)
- && sym.st_size == 0 && sym.st_other == 0
- && sym.st_name == 0)
- {
- if (sym.st_shndx == SHN_UNDEF)
- {
- while (sec < dso->ehdr.e_shnum && seen[sec])
- ++sec;
-
- if (sec >= dso->ehdr.e_shnum)
- sym.st_value = 0;
- else
- sym.st_value = dso->shdr[sec].sh_addr;
- sym.st_shndx = sec++;
- gelfx_update_sym (dso->elf, data, ndx, &sym);
- }
- }
- else
- break;
- }
-
- return 0;
-}
-
-struct section_move *
-init_section_move (DSO *dso)
-{
- struct section_move *move;
- int i;
-
- move = malloc (sizeof (struct section_move)
- + (dso->ehdr.e_shnum * 2 + 20) * sizeof (int));
- if (move == NULL)
- {
- error (0, ENOMEM, "%s: Could not move sections", dso->filename);
- return move;
- }
- move->old_shnum = dso->ehdr.e_shnum;
- move->new_shnum = dso->ehdr.e_shnum;
- move->old_to_new = (int *)(move + 1);
- move->new_to_old = move->old_to_new + move->new_shnum;
- for (i = 0; i < move->new_shnum; i++)
- {
- move->old_to_new[i] = i;
- move->new_to_old[i] = i;
- }
- return move;
-}
-
-void
-add_section (struct section_move *move, int sec)
-{
- int i;
-
- assert (move->new_shnum < move->old_shnum + 20);
- assert (sec <= move->new_shnum);
-
- memmove (move->new_to_old + sec + 1, move->new_to_old + sec,
- (move->new_shnum - sec) * sizeof (int));
- ++move->new_shnum;
- move->new_to_old[sec] = -1;
- for (i = 1; i < move->old_shnum; i++)
- if (move->old_to_new[i] >= sec)
- ++move->old_to_new[i];
-}
-
-void
-remove_section (struct section_move *move, int sec)
-{
- int i;
-
- assert (sec < move->new_shnum);
-
- memmove (move->new_to_old + sec, move->new_to_old + sec + 1,
- (move->new_shnum - sec - 1) * sizeof (int));
- --move->new_shnum;
- for (i = 1; i < move->old_shnum; i++)
- if (move->old_to_new[i] == sec)
- move->old_to_new[i] = -1;
- else if (move->old_to_new[i] > sec)
- --move->old_to_new[i];
-}
-
-int
-reopen_dso (DSO *dso, struct section_move *move, const char *temp_base)
-{
- char filename[strlen (temp_base ? temp_base : dso->filename)
- + sizeof ("/dev/shm/.#prelink#.XXXXXX")];
- int adddel = 0;
- int free_move = 0;
- Elf *elf = NULL;
- GElf_Ehdr ehdr;
- char *e_ident;
- int fd, i, j;
-
- if (move == NULL)
- {
- move = init_section_move (dso);
- if (move == NULL)
- return 1;
- free_move = 1;
- }
- else
- assert (dso->ehdr.e_shnum == move->old_shnum);
-
- if (temp_base == NULL)
- temp_base = dso->filename;
- sprintf (filename, "%s.#prelink#.XXXXXX", temp_base);
-
- fd = wrap_mkstemp (filename);
- if (fd == -1)
- {
- strcpy (filename, "/tmp/#prelink#.XXXXXX");
- fd = wrap_mkstemp (filename);
- if (fd == -1)
- {
- strcpy (filename, "/dev/shm/#prelink#.XXXXXX");
- fd = wrap_mkstemp (filename);
- }
- if (fd == -1)
- {
- error (0, errno, "Could not create temporary file %s", filename);
- goto error_out;
- }
- }
-
- elf = elf_begin (fd, ELF_C_WRITE, NULL);
- if (elf == NULL)
- {
- error (0, 0, "cannot open ELF file: %s (elf_begin failed, dso_readonly)", elf_errmsg (-1));
- goto error_out;
-
- }
-
- /* Some gelf_newehdr implementations don't return the resulting
- ElfNN_Ehdr, so we have to do it the hard way instead of:
- e_ident = (char *) gelf_newehdr (elf, gelf_getclass (dso->elf)); */
- switch (gelf_getclass (dso->elf))
- {
- case ELFCLASS32:
- e_ident = (char *) elf32_newehdr (elf);
- break;
- case ELFCLASS64:
- e_ident = (char *) elf64_newehdr (elf);
- break;
- default:
- e_ident = NULL;
- break;
- }
-
- if (e_ident == NULL
- /* This is here just for the gelfx wrapper, so that gelf_update_ehdr
- already has the correct ELF class. */
- || memcpy (e_ident, dso->ehdr.e_ident, EI_NIDENT) == NULL
- || gelf_update_ehdr (elf, &dso->ehdr) == 0
- || gelf_newphdr (elf, dso->ehdr.e_phnum) == 0)
- {
- error (0, 0, "Could not create new ELF headers");
- goto error_out;
- }
- ehdr = dso->ehdr;
- elf_flagelf (elf, ELF_C_SET, ELF_F_LAYOUT | ELF_F_PERMISSIVE);
- for (i = 0; i < ehdr.e_phnum; ++i)
- gelf_update_phdr (elf, i, dso->phdr + i);
-
- for (i = 1; i < move->new_shnum; ++i)
- {
- Elf_Scn *scn;
- Elf_Data data, *data1, *data2;
-
- if (move->new_to_old[i] == -1)
- {
- scn = elf_newscn (elf);
- elf_newdata (scn);
- }
- else
- {
- j = move->new_to_old[i];
- scn = elf_newscn (elf);
- gelfx_update_shdr (elf, scn, &dso->shdr[j]);
- if (dso->shdr[j].sh_type == SHT_NOBITS)
- {
- data1 = elf_getdata (dso->scn[j], NULL);
- data2 = elf_newdata (scn);
- memcpy (data2, data1, sizeof (*data1));
- }
- else
- {
- memset (&data, 0, sizeof data);
- data.d_type = ELF_T_NUM;
- data1 = NULL;
- while ((data1 = elf_getdata (dso->scn[j], data1))
- != NULL)
- {
- if (data.d_type == ELF_T_NUM)
- data = *data1;
- else if (data.d_type != data1->d_type
- || data.d_version != data1->d_version)
- abort ();
- else
- {
- if (data1->d_off < data.d_off)
- {
- data.d_size += data.d_off - data1->d_off;
- data.d_off = data1->d_off;
- }
- if (data1->d_off + data1->d_size
- > data.d_off + data.d_size)
- data.d_size = data1->d_off + data1->d_size
- - data.d_off;
- if (data1->d_align > data.d_align)
- data.d_align = data1->d_align;
- }
- }
- if (data.d_type == ELF_T_NUM)
- {
- assert (dso->shdr[j].sh_size == 0);
- continue;
- }
- if (data.d_size != 0)
- {
- data.d_buf = calloc (1, data.d_size);
- if (data.d_buf == NULL)
- {
- error (0, ENOMEM, "%s: Could not copy section",
- dso->filename);
- goto error_out;
- }
- }
- else
- data.d_buf = NULL;
- data1 = NULL;
- while ((data1 = elf_getdata (dso->scn[j], data1))
- != NULL)
- memcpy (data.d_buf + data1->d_off - data.d_off, data1->d_buf,
- data1->d_size);
- data2 = elf_newdata (scn);
- memcpy (data2, &data, sizeof (data));
- }
- }
- }
-
- ehdr.e_shnum = move->new_shnum;
- dso->temp_filename = strdup (filename);
- if (dso->temp_filename == NULL)
- {
- error (0, ENOMEM, "%s: Could not save temporary filename", dso->filename);
- goto error_out;
- }
- dso->elfro = dso->elf;
- dso->elf = elf;
- dso->fdro = dso->fd;
- dso->fd = fd;
- dso->ehdr = ehdr;
- dso->lastscn = 0;
- elf = NULL;
- fd = -1;
- for (i = 1; i < move->old_shnum; i++)
- if (move->old_to_new[i] != i)
- {
- adddel = 1;
- break;
- }
- if (! adddel)
- for (i = 1; i < move->new_shnum; i++)
- if (move->new_to_old[i] != i)
- {
- adddel = 1;
- break;
- }
-
- for (i = 1; i < move->new_shnum; i++)
- {
- dso->scn[i] = elf_getscn (dso->elf, i);
- gelfx_getshdr (dso->elf, dso->scn[i], dso->shdr + i);
- if (move->new_to_old[i] == -1)
- continue;
- if (dso->move
- && (dso->shdr[i].sh_type == SHT_SYMTAB
- || dso->shdr[i].sh_type == SHT_DYNSYM))
- {
- if (adjust_symtab_section_indices (dso, i, dso->move->old_shnum,
- dso->move->old_to_new))
- goto error_out;
- }
- if (adddel)
- {
- if (dso->shdr[i].sh_link)
- {
- if (dso->shdr[i].sh_link >= move->old_shnum)
- {
- error (0, 0, "%s: bogus sh_link value %d", dso->filename,
- dso->shdr[i].sh_link);
- goto error_out;
- }
- if (move->old_to_new[dso->shdr[i].sh_link] == -1)
- {
- error (0, 0, "Section sh_link points to has been removed");
- goto error_out;
- }
- dso->shdr[i].sh_link = move->old_to_new[dso->shdr[i].sh_link];
- }
- /* Only some section types use sh_info for section index. */
- if (dso->shdr[i].sh_info
- && (dso->shdr[i].sh_type == SHT_REL
- || dso->shdr[i].sh_type == SHT_RELA
- || (dso->shdr[i].sh_flags & SHF_INFO_LINK)))
- {
- if (dso->shdr[i].sh_info >= move->old_shnum)
- {
- error (0, 0, "%s: bogus sh_info value %d", dso->filename,
- dso->shdr[i].sh_info);
- goto error_out;
- }
- if (move->old_to_new[dso->shdr[i].sh_info] == -1)
- {
- error (0, 0, "Section sh_info points to has been removed");
- goto error_out;
- }
- dso->shdr[i].sh_info = move->old_to_new[dso->shdr[i].sh_info];
- }
- if (dso->shdr[i].sh_type == SHT_SYMTAB
- || dso->shdr[i].sh_type == SHT_DYNSYM)
- {
- if (adjust_symtab_section_indices (dso, i, move->old_shnum,
- move->old_to_new))
- goto error_out;
- }
- }
- }
-
- free (dso->move);
- dso->move = NULL;
-
- dso->ehdr.e_shstrndx = move->old_to_new[dso->ehdr.e_shstrndx];
- gelf_update_ehdr (dso->elf, &dso->ehdr);
-
- read_dynamic (dso);
-
- /* If shoff does not point after last section, we need to adjust the sections
- after it if we added or removed some sections. */
- if (move->old_shnum != move->new_shnum
- && adjust_dso_nonalloc (dso, 0, dso->ehdr.e_shoff + 1,
- ((long) move->new_shnum - (long) move->old_shnum)
- * gelf_fsize (dso->elf, ELF_T_SHDR, 1,
- EV_CURRENT)))
- goto error_out;
-
- if (free_move)
- free (move);
- return 0;
-
-error_out:
- if (free_move)
- free (move);
- if (elf)
- elf_end (elf);
- if (fd != -1)
- {
- wrap_unlink (filename);
- fsync (fd);
- close (fd);
- }
- return 1;
-}
-
-/* Return true if the value of symbol SYM, which belongs to DSO,
- should be treated as an address within the DSO, and should
- therefore track DSO's relocations. */
-
-int
-adjust_symbol_p (DSO *dso, GElf_Sym *sym)
-{
- if (sym->st_shndx == SHN_ABS
- && sym->st_value != 0
- && (GELF_ST_TYPE (sym->st_info) <= STT_FUNC
- || (dso->ehdr.e_machine == EM_ARM
- && GELF_ST_TYPE (sym->st_info) == STT_ARM_TFUNC)))
- /* This is problematic. How do we find out if
- we should relocate this? Assume we should. */
- return 1;
-
- /* If a MIPS object does not define a symbol, but has a lazy binding
- stub for it, st_value will point to that stub. Note that unlike
- other targets, these stub addresses never participate in symbol
- lookup; the stubs can only be called by the object that defines them.
- st_values are only used in this way so that the associated GOT entry
- can store a Quickstart value without losing the original stub
- address. */
- if (dso->ehdr.e_machine == EM_MIPS
- && sym->st_shndx == SHN_UNDEF
- && sym->st_value != 0)
- return 1;
-
- return (sym->st_shndx > SHN_UNDEF
- && sym->st_shndx < dso->ehdr.e_shnum
- && ELF32_ST_TYPE (sym->st_info) != STT_TLS
- && RELOCATE_SCN (dso->shdr[sym->st_shndx].sh_flags));
-}
-
-static int
-adjust_symtab (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust)
-{
- Elf_Data *data = NULL;
- Elf_Scn *scn = dso->scn[n];
- GElf_Sym sym;
- int ndx, maxndx;
-
- while ((data = elf_getdata (scn, data)) != NULL)
- {
- maxndx = data->d_size / dso->shdr[n].sh_entsize;
- for (ndx = 0; ndx < maxndx; ++ndx)
- {
- gelfx_getsym (dso->elf, data, ndx, &sym);
- if (adjust_symbol_p (dso, &sym) && sym.st_value >= start)
- {
- sym.st_value += adjust;
- gelfx_update_sym (dso->elf, data, ndx, &sym);
- }
- }
- }
-
- elf_flagscn (scn, ELF_C_SET, ELF_F_DIRTY);
- return 0;
-}
-
-#endif
-
-int
-dso_is_rdwr (DSO *dso)
-{
- return dso->elfro != NULL;
-}
-
-#if 0
-
-GElf_Addr
-adjust_old_to_new (DSO *dso, GElf_Addr addr)
-{
- int i;
-
- if (dso->adjust == NULL)
- return addr; /* Fast path. */
-
- for (i = 0; i < dso->nadjust; i++)
- if (addr >= dso->adjust[i].start)
- {
- addr += dso->adjust[i].adjust;
- assert (dso->ehdr.e_ident[EI_CLASS] != ELFCLASS32
- || addr == (Elf32_Addr) addr);
- return addr;
- }
-
- return addr;
-}
-
-GElf_Addr
-adjust_new_to_old (DSO *dso, GElf_Addr addr)
-{
- int i;
-
- if (dso->adjust == NULL)
- return addr; /* Fast path. */
-
- for (i = 0; i < dso->nadjust; i++)
- if (addr >= dso->adjust[i].start + dso->adjust[i].adjust)
- {
- addr -= dso->adjust[i].adjust;
- assert (dso->ehdr.e_ident[EI_CLASS] != ELFCLASS32
- || addr == (Elf32_Addr) addr);
- return addr;
- }
-
- return addr;
-}
-
-static int
-adjust_dynamic (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust)
-{
- Elf_Data *data = NULL;
- Elf_Scn *scn = dso->scn[n];
- GElf_Dyn dyn;
- int ndx, maxndx;
-
- while ((data = elf_getdata (scn, data)) != NULL)
- {
- maxndx = data->d_size / dso->shdr[n].sh_entsize;
- for (ndx = 0; ndx < maxndx; ++ndx)
- {
- gelfx_getdyn (dso->elf, data, ndx, &dyn);
- if (dso->arch->adjust_dyn (dso, n, &dyn, start, adjust) == 0)
- switch (dyn.d_tag)
- {
- case DT_REL:
- case DT_RELA:
- /* On some arches DT_REL* may be 0 indicating no relocations
- (if DT_REL*SZ is also 0). Don't adjust it in that case. */
- if (dyn.d_un.d_ptr && dyn.d_un.d_ptr >= start)
- {
- dyn.d_un.d_ptr += adjust;
- gelfx_update_dyn (dso->elf, data, ndx, &dyn);
- }
- break;
- default:
- if (dyn.d_tag < DT_ADDRRNGLO || dyn.d_tag > DT_ADDRRNGHI)
- break;
- /* FALLTHROUGH */
- case DT_INIT:
- case DT_FINI:
- case DT_HASH:
- case DT_STRTAB:
- case DT_SYMTAB:
- case DT_JMPREL:
- case DT_INIT_ARRAY:
- case DT_FINI_ARRAY:
- case DT_PREINIT_ARRAY:
- case DT_VERDEF:
- case DT_VERNEED:
- case DT_VERSYM:
- case DT_PLTGOT:
- if (dyn.d_un.d_ptr >= start)
- {
- dyn.d_un.d_ptr += adjust;
- gelfx_update_dyn (dso->elf, data, ndx, &dyn);
- }
- break;
- }
- else
- gelfx_update_dyn (dso->elf, data, ndx, &dyn);
- }
- }
-
- elf_flagscn (scn, ELF_C_SET, ELF_F_DIRTY);
-
- /* Update the cached dynamic info as well. */
- read_dynamic (dso);
- return 0;
-}
-
-#endif
-
-int
-addr_to_sec (DSO *dso, GElf_Addr addr)
-{
- GElf_Shdr *shdr;
- int i;
-
- shdr = &dso->shdr[dso->lastscn];
- for (i = -1; i < dso->ehdr.e_shnum; shdr = &dso->shdr[++i])
- if (RELOCATE_SCN (shdr->sh_flags)
- && shdr->sh_addr <= addr && shdr->sh_addr + shdr->sh_size > addr
- && (shdr->sh_type != SHT_NOBITS || (shdr->sh_flags & SHF_TLS) == 0))
- {
- if (i != -1)
- dso->lastscn = i;
- return dso->lastscn;
- }
-
- return -1;
-}
-
-#if 0
-
-static int
-adjust_rel (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust)
-{
- Elf_Data *data = NULL;
- Elf_Scn *scn = dso->scn[n];
- GElf_Rel rel;
- int sec, ndx, maxndx;
-
- while ((data = elf_getdata (scn, data)) != NULL)
- {
- maxndx = data->d_size / dso->shdr[n].sh_entsize;
- for (ndx = 0; ndx < maxndx; ++ndx)
- {
- gelfx_getrel (dso->elf, data, ndx, &rel);
- sec = addr_to_sec (dso, rel.r_offset);
- if (sec == -1)
- continue;
-
- dso->arch->adjust_rel (dso, &rel, start, adjust);
- addr_adjust (rel.r_offset, start, adjust);
- gelfx_update_rel (dso->elf, data, ndx, &rel);
- }
- }
-
- elf_flagscn (scn, ELF_C_SET, ELF_F_DIRTY);
- return 0;
-}
-
-static int
-adjust_rela (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust)
-{
- Elf_Data *data = NULL;
- Elf_Scn *scn = dso->scn[n];
- GElf_Rela rela;
- int sec, ndx, maxndx;
-
- while ((data = elf_getdata (scn, data)) != NULL)
- {
- maxndx = data->d_size / dso->shdr[n].sh_entsize;
- for (ndx = 0; ndx < maxndx; ++ndx)
- {
- gelfx_getrela (dso->elf, data, ndx, &rela);
- sec = addr_to_sec (dso, rela.r_offset);
- if (sec == -1)
- continue;
-
- dso->arch->adjust_rela (dso, &rela, start, adjust);
- addr_adjust (rela.r_offset, start, adjust);
- gelfx_update_rela (dso->elf, data, ndx, &rela);
- }
- }
-
- elf_flagscn (scn, ELF_C_SET, ELF_F_DIRTY);
- return 0;
-}
-
-int
-adjust_nonalloc (DSO *dso, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int first,
- GElf_Addr start, GElf_Addr adjust)
-{
- int i;
-
- for (i = 1; i < ehdr->e_shnum; i++)
- {
- if (RELOCATE_SCN (shdr[i].sh_flags) || shdr[i].sh_type == SHT_NULL)
- continue;
-
- if ((shdr[i].sh_offset > start
- || (shdr[i].sh_offset == start && i >= first))
- && (adjust & (shdr[i].sh_addralign - 1)))
- adjust = (adjust + shdr[i].sh_addralign - 1)
- & ~(shdr[i].sh_addralign - 1);
- }
-
- if (ehdr->e_shoff >= start)
- {
- GElf_Addr shdralign = gelf_fsize (dso->elf, ELF_T_ADDR, 1, EV_CURRENT);
-
- if (adjust & (shdralign - 1))
- adjust = (adjust + shdralign - 1) & ~(shdralign - 1);
- ehdr->e_shoff += adjust;
- }
-
- for (i = 1; i < ehdr->e_shnum; i++)
- {
- if (RELOCATE_SCN (shdr[i].sh_flags) || shdr[i].sh_type == SHT_NULL)
- continue;
-
- if (shdr[i].sh_offset > start
- || (shdr[i].sh_offset == start && i >= first))
- shdr[i].sh_offset += adjust;
- }
- return 0;
-}
-
-int
-adjust_dso_nonalloc (DSO *dso, int first, GElf_Addr start, GElf_Addr adjust)
-{
- return adjust_nonalloc (dso, &dso->ehdr, dso->shdr, first, start, adjust);
-}
-
-/* Add ADJUST to all addresses above START. */
-int
-adjust_dso (DSO *dso, GElf_Addr start, GElf_Addr adjust)
-{
- int i;
-
- if (dso->arch->arch_adjust
- && dso->arch->arch_adjust (dso, start, adjust))
- return 1;
-
- if (dso->ehdr.e_entry >= start)
- {
- dso->ehdr.e_entry += adjust;
- gelf_update_ehdr (dso->elf, &dso->ehdr);
- elf_flagehdr (dso->elf, ELF_C_SET, ELF_F_DIRTY);
- }
-
- for (i = 0; i < dso->ehdr.e_phnum; i++)
- {
- /* Leave STACK segment alone, it has
- p_vaddr == p_paddr == p_offset == p_filesz == p_memsz == 0. */
- if (dso->phdr[i].p_type == PT_GNU_STACK)
- continue;
- if (! start)
- {
- dso->phdr[i].p_vaddr += adjust;
- dso->phdr[i].p_paddr += adjust;
- }
- else if (start <= dso->phdr[i].p_vaddr)
- {
- dso->phdr[i].p_vaddr += adjust;
- dso->phdr[i].p_paddr += adjust;
- dso->phdr[i].p_offset += adjust;
- }
- else if (start < dso->phdr[i].p_vaddr + dso->phdr[i].p_filesz)
- {
- dso->phdr[i].p_filesz += adjust;
- dso->phdr[i].p_memsz += adjust;
- }
- else if (start < dso->phdr[i].p_vaddr + dso->phdr[i].p_memsz)
- dso->phdr[i].p_memsz += adjust;
- else
- continue;
- if (dso->phdr[i].p_type == PT_LOAD
- && (dso->phdr[i].p_vaddr - dso->phdr[i].p_offset)
- % dso->phdr[i].p_align)
- {
- error (0, 0, "%s: PT_LOAD %08llx %08llx 0x%x would be not properly aligned",
- dso->filename, (long long) dso->phdr[i].p_offset,
- (long long) dso->phdr[i].p_vaddr, (int) dso->phdr[i].p_align);
- return 1;
- }
- gelf_update_phdr (dso->elf, i, dso->phdr + i);
- }
- elf_flagphdr (dso->elf, ELF_C_SET, ELF_F_DIRTY);
-
- for (i = 1; i < dso->ehdr.e_shnum; i++)
- {
- const char *name;
-
- if (dso->arch->adjust_section)
- {
- int ret = dso->arch->adjust_section (dso, i, start, adjust);
-
- if (ret == 1)
- return 1;
- else if (ret)
- continue;
- }
- switch (dso->shdr[i].sh_type)
- {
- case SHT_PROGBITS:
- case SHT_MIPS_DWARF:
- name = strptr (dso, dso->ehdr.e_shstrndx, dso->shdr[i].sh_name);
- if (strcmp (name, ".stab") == 0
- && adjust_stabs (dso, i, start, adjust))
- return 1;
- if (strcmp (name, ".debug_info") == 0
- && adjust_dwarf2 (dso, i, start, adjust))
- return 1;
- break;
- case SHT_HASH:
- case SHT_GNU_HASH:
- case SHT_NOBITS:
- case SHT_STRTAB:
- break;
- case SHT_SYMTAB:
- case SHT_DYNSYM:
- if (adjust_symtab (dso, i, start, adjust))
- return 1;
- break;
- case SHT_DYNAMIC:
- if (adjust_dynamic (dso, i, start, adjust))
- return 1;
- break;
- case SHT_REL:
- /* Don't adjust reloc sections for debug info. */
- if (dso->shdr[i].sh_flags & SHF_ALLOC)
- if (adjust_rel (dso, i, start, adjust))
- return 1;
- break;
- case SHT_RELA:
- if (dso->shdr[i].sh_flags & SHF_ALLOC)
- if (adjust_rela (dso, i, start, adjust))
- return 1;
- break;
- }
- if ((dso->arch->machine == EM_ALPHA
- && dso->shdr[i].sh_type == SHT_ALPHA_DEBUG)
- || (dso->arch->machine == EM_MIPS
- && dso->shdr[i].sh_type == SHT_MIPS_DEBUG))
- if (adjust_mdebug (dso, i, start, adjust))
- return 1;
- }
-
- for (i = 0; i < dso->ehdr.e_shnum; i++)
- {
- if (RELOCATE_SCN (dso->shdr[i].sh_flags))
- {
- if (dso->shdr[i].sh_addr >= start)
- {
- Elf_Scn *scn = dso->scn[i];
-
- dso->shdr[i].sh_addr += adjust;
- if (start)
- dso->shdr[i].sh_offset += adjust;
- gelfx_update_shdr (dso->elf, scn, dso->shdr + i);
- elf_flagshdr (scn, ELF_C_SET, ELF_F_DIRTY);
- }
- }
- }
-
- addr_adjust (dso->base, start, adjust);
- addr_adjust (dso->end, start, adjust);
-
- if (start)
- {
- start = adjust_new_to_old (dso, start);
- for (i = 0; i < dso->nadjust; i++)
- if (start < dso->adjust[i].start)
- dso->adjust[i].adjust += adjust;
- else
- break;
- if (i < dso->nadjust && start == dso->adjust[i].start)
- dso->adjust[i].adjust += adjust;
- else
- {
- dso->adjust =
- realloc (dso->adjust, (dso->nadjust + 1) * sizeof (*dso->adjust));
- if (dso->adjust == NULL)
- {
- error (0, ENOMEM, "Cannot record the list of adjustements being made");
- return 1;
- }
- memmove (dso->adjust + i + 1, dso->adjust + i, dso->nadjust - i);
- dso->adjust[i].start = start;
- dso->adjust[i].adjust = adjust;
- ++dso->nadjust;
- }
- }
-
- return start ? adjust_dso_nonalloc (dso, 0, 0, adjust) : 0;
-}
-
-int
-recompute_nonalloc_offsets (DSO *dso)
-{
- int i, first_nonalloc, sec_before_shoff = 0;
- GElf_Addr last_offset = 0;
- GElf_Addr shdralign = gelf_fsize (dso->elf, ELF_T_ADDR, 1, EV_CURRENT);
- GElf_Addr shdrsize = gelf_fsize (dso->elf, ELF_T_SHDR, 1, EV_CURRENT)
- * dso->ehdr.e_shnum;
-
- for (i = 1; i < dso->ehdr.e_shnum; ++i)
- if (RELOCATE_SCN (dso->shdr[i].sh_flags))
- {
- if (dso->shdr[i].sh_type == SHT_NOBITS)
- last_offset = dso->shdr[i].sh_offset;
- else
- last_offset = dso->shdr[i].sh_offset + dso->shdr[i].sh_size;
- }
- else
- break;
-
- first_nonalloc = i;
- if (dso->ehdr.e_shoff < dso->shdr[i].sh_offset)
- {
- dso->ehdr.e_shoff = (last_offset + shdralign - 1) & ~(shdralign - 1);
- last_offset = dso->ehdr.e_shoff + shdrsize;
- }
- else
- for (; i < dso->ehdr.e_shnum; ++i)
- if (dso->shdr[i].sh_offset < dso->ehdr.e_shoff
- && (i == dso->ehdr.e_shnum - 1
- || dso->shdr[i + 1].sh_offset > dso->ehdr.e_shoff))
- {
- sec_before_shoff = i;
- break;
- }
-
- for (i = first_nonalloc; i < dso->ehdr.e_shnum; ++i)
- {
- assert (!RELOCATE_SCN (dso->shdr[i].sh_flags));
- assert (dso->shdr[i].sh_type != SHT_NOBITS);
- dso->shdr[i].sh_offset = (last_offset + dso->shdr[i].sh_addralign - 1)
- & ~(dso->shdr[i].sh_addralign - 1);
- last_offset = dso->shdr[i].sh_offset + dso->shdr[i].sh_size;
- if (i == sec_before_shoff)
- {
- dso->ehdr.e_shoff = (last_offset + shdralign - 1) & ~(shdralign - 1);
- last_offset = dso->ehdr.e_shoff + shdrsize;
- }
- }
-
- return 0;
-}
-
-int
-strtabfind (DSO *dso, int strndx, const char *name)
-{
- Elf_Scn *scn;
- Elf_Data *data;
- const char *p, *q, *r;
- size_t len = strlen (name);
-
- if (dso->shdr[strndx].sh_type != SHT_STRTAB)
- return 0;
-
- scn = dso->scn[strndx];
- data = elf_getdata (scn, NULL);
- assert (elf_getdata (scn, data) == NULL);
- assert (data->d_off == 0);
- assert (data->d_size == dso->shdr[strndx].sh_size);
- q = data->d_buf + data->d_size;
- for (p = data->d_buf; p < q; p = r + 1)
- {
- r = strchr (p, '\0');
- if (r - p >= len && memcmp (r - len, name, len) == 0)
- return (r - (const char *) data->d_buf) - len;
- }
-
- return 0;
-}
-
-int
-shstrtabadd (DSO *dso, const char *name)
-{
- Elf_Scn *scn;
- Elf_Data *data;
- GElf_Addr adjust;
- const char *p, *q, *r;
- size_t len = strlen (name), align;
- int ret;
-
- scn = dso->scn[dso->ehdr.e_shstrndx];
- data = elf_getdata (scn, NULL);
- assert (elf_getdata (scn, data) == NULL);
- assert (data->d_off == 0);
- assert (data->d_size == dso->shdr[dso->ehdr.e_shstrndx].sh_size);
- q = data->d_buf + data->d_size;
- for (p = data->d_buf; p < q; p = r + 1)
- {
- r = strchr (p, '\0');
- if (r - p >= len && memcmp (r - len, name, len) == 0)
- return (r - (const char *) data->d_buf) - len;
- }
-
- data->d_buf = realloc (data->d_buf, data->d_size + len + 1);
- if (data->d_buf == NULL)
- {
- error (0, ENOMEM, "Cannot add new section name %s", name);
- return 0;
- }
-
- memcpy (data->d_buf + data->d_size, name, len + 1);
- ret = data->d_size;
- data->d_size += len + 1;
- align = gelf_fsize (dso->elf, ELF_T_ADDR, 1, EV_CURRENT);
- adjust = (len + 1 + align - 1) & ~(align - 1);
- if (adjust_dso_nonalloc (dso, 0,
- dso->shdr[dso->ehdr.e_shstrndx].sh_offset
- + dso->shdr[dso->ehdr.e_shstrndx].sh_size,
- adjust))
- return 0;
- dso->shdr[dso->ehdr.e_shstrndx].sh_size += len + 1;
- return ret;
-}
-
-int
-relocate_dso (DSO *dso, GElf_Addr base)
-{
- /* Check if it is already relocated. */
- if (dso->base == base)
- return 0;
-
- if (! dso_is_rdwr (dso))
- {
- if (reopen_dso (dso, NULL, NULL))
- return 1;
- }
-
- return adjust_dso (dso, 0, base - dso->base);
-}
-
-#endif
-
-static int
-close_dso_1 (DSO *dso)
-{
- if (dso_is_rdwr (dso))
- {
- int i;
-
- for (i = 1; i < dso->ehdr.e_shnum; ++i)
- {
- Elf_Scn *scn = dso->scn[i];
- Elf_Data *data = NULL;
-
- while ((data = elf_getdata (scn, data)) != NULL)
- {
- free (data->d_buf);
- data->d_buf = NULL;
- }
- }
- }
-
- elf_end (dso->elf);
- fsync (dso->fd);
- close (dso->fd);
- if (dso->elfro)
- {
- elf_end (dso->elfro);
- fsync (dso->fdro);
- close (dso->fdro);
- }
- if (dso->filename != dso->soname)
- free ((char *) dso->soname);
- free ((char *) dso->filename);
- free ((char *) dso->temp_filename);
- free (dso->move);
- free (dso->adjust);
- free (dso->undo.d_buf);
- free (dso);
- return 0;
-}
-
-int
-close_dso (DSO *dso)
-{
- int rdwr = dso_is_rdwr (dso);
-
- if (rdwr && dso->temp_filename != NULL)
- wrap_unlink (dso->temp_filename);
- close_dso_1 (dso);
- return 0;
-}
-
-#if 0
-
-int
-prepare_write_dso (DSO *dso)
-{
- int i;
-
- if (check_dso (dso)
- || (dso->mdebug_orig_offset && finalize_mdebug (dso)))
- return 1;
-
- gelf_update_ehdr (dso->elf, &dso->ehdr);
- for (i = 0; i < dso->ehdr.e_phnum; ++i)
- gelf_update_phdr (dso->elf, i, dso->phdr + i);
- for (i = 0; i < dso->ehdr.e_shnum; ++i)
- {
- gelfx_update_shdr (dso->elf, dso->scn[i], dso->shdr + i);
- if (dso->shdr[i].sh_type == SHT_SYMTAB
- || dso->shdr[i].sh_type == SHT_DYNSYM)
- set_stt_section_values (dso, i);
- }
- return 0;
-}
-
-int
-write_dso (DSO *dso)
-{
- if (prepare_write_dso (dso))
- return 1;
-
- if (! dso->permissive && ELF_F_PERMISSIVE)
- elf_flagelf (dso->elf, ELF_C_CLR, ELF_F_PERMISSIVE);
-
- if (elf_update (dso->elf, ELF_C_WRITE) == -1)
- return 2;
- return 0;
-}
-
-static int
-set_security_context (const char *temp_name, const char *name,
- int ignore_errors)
-{
-#ifdef USE_SELINUX
- static int selinux_enabled = -1;
- if (selinux_enabled == -1)
- selinux_enabled = is_selinux_enabled ();
- if (selinux_enabled > 0)
- {
- security_context_t scontext;
- if (getfilecon (name, &scontext) < 0)
- {
- /* If the filesystem doesn't support extended attributes,
- the original had no special security context and the
- target cannot have one either. */
- if (errno == EOPNOTSUPP)
- return 0;
-
- error (0, errno, "Could not get security context for %s",
- name);
- return 1;
- }
- if (setfilecon (temp_name, scontext) < 0 && !ignore_errors)
- {
- error (0, errno, "Could not set security context for %s",
- name);
- freecon (scontext);
- return 1;
- }
- freecon (scontext);
- }
-#endif
- return 0;
-}
-
-int
-copy_fd_to_file (int fdin, const char *name, struct stat64 *st)
-{
- struct stat64 stt;
- off_t off = 0;
- int err, fdout;
- struct utimbuf u;
-
- if (strcmp (name, "-") == 0)
- fdout = 1;
- else
- fdout = wrap_open (name, O_WRONLY | O_CREAT, 0600);
- if (fdout != -1
- && fstat64 (fdin, &stt) >= 0
- && send_file (fdout, fdin, &off, stt.st_size) == stt.st_size)
- {
- if (fchown (fdout, st->st_uid, st->st_gid) >= 0)
- fchmod (fdout, st->st_mode & 07777);
- if (strcmp (name, "-") != 0)
- {
- set_security_context (name, name, 1);
- u.actime = time (NULL);
- u.modtime = st->st_mtime;
- wrap_utime (name, &u);
- close (fdout);
- }
- return 0;
- }
- else if (fdout != -1)
- {
- err = errno;
- if (strcmp (name, "-") == 0)
- close (fdout);
- }
- else
- err = errno;
- return err;
-}
-
-int
-update_dso (DSO *dso, const char *orig_name)
-{
- int rdwr = dso_is_rdwr (dso);
-
- if (rdwr)
- {
- char *name1, *name2;
- struct utimbuf u;
- struct stat64 st;
- int fdin;
-
- switch (write_dso (dso))
- {
- case 2:
- error (0, 0, "Could not write %s: %s", dso->filename,
- elf_errmsg (-1));
- /* FALLTHROUGH */
- case 1:
- close_dso (dso);
- return 1;
- case 0:
- break;
- }
-
- name1 = strdupa (dso->filename);
- name2 = strdupa (dso->temp_filename);
- if (fstat64 (dso->fdro, &st) < 0)
- {
- error (0, errno, "Could not stat %s", dso->filename);
- close_dso (dso);
- return 1;
- }
- if ((fchown (dso->fd, st.st_uid, st.st_gid) < 0
- || fchmod (dso->fd, st.st_mode & 07777) < 0)
- && orig_name == NULL)
- {
- error (0, errno, "Could not set %s owner or mode", dso->filename);
- close_dso (dso);
- return 1;
- }
- if (orig_name != NULL)
- fdin = dup (dso->fd);
- else
- fdin = -1;
- close_dso_1 (dso);
- u.actime = time (NULL);
- u.modtime = st.st_mtime;
- wrap_utime (name2, &u);
-
- if (set_security_context (name2, orig_name ? orig_name : name1,
- orig_name != NULL))
- {
- if (fdin != -1)
- close (fdin);
- wrap_unlink (name2);
- return 1;
- }
-
- if ((orig_name != NULL && strcmp (name1, "-") == 0)
- || wrap_rename (name2, name1))
- {
- if (fdin != -1)
- {
- int err = copy_fd_to_file (fdin, name1, &st);
-
- close (fdin);
- wrap_unlink (name2);
- if (err == 0)
- return 0;
- error (0, err, "Could not rename nor copy temporary to %s",
- name1);
- return 1;
- }
- wrap_unlink (name2);
- error (0, errno, "Could not rename temporary to %s", name1);
- return 1;
- }
- if (fdin != -1)
- close (fdin);
- }
- else
- close_dso_1 (dso);
-
- return 0;
-}
-
-#endif