1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
|
/*
* Copyright 2001-2024 Petter Reinholdtsen
*
* 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 of the
* License, or (at your option) any later version.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <elf.h>
#if defined(HAVE_SYS_LINK_H)
# include <sys/link.h> /* Find DT_RPATH on Solaris 2.6 */
#endif /* HAVE_SYS_LINK_H */
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include "protos.h"
#define EHDR_PWS(x) (is_e32() ? DO_SWAPS32(ehdr->e32.x) : DO_SWAPS64(ehdr->e64.x))
#define EHDR_PHS(x) (is_e32() ? DO_SWAPS16(ehdr->e32.x) : DO_SWAPS16(ehdr->e64.x))
#define PHDR_PWS(x) (is_e32() ? DO_SWAPS32(phdr->e32.x) : DO_SWAPS64(phdr->e64.x))
#define EHDR_PWU(x) (is_e32() ? DO_SWAPU32(ehdr->e32.x) : DO_SWAPU64(ehdr->e64.x))
#define EHDR_PHU(x) (is_e32() ? DO_SWAPU16(ehdr->e32.x) : DO_SWAPU16(ehdr->e64.x))
#define PHDR_PWU(x) (is_e32() ? DO_SWAPU32(phdr->e32.x) : DO_SWAPU32(phdr->e64.x))
#define PHDR_POU(x) (is_e32() ? DO_SWAPU32(phdr->e32.x) : DO_SWAPU64(phdr->e64.x))
static int is_e32_flag;
static int swap_bytes_flag;
int
is_e32(void)
{
return is_e32_flag;
}
int
swap_bytes(void)
{
return swap_bytes_flag;
}
int
elf_open(const char *filename, int flags, Elf_Ehdr *ehdr)
{
int fd;
size_t sz_ehdr;
size_t sz_phdr;
fd = open(filename, flags);
if (fd == -1)
{
perror ("open");
return -1;
}
if (read(fd, ehdr, EI_NIDENT) != EI_NIDENT)
{
perror ("reading header (e_ident)");
close(fd);
return -1;
}
if (0 != memcmp(ehdr->e_ident, ELFMAG, SELFMAG) ||
(ehdr->e_ident[EI_CLASS] != ELFCLASS32 &&
ehdr->e_ident[EI_CLASS] != ELFCLASS64) ||
(ehdr->e_ident[EI_DATA] != ELFDATA2LSB &&
ehdr->e_ident[EI_DATA] != ELFDATA2MSB) ||
ehdr->e_ident[EI_VERSION] != EV_CURRENT)
{
fprintf(stderr, "`%s' probably isn't an ELF file.\n", filename);
close(fd);
errno = ENOEXEC; /* Hm, is this the best errno code to use? */
return -1;
}
is_e32_flag = ehdr->e_ident[EI_CLASS] == ELFCLASS32;
swap_bytes_flag = ehdr->e_ident[EI_DATA] != ELFDATA2;
sz_ehdr = is_e32() ? sizeof(Elf32_Ehdr) : sizeof(Elf64_Ehdr);
if (read(fd, ((char *)ehdr) + EI_NIDENT, sz_ehdr - EI_NIDENT)
!= (ssize_t)(sz_ehdr - EI_NIDENT))
{
perror ("reading header");
close(fd);
return -1;
}
sz_phdr = is_e32() ? sizeof(Elf32_Phdr) : sizeof(Elf64_Phdr);
if ((size_t)EHDR_PHS(e_phentsize) != sz_phdr)
{
fprintf(stderr, "section size was read as %zd, not %zd!\n",
(size_t)EHDR_PHS(e_phentsize), sz_phdr);
close(fd);
return -1;
}
return fd;
}
int
elf_find_dynamic_section(int fd, Elf_Ehdr *ehdr, Elf_Phdr *phdr)
{
int i;
if (lseek(fd, EHDR_PWU(e_phoff), SEEK_SET) == -1)
{
perror ("positioning for sections");
return 1;
}
for (i = 0; i < EHDR_PHS(e_phnum); i++)
{
const size_t sz_phdr = is_e32() ? sizeof(Elf32_Phdr) : sizeof(Elf64_Phdr);
if (read(fd, phdr, sz_phdr) != (ssize_t)sz_phdr)
{
perror ("reading section header");
return 1;
}
if (PHDR_PWU(p_type) == PT_DYNAMIC)
break;
}
if (i == EHDR_PHS(e_phnum))
{
fprintf (stderr, "No dynamic section found.\n");
return 2;
}
if (0 == PHDR_POU(p_filesz))
{
fprintf (stderr, "Length of dynamic section is zero.\n");
return 3;
}
return 0;
}
void
elf_close(int fd)
{
close(fd);
}
const char *
elf_tagname(int tag)
{
switch (tag) {
case DT_RPATH:
return "RPATH";
break;
#if defined(DT_RUNPATH)
case DT_RUNPATH:
return "RUNPATH";
break;
#endif /* DT_RUNPATH */
}
return "UNKNOWN";
}
int
elf_dynpath_tag(int tag)
{
return ( tag == DT_RPATH
#if defined(DT_RUNPATH)
|| tag == DT_RUNPATH
#endif /* DT_RUNPATH */
);
}
|