]> pd.if.org Git - zpackage/blob - elf/libelf.c
add test vectors for zpm-sign
[zpackage] / elf / libelf.c
1 #define _POSIX_C_SOURCE 200112L
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <sys/mman.h>
5 #include <fcntl.h>
6 #include <unistd.h>
7 #include <limits.h>
8 #include <errno.h>
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13
14 #include "elf.h"
15
16 void *libelf_map(char *path, size_t *fsize);
17 int libelf_iself(void *elf);
18 char *libelf_soname(void *elf);
19 int libelf_type(void *elf);
20
21 Elf64_Ehdr *libelf_header(void *elf) {
22         return elf;
23 }
24
25 #if 0
26 Elf64_Shdr *libelf_shdr(void *elf, int n) {
27         return 0;
28 }
29 #endif
30
31 Elf64_Shdr *libelf_sht_strtab(void *elf) {
32         int i;
33         Elf64_Ehdr *hdr;
34         Elf64_Shdr *shdr;
35
36         hdr = libelf_header(elf);
37
38         for (i = 0; i < hdr->e_shnum; i++) {
39                 shdr = (Elf64_Shdr *)((char *)elf + hdr->e_shoff + i * hdr->e_shentsize);
40                 if (shdr->sh_type == SHT_STRTAB && i == hdr->e_shstrndx) {
41                         return shdr;
42                 }
43         }
44         return 0;
45 }
46
47 char *libelf_sectionname(Elf64_Shdr *section, Elf64_Shdr *strtab) {
48         return (char *)strtab + section->sh_name;
49 }
50
51 Elf64_Shdr *libelf_section_n(void *elf, int n) {
52         Elf64_Ehdr *hdr;
53
54         hdr = libelf_header(elf);
55
56         if (n > hdr->e_shnum) {
57                 return 0;
58         }
59
60         return (Elf64_Shdr *)((char *)elf + hdr->e_shoff + n * hdr->e_shentsize);
61 }
62
63 Elf64_Shdr *libelf_section(void *elf, unsigned int type) {
64         int i;
65         Elf64_Ehdr *hdr;
66         Elf64_Shdr *shdr;
67
68         hdr = libelf_header(elf);
69
70         for (i = 0; i < hdr->e_shnum; i++) {
71                 shdr = (Elf64_Shdr *)((char *)elf + hdr->e_shoff + i * hdr->e_shentsize);
72                 if (shdr->sh_type == type) {
73                         return shdr;
74                 }
75         }
76         return 0;
77 }
78
79 int libelf_type(void *elf) {
80         return libelf_iself(elf) ? libelf_header(elf)->e_type : 0;
81 }
82
83 int libelf_iself(void *elf) {
84         Elf64_Ehdr *hdr;
85         hdr = elf;
86         if (hdr->e_ident[EI_MAG0] != ELFMAG0
87                         || hdr->e_ident[EI_MAG1] != ELFMAG1
88                         || hdr->e_ident[EI_MAG2] != ELFMAG2
89                         || hdr->e_ident[EI_MAG3] != ELFMAG3
90            ) {
91                 return 0;
92         }
93         return 1;
94 }
95
96 void *libelf_map(char *path, size_t *fsize) {
97         int elffd;
98         struct stat sbuf;
99         void *elfbase;
100
101         errno = 0;
102
103         elffd = open(path, O_RDONLY);
104         if (elffd == -1) {
105                 perror("open");
106                 return NULL;
107         }
108         if (fstat(elffd, &sbuf) == -1) {
109                 close(elffd);
110                 return NULL;
111         }
112         /* not a regular file? */
113         if (!S_ISREG(sbuf.st_mode)) {
114                 close(elffd);
115                 return NULL;
116         }
117         /* not at least the size of the elf header? */
118         if ((size_t)sbuf.st_size < sizeof(Elf64_Ehdr)) {
119                 close(elffd);
120                 return NULL;
121         }
122
123         elfbase = mmap(0, sbuf.st_size, PROT_READ,MAP_PRIVATE, elffd, 0);
124         close(elffd);
125         if (!elfbase) {
126                 return NULL;
127         }
128
129         if (!libelf_iself(elfbase)) {
130                 munmap(elfbase, sbuf.st_size);
131                 return NULL;
132         }
133
134         *fsize = sbuf.st_size;
135
136         return elfbase;
137 }
138
139 char *libelf_soname(void *elfbase) {
140         Elf64_Ehdr *hdr;
141         int i;
142         Elf64_Shdr *shdr;
143         Elf64_Shdr *dynsect = 0;
144         Elf64_Shdr *strtab = 0, *dyntab = 0;
145         char *name, *dynname;
146         Elf64_Dyn *dent;
147
148         if (!libelf_iself(elfbase)) {
149                 return 0;
150         }
151         hdr = libelf_header(elfbase);
152
153         /* only dynamic files will have an soname */
154         if (hdr->e_type != ET_DYN) {
155                 return 0;
156         }
157
158         switch (hdr->e_ident[EI_CLASS]) {
159                 case ELFCLASS64:
160                 case ELFCLASS32:
161                 case ELFCLASSNONE:
162                         break;
163                 default: return 0; break;
164         }
165
166         /* check endian ness */
167         switch (hdr->e_ident[EI_DATA]) {
168                 case ELFDATA2LSB: break;
169                 case ELFDATA2MSB: break;
170                 default: return 0; break;
171         }
172         
173         /* find the section header table */
174         for (i = 0; i < hdr->e_shnum; i++) {
175                 shdr = (Elf64_Shdr *)((char *)elfbase + hdr->e_shoff + i * hdr->e_shentsize);
176                 if (shdr->sh_type == SHT_DYNAMIC) {
177                         dynsect = shdr;
178                 } else if (shdr->sh_type == SHT_STRTAB && i == hdr->e_shstrndx) {
179                         strtab = shdr;
180                 }
181         }
182         if (!strtab) {
183                 return 0;
184         }
185         if (!dynsect) {
186                 return 0;
187         }
188
189         name = (char *) elfbase + strtab->sh_offset;
190         for (i = 0; i < hdr->e_shnum; i++) {
191                 shdr = (Elf64_Shdr *)((char *)elfbase + hdr->e_shoff + i * hdr->e_shentsize);
192                 if (shdr->sh_type == SHT_STRTAB && !strcmp(".dynstr", name+shdr->sh_name)) {
193                         dyntab = shdr;
194                 }
195         }
196         if (!dyntab) {
197                 return 0;
198         }
199
200         dynname = (char *) elfbase + dyntab->sh_offset;
201         for (dent = (Elf64_Dyn *)((char *)elfbase + dynsect->sh_offset); dent->d_tag != DT_NULL; dent++) {
202                 if (dent->d_tag == DT_SONAME) {
203                         return dynname + dent->d_un.d_val;
204                 }
205         }
206
207         return 0;
208 }