Use ctf_off2name() when dumping the string table
[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 (eh->e_ehsize < sizeof(Elf_Ehdr) || !IS_ELF(*eh))
29                 return 0;
30
31         if (eh->e_ident[EI_CLASS] != ELFCLASS) {
32                 warnx("unexpected word size %u", eh->e_ident[EI_CLASS]);
33                 return 0;
34         }
35         if (eh->e_ident[EI_VERSION] != ELF_TARG_VER) {
36                 warnx("unexpected version %u", eh->e_ident[EI_VERSION]);
37                 return 0;
38         }
39         if (eh->e_ident[EI_DATA] >= ELFDATANUM) {
40                 warnx("unexpected data format %u", eh->e_ident[EI_DATA]);
41                 return 0;
42         }
43         if (eh->e_shoff > filesize) {
44                 warnx("bogus section table offset 0x%llx", (off_t)eh->e_shoff);
45                 return 0;
46         }
47         if (eh->e_shentsize < sizeof(Elf_Shdr)) {
48                 warnx("bogus section header size %u", eh->e_shentsize);
49                 return 0;
50         }
51         if (eh->e_shnum > (filesize - eh->e_shoff) / eh->e_shentsize) {
52                 warnx("bogus section header count %u", eh->e_shnum);
53                 return 0;
54         }
55         if (eh->e_shstrndx >= eh->e_shnum) {
56                 warnx("bogus string table index %u", eh->e_shstrndx);
57                 return 0;
58         }
59
60         return 1;
61 }
62
63 int
64 elf_getshstrtab(const char *p, size_t filesize, const char **shstrtab,
65     size_t *shstrtabsize)
66 {
67         Elf_Ehdr                *eh = (Elf_Ehdr *)p;
68         Elf_Shdr                *sh;
69
70         sh = (Elf_Shdr *)(p + eh->e_shoff + eh->e_shstrndx * eh->e_shentsize);
71         if (sh->sh_type != SHT_STRTAB) {
72                 warnx("unexpected string table type");
73                 return 1;
74         }
75         if (sh->sh_offset > filesize) {
76                 warnx("bogus string table offset");
77                 return 1;
78         }
79         if (sh->sh_size > filesize - sh->sh_offset) {
80                 warnx("bogus string table size");
81                 return 1;
82         }
83         if (shstrtab != NULL)
84                 *shstrtab = p + sh->sh_offset;
85         if (shstrtabsize != NULL)
86                 *shstrtabsize = sh->sh_size;
87
88         return 0;
89 }
90
91 int
92 elf_getsymtab(const char *p, const char *shstrtab, size_t shstrtabsize,
93     const Elf_Sym **symtab, size_t *nsymb)
94 {
95         Elf_Ehdr        *eh = (Elf_Ehdr *)p;
96         Elf_Shdr        *sh;
97         size_t           i;
98
99         for (i = 0; i < eh->e_shnum; i++) {
100                 sh = (Elf_Shdr *)(p + eh->e_shoff + i * eh->e_shentsize);
101
102                 if (sh->sh_type != SHT_SYMTAB)
103                         continue;
104
105                 if ((sh->sh_link >= eh->e_shnum) ||
106                     (sh->sh_name >= shstrtabsize))
107                         continue;
108
109                 if (strncmp(shstrtab + sh->sh_name, ELF_SYMTAB,
110                     strlen(ELF_SYMTAB)) == 0) {
111                         if (symtab != NULL)
112                                 *symtab = (Elf_Sym *)(p + sh->sh_offset);
113                         if (nsymb != NULL)
114                                 *nsymb = (sh->sh_size / sh->sh_entsize);
115
116                         return 0;
117                 }
118         }
119
120         return 1;
121 }
122
123 int
124 elf_getstrtab(const char *p, const char *shstrtab, size_t shstrtabsize,
125     const char **strtab, size_t *strtabsize)
126 {
127         Elf_Ehdr        *eh = (Elf_Ehdr *)p;
128         Elf_Shdr        *sh;
129         size_t           i;
130
131         for (i = 0; i < eh->e_shnum; i++) {
132                 sh = (Elf_Shdr *)(p + eh->e_shoff + i * eh->e_shentsize);
133
134                 if (sh->sh_type != SHT_STRTAB)
135                         continue;
136
137                 if ((sh->sh_link >= eh->e_shnum) ||
138                     (sh->sh_name >= shstrtabsize))
139                         continue;
140
141                 if (strncmp(shstrtab + sh->sh_name, ELF_STRTAB,
142                     strlen(ELF_STRTAB)) == 0) {
143                         if (strtab != NULL)
144                                 *strtab = p + sh->sh_offset;
145                         if (strtabsize != NULL)
146                                 *strtabsize = sh->sh_size;
147
148                         return 0;
149                 }
150         }
151
152         return 1;
153 }