xref: /openbsd-src/sys/ddb/db_ctf.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: db_ctf.c,v 1.4 2016/09/18 13:31:12 jasper Exp $	*/
2 
3 /*
4  * Copyright (c) 2016 Jasper Lievisse Adriaanse <jasper@openbsd.org>
5  * Copyright (c) 2016 Martin Pieuchot <mpi@openbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/types.h>
21 #include <sys/stdint.h>
22 #include <sys/param.h>
23 #include <sys/systm.h>
24 #include <sys/exec.h>
25 
26 #include <machine/db_machdep.h>
27 
28 #include <ddb/db_extern.h>
29 #include <ddb/db_sym.h>
30 #include <ddb/db_elf.h>
31 #include <ddb/db_output.h>
32 
33 #include <sys/exec_elf.h>
34 #include <sys/ctf.h>
35 #include <sys/malloc.h>
36 #include <lib/libz/zlib.h>
37 
38 extern db_symtab_t		db_symtab;
39 
40 struct ddb_ctf {
41 	struct ctf_header 	*cth;
42 	const char 		*data;
43 	off_t			 dlen;
44 	unsigned int 		 ctf_found;
45 	unsigned int 		 nsyms;
46         size_t			 ctftab_size;
47 	const char		*ctftab;
48 };
49 
50 struct ddb_ctf db_ctf;
51 
52 /*
53  * We need a way to get the number of symbols, so (ab)use db_elf_sym_forall()
54  * to give us the count.
55  */
56 struct db_ctf_forall_arg {
57 	int		cnt;
58 	db_sym_t	sym;
59 };
60 
61 static const char	*db_ctf_lookup_name(unsigned int);
62 static const char	*db_ctf_idx2sym(size_t *, unsigned char);
63 static const char	*db_elf_find_ctftab(db_symtab_t *, size_t *);
64 static char		*db_ctf_decompress(const char *, size_t, off_t);
65 static int		 db_ctf_print_functions();
66 static void		 db_ctf_forall(db_sym_t, char *, char *, int, void *);
67 
68 /*
69  * Entrypoint to verify CTF presence, initialize the header, decompress
70  * the data, etc.
71  */
72 void
73 db_ctf_init(void)
74 {
75 	struct db_ctf_forall_arg dfa;
76 	db_symtab_t *stab = &db_symtab;
77 	const char *ctftab;
78 	size_t ctftab_size;
79 	int nsyms;
80 
81 	/* Assume nothing was correct found until proven otherwise. */
82 	db_ctf.ctf_found = 0;
83 
84 	ctftab = db_elf_find_ctftab(stab, &ctftab_size);
85 	if (ctftab == NULL) {
86 		return;
87 	}
88 
89 	db_ctf.ctftab = ctftab;
90 	db_ctf.ctftab_size = ctftab_size;
91 	db_ctf.cth = (struct ctf_header *)ctftab;
92 	db_ctf.dlen = db_ctf.cth->cth_stroff + db_ctf.cth->cth_strlen;
93 
94 	/* Now decompress the section, take into account to skip the header */
95 	if (db_ctf.cth->cth_flags & CTF_F_COMPRESS) {
96 		if ((db_ctf.data =
97 		     db_ctf_decompress(db_ctf.ctftab + sizeof(*db_ctf.cth),
98 				      db_ctf.ctftab_size - sizeof(*db_ctf.cth),
99 				       db_ctf.dlen)) == NULL)
100 			return;
101 	} else {
102 		db_printf("Unsupported non-compressed CTF section encountered\n");
103 		return;
104 	}
105 
106 	/*
107 	 * Lookup the total number of kernel symbols. It's unlikely for the
108 	 * kernel to have zero symbols so bail out if that's what we end
109 	 * up finding.
110 	 */
111 	dfa.cnt = 0;
112 	db_elf_sym_forall(db_ctf_forall, &dfa);
113 	nsyms = -dfa.cnt;
114 
115 	if (nsyms == 0)
116 		return;
117 	else
118 		db_ctf.nsyms = nsyms;
119 
120 	/* We made it this far, everything seems fine. */
121 	db_ctf.ctf_found = 1;
122 }
123 
124 static void
125 db_ctf_forall(db_sym_t sym, char *name, char *suff, int pre, void *varg)
126 {
127 	struct db_ctf_forall_arg *arg = varg;
128 
129 	if (arg->cnt-- == 0)
130 		arg->sym = sym;
131 }
132 
133 /*
134  * Internal helper function - return a pointer to the CTF table
135  * for the current symbol table (and update the size).
136  */
137 static const char *
138 db_elf_find_ctftab(db_symtab_t *stab, size_t *size)
139 {
140 	Elf_Ehdr *elf = STAB_TO_EHDR(stab);
141 	Elf_Shdr *shp = STAB_TO_SHDR(stab, elf);
142 	char *shstrtab;
143 	int i;
144 
145 	shstrtab = (char *)elf + shp[elf->e_shstrndx].sh_offset;
146 
147 	for (i = 0; i < elf->e_shnum; i++) {
148 		if ((shp[i].sh_flags & SHF_ALLOC) != 0 &&
149 		    strcmp(ELF_CTF, shstrtab+shp[i].sh_name) == 0) {
150 			*size = shp[i].sh_size;
151 			return ((char *)elf + shp[i].sh_offset);
152 		}
153 	}
154 
155 	return (NULL);
156 }
157 
158 void
159 db_dump_ctf_header(void)
160 {
161 	if (!db_ctf.ctf_found)
162 		return;
163 
164 	db_printf("CTF header found at %p (%ld)\n", db_ctf.ctftab,
165 		  db_ctf.ctftab_size);
166 	db_printf("cth_magic: 0x%04x\n", db_ctf.cth->cth_magic);
167 	db_printf("cth_verion: %d\n", db_ctf.cth->cth_version);
168 	db_printf("cth_flags: 0x%02x", db_ctf.cth->cth_flags);
169 	if (db_ctf.cth->cth_flags & CTF_F_COMPRESS) {
170 		db_printf(" (compressed)");
171 	}
172 	db_printf("\n");
173 	db_printf("cth_parlabel: %s\n",
174 		  db_ctf_lookup_name(db_ctf.cth->cth_parlabel));
175 	db_printf("cth_parname: %s\n",
176 		  db_ctf_lookup_name(db_ctf.cth->cth_parname));
177 	db_printf("cth_lbloff: %d\n", db_ctf.cth->cth_lbloff);
178 	db_printf("cth_objtoff: %d\n", db_ctf.cth->cth_objtoff);
179 	db_printf("cth_funcoff: %d\n", db_ctf.cth->cth_funcoff);
180 	db_printf("cth_typeoff: %d\n", db_ctf.cth->cth_typeoff);
181 	db_printf("cth_stroff: %d\n", db_ctf.cth->cth_stroff);
182 	db_printf("cth_strlen: %d\n", db_ctf.cth->cth_strlen);
183 
184 #if 1
185 	db_ctf_print_functions();
186 #endif
187 }
188 
189 /*
190  * Convert an index to a symbol name while ensuring the type is matched.
191  * It must be noted this only works if the CTF table has the same order
192  * as the symbol table.
193  */
194 static const char *
195 db_ctf_idx2sym(size_t *idx, unsigned char type)
196 {
197 	db_symtab_t *stab = &db_symtab;
198 	Elf_Sym *symp, *symtab_start;
199 	const Elf_Sym *st;
200 	char *strtab;
201 	size_t i;
202 
203 	if (stab->private == NULL)
204 		return (NULL);
205 
206 	strtab = db_elf_find_strtab(stab);
207 	if (strtab == NULL)
208 		return (NULL);
209 
210 	symtab_start = STAB_TO_SYMSTART(stab);
211 	symp = symtab_start;
212 
213 	for (i = *idx + 1; i < db_ctf.nsyms; i++) {
214 		st = &symp[i];
215 
216 		if (ELF_ST_TYPE(st->st_info) != type)
217 			continue;
218 
219 		*idx = i;
220 		return strtab + st->st_name;
221 	}
222 
223 	return (NULL);
224 }
225 
226 /*
227  * For a given function name, return the number of arguments.
228  */
229 int
230 db_ctf_func_numargs(const char *funcname)
231 {
232 	const char		*s;
233 	unsigned short		*fsp, kind, vlen;
234 	size_t			 idx = 0;
235 	int			 nargs;
236 
237 	if (!db_ctf.ctf_found)
238 		return (0);
239 
240 	fsp = (unsigned short *)(db_ctf.data + db_ctf.cth->cth_funcoff);
241 	while (fsp < (unsigned short *)(db_ctf.data + db_ctf.cth->cth_typeoff)) {
242 		kind = CTF_INFO_KIND(*fsp);
243 		vlen = CTF_INFO_VLEN(*fsp);
244 		s = db_ctf_idx2sym(&idx, STT_FUNC);
245 		fsp++;
246 
247 		if (kind == CTF_K_UNKNOWN && vlen == 0)
248 			continue;
249 
250 		nargs = 0;
251 		if (s != NULL) {
252 			/*
253 			 * We have to keep increasing fsp++ while walking the
254 			 * table even if we discard the value at that location.
255 			 * This is required to keep a moving index.
256 			 *
257 			 * First increment for the return type, then for each
258 			 * parameter type.
259 			 */
260 			fsp++;
261 
262 			while (vlen-- > 0) {
263 				nargs++;
264 				fsp++;
265 			}
266 
267 			if (strncmp(funcname, s, strlen(funcname)) == 0) {
268 				return (nargs);
269 			}
270 		}
271 	}
272 
273 	return (0);
274 }
275 
276 static int
277 db_ctf_print_functions(void)
278 {
279 	unsigned short		*fsp, kind, vlen;
280 	size_t			 idx = 0, i = 0;
281 	const char		*s;
282 	int			 l;
283 
284 	if (!db_ctf.ctf_found)
285 		return 1;
286 
287 	fsp = (unsigned short *)(db_ctf.data + db_ctf.cth->cth_funcoff);
288 	while (fsp < (unsigned short *)(db_ctf.data + db_ctf.cth->cth_typeoff)) {
289 		kind = CTF_INFO_KIND(*fsp);
290 		vlen = CTF_INFO_VLEN(*fsp);
291 		fsp++;
292 
293 		if (kind == CTF_K_UNKNOWN && vlen == 0)
294 			continue;
295 
296 		l = db_printf("  [%zu] FUNC ", i++);
297 		if ((s = db_ctf_idx2sym(&idx, STT_FUNC)) != NULL)
298 			db_printf("(%s)", s);
299 		db_printf(" returns: %u args: (", *fsp++);
300 		while (vlen-- > 0)
301 			db_printf("%u%s", *fsp++, (vlen > 0) ? ", " : "");
302 		db_printf(") idx: %zu\n", idx);
303 	}
304 	db_printf("\n");
305 	return 0;
306 }
307 
308 static const char *
309 db_ctf_lookup_name(unsigned int offset)
310 {
311 	const char		*name;
312 
313 	if (CTF_NAME_STID(offset) != CTF_STRTAB_0)
314 		return "external";
315 
316 	if (CTF_NAME_OFFSET(offset) >= db_ctf.cth->cth_strlen)
317 		return "exceeds strlab";
318 
319 	if (db_ctf.cth->cth_stroff + CTF_NAME_OFFSET(offset) >= db_ctf.dlen)
320 		return "invalid";
321 
322 	name = db_ctf.data + db_ctf.cth->cth_stroff + CTF_NAME_OFFSET(offset);
323 	if (*name == '\0')
324 		return "(anon)";
325 
326 	return name;
327 }
328 
329 static char *
330 db_ctf_decompress(const char *buf, size_t size, off_t len)
331 {
332 	z_stream		 stream;
333 	char			*data;
334 	int			 error;
335 
336 	/* XXX: drop malloc(9) usage */
337 	data = malloc(len, M_TEMP, M_WAITOK|M_ZERO|M_CANFAIL);
338 	if (data == NULL) {
339 		return (NULL);
340 	}
341 
342 	memset(&stream, 0, sizeof(stream));
343 	stream.next_in = (void *)buf;
344 	stream.avail_in = size;
345 	stream.next_out = data;
346 	stream.avail_out = len;
347 
348 	if ((error = inflateInit(&stream)) != Z_OK) {
349 		db_printf("zlib inflateInit failed: %s", zError(error));
350 		goto exit;
351 	}
352 
353 	if ((error = inflate(&stream, Z_FINISH)) != Z_STREAM_END) {
354 		db_printf("zlib inflate failed: %s", zError(error));
355 		inflateEnd(&stream);
356 		goto exit;
357 	}
358 
359 	if ((error = inflateEnd(&stream)) != Z_OK) {
360 		db_printf("zlib inflateEnd failed: %s", zError(error));
361 		goto exit;
362 	}
363 
364 	if (stream.total_out != len) {
365 		db_printf("decompression failed: %llu != %llu",
366 		    stream.total_out, len);
367 		goto exit;
368 	}
369 
370 	return (data);
371 
372 exit:
373 	free(data, M_DEVBUF, sizeof(*data));
374 	return (NULL);
375 }
376