Fix an unsigned cast madness.
[ctfdump/.git] / elf.c
1 /*
2  * Copyright (c) 2016 Martin Pieuchot <mpi@openbsd.org>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include <sys/param.h>
18 #include <sys/exec_elf.h>
19
20 #include <err.h>
21 #include <string.h>
22
23 int
24 iself(const char *p, size_t filesize)
25 {
26         Elf_Ehdr                *eh = (Elf_Ehdr *)p;
27
28         if (filesize < sizeof(Elf_Ehdr))
29                 return 0;
30
31         if (eh->e_ehsize < sizeof(Elf_Ehdr) || !IS_ELF(*eh))
32                 return 0;
33
34         if (eh->e_ident[EI_CLASS] != ELFCLASS) {
35                 warnx("unexpected word size %u", eh->e_ident[EI_CLASS]);
36                 return 0;
37         }
38         if (eh->e_ident[EI_VERSION] != ELF_TARG_VER) {
39                 warnx("unexpected version %u", eh->e_ident[EI_VERSION]);
40                 return 0;
41         }
42         if (eh->e_ident[EI_DATA] >= ELFDATANUM) {
43                 warnx("unexpected data format %u", eh->e_ident[EI_DATA]);
44                 return 0;
45         }
46         if (eh->e_shoff > filesize) {
47                 warnx("bogus section table offset 0x%llx", (off_t)eh->e_shoff);
48                 return 0;
49         }
50         if (eh->e_shentsize < sizeof(Elf_Shdr)) {
51                 warnx("bogus section header size %u", eh->e_shentsize);
52                 return 0;
53         }
54         if (eh->e_shnum > (filesize - eh->e_shoff) / eh->e_shentsize) {
55                 warnx("bogus section header count %u", eh->e_shnum);
56                 return 0;
57         }
58         if (eh->e_shstrndx >= eh->e_shnum) {
59                 warnx("bogus string table index %u", eh->e_shstrndx);
60                 return 0;
61         }
62
63         return 1;
64 }
65
66 int
67 elf_getshstrtab(const char *p, size_t filesize, const char **shstrtab,
68     size_t *shstrtabsize)
69 {
70         Elf_Ehdr                *eh = (Elf_Ehdr *)p;
71         Elf_Shdr                *sh;
72
73         sh = (Elf_Shdr *)(p + eh->e_shoff + eh->e_shstrndx * eh->e_shentsize);
74         if (sh->sh_type != SHT_STRTAB) {
75                 warnx("unexpected string table type");
76                 return 1;
77         }
78         if (sh->sh_offset > filesize) {
79                 warnx("bogus string table offset");
80                 return 1;
81         }
82         if (sh->sh_size > filesize - sh->sh_offset) {
83                 warnx("bogus string table size");
84                 return 1;
85         }
86         if (shstrtab != NULL)
87                 *shstrtab = p + sh->sh_offset;
88         if (shstrtabsize != NULL)
89                 *shstrtabsize = sh->sh_size;
90
91         return 0;
92 }
93
94 int
95 elf_getsymtab(const char *p, const char *shstrtab, size_t shstrtabsize,
96     const Elf_Sym **symtab, size_t *nsymb)
97 {
98         Elf_Ehdr        *eh = (Elf_Ehdr *)p;
99         Elf_Shdr        *sh;
100         size_t           i;
101
102         for (i = 0; i < eh->e_shnum; i++) {
103                 sh = (Elf_Shdr *)(p + eh->e_shoff + i * eh->e_shentsize);
104
105                 if (sh->sh_type != SHT_SYMTAB)
106                         continue;
107
108                 if ((sh->sh_link >= eh->e_shnum) ||
109                     (sh->sh_name >= shstrtabsize))
110                         continue;
111
112                 if (strncmp(shstrtab + sh->sh_name, ELF_SYMTAB,
113                     strlen(ELF_SYMTAB)) == 0) {
114                         if (symtab != NULL)
115                                 *symtab = (Elf_Sym *)(p + sh->sh_offset);
116                         if (nsymb != NULL)
117                                 *nsymb = (sh->sh_size / sh->sh_entsize);
118
119                         return 0;
120                 }
121         }
122
123         return 1;
124 }
125
126 int
127 elf_getsection(const char *p, const char *sname, const char *shstrtab,
128     size_t shstrtabsize, const char **sdata, size_t *ssize)
129 {
130         Elf_Ehdr        *eh = (Elf_Ehdr *)p;
131         Elf_Shdr        *sh;
132         size_t           i;
133
134         for (i = 0; i < eh->e_shnum; i++) {
135                 sh = (Elf_Shdr *)(p + eh->e_shoff + i * eh->e_shentsize);
136
137                 if ((sh->sh_link >= eh->e_shnum) ||
138                     (sh->sh_name >= shstrtabsize))
139                         continue;
140
141                 if (strncmp(shstrtab + sh->sh_name, sname,
142                     strlen(sname)) == 0) {
143                         if (sdata != NULL)
144                                 *sdata = p + sh->sh_offset;
145                         if (ssize != NULL)
146                                 *ssize = sh->sh_size;
147
148                         return 0;
149                 }
150         }
151
152         return 1;
153 }