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