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