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