xref: /openbsd-src/sys/ddb/db_ctf.c (revision 949c1c4ec8cc03255798b09f6078e1d0aed70a6a)
1*949c1c4eSmiod /*	$OpenBSD: db_ctf.c,v 1.35 2024/11/07 16:02:29 miod Exp $	*/
2fd68ecf3Sjasper 
3fd68ecf3Sjasper /*
48cd47547Smpi  * Copyright (c) 2016-2017 Martin Pieuchot
5fd68ecf3Sjasper  * Copyright (c) 2016 Jasper Lievisse Adriaanse <jasper@openbsd.org>
6fd68ecf3Sjasper  *
7fd68ecf3Sjasper  * Permission to use, copy, modify, and distribute this software for any
8fd68ecf3Sjasper  * purpose with or without fee is hereby granted, provided that the above
9fd68ecf3Sjasper  * copyright notice and this permission notice appear in all copies.
10fd68ecf3Sjasper  *
11fd68ecf3Sjasper  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12fd68ecf3Sjasper  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13fd68ecf3Sjasper  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14fd68ecf3Sjasper  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15fd68ecf3Sjasper  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16fd68ecf3Sjasper  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17fd68ecf3Sjasper  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18fd68ecf3Sjasper  */
19fd68ecf3Sjasper 
20fd68ecf3Sjasper #include <sys/param.h>
21b27348b2Sderaadt #include <sys/stdint.h>
22fd68ecf3Sjasper #include <sys/systm.h>
23fd68ecf3Sjasper #include <sys/exec.h>
24fd68ecf3Sjasper 
25fd68ecf3Sjasper #include <machine/db_machdep.h>
26fd68ecf3Sjasper 
27fd68ecf3Sjasper #include <ddb/db_extern.h>
28ad205586Smpi #include <ddb/db_command.h>
29fd68ecf3Sjasper #include <ddb/db_elf.h>
30ad205586Smpi #include <ddb/db_lex.h>
31fd68ecf3Sjasper #include <ddb/db_output.h>
32ad205586Smpi #include <ddb/db_sym.h>
330488a471Sdlg #include <ddb/db_access.h>
34fd68ecf3Sjasper 
35fd68ecf3Sjasper #include <sys/exec_elf.h>
362c89ed74Sjasper #include <sys/ctf.h>
37fd68ecf3Sjasper #include <sys/malloc.h>
38fd68ecf3Sjasper #include <lib/libz/zlib.h>
39fd68ecf3Sjasper 
40fd68ecf3Sjasper extern db_symtab_t		db_symtab;
41fd68ecf3Sjasper 
42fd68ecf3Sjasper struct ddb_ctf {
43fd68ecf3Sjasper 	struct ctf_header	*cth;
44b42aa555Smpi 	const char		*rawctf;	/* raw .SUNW_ctf section */
45b42aa555Smpi 	size_t			 rawctflen;	/* raw .SUNW_ctf section size */
46b42aa555Smpi 	const char		*data;		/* decompressed CTF data */
47b42aa555Smpi 	size_t			 dlen;		/* decompressed CTF data size */
48*949c1c4eSmiod 	const char		*strtab;	/* ELF string table */
49ba42e451Smpi 	uint32_t		 ctf_found;
50fd68ecf3Sjasper };
51fd68ecf3Sjasper 
52fd68ecf3Sjasper struct ddb_ctf db_ctf;
53fd68ecf3Sjasper 
54ad205586Smpi static const char	*db_ctf_off2name(uint32_t);
553dc63949Smpi static Elf_Sym		*db_ctf_idx2sym(size_t *, uint8_t);
5627fc743bSmillert static char		*db_ctf_decompress(const char *, size_t, size_t);
57fd68ecf3Sjasper 
58609e0b1cSclaudio uint32_t		 db_ctf_type_len(const struct ctf_type *);
59609e0b1cSclaudio size_t			 db_ctf_type_size(const struct ctf_type *);
60266ad235Sdlg const struct ctf_type	*db_ctf_type_by_name(const char *, unsigned int);
61ad205586Smpi const struct ctf_type	*db_ctf_type_by_symbol(Elf_Sym *);
62ad205586Smpi const struct ctf_type	*db_ctf_type_by_index(uint16_t);
638c31a435Sjasper void			 db_ctf_pprint(const struct ctf_type *, vaddr_t);
64ad205586Smpi void			 db_ctf_pprint_struct(const struct ctf_type *, vaddr_t);
65609e0b1cSclaudio void			 db_ctf_pprint_enum(const struct ctf_type *, vaddr_t);
66bebdad71Smpi void			 db_ctf_pprint_ptr(const struct ctf_type *, vaddr_t);
67ad205586Smpi 
68fd68ecf3Sjasper /*
69fd68ecf3Sjasper  * Entrypoint to verify CTF presence, initialize the header, decompress
70fd68ecf3Sjasper  * the data, etc.
71fd68ecf3Sjasper  */
72fd68ecf3Sjasper void
73fd68ecf3Sjasper db_ctf_init(void)
74fd68ecf3Sjasper {
75fd68ecf3Sjasper 	db_symtab_t *stab = &db_symtab;
76b42aa555Smpi 	size_t rawctflen;
77fd68ecf3Sjasper 
78fd68ecf3Sjasper 	/* Assume nothing was correct found until proven otherwise. */
79fd68ecf3Sjasper 	db_ctf.ctf_found = 0;
80fd68ecf3Sjasper 
81b42aa555Smpi 	if (stab->private == NULL)
82fd68ecf3Sjasper 		return;
83fd68ecf3Sjasper 
84b42aa555Smpi 	db_ctf.strtab = db_elf_find_strtab(stab);
85b42aa555Smpi 	if (db_ctf.strtab == NULL)
86b42aa555Smpi 		return;
87b42aa555Smpi 
884916abc8Smpi 	db_ctf.rawctf = db_elf_find_section(stab, &rawctflen, ELF_CTF);
89b42aa555Smpi 	if (db_ctf.rawctf == NULL)
90b42aa555Smpi 		return;
91b42aa555Smpi 
92b42aa555Smpi 	db_ctf.rawctflen = rawctflen;
93b42aa555Smpi 	db_ctf.cth = (struct ctf_header *)db_ctf.rawctf;
94fd68ecf3Sjasper 	db_ctf.dlen = db_ctf.cth->cth_stroff + db_ctf.cth->cth_strlen;
95fd68ecf3Sjasper 
96b42aa555Smpi 	if ((db_ctf.cth->cth_flags & CTF_F_COMPRESS) == 0) {
971c302ed1Sjasper 		db_printf("unsupported non-compressed CTF section\n");
98fd68ecf3Sjasper 		return;
99fd68ecf3Sjasper 	}
100fd68ecf3Sjasper 
101b42aa555Smpi 	/* Now decompress the section, take into account to skip the header */
102b42aa555Smpi 	db_ctf.data = db_ctf_decompress(db_ctf.rawctf + sizeof(*db_ctf.cth),
103b42aa555Smpi 	    db_ctf.rawctflen - sizeof(*db_ctf.cth), db_ctf.dlen);
104b42aa555Smpi 	if (db_ctf.data == NULL)
105fd68ecf3Sjasper 		return;
106fd68ecf3Sjasper 
107fd68ecf3Sjasper 	/* We made it this far, everything seems fine. */
108fd68ecf3Sjasper 	db_ctf.ctf_found = 1;
109fd68ecf3Sjasper }
110fd68ecf3Sjasper 
111fd68ecf3Sjasper /*
112fd68ecf3Sjasper  * Convert an index to a symbol name while ensuring the type is matched.
113fd68ecf3Sjasper  * It must be noted this only works if the CTF table has the same order
114fd68ecf3Sjasper  * as the symbol table.
115fd68ecf3Sjasper  */
1163dc63949Smpi Elf_Sym *
117ba42e451Smpi db_ctf_idx2sym(size_t *idx, uint8_t type)
118fd68ecf3Sjasper {
119b42aa555Smpi 	Elf_Sym *symp, *symtab_start, *symtab_end;
120b42aa555Smpi 	size_t i = *idx + 1;
121fd68ecf3Sjasper 
122b42aa555Smpi 	symtab_start = STAB_TO_SYMSTART(&db_symtab);
123b42aa555Smpi 	symtab_end = STAB_TO_SYMEND(&db_symtab);
124fd68ecf3Sjasper 
125b42aa555Smpi 	for (symp = &symtab_start[i]; symp < symtab_end; i++, symp++) {
126b42aa555Smpi 		if (ELF_ST_TYPE(symp->st_info) != type)
127fd68ecf3Sjasper 			continue;
128fd68ecf3Sjasper 
129fd68ecf3Sjasper 		*idx = i;
1303dc63949Smpi 		return symp;
131fd68ecf3Sjasper 	}
132fd68ecf3Sjasper 
133b42aa555Smpi 	return NULL;
134fd68ecf3Sjasper }
135fd68ecf3Sjasper 
136fd68ecf3Sjasper /*
137fd68ecf3Sjasper  * For a given function name, return the number of arguments.
138fd68ecf3Sjasper  */
139fd68ecf3Sjasper int
14062781896Smpi db_ctf_func_numargs(Elf_Sym *st)
141fd68ecf3Sjasper {
142ad205586Smpi 	Elf_Sym			*symp;
143b42aa555Smpi 	uint16_t		*fstart, *fend;
144ba42e451Smpi 	uint16_t		*fsp, kind, vlen;
145b42aa555Smpi 	size_t			 i, idx = 0;
146fd68ecf3Sjasper 
147ad205586Smpi 	if (!db_ctf.ctf_found || st == NULL)
148ed3d2e34Smpi 		return -1;
149fd68ecf3Sjasper 
150b42aa555Smpi 	fstart = (uint16_t *)(db_ctf.data + db_ctf.cth->cth_funcoff);
151b42aa555Smpi 	fend = (uint16_t *)(db_ctf.data + db_ctf.cth->cth_typeoff);
152fd68ecf3Sjasper 
153b42aa555Smpi 	fsp = fstart;
154b42aa555Smpi 	while (fsp < fend) {
1553dc63949Smpi 		symp = db_ctf_idx2sym(&idx, STT_FUNC);
1563dc63949Smpi 		if (symp == NULL)
157b42aa555Smpi 			break;
158fd68ecf3Sjasper 
159fd68ecf3Sjasper 		kind = CTF_INFO_KIND(*fsp);
160fd68ecf3Sjasper 		vlen = CTF_INFO_VLEN(*fsp);
161fd68ecf3Sjasper 		fsp++;
162fd68ecf3Sjasper 
163fd68ecf3Sjasper 		if (kind == CTF_K_UNKNOWN && vlen == 0)
164fd68ecf3Sjasper 			continue;
165fd68ecf3Sjasper 
166b42aa555Smpi 		/* Skip return type */
167b42aa555Smpi 		fsp++;
168b42aa555Smpi 
169b42aa555Smpi 		/* Skip argument types */
170b42aa555Smpi 		for (i = 0; i < vlen; i++)
171b42aa555Smpi 			fsp++;
172b42aa555Smpi 
173ad205586Smpi 		if (symp == st)
174b42aa555Smpi 			return vlen;
175fd68ecf3Sjasper 	}
176b42aa555Smpi 
1773998cbb6Smpi 	return 0;
178fd68ecf3Sjasper }
179fd68ecf3Sjasper 
180ad205586Smpi /*
181ad205586Smpi  * Return the length of the type record in the CTF section.
182ad205586Smpi  */
183ad205586Smpi uint32_t
184ad205586Smpi db_ctf_type_len(const struct ctf_type *ctt)
185ad205586Smpi {
186ad205586Smpi 	uint16_t		 kind, vlen, i;
187ad205586Smpi 	uint32_t		 tlen;
188ad205586Smpi 	uint64_t		 size;
189ad205586Smpi 
190ad205586Smpi 	kind = CTF_INFO_KIND(ctt->ctt_info);
191ad205586Smpi 	vlen = CTF_INFO_VLEN(ctt->ctt_info);
192ad205586Smpi 
193ad205586Smpi 	if (ctt->ctt_size <= CTF_MAX_SIZE) {
194ad205586Smpi 		size = ctt->ctt_size;
195ad205586Smpi 		tlen = sizeof(struct ctf_stype);
196ad205586Smpi 	} else {
197ad205586Smpi 		size = CTF_TYPE_LSIZE(ctt);
198ad205586Smpi 		tlen = sizeof(struct ctf_type);
199ad205586Smpi 	}
200ad205586Smpi 
201ad205586Smpi 	switch (kind) {
202ad205586Smpi 	case CTF_K_UNKNOWN:
203ad205586Smpi 	case CTF_K_FORWARD:
204ad205586Smpi 		break;
205ad205586Smpi 	case CTF_K_INTEGER:
206ad205586Smpi 		tlen += sizeof(uint32_t);
207ad205586Smpi 		break;
208ad205586Smpi 	case CTF_K_FLOAT:
209ad205586Smpi 		tlen += sizeof(uint32_t);
210ad205586Smpi 		break;
211ad205586Smpi 	case CTF_K_ARRAY:
212ad205586Smpi 		tlen += sizeof(struct ctf_array);
213ad205586Smpi 		break;
214ad205586Smpi 	case CTF_K_FUNCTION:
215ad205586Smpi 		tlen += (vlen + (vlen & 1)) * sizeof(uint16_t);
216ad205586Smpi 		break;
217ad205586Smpi 	case CTF_K_STRUCT:
218ad205586Smpi 	case CTF_K_UNION:
219ad205586Smpi 		if (size < CTF_LSTRUCT_THRESH) {
220ad205586Smpi 			for (i = 0; i < vlen; i++) {
221ad205586Smpi 				tlen += sizeof(struct ctf_member);
222ad205586Smpi 			}
223ad205586Smpi 		} else {
224ad205586Smpi 			for (i = 0; i < vlen; i++) {
225ad205586Smpi 				tlen += sizeof(struct ctf_lmember);
226ad205586Smpi 			}
227ad205586Smpi 		}
228ad205586Smpi 		break;
229ad205586Smpi 	case CTF_K_ENUM:
230ad205586Smpi 		for (i = 0; i < vlen; i++) {
231ad205586Smpi 			tlen += sizeof(struct ctf_enum);
232ad205586Smpi 		}
233ad205586Smpi 		break;
234ad205586Smpi 	case CTF_K_POINTER:
235ad205586Smpi 	case CTF_K_TYPEDEF:
236ad205586Smpi 	case CTF_K_VOLATILE:
237ad205586Smpi 	case CTF_K_CONST:
238ad205586Smpi 	case CTF_K_RESTRICT:
239ad205586Smpi 		break;
240ad205586Smpi 	default:
241ad205586Smpi 		return 0;
242ad205586Smpi 	}
243ad205586Smpi 
244ad205586Smpi 	return tlen;
245ad205586Smpi }
246ad205586Smpi 
2478cd47547Smpi /*
248609e0b1cSclaudio  * Return the size of the type.
249609e0b1cSclaudio  */
250609e0b1cSclaudio size_t
251609e0b1cSclaudio db_ctf_type_size(const struct ctf_type *ctt)
252609e0b1cSclaudio {
253609e0b1cSclaudio 	vaddr_t			 taddr = (vaddr_t)ctt;
254609e0b1cSclaudio 	const struct ctf_type	*ref;
255609e0b1cSclaudio 	const struct ctf_array	*arr;
256609e0b1cSclaudio 	size_t			 tlen = 0;
257609e0b1cSclaudio 	uint16_t		 kind;
258609e0b1cSclaudio 	uint32_t		 toff;
259609e0b1cSclaudio 	uint64_t		 size;
260609e0b1cSclaudio 
261609e0b1cSclaudio 	kind = CTF_INFO_KIND(ctt->ctt_info);
262609e0b1cSclaudio 
263609e0b1cSclaudio 	if (ctt->ctt_size <= CTF_MAX_SIZE) {
264609e0b1cSclaudio 		size = ctt->ctt_size;
265609e0b1cSclaudio 		toff = sizeof(struct ctf_stype);
266609e0b1cSclaudio 	} else {
267609e0b1cSclaudio 		size = CTF_TYPE_LSIZE(ctt);
268609e0b1cSclaudio 		toff = sizeof(struct ctf_type);
269609e0b1cSclaudio 	}
270609e0b1cSclaudio 
271609e0b1cSclaudio 	switch (kind) {
272609e0b1cSclaudio 	case CTF_K_UNKNOWN:
273609e0b1cSclaudio 	case CTF_K_FORWARD:
274609e0b1cSclaudio 		break;
275609e0b1cSclaudio 	case CTF_K_INTEGER:
276609e0b1cSclaudio 	case CTF_K_FLOAT:
277609e0b1cSclaudio 		tlen = size;
278609e0b1cSclaudio 		break;
279609e0b1cSclaudio 	case CTF_K_ARRAY:
280609e0b1cSclaudio 		arr = (struct ctf_array *)(taddr + toff);
281609e0b1cSclaudio 		ref = db_ctf_type_by_index(arr->cta_contents);
282609e0b1cSclaudio 		tlen = arr->cta_nelems * db_ctf_type_size(ref);
283609e0b1cSclaudio 		break;
284609e0b1cSclaudio 	case CTF_K_FUNCTION:
285609e0b1cSclaudio 		tlen = 0;
286609e0b1cSclaudio 		break;
287609e0b1cSclaudio 	case CTF_K_STRUCT:
288609e0b1cSclaudio 	case CTF_K_UNION:
289609e0b1cSclaudio 	case CTF_K_ENUM:
290609e0b1cSclaudio 		tlen = size;
291609e0b1cSclaudio 		break;
292609e0b1cSclaudio 	case CTF_K_POINTER:
293609e0b1cSclaudio 		tlen = sizeof(void *);
294609e0b1cSclaudio 		break;
295609e0b1cSclaudio 	case CTF_K_TYPEDEF:
296609e0b1cSclaudio 	case CTF_K_VOLATILE:
297609e0b1cSclaudio 	case CTF_K_CONST:
298609e0b1cSclaudio 	case CTF_K_RESTRICT:
299609e0b1cSclaudio 		ref = db_ctf_type_by_index(ctt->ctt_type);
300609e0b1cSclaudio 		tlen = db_ctf_type_size(ref);
301609e0b1cSclaudio 		break;
302609e0b1cSclaudio 	default:
303609e0b1cSclaudio 		return 0;
304609e0b1cSclaudio 	}
305609e0b1cSclaudio 
306609e0b1cSclaudio 	return tlen;
307609e0b1cSclaudio }
308609e0b1cSclaudio 
309609e0b1cSclaudio /*
3108cd47547Smpi  * Return the CTF type associated to an ELF symbol.
3118cd47547Smpi  */
312ad205586Smpi const struct ctf_type *
313ad205586Smpi db_ctf_type_by_symbol(Elf_Sym *st)
314ad205586Smpi {
315ad205586Smpi 	Elf_Sym			*symp;
316ece49713Sjasper 	uint32_t		 objtoff;
317ad205586Smpi 	uint16_t		*dsp;
318ad205586Smpi 	size_t			 idx = 0;
319ad205586Smpi 
32016be3460Smpi 	if (!db_ctf.ctf_found || st == NULL)
32116be3460Smpi 		return NULL;
32216be3460Smpi 
323ece49713Sjasper 	objtoff = db_ctf.cth->cth_objtoff;
324ece49713Sjasper 
325ad205586Smpi 	while (objtoff < db_ctf.cth->cth_funcoff) {
326ad205586Smpi 		dsp = (uint16_t *)(db_ctf.data + objtoff);
327ad205586Smpi 
328ad205586Smpi 		symp = db_ctf_idx2sym(&idx, STT_OBJECT);
329ad205586Smpi 		if (symp == NULL)
330ad205586Smpi 			break;
331ad205586Smpi 		if (symp == st)
332ad205586Smpi 			return db_ctf_type_by_index(*dsp);
333ad205586Smpi 
334ad205586Smpi 		objtoff += sizeof(*dsp);
335ad205586Smpi 	}
336ad205586Smpi 
337ad205586Smpi 	return NULL;
338ad205586Smpi }
339ad205586Smpi 
340266ad235Sdlg const struct ctf_type *
341266ad235Sdlg db_ctf_type_by_name(const char *name, unsigned int kind)
342266ad235Sdlg {
343266ad235Sdlg 	struct ctf_header	*cth;
344266ad235Sdlg 	const struct ctf_type   *ctt;
345266ad235Sdlg 	const char		*tname;
346266ad235Sdlg 	uint32_t		 off, toff;
347266ad235Sdlg 
348266ad235Sdlg 	if (!db_ctf.ctf_found)
349266ad235Sdlg 		return (NULL);
350266ad235Sdlg 
351266ad235Sdlg 	cth = db_ctf.cth;
352266ad235Sdlg 
353266ad235Sdlg 	for (off = cth->cth_typeoff; off < cth->cth_stroff; off += toff) {
354266ad235Sdlg 		ctt = (struct ctf_type *)(db_ctf.data + off);
355266ad235Sdlg 		toff = db_ctf_type_len(ctt);
356266ad235Sdlg 		if (toff == 0) {
357266ad235Sdlg 			db_printf("incorrect type at offset %u", off);
358266ad235Sdlg 			break;
359266ad235Sdlg 		}
360266ad235Sdlg 
361266ad235Sdlg 		if (CTF_INFO_KIND(ctt->ctt_info) != kind)
362266ad235Sdlg 			continue;
363266ad235Sdlg 
364266ad235Sdlg 		tname = db_ctf_off2name(ctt->ctt_name);
365266ad235Sdlg 		if (tname == NULL)
366266ad235Sdlg 			continue;
367266ad235Sdlg 
368266ad235Sdlg 		if (strcmp(name, tname) == 0)
369266ad235Sdlg 			return (ctt);
370266ad235Sdlg 	}
371266ad235Sdlg 
372266ad235Sdlg 	return (NULL);
373266ad235Sdlg }
374266ad235Sdlg 
3758cd47547Smpi /*
3768cd47547Smpi  * Return the CTF type corresponding to a given index in the type section.
3778cd47547Smpi  */
378ad205586Smpi const struct ctf_type *
379ad205586Smpi db_ctf_type_by_index(uint16_t index)
380ad205586Smpi {
381ad205586Smpi 	uint32_t		 offset = db_ctf.cth->cth_typeoff;
382ad205586Smpi 	uint16_t		 idx = 1;
383ad205586Smpi 
384ad205586Smpi 	if (!db_ctf.ctf_found)
385ad205586Smpi 		return NULL;
386ad205586Smpi 
387ad205586Smpi 	while (offset < db_ctf.cth->cth_stroff) {
388ad205586Smpi 		const struct ctf_type   *ctt;
389ad205586Smpi 		uint32_t		 toff;
390ad205586Smpi 
391ad205586Smpi 		ctt = (struct ctf_type *)(db_ctf.data + offset);
392ad205586Smpi 		if (idx == index)
393ad205586Smpi 			return ctt;
394ad205586Smpi 
395ad205586Smpi 		toff = db_ctf_type_len(ctt);
396ad205586Smpi 		if (toff == 0) {
397ad205586Smpi 			db_printf("incorrect type at offset %u", offset);
398ad205586Smpi 			break;
399ad205586Smpi 		}
400ad205586Smpi 		offset += toff;
401ad205586Smpi 		idx++;
402ad205586Smpi 	}
403ad205586Smpi 
404ad205586Smpi 	return NULL;
405ad205586Smpi }
406ad205586Smpi 
4078cd47547Smpi /*
4088cd47547Smpi  * Pretty print `addr'.
4098cd47547Smpi  */
410ad205586Smpi void
41192b2adbfSuwe db_ctf_pprint(const struct ctf_type *ctt, vaddr_t addr)
412ad205586Smpi {
41308f058f8Smpi 	vaddr_t			 taddr = (vaddr_t)ctt;
414ad205586Smpi 	const struct ctf_type	*ref;
415609e0b1cSclaudio 	const struct ctf_array	*arr;
416ad205586Smpi 	uint16_t		 kind;
417609e0b1cSclaudio 	uint32_t		 eob, toff, i;
418609e0b1cSclaudio 	db_expr_t		 val;
419609e0b1cSclaudio 	size_t			 elm_size;
420609e0b1cSclaudio 
421609e0b1cSclaudio 	if (ctt == NULL)
422609e0b1cSclaudio 		return;
423ad205586Smpi 
424ad205586Smpi 	kind = CTF_INFO_KIND(ctt->ctt_info);
425ab77b743Smpi 	if (ctt->ctt_size <= CTF_MAX_SIZE)
426ab77b743Smpi 		toff = sizeof(struct ctf_stype);
427ab77b743Smpi 	else
428ab77b743Smpi 		toff = sizeof(struct ctf_type);
429ad205586Smpi 
430ad205586Smpi 	switch (kind) {
431ad205586Smpi 	case CTF_K_ARRAY:
432609e0b1cSclaudio 		arr = (struct ctf_array *)(taddr + toff);
433609e0b1cSclaudio 		ref = db_ctf_type_by_index(arr->cta_contents);
434609e0b1cSclaudio 		elm_size = db_ctf_type_size(ref);
435609e0b1cSclaudio 		db_printf("[");
436609e0b1cSclaudio 		for (i = 0; i < arr->cta_nelems; i++) {
437609e0b1cSclaudio 			db_ctf_pprint(ref, addr + i * elm_size);
438609e0b1cSclaudio 			if (i + 1 < arr->cta_nelems)
439609e0b1cSclaudio 				db_printf(",");
440609e0b1cSclaudio 		}
441609e0b1cSclaudio 		db_printf("]");
442609e0b1cSclaudio 		break;
443609e0b1cSclaudio 	case CTF_K_ENUM:
444609e0b1cSclaudio 		db_ctf_pprint_enum(ctt, addr);
445609e0b1cSclaudio 		break;
446609e0b1cSclaudio 	case CTF_K_FLOAT:
447ad205586Smpi 	case CTF_K_FUNCTION:
448609e0b1cSclaudio 		val = db_get_value(addr, sizeof(val), 0);
449609e0b1cSclaudio 		db_printf("%lx", (unsigned long)val);
450ad205586Smpi 		break;
451ad205586Smpi 	case CTF_K_INTEGER:
452ab77b743Smpi 		eob = db_get_value((taddr + toff), sizeof(eob), 0);
453ab77b743Smpi 		switch (CTF_INT_BITS(eob)) {
454609e0b1cSclaudio #ifndef __LP64__
455609e0b1cSclaudio 		case 64: {
456609e0b1cSclaudio 			uint64_t val64;
457609e0b1cSclaudio #if BYTE_ORDER == LITTLE_ENDIAN
458609e0b1cSclaudio 			val64 = db_get_value(addr + 4, CTF_INT_BITS(eob) / 8,
459609e0b1cSclaudio 			   CTF_INT_ENCODING(eob) & CTF_INT_SIGNED);
460609e0b1cSclaudio 			val64 <<= 32;
461609e0b1cSclaudio 			val64 |= db_get_value(addr, CTF_INT_BITS(eob) / 8, 0);
462609e0b1cSclaudio #else
463609e0b1cSclaudio 			val64 = db_get_value(addr, CTF_INT_BITS(eob) / 8,
464609e0b1cSclaudio 			   CTF_INT_ENCODING(eob) & CTF_INT_SIGNED);
465609e0b1cSclaudio 			val64 <<= 32;
466609e0b1cSclaudio 			val64 |= db_get_value(addr + 4, CTF_INT_BITS(eob) / 8,
467609e0b1cSclaudio 			    0);
468609e0b1cSclaudio #endif
469609e0b1cSclaudio 			if (CTF_INT_ENCODING(eob) & CTF_INT_SIGNED)
470609e0b1cSclaudio 				db_printf("%lld", val64);
471609e0b1cSclaudio 			else
472609e0b1cSclaudio 				db_printf("%llu", val64);
473ab77b743Smpi 			break;
474609e0b1cSclaudio 		}
475609e0b1cSclaudio #endif
476ab77b743Smpi 		default:
477609e0b1cSclaudio 			val = db_get_value(addr, CTF_INT_BITS(eob) / 8,
478609e0b1cSclaudio 			   CTF_INT_ENCODING(eob) & CTF_INT_SIGNED);
479609e0b1cSclaudio 			if (CTF_INT_ENCODING(eob) & CTF_INT_SIGNED)
480609e0b1cSclaudio 				db_printf("%ld", val);
481609e0b1cSclaudio 			else
482609e0b1cSclaudio 				db_printf("%lu", val);
483ab77b743Smpi 			break;
484ab77b743Smpi 		}
485ad205586Smpi 		break;
486ad205586Smpi 	case CTF_K_STRUCT:
487ad205586Smpi 	case CTF_K_UNION:
488ad205586Smpi 		db_ctf_pprint_struct(ctt, addr);
489ad205586Smpi 		break;
490ad205586Smpi 	case CTF_K_POINTER:
491bebdad71Smpi 		db_ctf_pprint_ptr(ctt, addr);
492ad205586Smpi 		break;
493ad205586Smpi 	case CTF_K_TYPEDEF:
494ad205586Smpi 	case CTF_K_VOLATILE:
495ad205586Smpi 	case CTF_K_CONST:
496ad205586Smpi 	case CTF_K_RESTRICT:
497ad205586Smpi 		ref = db_ctf_type_by_index(ctt->ctt_type);
49892b2adbfSuwe 		db_ctf_pprint(ref, addr);
499ad205586Smpi 		break;
500ad205586Smpi 	case CTF_K_UNKNOWN:
501ad205586Smpi 	case CTF_K_FORWARD:
502ad205586Smpi 	default:
503ad205586Smpi 		break;
504ad205586Smpi 	}
505ad205586Smpi }
506ad205586Smpi 
507ad205586Smpi void
508ad205586Smpi db_ctf_pprint_struct(const struct ctf_type *ctt, vaddr_t addr)
509ad205586Smpi {
510ad205586Smpi 	const char		*name, *p = (const char *)ctt;
511ad205586Smpi 	const struct ctf_type	*ref;
512ad205586Smpi 	uint32_t		 toff;
513ad205586Smpi 	uint64_t		 size;
514ad205586Smpi 	uint16_t		 i, vlen;
515ad205586Smpi 
516ad205586Smpi 	vlen = CTF_INFO_VLEN(ctt->ctt_info);
517ad205586Smpi 
518ad205586Smpi 	if (ctt->ctt_size <= CTF_MAX_SIZE) {
519ad205586Smpi 		size = ctt->ctt_size;
520ad205586Smpi 		toff = sizeof(struct ctf_stype);
521ad205586Smpi 	} else {
522ad205586Smpi 		size = CTF_TYPE_LSIZE(ctt);
523ad205586Smpi 		toff = sizeof(struct ctf_type);
524ad205586Smpi 	}
525ad205586Smpi 
526ad205586Smpi 	db_printf("{");
527ad205586Smpi 	if (size < CTF_LSTRUCT_THRESH) {
528ad205586Smpi 		for (i = 0; i < vlen; i++) {
529ad205586Smpi 			struct ctf_member	*ctm;
530ad205586Smpi 
531ad205586Smpi 			ctm = (struct ctf_member *)(p + toff);
532ad205586Smpi 			toff += sizeof(struct ctf_member);
533ad205586Smpi 
534ad205586Smpi 			name = db_ctf_off2name(ctm->ctm_name);
535ad205586Smpi 			if (name != NULL)
536ad205586Smpi 				db_printf("%s = ", name);
537ad205586Smpi 			ref = db_ctf_type_by_index(ctm->ctm_type);
53892b2adbfSuwe 			db_ctf_pprint(ref, addr + ctm->ctm_offset / 8);
539ad205586Smpi 			if (i < vlen - 1)
540ad205586Smpi 				db_printf(", ");
541ad205586Smpi 		}
542ad205586Smpi 	} else {
543ad205586Smpi 		for (i = 0; i < vlen; i++) {
544ad205586Smpi 			struct ctf_lmember	*ctlm;
545ad205586Smpi 
546ad205586Smpi 			ctlm = (struct ctf_lmember *)(p + toff);
547ad205586Smpi 			toff += sizeof(struct ctf_lmember);
548ad205586Smpi 
549ad205586Smpi 			name = db_ctf_off2name(ctlm->ctlm_name);
550ad205586Smpi 			if (name != NULL)
551ad205586Smpi 				db_printf("%s = ", name);
552ad205586Smpi 			ref = db_ctf_type_by_index(ctlm->ctlm_type);
55392b2adbfSuwe 			db_ctf_pprint(ref, addr +
554ad205586Smpi 			    CTF_LMEM_OFFSET(ctlm) / 8);
555ad205586Smpi 			if (i < vlen - 1)
556ad205586Smpi 				db_printf(", ");
557ad205586Smpi 		}
558ad205586Smpi 	}
559ad205586Smpi 	db_printf("}");
560ad205586Smpi }
561ad205586Smpi 
562bebdad71Smpi void
563609e0b1cSclaudio db_ctf_pprint_enum(const struct ctf_type *ctt, vaddr_t addr)
564609e0b1cSclaudio {
565609e0b1cSclaudio 	const char		*name = NULL, *p = (const char *)ctt;
566609e0b1cSclaudio 	struct ctf_enum		*cte;
567609e0b1cSclaudio 	uint32_t		 toff;
568609e0b1cSclaudio 	int32_t			 val;
569609e0b1cSclaudio 	uint16_t		 i, vlen;
570609e0b1cSclaudio 
571609e0b1cSclaudio 	vlen = CTF_INFO_VLEN(ctt->ctt_info);
572609e0b1cSclaudio 	toff = sizeof(struct ctf_stype);
573609e0b1cSclaudio 
574609e0b1cSclaudio 	val = (int32_t)db_get_value(addr, sizeof(val), 1);
575609e0b1cSclaudio 	for (i = 0; i < vlen; i++) {
576609e0b1cSclaudio 		cte = (struct ctf_enum *)(p + toff);
577609e0b1cSclaudio 		toff += sizeof(*cte);
578609e0b1cSclaudio 
579609e0b1cSclaudio 		if (val == cte->cte_value) {
580609e0b1cSclaudio 			name = db_ctf_off2name(cte->cte_name);
581609e0b1cSclaudio 			break;
582609e0b1cSclaudio 		}
583609e0b1cSclaudio 	}
584609e0b1cSclaudio 
585609e0b1cSclaudio 	if (name != NULL)
586609e0b1cSclaudio 		db_printf("%s", name);
587609e0b1cSclaudio 	else
588609e0b1cSclaudio 		db_printf("#%d", val);
589609e0b1cSclaudio }
590609e0b1cSclaudio 
591609e0b1cSclaudio void
592bebdad71Smpi db_ctf_pprint_ptr(const struct ctf_type *ctt, vaddr_t addr)
593bebdad71Smpi {
594bebdad71Smpi 	const char		*name, *modif = "";
595bebdad71Smpi 	const struct ctf_type	*ref;
596bebdad71Smpi 	uint16_t		 kind;
5970488a471Sdlg 	unsigned long		 ptr;
598bebdad71Smpi 
599bebdad71Smpi 	ref = db_ctf_type_by_index(ctt->ctt_type);
600bebdad71Smpi 	kind = CTF_INFO_KIND(ref->ctt_info);
601bebdad71Smpi 
602bebdad71Smpi 	switch (kind) {
603bebdad71Smpi 	case CTF_K_VOLATILE:
604bebdad71Smpi 		modif = "volatile ";
605bebdad71Smpi 		ref = db_ctf_type_by_index(ref->ctt_type);
606bebdad71Smpi 		break;
607bebdad71Smpi 	case CTF_K_CONST:
608bebdad71Smpi 		modif = "const ";
609bebdad71Smpi 		ref = db_ctf_type_by_index(ref->ctt_type);
610bebdad71Smpi 		break;
611bebdad71Smpi 	case CTF_K_STRUCT:
612bebdad71Smpi 		modif = "struct ";
613bebdad71Smpi 		break;
614bebdad71Smpi 	case CTF_K_UNION:
615bebdad71Smpi 		modif = "union ";
616bebdad71Smpi 		break;
617bebdad71Smpi 	default:
618bebdad71Smpi 		break;
619bebdad71Smpi 	}
620bebdad71Smpi 
621bebdad71Smpi 	name = db_ctf_off2name(ref->ctt_name);
622bebdad71Smpi 	if (name != NULL)
623bebdad71Smpi 		db_printf("(%s%s *)", modif, name);
624bebdad71Smpi 
625c0dc0921Sdlg 	ptr = (unsigned long)db_get_value(addr, sizeof(ptr), 0);
6260488a471Sdlg 
6270488a471Sdlg 	db_printf("0x%lx", ptr);
628bebdad71Smpi }
629bebdad71Smpi 
630fd68ecf3Sjasper static const char *
631ad205586Smpi db_ctf_off2name(uint32_t offset)
632fd68ecf3Sjasper {
633fd68ecf3Sjasper 	const char		*name;
634fd68ecf3Sjasper 
635ece49713Sjasper 	if (!db_ctf.ctf_found)
636ece49713Sjasper 		return NULL;
637ece49713Sjasper 
638fd68ecf3Sjasper 	if (CTF_NAME_STID(offset) != CTF_STRTAB_0)
639fd68ecf3Sjasper 		return "external";
640fd68ecf3Sjasper 
641fd68ecf3Sjasper 	if (CTF_NAME_OFFSET(offset) >= db_ctf.cth->cth_strlen)
642fd68ecf3Sjasper 		return "exceeds strlab";
643fd68ecf3Sjasper 
644fd68ecf3Sjasper 	if (db_ctf.cth->cth_stroff + CTF_NAME_OFFSET(offset) >= db_ctf.dlen)
645fd68ecf3Sjasper 		return "invalid";
646fd68ecf3Sjasper 
647fd68ecf3Sjasper 	name = db_ctf.data + db_ctf.cth->cth_stroff + CTF_NAME_OFFSET(offset);
648fd68ecf3Sjasper 	if (*name == '\0')
649ad205586Smpi 		return NULL;
650fd68ecf3Sjasper 
651fd68ecf3Sjasper 	return name;
652fd68ecf3Sjasper }
653fd68ecf3Sjasper 
654fd68ecf3Sjasper static char *
65527fc743bSmillert db_ctf_decompress(const char *buf, size_t size, size_t len)
656fd68ecf3Sjasper {
657fd68ecf3Sjasper 	z_stream		 stream;
658fd68ecf3Sjasper 	char			*data;
659fd68ecf3Sjasper 	int			 error;
660fd68ecf3Sjasper 
661fd68ecf3Sjasper 	data = malloc(len, M_TEMP, M_WAITOK|M_ZERO|M_CANFAIL);
662b42aa555Smpi 	if (data == NULL)
663b42aa555Smpi 		return NULL;
664fd68ecf3Sjasper 
665fd68ecf3Sjasper 	memset(&stream, 0, sizeof(stream));
666fd68ecf3Sjasper 	stream.next_in = (void *)buf;
667fd68ecf3Sjasper 	stream.avail_in = size;
668fd68ecf3Sjasper 	stream.next_out = data;
669fd68ecf3Sjasper 	stream.avail_out = len;
670fd68ecf3Sjasper 
671fd68ecf3Sjasper 	if ((error = inflateInit(&stream)) != Z_OK) {
672fd68ecf3Sjasper 		db_printf("zlib inflateInit failed: %s", zError(error));
673fd68ecf3Sjasper 		goto exit;
674fd68ecf3Sjasper 	}
675fd68ecf3Sjasper 
676fd68ecf3Sjasper 	if ((error = inflate(&stream, Z_FINISH)) != Z_STREAM_END) {
677fd68ecf3Sjasper 		db_printf("zlib inflate failed: %s", zError(error));
678fd68ecf3Sjasper 		inflateEnd(&stream);
679fd68ecf3Sjasper 		goto exit;
680fd68ecf3Sjasper 	}
681fd68ecf3Sjasper 
682fd68ecf3Sjasper 	if ((error = inflateEnd(&stream)) != Z_OK) {
683fd68ecf3Sjasper 		db_printf("zlib inflateEnd failed: %s", zError(error));
684fd68ecf3Sjasper 		goto exit;
685fd68ecf3Sjasper 	}
686fd68ecf3Sjasper 
68727fc743bSmillert 	if (stream.total_out != len) {
68827fc743bSmillert 		db_printf("decompression failed: %lu != %zu",
689fd68ecf3Sjasper 		    stream.total_out, len);
690fd68ecf3Sjasper 		goto exit;
691fd68ecf3Sjasper 	}
692fd68ecf3Sjasper 
693b42aa555Smpi 	return data;
694fd68ecf3Sjasper 
695fd68ecf3Sjasper exit:
69685e04346Sbluhm 	free(data, M_DEVBUF, len);
697b42aa555Smpi 	return NULL;
698fd68ecf3Sjasper }
699ad205586Smpi 
700ad205586Smpi /*
7012b6c37f3Suwe  * pprint <symbol name>
702ad205586Smpi  */
703ad205586Smpi void
70416be3460Smpi db_ctf_pprint_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
705ad205586Smpi {
706ad205586Smpi 	Elf_Sym *st;
707ad205586Smpi 	const struct ctf_type *ctt;
708ad205586Smpi 	int t;
709ad205586Smpi 
7101c302ed1Sjasper 	if (!db_ctf.ctf_found) {
7111c302ed1Sjasper 		db_printf("No CTF data found\n");
7121c302ed1Sjasper 		db_flush_lex();
7130938eda0Sjasper 		return;
7141c302ed1Sjasper 	}
7151c302ed1Sjasper 
716ad205586Smpi 	/*
717ad205586Smpi 	 * Read the struct name from the debugger input.
718ad205586Smpi 	 */
719ad205586Smpi 	t = db_read_token();
720ad205586Smpi 	if (t != tIDENT) {
721ad205586Smpi 		db_printf("Bad symbol name\n");
722ad205586Smpi 		db_flush_lex();
723ad205586Smpi 		return;
724ad205586Smpi 	}
725ad205586Smpi 
726ad205586Smpi 	if ((st = db_symbol_by_name(db_tok_string, &addr)) == NULL) {
727ad205586Smpi 		db_printf("Symbol not found %s\n", db_tok_string);
728ad205586Smpi 		db_flush_lex();
729ad205586Smpi 		return;
730ad205586Smpi 	}
731ad205586Smpi 
732ad205586Smpi 	if ((ctt = db_ctf_type_by_symbol(st)) == NULL) {
73316be3460Smpi 		modif[0] = '\0';
73416be3460Smpi 		db_print_cmd(addr, 0, 0, modif);
735ad205586Smpi 		db_flush_lex();
736ad205586Smpi 		return;
737ad205586Smpi 	}
738ad205586Smpi 
739ad205586Smpi 	db_printf("%s:\t", db_tok_string);
74092b2adbfSuwe 	db_ctf_pprint(ctt, addr);
741ad205586Smpi 	db_printf("\n");
742ad205586Smpi }
743266ad235Sdlg 
744266ad235Sdlg /*
745266ad235Sdlg  * show struct <struct name> [addr]: displays the data starting at addr
746266ad235Sdlg  * (`dot' if unspecified) as a struct of the given type.
747266ad235Sdlg  */
748266ad235Sdlg void
749266ad235Sdlg db_ctf_show_struct(db_expr_t addr, int have_addr, db_expr_t count,
750266ad235Sdlg     char *modifiers)
751266ad235Sdlg {
752266ad235Sdlg 	const struct ctf_type *ctt;
753266ad235Sdlg 	const char *name;
754266ad235Sdlg 	uint64_t sz;
755266ad235Sdlg 	int t;
756266ad235Sdlg 
757266ad235Sdlg 	/*
758266ad235Sdlg 	 * Read the struct name from the debugger input.
759266ad235Sdlg 	 */
760266ad235Sdlg 	t = db_read_token();
761266ad235Sdlg 	if (t != tIDENT) {
762266ad235Sdlg 		db_printf("Bad struct name\n");
763266ad235Sdlg 		db_flush_lex();
764266ad235Sdlg 		return;
765266ad235Sdlg 	}
766266ad235Sdlg 	name = db_tok_string;
767266ad235Sdlg 
768266ad235Sdlg 	ctt = db_ctf_type_by_name(name, CTF_K_STRUCT);
769266ad235Sdlg 	if (ctt == NULL) {
770266ad235Sdlg 		db_printf("unknown struct %s\n", name);
771266ad235Sdlg 		db_flush_lex();
772266ad235Sdlg 		return;
773266ad235Sdlg 	}
774266ad235Sdlg 
775266ad235Sdlg 	/*
776266ad235Sdlg 	 * Read the address, if any, from the debugger input.
777266ad235Sdlg 	 * In that case, update `dot' value.
778266ad235Sdlg 	 */
779266ad235Sdlg 	if (db_expression(&addr)) {
78008f058f8Smpi 		db_dot = (vaddr_t)addr;
781266ad235Sdlg 		db_last_addr = db_dot;
782266ad235Sdlg 	} else
783266ad235Sdlg 		addr = (db_expr_t)db_dot;
784266ad235Sdlg 
785266ad235Sdlg 	db_skip_to_eol();
786266ad235Sdlg 
787266ad235Sdlg 	/*
788266ad235Sdlg 	 * Display the structure contents.
789266ad235Sdlg 	 */
790266ad235Sdlg 	sz = (ctt->ctt_size <= CTF_MAX_SIZE) ?
791266ad235Sdlg 	    ctt->ctt_size : CTF_TYPE_LSIZE(ctt);
792266ad235Sdlg 	db_printf("struct %s at %p (%llu bytes) ", name, (void *)addr, sz);
793266ad235Sdlg 	db_ctf_pprint_struct(ctt, addr);
794266ad235Sdlg }
795