xref: /freebsd/sys/ddb/db_ctf.c (revision 637e67e0329058c86353dbe523740e34d8fefd11)
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 *
db_ctf_fetch_cth(linker_ctf_t * lc)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
sym_to_objtoff(linker_ctf_t * lc,const Elf_Sym * sym,const Elf_Sym * symtab,const Elf_Sym * symtab_end)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
db_ctf_type_size(struct ctf_type_v3 * t)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 *
db_ctf_typename_to_type(linker_ctf_t * lc,const char * name)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
db_ctf_lookup_typename(linker_ctf_t * lc,const char * typename)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 *
db_ctf_typeid_to_type(db_ctf_sym_data_t sd,uint32_t typeid)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 *
db_ctf_stroff_to_str(db_ctf_sym_data_t sd,uint32_t off)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 *
db_ctf_sym_to_type(db_ctf_sym_data_t sd)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
db_ctf_find_symbol(const char * name,db_ctf_sym_data_t sd)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 *
db_ctf_find_typename(db_ctf_sym_data_t sd,const char * typename)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