xref: /freebsd/sys/ddb/db_ctf.c (revision 637e67e0329058c86353dbe523740e34d8fefd11)
1c21bc6f3SBojan Novković /*-
2*637e67e0SBojan Novković  * SPDX-License-Identifier: BSD-2-Clause
3c21bc6f3SBojan Novković  *
4c21bc6f3SBojan Novković  * Copyright (c) 2023 Bojan Novković <bnovkov@freebsd.org>
5c21bc6f3SBojan Novković  *
6c21bc6f3SBojan Novković  * Redistribution and use in source and binary forms, with or without
7c21bc6f3SBojan Novković  * modification, are permitted provided that the following conditions
8c21bc6f3SBojan Novković  * are met:
9c21bc6f3SBojan Novković  * 1. Redistributions of source code must retain the above copyright
10c21bc6f3SBojan Novković  *    notice, this list of conditions and the following disclaimer.
11c21bc6f3SBojan Novković  * 2. Redistributions in binary form must reproduce the above copyright
12c21bc6f3SBojan Novković  *    notice, this list of conditions and the following disclaimer in the
13c21bc6f3SBojan Novković  *    documentation and/or other materials provided with the distribution.
14c21bc6f3SBojan Novković  *
15c21bc6f3SBojan Novković  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16c21bc6f3SBojan Novković  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17c21bc6f3SBojan Novković  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18c21bc6f3SBojan Novković  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19c21bc6f3SBojan Novković  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20c21bc6f3SBojan Novković  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21c21bc6f3SBojan Novković  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22c21bc6f3SBojan Novković  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23c21bc6f3SBojan Novković  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24c21bc6f3SBojan Novković  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25c21bc6f3SBojan Novković  * SUCH DAMAGE.
26c21bc6f3SBojan Novković  */
27c21bc6f3SBojan Novković 
28c21bc6f3SBojan Novković #include <sys/cdefs.h>
29c21bc6f3SBojan Novković #include <sys/types.h>
30c21bc6f3SBojan Novković #include <sys/param.h>
31c21bc6f3SBojan Novković #include <sys/systm.h>
32c21bc6f3SBojan Novković #include <sys/ctype.h>
33c21bc6f3SBojan Novković #include <sys/linker.h>
34c21bc6f3SBojan Novković #include <sys/malloc.h>
35c21bc6f3SBojan Novković #include <sys/mutex.h>
36c21bc6f3SBojan Novković 
37c21bc6f3SBojan Novković #include <ddb/ddb.h>
38c21bc6f3SBojan Novković #include <ddb/db_ctf.h>
39c21bc6f3SBojan Novković 
40c21bc6f3SBojan Novković static const ctf_header_t *
db_ctf_fetch_cth(linker_ctf_t * lc)41c21bc6f3SBojan Novković db_ctf_fetch_cth(linker_ctf_t *lc)
42c21bc6f3SBojan Novković {
43c21bc6f3SBojan Novković 	return (const ctf_header_t *)lc->ctftab;
44c21bc6f3SBojan Novković }
45c21bc6f3SBojan Novković 
46c21bc6f3SBojan Novković /*
47c21bc6f3SBojan Novković  * Tries to look up the ELF symbol -> CTF type identifier mapping by scanning
48c21bc6f3SBojan Novković  * the CTF object section.
49c21bc6f3SBojan Novković  */
50c21bc6f3SBojan Novković static uint32_t
sym_to_objtoff(linker_ctf_t * lc,const Elf_Sym * sym,const Elf_Sym * symtab,const Elf_Sym * symtab_end)51c21bc6f3SBojan Novković sym_to_objtoff(linker_ctf_t *lc, const Elf_Sym *sym, const Elf_Sym *symtab,
52c21bc6f3SBojan Novković     const Elf_Sym *symtab_end)
53c21bc6f3SBojan Novković {
54c21bc6f3SBojan Novković 	const ctf_header_t *hp = db_ctf_fetch_cth(lc);
55c21bc6f3SBojan Novković 	uint32_t objtoff = hp->cth_objtoff;
56c21bc6f3SBojan Novković 	const size_t idwidth = 4;
57c21bc6f3SBojan Novković 
58c21bc6f3SBojan Novković 	/* Ignore non-object symbols */
59c21bc6f3SBojan Novković 	if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) {
60c21bc6f3SBojan Novković 		return (DB_CTF_INVALID_OFF);
61c21bc6f3SBojan Novković 	}
62c21bc6f3SBojan Novković 	/* Sanity check */
63c21bc6f3SBojan Novković 	if (!(sym >= symtab && sym <= symtab_end)) {
64c21bc6f3SBojan Novković 		return (DB_CTF_INVALID_OFF);
65c21bc6f3SBojan Novković 	}
66c21bc6f3SBojan Novković 
67c21bc6f3SBojan Novković 	for (const Elf_Sym *symp = symtab; symp < symtab_end; symp++) {
68c21bc6f3SBojan Novković 		/* Make sure we do not go beyond the objtoff section */
69c21bc6f3SBojan Novković 		if (objtoff >= hp->cth_funcoff) {
70c21bc6f3SBojan Novković 			objtoff = DB_CTF_INVALID_OFF;
71c21bc6f3SBojan Novković 			break;
72c21bc6f3SBojan Novković 		}
73c21bc6f3SBojan Novković 		if (symp->st_name == 0 || symp->st_shndx == SHN_UNDEF) {
74c21bc6f3SBojan Novković 			continue;
75c21bc6f3SBojan Novković 		}
76c21bc6f3SBojan Novković 		if (symp->st_shndx == SHN_ABS && symp->st_value == 0) {
77c21bc6f3SBojan Novković 			continue;
78c21bc6f3SBojan Novković 		}
79c21bc6f3SBojan Novković 
80c21bc6f3SBojan Novković 		/* Skip non-object symbols */
81c21bc6f3SBojan Novković 		if (ELF_ST_TYPE(symp->st_info) != STT_OBJECT) {
82c21bc6f3SBojan Novković 			continue;
83c21bc6f3SBojan Novković 		}
84c21bc6f3SBojan Novković 		if (symp == sym) {
85c21bc6f3SBojan Novković 			break;
86c21bc6f3SBojan Novković 		}
87c21bc6f3SBojan Novković 		objtoff += idwidth;
88c21bc6f3SBojan Novković 	}
89c21bc6f3SBojan Novković 
90c21bc6f3SBojan Novković 	return (objtoff);
91c21bc6f3SBojan Novković }
92c21bc6f3SBojan Novković 
93c21bc6f3SBojan Novković /*
94c21bc6f3SBojan Novković  * Returns the size of CTF type 't'.
95c21bc6f3SBojan Novković  */
96c21bc6f3SBojan Novković static u_int
db_ctf_type_size(struct ctf_type_v3 * t)97c21bc6f3SBojan Novković db_ctf_type_size(struct ctf_type_v3 *t)
98c21bc6f3SBojan Novković {
99c21bc6f3SBojan Novković 	u_int vlen, kind, ssize;
100c21bc6f3SBojan Novković 	u_int type_struct_size, kind_size;
101c21bc6f3SBojan Novković 
102c21bc6f3SBojan Novković 	vlen = CTF_V3_INFO_VLEN(t->ctt_info);
103c21bc6f3SBojan Novković 	kind = CTF_V3_INFO_KIND(t->ctt_info);
104c21bc6f3SBojan Novković 	ssize = ((t->ctt_size == CTF_V3_LSIZE_SENT) ? CTF_TYPE_LSIZE(t) :
105c21bc6f3SBojan Novković 						      t->ctt_size);
106c21bc6f3SBojan Novković 	type_struct_size = ((t->ctt_size == CTF_V3_LSIZE_SENT) ?
107c21bc6f3SBojan Novković 		sizeof(struct ctf_type_v3) :
108c21bc6f3SBojan Novković 		sizeof(struct ctf_stype_v3));
109c21bc6f3SBojan Novković 
110c21bc6f3SBojan Novković 	switch (kind) {
111c21bc6f3SBojan Novković 	case CTF_K_INTEGER:
112c21bc6f3SBojan Novković 	case CTF_K_FLOAT:
113c21bc6f3SBojan Novković 		kind_size = sizeof(uint32_t);
114c21bc6f3SBojan Novković 		break;
115c21bc6f3SBojan Novković 	case CTF_K_ARRAY:
116c21bc6f3SBojan Novković 		kind_size = sizeof(struct ctf_array_v3);
117c21bc6f3SBojan Novković 		break;
118c21bc6f3SBojan Novković 	case CTF_K_UNION:
119c21bc6f3SBojan Novković 	case CTF_K_STRUCT:
120c21bc6f3SBojan Novković 		kind_size = vlen *
121c21bc6f3SBojan Novković 		    ((ssize < CTF_V3_LSTRUCT_THRESH) ?
122c21bc6f3SBojan Novković 			    sizeof(struct ctf_member_v3) :
123c21bc6f3SBojan Novković 			    sizeof(struct ctf_lmember_v3));
124c21bc6f3SBojan Novković 		break;
125c21bc6f3SBojan Novković 	case CTF_K_ENUM:
126c21bc6f3SBojan Novković 		kind_size = vlen * sizeof(struct ctf_enum);
127c21bc6f3SBojan Novković 		break;
128c21bc6f3SBojan Novković 	case CTF_K_FUNCTION:
129c21bc6f3SBojan Novković 		kind_size = vlen * sizeof(uint32_t);
130c21bc6f3SBojan Novković 		break;
131c21bc6f3SBojan Novković 	case CTF_K_UNKNOWN:
132c21bc6f3SBojan Novković 	case CTF_K_FORWARD:
133c21bc6f3SBojan Novković 	case CTF_K_POINTER:
134c21bc6f3SBojan Novković 	case CTF_K_TYPEDEF:
135c21bc6f3SBojan Novković 	case CTF_K_VOLATILE:
136c21bc6f3SBojan Novković 	case CTF_K_CONST:
137c21bc6f3SBojan Novković 	case CTF_K_RESTRICT:
138c21bc6f3SBojan Novković 		kind_size = 0;
139c21bc6f3SBojan Novković 		break;
140c21bc6f3SBojan Novković 	default:
141c21bc6f3SBojan Novković 		db_printf("Error: invalid CTF type kind encountered\n");
142c21bc6f3SBojan Novković 		return (-1);
143c21bc6f3SBojan Novković 	}
144c21bc6f3SBojan Novković 
145c21bc6f3SBojan Novković 	return (type_struct_size + kind_size);
146c21bc6f3SBojan Novković }
147c21bc6f3SBojan Novković 
148c21bc6f3SBojan Novković /*
149c21bc6f3SBojan Novković  * Looks up type name 'name' in the CTF string table and returns the
150c21bc6f3SBojan Novković  * corresponding CTF type struct, if any.
151c21bc6f3SBojan Novković  */
152c21bc6f3SBojan Novković struct ctf_type_v3 *
db_ctf_typename_to_type(linker_ctf_t * lc,const char * name)153c21bc6f3SBojan Novković db_ctf_typename_to_type(linker_ctf_t *lc, const char *name)
154c21bc6f3SBojan Novković {
155c21bc6f3SBojan Novković 	const ctf_header_t *hp = db_ctf_fetch_cth(lc);
156c21bc6f3SBojan Novković 	char *start, *cur, *end;
157c21bc6f3SBojan Novković 	uint32_t stroff = hp->cth_stroff;
158c21bc6f3SBojan Novković 	uint32_t typeoff = hp->cth_typeoff;
159c21bc6f3SBojan Novković 	uint32_t name_stroff;
160c21bc6f3SBojan Novković 	const uint8_t *ctfstart = (const uint8_t *)hp + sizeof(ctf_header_t);
161c21bc6f3SBojan Novković 
162c21bc6f3SBojan Novković 	u_int skiplen;
163c21bc6f3SBojan Novković 
164c21bc6f3SBojan Novković 	/* Scan ctf strtab for typename. */
165c21bc6f3SBojan Novković 	start = cur = __DECONST(char *, hp) + sizeof(ctf_header_t) +
166c21bc6f3SBojan Novković 	    hp->cth_stroff;
167c21bc6f3SBojan Novković 	end = cur + hp->cth_strlen;
168c21bc6f3SBojan Novković 	while (cur < end) {
169c21bc6f3SBojan Novković 		if (strcmp(cur, name) == 0)
170c21bc6f3SBojan Novković 			break;
171c21bc6f3SBojan Novković 		cur += strlen(cur) + 1;
172c21bc6f3SBojan Novković 	}
173c21bc6f3SBojan Novković 	if (cur >= end)
174c21bc6f3SBojan Novković 		return (NULL);
175c21bc6f3SBojan Novković 	name_stroff = (uint32_t)(cur - start);
176c21bc6f3SBojan Novković 
177c21bc6f3SBojan Novković 	/* Scan for type containing the found stroff. */
178c21bc6f3SBojan Novković 	while (typeoff < stroff) {
179c21bc6f3SBojan Novković 		struct ctf_type_v3 *t =
180c21bc6f3SBojan Novković 		    (struct ctf_type_v3 *)(__DECONST(uint8_t *, ctfstart) +
181c21bc6f3SBojan Novković 			typeoff);
182c21bc6f3SBojan Novković 		/* We found the type struct */
183c21bc6f3SBojan Novković 		if (t->ctt_name == name_stroff) {
184c21bc6f3SBojan Novković 			break;
185c21bc6f3SBojan Novković 		}
186c21bc6f3SBojan Novković 		if ((skiplen = db_ctf_type_size(t)) == -1) {
187c21bc6f3SBojan Novković 			return (NULL);
188c21bc6f3SBojan Novković 		}
189c21bc6f3SBojan Novković 		typeoff += skiplen;
190c21bc6f3SBojan Novković 	}
191c21bc6f3SBojan Novković 	if (typeoff < stroff) {
192c21bc6f3SBojan Novković 		return (struct ctf_type_v3 *)(__DECONST(uint8_t *, ctfstart) +
193c21bc6f3SBojan Novković 		    typeoff);
194c21bc6f3SBojan Novković 	} else { /* A type struct was not found */
195c21bc6f3SBojan Novković 		return (NULL);
196c21bc6f3SBojan Novković 	}
197c21bc6f3SBojan Novković }
198c21bc6f3SBojan Novković 
199c21bc6f3SBojan Novković /*
200c21bc6f3SBojan Novković  * Wrapper used by the kernel linker CTF routines.
201c21bc6f3SBojan Novković  * Currently used to implement lookup of CTF types accross all loaded kernel
202c21bc6f3SBojan Novković  * modules.
203c21bc6f3SBojan Novković  */
204c21bc6f3SBojan Novković bool
db_ctf_lookup_typename(linker_ctf_t * lc,const char * typename)205c21bc6f3SBojan Novković db_ctf_lookup_typename(linker_ctf_t *lc, const char *typename)
206c21bc6f3SBojan Novković {
207c21bc6f3SBojan Novković 	return (db_ctf_typename_to_type(lc, typename) != NULL);
208c21bc6f3SBojan Novković }
209c21bc6f3SBojan Novković 
210c21bc6f3SBojan Novković /*
211c21bc6f3SBojan Novković  * Returns the type corresponding to the 'typeid' parameter from the CTF type
212c21bc6f3SBojan Novković  * section.
213c21bc6f3SBojan Novković  */
214c21bc6f3SBojan Novković struct ctf_type_v3 *
db_ctf_typeid_to_type(db_ctf_sym_data_t sd,uint32_t typeid)215c21bc6f3SBojan Novković db_ctf_typeid_to_type(db_ctf_sym_data_t sd, uint32_t typeid)
216c21bc6f3SBojan Novković {
217c21bc6f3SBojan Novković 	const ctf_header_t *hp = db_ctf_fetch_cth(&sd->lc);
218c21bc6f3SBojan Novković 	const uint8_t *ctfstart = (const uint8_t *)hp + sizeof(ctf_header_t);
219c21bc6f3SBojan Novković 	uint32_t typeoff = hp->cth_typeoff;
220c21bc6f3SBojan Novković 	uint32_t stroff = hp->cth_stroff;
221c21bc6f3SBojan Novković 	/* CTF typeids start at 0x1 */
222c21bc6f3SBojan Novković 	size_t cur_typeid = 1;
223c21bc6f3SBojan Novković 	u_int skiplen;
224c21bc6f3SBojan Novković 
225c21bc6f3SBojan Novković 	/* Find corresponding type */
226c21bc6f3SBojan Novković 	while (typeoff < stroff) {
227c21bc6f3SBojan Novković 		struct ctf_type_v3 *t =
228c21bc6f3SBojan Novković 		    (struct ctf_type_v3 *)(__DECONST(uint8_t *, ctfstart) +
229c21bc6f3SBojan Novković 			typeoff);
230c21bc6f3SBojan Novković 
231c21bc6f3SBojan Novković 		/* We found the type struct */
232c21bc6f3SBojan Novković 		if (cur_typeid == typeid) {
233c21bc6f3SBojan Novković 			break;
234c21bc6f3SBojan Novković 		}
235c21bc6f3SBojan Novković 		cur_typeid++;
236c21bc6f3SBojan Novković 		if ((skiplen = db_ctf_type_size(t)) == -1) {
237c21bc6f3SBojan Novković 			return (NULL);
238c21bc6f3SBojan Novković 		}
239c21bc6f3SBojan Novković 		typeoff += skiplen;
240c21bc6f3SBojan Novković 	}
241c21bc6f3SBojan Novković 	if (typeoff < stroff) {
242c21bc6f3SBojan Novković 		return (struct ctf_type_v3 *)(__DECONST(uint8_t *, ctfstart) +
243c21bc6f3SBojan Novković 		    typeoff);
244c21bc6f3SBojan Novković 	} else { /* A type struct was not found */
245c21bc6f3SBojan Novković 		return (NULL);
246c21bc6f3SBojan Novković 	}
247c21bc6f3SBojan Novković }
248c21bc6f3SBojan Novković 
249c21bc6f3SBojan Novković const char *
db_ctf_stroff_to_str(db_ctf_sym_data_t sd,uint32_t off)250c21bc6f3SBojan Novković db_ctf_stroff_to_str(db_ctf_sym_data_t sd, uint32_t off)
251c21bc6f3SBojan Novković {
252c21bc6f3SBojan Novković 	const ctf_header_t *hp = db_ctf_fetch_cth(&sd->lc);
253c21bc6f3SBojan Novković 	uint32_t stroff = hp->cth_stroff + off;
254c21bc6f3SBojan Novković 	const char *ret;
255c21bc6f3SBojan Novković 
256c21bc6f3SBojan Novković 	if (stroff >= (hp->cth_stroff + hp->cth_strlen)) {
257c21bc6f3SBojan Novković 		return ("invalid");
258c21bc6f3SBojan Novković 	}
259c21bc6f3SBojan Novković 	ret = ((const char *)hp + sizeof(ctf_header_t)) + stroff;
260c21bc6f3SBojan Novković 	if (*ret == '\0') {
261c21bc6f3SBojan Novković 		return (NULL);
262c21bc6f3SBojan Novković 	}
263c21bc6f3SBojan Novković 
264c21bc6f3SBojan Novković 	return (ret);
265c21bc6f3SBojan Novković }
266c21bc6f3SBojan Novković 
267c21bc6f3SBojan Novković /*
268c21bc6f3SBojan Novković  * Tries to find the type of the symbol specified in 'sd->sym'.
269c21bc6f3SBojan Novković  */
270c21bc6f3SBojan Novković struct ctf_type_v3 *
db_ctf_sym_to_type(db_ctf_sym_data_t sd)271c21bc6f3SBojan Novković db_ctf_sym_to_type(db_ctf_sym_data_t sd)
272c21bc6f3SBojan Novković {
273c21bc6f3SBojan Novković 	uint32_t objtoff, typeid;
274c21bc6f3SBojan Novković 	const Elf_Sym *symtab, *symtab_end;
275c21bc6f3SBojan Novković 
276c21bc6f3SBojan Novković 	if (sd->sym == NULL) {
277c21bc6f3SBojan Novković 		return (NULL);
278c21bc6f3SBojan Novković 	}
279c21bc6f3SBojan Novković 	symtab = sd->lc.symtab;
280c21bc6f3SBojan Novković 	symtab_end = symtab + sd->lc.nsym;
281c21bc6f3SBojan Novković 
282c21bc6f3SBojan Novković 	objtoff = sym_to_objtoff(&sd->lc, sd->sym, symtab, symtab_end);
283c21bc6f3SBojan Novković 	/* Sanity check - should not happen */
284c21bc6f3SBojan Novković 	if (objtoff == DB_CTF_INVALID_OFF) {
285c21bc6f3SBojan Novković 		db_printf("Could not find CTF object offset.\n");
286c21bc6f3SBojan Novković 		return (NULL);
287c21bc6f3SBojan Novković 	}
288c21bc6f3SBojan Novković 
289c21bc6f3SBojan Novković 	typeid = *(
290c21bc6f3SBojan Novković 	    const uint32_t *)(sd->lc.ctftab + sizeof(ctf_header_t) + objtoff);
291c21bc6f3SBojan Novković 
292c21bc6f3SBojan Novković 	return (db_ctf_typeid_to_type(sd, typeid));
293c21bc6f3SBojan Novković }
294c21bc6f3SBojan Novković 
295c21bc6f3SBojan Novković /*
296c21bc6f3SBojan Novković  * Scans the kernel file and all loaded module for symbol 'name'.
297c21bc6f3SBojan Novković  */
298c21bc6f3SBojan Novković int
db_ctf_find_symbol(const char * name,db_ctf_sym_data_t sd)299c21bc6f3SBojan Novković db_ctf_find_symbol(const char *name, db_ctf_sym_data_t sd)
300c21bc6f3SBojan Novković {
301c21bc6f3SBojan Novković 	int error;
302c21bc6f3SBojan Novković 	c_linker_sym_t lsym = NULL;
303c21bc6f3SBojan Novković 
304c21bc6f3SBojan Novković 	error = linker_ctf_lookup_sym_ddb(name, &lsym, &sd->lc);
305c21bc6f3SBojan Novković 	if (error != 0) {
306c21bc6f3SBojan Novković 		db_printf(
307c21bc6f3SBojan Novković 		    "failed to look up symbol and CTF info for %s: error %d\n",
308c21bc6f3SBojan Novković 		    name, error);
309c21bc6f3SBojan Novković 		return (error);
310c21bc6f3SBojan Novković 	}
311c21bc6f3SBojan Novković 	sd->sym = __DECONST(Elf_Sym *, lsym);
312c21bc6f3SBojan Novković 
313c21bc6f3SBojan Novković 	return (0);
314c21bc6f3SBojan Novković }
315c21bc6f3SBojan Novković 
316c21bc6f3SBojan Novković /*
317c21bc6f3SBojan Novković  * Scans the kernel file and all loaded module for type specified by 'typename'.
318c21bc6f3SBojan Novković  */
319c21bc6f3SBojan Novković struct ctf_type_v3 *
db_ctf_find_typename(db_ctf_sym_data_t sd,const char * typename)320c21bc6f3SBojan Novković db_ctf_find_typename(db_ctf_sym_data_t sd, const char *typename)
321c21bc6f3SBojan Novković {
322c21bc6f3SBojan Novković 	if (linker_ctf_lookup_typename_ddb(&sd->lc, typename) != 0) {
323c21bc6f3SBojan Novković 		return (NULL);
324c21bc6f3SBojan Novković 	}
325c21bc6f3SBojan Novković 	return (db_ctf_typename_to_type(&sd->lc, typename));
326c21bc6f3SBojan Novković }
327