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