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