From nobody Fri Mar 22 15:17:28 2024 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4V1Qty60Hwz5F8W4; Fri, 22 Mar 2024 15:18:02 +0000 (UTC) (envelope-from freebsd@walstatt-de.de) Received: from smtp052.goneo.de (smtp5.goneo.de [IPv6:2001:1640:5::8:30]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 4V1Qty2nv6z4Nhf; Fri, 22 Mar 2024 15:18:02 +0000 (UTC) (envelope-from freebsd@walstatt-de.de) Authentication-Results: mx1.freebsd.org; none Received: from hub1.goneo.de (hub1.goneo.de [IPv6:2001:1640:5::8:52]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by smtp5.goneo.de (Postfix) with ESMTPS id D1EA6240446; Fri, 22 Mar 2024 16:17:58 +0100 (CET) Received: from hub1.goneo.de (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by hub1.goneo.de (Postfix) with ESMTPS id 07A49240591; Fri, 22 Mar 2024 16:17:57 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=walstatt-de.de; s=DKIM001; t=1711120677; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=wtKibkxwELUjN6XNXKiKybfles/dnisfawT73bckqVM=; b=IrlnDbsFnjq7bIFtFF0nmOpWu6eTZFzm8zHzSv5lRl8cVB8Z/Ndw7diC7BjMfvLFVpSRQ9 TD6UHUYYt59TWeLBcPaewG/LeQGPGQUa6YxgUU4z362TCJaNfRrlWCobv0V/xjA3s4AiyS EhJnvoaDbtUovEAdON96LCepEdaCJfeYg+DJ1e5kN/KpjydXCu0zRbscRw1ndLD8pQVOfz ZZmSHj1M2HwR00VHvclQQ89omHDqk56BVg3C05oMKap6nJGH+zRsAOaZXwTwgSG7BaM+S7 rWlHNKIVvD+h9AfHK645cymGk65Yu5Fg7HLTHjZcFws1NjbqMEJIYlpHYlDEPQ== Received: from thor.intern.walstatt.dynvpn.de (dynamic-089-014-073-145.89.14.pool.telefonica.de [89.14.73.145]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (prime256v1) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by hub1.goneo.de (Postfix) with ESMTPSA id 9E0742404DE; Fri, 22 Mar 2024 16:17:56 +0100 (CET) Date: Fri, 22 Mar 2024 16:17:28 +0100 From: FreeBSD User To: Bojan =?UTF-8?B?Tm92a292acSH?= Cc: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: Re: git: c21bc6f3c242 - main - ddb: Add CTF-based pretty printing Message-ID: <20240322161755.56389691@thor.intern.walstatt.dynvpn.de> In-Reply-To: <202403220356.42M3uJh3021416@gitrepo.freebsd.org> References: <202403220356.42M3uJh3021416@gitrepo.freebsd.org> Organization: walstatt-de.de List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-main@freebsd.org X-BeenThere: dev-commits-src-main@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable X-Rspamd-UID: 58b5b5 X-Rspamd-UID: 48fde3 X-Spamd-Bar: ---- X-Rspamd-Pre-Result: action=no action; module=replies; Message is reply to one we originated X-Spamd-Result: default: False [-4.00 / 15.00]; REPLY(-4.00)[]; ASN(0.00)[asn:25394, ipnet:2001:1640::/32, country:DE] X-Rspamd-Queue-Id: 4V1Qty2nv6z4Nhf Am Fri, 22 Mar 2024 03:56:19 GMT Bojan Novkovi=C4=87 schrieb: This commit breaks buildkernel of GENERIC and custom configs, when either options KDB or options DDB or both are commented out: [...] --- kernel --- linking kernel ld: error: undefined symbol: db_ctf_lookup_typename >>> referenced by link_elf_obj.c >>> link_elf_obj.o:(link_elf_ctf_lookup_typename) >>> referenced by link_elf.c >>> link_elf.o:(link_elf_ctf_lookup_typename) *** [kernel] Error code 1 make[2]: stopped in /usr/obj/usr/src/amd64.amd64/sys/THOR make[2]: 1 error make[2]: stopped in /usr/obj/usr/src/amd64.amd64/sys/THOR 605.46 real 2122.47 user 197.81 sys make[1]: stopped in /usr/src make: stopped in /usr/src > The branch main has been updated by bnovkov: >=20 > URL: https://cgit.FreeBSD.org/src/commit/?id=3Dc21bc6f3c2425de74141bfee07= b609bf65b5a6b3 >=20 > commit c21bc6f3c2425de74141bfee07b609bf65b5a6b3 > Author: Bojan Novkovi=C4=87 > AuthorDate: 2024-03-22 03:01:34 +0000 > Commit: Bojan Novkovi=C4=87 > CommitDate: 2024-03-22 03:03:33 +0000 >=20 > ddb: Add CTF-based pretty printing > =20 > Add basic CTF support and a CTF-powered pretty-printer to ddb. > =20 > The db_ctf.* files expose a basic interface for fetching type > data for ELF symbols, interacting with the CTF string table, > and translating type identifiers to type data. > =20 > The db_pprint.c file uses those interfaces to implement > a pretty-printer for all kernel ELF symbols. > The pretty-printer works with symbol names and arbitrary addresses: > pprint struct thread 0xffffffff8194ad90 > =20 > Pretty-printing currently only works after the root filesystem > gets mounted because the CTF info is not available during > early boot. > =20 > Differential Revision: https://reviews.freebsd.org/D37899 > Approved by: markj (mentor) > --- > share/man/man4/ddb.4 | 26 +++ > sys/conf/files | 2 + > sys/ddb/db_command.c | 1 + > sys/ddb/db_ctf.c | 326 +++++++++++++++++++++++++++++++++++ > sys/ddb/db_ctf.h | 64 +++++++ > sys/ddb/db_pprint.c | 450 ++++++++++++++++++++++++++++++++++++++++++= ++++++ > sys/ddb/ddb.h | 1 + > sys/kern/kern_ctf.c | 40 +++++ > sys/kern/kern_linker.c | 68 +++++++- > sys/kern/link_elf.c | 37 ++++ > sys/kern/link_elf_obj.c | 14 ++ > sys/kern/linker_if.m | 23 +++ > sys/sys/linker.h | 3 + > 13 files changed, 1054 insertions(+), 1 deletion(-) >=20 > diff --git a/share/man/man4/ddb.4 b/share/man/man4/ddb.4 > index 3648c9ca58cb..f3443cbac127 100644 > --- a/share/man/man4/ddb.4 > +++ b/share/man/man4/ddb.4 > @@ -289,6 +289,32 @@ eax =3D xxxxxx > ecx =3D yyyyyy > .Ed > .Pp > +.It Ic pprint Ns Oo Li / Ns Cm d depth Oc Oo Ar name Oc > +Pretty-print symbol specified by > +.Ar name > +using CTF debugging data. Works for all symbols exported by the kernel a= nd loaded kernel > modules. +.Pp > +If the > +.Cm d > +modifier has been specified, contents of structs nested up to > +.Ar depth > +levels deep will also be included in the output. > +.Ed > +.Pp > +.It Ic pprint struct Ns Oo Li / Ns Cm d depth Ic Oc Oo Ar name Oc Ns Op = Ns Ar addr > +Print memory at > +.Ar addr > +as struct > +.Ar name Ns . > +Works for all structs defined by the kernel and loaded kernel modules. > +.Pp > +If the > +.Cm d > +modifier has been specified, contents of structs nested up to > +.Ar depth > +levels deep will also be included in the output. > +.Ed > +.Pp > .It Xo > .Ic write Ns Op Li / Ns Cm bhl > .Ar addr expr1 Op Ar expr2 ... > diff --git a/sys/conf/files b/sys/conf/files > index c902bcfdbd52..021829408c0f 100644 > --- a/sys/conf/files > +++ b/sys/conf/files > @@ -718,12 +718,14 @@ ddb/db_access.c optional ddb > ddb/db_break.c optional ddb > ddb/db_capture.c optional ddb > ddb/db_command.c optional ddb > +ddb/db_ctf.c optional ddb > ddb/db_examine.c optional ddb > ddb/db_expr.c optional ddb > ddb/db_input.c optional ddb > ddb/db_lex.c optional ddb > ddb/db_main.c optional ddb > ddb/db_output.c optional ddb > +ddb/db_pprint.c optional ddb > ddb/db_print.c optional ddb > ddb/db_ps.c optional ddb > ddb/db_run.c optional ddb > diff --git a/sys/ddb/db_command.c b/sys/ddb/db_command.c > index 9d79e3b2a6d3..0c88d496f6b8 100644 > --- a/sys/ddb/db_command.c > +++ b/sys/ddb/db_command.c > @@ -163,6 +163,7 @@ static struct db_command db_cmds[] =3D { > DB_CMD("capture", db_capture_cmd, CS_OWN|DB_CMD_MEMSAFE), > DB_CMD("textdump", db_textdump_cmd, CS_OWN|DB_CMD_MEMSAFE), > DB_CMD("findstack", db_findstack_cmd, 0), > + DB_CMD("pprint", db_pprint_cmd, CS_OWN), > }; > struct db_command_table db_cmd_table =3D LIST_HEAD_INITIALIZER(db_cmd_ta= ble); > =20 > diff --git a/sys/ddb/db_ctf.c b/sys/ddb/db_ctf.c > new file mode 100644 > index 000000000000..03145064885c > --- /dev/null > +++ b/sys/ddb/db_ctf.c > @@ -0,0 +1,326 @@ > +/*- > + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD > + * > + * Copyright (c) 2023 Bojan Novkovi=C4=87 > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * 2. Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in the > + * documentation and/or other materials provided with the distributio= n. > + * > + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND > + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PU= RPOSE > + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIAB= LE > + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUE= NTIAL > + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOO= DS > + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) > + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, S= TRICT > + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY= WAY > + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF > + * SUCH DAMAGE. > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > + > +static const ctf_header_t * > +db_ctf_fetch_cth(linker_ctf_t *lc) > +{ > + return (const ctf_header_t *)lc->ctftab; > +} > + > +/* > + * Tries to look up the ELF symbol -> CTF type identifier mapping by sca= nning > + * the CTF object section. > + */ > +static uint32_t > +sym_to_objtoff(linker_ctf_t *lc, const Elf_Sym *sym, const Elf_Sym *symt= ab, > + const Elf_Sym *symtab_end) > +{ > + const ctf_header_t *hp =3D db_ctf_fetch_cth(lc); > + uint32_t objtoff =3D hp->cth_objtoff; > + const size_t idwidth =3D 4; > + > + /* Ignore non-object symbols */ > + if (ELF_ST_TYPE(sym->st_info) !=3D STT_OBJECT) { > + return (DB_CTF_INVALID_OFF); > + } > + /* Sanity check */ > + if (!(sym >=3D symtab && sym <=3D symtab_end)) { > + return (DB_CTF_INVALID_OFF); > + } > + > + for (const Elf_Sym *symp =3D symtab; symp < symtab_end; symp++) { > + /* Make sure we do not go beyond the objtoff section */ > + if (objtoff >=3D hp->cth_funcoff) { > + objtoff =3D DB_CTF_INVALID_OFF; > + break; > + } > + if (symp->st_name =3D=3D 0 || symp->st_shndx =3D=3D SHN_UNDEF) { > + continue; > + } > + if (symp->st_shndx =3D=3D SHN_ABS && symp->st_value =3D=3D 0) { > + continue; > + } > + > + /* Skip non-object symbols */ > + if (ELF_ST_TYPE(symp->st_info) !=3D STT_OBJECT) { > + continue; > + } > + if (symp =3D=3D sym) { > + break; > + } > + objtoff +=3D idwidth; > + } > + > + return (objtoff); > +} > + > +/* > + * Returns the size of CTF type 't'. > + */ > +static u_int > +db_ctf_type_size(struct ctf_type_v3 *t) > +{ > + u_int vlen, kind, ssize; > + u_int type_struct_size, kind_size; > + > + vlen =3D CTF_V3_INFO_VLEN(t->ctt_info); > + kind =3D CTF_V3_INFO_KIND(t->ctt_info); > + ssize =3D ((t->ctt_size =3D=3D CTF_V3_LSIZE_SENT) ? CTF_TYPE_LSIZE(t) : > + t->ctt_size); > + type_struct_size =3D ((t->ctt_size =3D=3D CTF_V3_LSIZE_SENT) ? > + sizeof(struct ctf_type_v3) : > + sizeof(struct ctf_stype_v3)); > + > + switch (kind) { > + case CTF_K_INTEGER: > + case CTF_K_FLOAT: > + kind_size =3D sizeof(uint32_t); > + break; > + case CTF_K_ARRAY: > + kind_size =3D sizeof(struct ctf_array_v3); > + break; > + case CTF_K_UNION: > + case CTF_K_STRUCT: > + kind_size =3D vlen * > + ((ssize < CTF_V3_LSTRUCT_THRESH) ? > + sizeof(struct ctf_member_v3) : > + sizeof(struct ctf_lmember_v3)); > + break; > + case CTF_K_ENUM: > + kind_size =3D vlen * sizeof(struct ctf_enum); > + break; > + case CTF_K_FUNCTION: > + kind_size =3D vlen * sizeof(uint32_t); > + break; > + case CTF_K_UNKNOWN: > + case CTF_K_FORWARD: > + case CTF_K_POINTER: > + case CTF_K_TYPEDEF: > + case CTF_K_VOLATILE: > + case CTF_K_CONST: > + case CTF_K_RESTRICT: > + kind_size =3D 0; > + break; > + default: > + db_printf("Error: invalid CTF type kind encountered\n"); > + return (-1); > + } > + > + return (type_struct_size + kind_size); > +} > + > +/* > + * Looks up type name 'name' in the CTF string table and returns the > + * corresponding CTF type struct, if any. > + */ > +struct ctf_type_v3 * > +db_ctf_typename_to_type(linker_ctf_t *lc, const char *name) > +{ > + const ctf_header_t *hp =3D db_ctf_fetch_cth(lc); > + char *start, *cur, *end; > + uint32_t stroff =3D hp->cth_stroff; > + uint32_t typeoff =3D hp->cth_typeoff; > + uint32_t name_stroff; > + const uint8_t *ctfstart =3D (const uint8_t *)hp + sizeof(ctf_header_t); > + > + u_int skiplen; > + > + /* Scan ctf strtab for typename. */ > + start =3D cur =3D __DECONST(char *, hp) + sizeof(ctf_header_t) + > + hp->cth_stroff; > + end =3D cur + hp->cth_strlen; > + while (cur < end) { > + if (strcmp(cur, name) =3D=3D 0) > + break; > + cur +=3D strlen(cur) + 1; > + } > + if (cur >=3D end) > + return (NULL); > + name_stroff =3D (uint32_t)(cur - start); > + > + /* Scan for type containing the found stroff. */ > + while (typeoff < stroff) { > + struct ctf_type_v3 *t =3D > + (struct ctf_type_v3 *)(__DECONST(uint8_t *, ctfstart) + > + typeoff); > + /* We found the type struct */ > + if (t->ctt_name =3D=3D name_stroff) { > + break; > + } > + if ((skiplen =3D db_ctf_type_size(t)) =3D=3D -1) { > + return (NULL); > + } > + typeoff +=3D skiplen; > + } > + if (typeoff < stroff) { > + return (struct ctf_type_v3 *)(__DECONST(uint8_t *, ctfstart) + > + typeoff); > + } else { /* A type struct was not found */ > + return (NULL); > + } > +} > + > +/* > + * Wrapper used by the kernel linker CTF routines. > + * Currently used to implement lookup of CTF types accross all loaded ke= rnel > + * modules. > + */ > +bool > +db_ctf_lookup_typename(linker_ctf_t *lc, const char *typename) > +{ > + return (db_ctf_typename_to_type(lc, typename) !=3D NULL); > +} > + > +/* > + * Returns the type corresponding to the 'typeid' parameter from the CTF= type > + * section. > + */ > +struct ctf_type_v3 * > +db_ctf_typeid_to_type(db_ctf_sym_data_t sd, uint32_t typeid) > +{ > + const ctf_header_t *hp =3D db_ctf_fetch_cth(&sd->lc); > + const uint8_t *ctfstart =3D (const uint8_t *)hp + sizeof(ctf_header_t); > + uint32_t typeoff =3D hp->cth_typeoff; > + uint32_t stroff =3D hp->cth_stroff; > + /* CTF typeids start at 0x1 */ > + size_t cur_typeid =3D 1; > + u_int skiplen; > + > + /* Find corresponding type */ > + while (typeoff < stroff) { > + struct ctf_type_v3 *t =3D > + (struct ctf_type_v3 *)(__DECONST(uint8_t *, ctfstart) + > + typeoff); > + > + /* We found the type struct */ > + if (cur_typeid =3D=3D typeid) { > + break; > + } > + cur_typeid++; > + if ((skiplen =3D db_ctf_type_size(t)) =3D=3D -1) { > + return (NULL); > + } > + typeoff +=3D skiplen; > + } > + if (typeoff < stroff) { > + return (struct ctf_type_v3 *)(__DECONST(uint8_t *, ctfstart) + > + typeoff); > + } else { /* A type struct was not found */ > + return (NULL); > + } > +} > + > +const char * > +db_ctf_stroff_to_str(db_ctf_sym_data_t sd, uint32_t off) > +{ > + const ctf_header_t *hp =3D db_ctf_fetch_cth(&sd->lc); > + uint32_t stroff =3D hp->cth_stroff + off; > + const char *ret; > + > + if (stroff >=3D (hp->cth_stroff + hp->cth_strlen)) { > + return ("invalid"); > + } > + ret =3D ((const char *)hp + sizeof(ctf_header_t)) + stroff; > + if (*ret =3D=3D '\0') { > + return (NULL); > + } > + > + return (ret); > +} > + > +/* > + * Tries to find the type of the symbol specified in 'sd->sym'. > + */ > +struct ctf_type_v3 * > +db_ctf_sym_to_type(db_ctf_sym_data_t sd) > +{ > + uint32_t objtoff, typeid; > + const Elf_Sym *symtab, *symtab_end; > + > + if (sd->sym =3D=3D NULL) { > + return (NULL); > + } > + symtab =3D sd->lc.symtab; > + symtab_end =3D symtab + sd->lc.nsym; > + > + objtoff =3D sym_to_objtoff(&sd->lc, sd->sym, symtab, symtab_end); > + /* Sanity check - should not happen */ > + if (objtoff =3D=3D DB_CTF_INVALID_OFF) { > + db_printf("Could not find CTF object offset.\n"); > + return (NULL); > + } > + > + typeid =3D *( > + const uint32_t *)(sd->lc.ctftab + sizeof(ctf_header_t) + objtoff); > + > + return (db_ctf_typeid_to_type(sd, typeid)); > +} > + > +/* > + * Scans the kernel file and all loaded module for symbol 'name'. > + */ > +int > +db_ctf_find_symbol(const char *name, db_ctf_sym_data_t sd) > +{ > + int error; > + c_linker_sym_t lsym =3D NULL; > + > + error =3D linker_ctf_lookup_sym_ddb(name, &lsym, &sd->lc); > + if (error !=3D 0) { > + db_printf( > + "failed to look up symbol and CTF info for %s: error %d\n", > + name, error); > + return (error); > + } > + sd->sym =3D __DECONST(Elf_Sym *, lsym); > + > + return (0); > +} > + > +/* > + * Scans the kernel file and all loaded module for type specified by 'ty= pename'. > + */ > +struct ctf_type_v3 * > +db_ctf_find_typename(db_ctf_sym_data_t sd, const char *typename) > +{ > + if (linker_ctf_lookup_typename_ddb(&sd->lc, typename) !=3D 0) { > + return (NULL); > + } > + return (db_ctf_typename_to_type(&sd->lc, typename)); > +} > diff --git a/sys/ddb/db_ctf.h b/sys/ddb/db_ctf.h > new file mode 100644 > index 000000000000..6da5f76b6cf6 > --- /dev/null > +++ b/sys/ddb/db_ctf.h > @@ -0,0 +1,64 @@ > +/*- > + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD > + * > + * Copyright (c) 2023 Bojan Novkovi=C4=87 > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * 2. Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in the > + * documentation and/or other materials provided with the distributio= n. > + * > + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND > + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PU= RPOSE > + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIAB= LE > + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUE= NTIAL > + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOO= DS > + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) > + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, S= TRICT > + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY= WAY > + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF > + * SUCH DAMAGE. > + */ > + > +#ifndef _DDB_DB_CTF_H_ > +#define _DDB_DB_CTF_H_ > + > +#include > +#include > +#include > + > +#include > +#include > + > +#define DB_CTF_INVALID_OFF 0xffffffff > + > +struct db_ctf_sym_data { > + linker_ctf_t lc; > + Elf_Sym *sym; > +}; > + > +typedef struct db_ctf_sym_data *db_ctf_sym_data_t; > + > +/* > + * Routines for finding symbols and CTF info accross all loaded linker f= iles. > + */ > +int db_ctf_find_symbol(const char *name, db_ctf_sym_data_t sd); > +struct ctf_type_v3 *db_ctf_find_typename(db_ctf_sym_data_t sd, > + const char *typename); > +bool db_ctf_lookup_typename(linker_ctf_t *lc, const char *typename); > + > +/* > + * Routines for working with CTF data. > + */ > +struct ctf_type_v3 *db_ctf_sym_to_type(db_ctf_sym_data_t sd); > +const char *db_ctf_stroff_to_str(db_ctf_sym_data_t sd, uint32_t off); > +struct ctf_type_v3 *db_ctf_typename_to_type(linker_ctf_t *lc, const char= *name); > +struct ctf_type_v3 *db_ctf_typeid_to_type(db_ctf_sym_data_t sd, > + uint32_t typeid); > + > +#endif /* !_DDB_DB_CTF_H_ */ > diff --git a/sys/ddb/db_pprint.c b/sys/ddb/db_pprint.c > new file mode 100644 > index 000000000000..dc7582864957 > --- /dev/null > +++ b/sys/ddb/db_pprint.c > @@ -0,0 +1,450 @@ > +/*- > + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD > + * > + * Copyright (c) 2022 Bojan Novkovi=C4=87 > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * 2. Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in the > + * documentation and/or other materials provided with the distributio= n. > + * > + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND > + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PU= RPOSE > + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIAB= LE > + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUE= NTIAL > + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOO= DS > + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) > + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, S= TRICT > + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY= WAY > + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF > + * SUCH DAMAGE. > + */ > + > +#include > +#include > +#include > +#include > + > +#include > + > +#include > +#include > +#include > +#include > +#include > + > +#define DB_PPRINT_DEFAULT_DEPTH 1 > + > +static void db_pprint_type(db_addr_t addr, struct ctf_type_v3 *type, > + u_int depth); > + > +static u_int max_depth =3D DB_PPRINT_DEFAULT_DEPTH; > +static struct db_ctf_sym_data sym_data; > + > +/* > + * Pretty-prints a CTF_INT type. > + */ > +static inline void > +db_pprint_int(db_addr_t addr, struct ctf_type_v3 *type, u_int depth) > +{ > + uint32_t data; > + size_t type_struct_size; > + > + type_struct_size =3D (type->ctt_size =3D=3D CTF_V3_LSIZE_SENT) ? > + sizeof(struct ctf_type_v3) : > + sizeof(struct ctf_stype_v3); > + > + data =3D db_get_value((db_expr_t)type + type_struct_size, > + sizeof(uint32_t), 0); > + u_int bits =3D CTF_INT_BITS(data); > + boolean_t sign =3D !!(CTF_INT_ENCODING(data) & CTF_INT_SIGNED); > + > + if (db_pager_quit) { > + return; > + } > + if (bits > 64) { > + db_printf("Invalid size '%d' found for integer type\n", bits); > + return; > + } > + db_printf("0x%lx", > + db_get_value(addr, (bits / 8) ? (bits / 8) : 1, sign)); > +} > + > +/* > + * Pretty-prints a struct. Nested structs are pretty-printed up 'depth' = nested > + * levels. > + */ > +static inline void > +db_pprint_struct(db_addr_t addr, struct ctf_type_v3 *type, u_int depth) > +{ > + size_t type_struct_size; > + size_t struct_size; > + struct ctf_type_v3 *mtype; > + const char *mname; > + db_addr_t maddr; > + u_int vlen; > + > + type_struct_size =3D (type->ctt_size =3D=3D CTF_V3_LSIZE_SENT) ? > + sizeof(struct ctf_type_v3) : > + sizeof(struct ctf_stype_v3); > + struct_size =3D ((type->ctt_size =3D=3D CTF_V3_LSIZE_SENT) ? > + CTF_TYPE_LSIZE(type) : > + type->ctt_size); > + vlen =3D CTF_V3_INFO_VLEN(type->ctt_info); > + > + if (db_pager_quit) { > + return; > + } > + if (depth > max_depth) { > + db_printf("{ ... }"); > + return; > + } > + db_printf("{\n"); > + > + if (struct_size < CTF_V3_LSTRUCT_THRESH) { > + struct ctf_member_v3 *mp, *endp; > + > + mp =3D (struct ctf_member_v3 *)((db_addr_t)type + > + type_struct_size); > + endp =3D mp + vlen; > + for (; mp < endp; mp++) { > + if (db_pager_quit) { > + return; > + } > + mtype =3D db_ctf_typeid_to_type(&sym_data, mp->ctm_type); > + maddr =3D addr + mp->ctm_offset; > + mname =3D db_ctf_stroff_to_str(&sym_data, mp->ctm_name); > + db_indent =3D depth; > + if (mname !=3D NULL) { > + db_iprintf("%s =3D ", mname); > + } else { > + db_iprintf(""); > + } > + > + db_pprint_type(maddr, mtype, depth + 1); > + db_printf(",\n"); > + } > + } else { > + struct ctf_lmember_v3 *mp, *endp; > + > + mp =3D (struct ctf_lmember_v3 *)((db_addr_t)type + > + type_struct_size); > + endp =3D mp + vlen; > + for (; mp < endp; mp++) { > + if (db_pager_quit) { > + return; > + } > + mtype =3D db_ctf_typeid_to_type(&sym_data, mp->ctlm_type); > + maddr =3D addr + CTF_LMEM_OFFSET(mp); > + mname =3D db_ctf_stroff_to_str(&sym_data, mp->ctlm_name); > + db_indent =3D depth; > + if (mname !=3D NULL) { > + db_iprintf("%s =3D ", mname); > + } else { > + db_iprintf(""); > + } > + > + db_pprint_type(maddr, mtype, depth + 1); > + db_printf(","); > + } > + } > + db_indent =3D depth - 1; > + db_iprintf("}"); > +} > + > +/* > + * Pretty-prints an array. Each array member is printed out in a separat= e line > + * indented with 'depth' spaces. > + */ > +static inline void > +db_pprint_arr(db_addr_t addr, struct ctf_type_v3 *type, u_int depth) > +{ > + struct ctf_type_v3 *elem_type; > + struct ctf_array_v3 *arr; > + db_addr_t elem_addr, end; > + size_t type_struct_size; > + size_t elem_size; > + > + type_struct_size =3D (type->ctt_size =3D=3D CTF_V3_LSIZE_SENT) ? > + sizeof(struct ctf_type_v3) : > + sizeof(struct ctf_stype_v3); > + arr =3D (struct ctf_array_v3 *)((db_addr_t)type + type_struct_size); > + elem_type =3D db_ctf_typeid_to_type(&sym_data, arr->cta_contents); > + elem_size =3D ((elem_type->ctt_size =3D=3D CTF_V3_LSIZE_SENT) ? > + CTF_TYPE_LSIZE(elem_type) : > + elem_type->ctt_size); > + elem_addr =3D addr; > + end =3D addr + (arr->cta_nelems * elem_size); > + > + db_indent =3D depth; > + db_printf("[\n"); > + /* Loop through and print individual elements. */ > + for (; elem_addr < end; elem_addr +=3D elem_size) { > + if (db_pager_quit) { > + return; > + } > + db_iprintf(""); > + db_pprint_type(elem_addr, elem_type, depth); > + if ((elem_addr + elem_size) < end) { > + db_printf(",\n"); > + } > + } > + db_printf("\n"); > + db_indent =3D depth - 1; > + db_iprintf("]"); > +} > + > +/* > + * Pretty-prints an enum value. Also prints out symbolic name of value, = if any. > + */ > +static inline void > +db_pprint_enum(db_addr_t addr, struct ctf_type_v3 *type, u_int depth) > +{ > + struct ctf_enum *ep, *endp; > + size_t type_struct_size; > + const char *valname; > + db_expr_t val; > + u_int vlen; > + > + type_struct_size =3D (type->ctt_size =3D=3D CTF_V3_LSIZE_SENT) ? > + sizeof(struct ctf_type_v3) : > + sizeof(struct ctf_stype_v3); > + vlen =3D CTF_V3_INFO_VLEN(type->ctt_info); > + val =3D db_get_value(addr, sizeof(int), 0); > + > + if (db_pager_quit) { > + return; > + } > + ep =3D (struct ctf_enum *)((db_addr_t)type + type_struct_size); > + endp =3D ep + vlen; > + for (; ep < endp; ep++) { > + if (val =3D=3D ep->cte_value) { > + valname =3D db_ctf_stroff_to_str(&sym_data, ep->cte_name); > + if (valname !=3D NULL) > + db_printf("%s (0x%lx)", valname, val); > + else > + db_printf("(0x%lx)", val); > + break; > + } > + } > +} > + > +/* > + * Pretty-prints a pointer. If the 'depth' parameter is less than the > + * 'max_depth' global var, the pointer is "dereference", i.e. the conten= ts of > + * the memory it points to are also printed. The value of the pointer is= printed > + * otherwise. > + */ > +static inline void > +db_pprint_ptr(db_addr_t addr, struct ctf_type_v3 *type, u_int depth) > +{ > + struct ctf_type_v3 *ref_type; > + const char *qual =3D ""; > + const char *name; > + db_addr_t val; > + u_int kind; > + > + ref_type =3D db_ctf_typeid_to_type(&sym_data, type->ctt_type); > + kind =3D CTF_V3_INFO_KIND(ref_type->ctt_info); > + switch (kind) { > + case CTF_K_STRUCT: > + qual =3D "struct "; > + break; > + case CTF_K_VOLATILE: > + qual =3D "volatile "; > + break; > + case CTF_K_CONST: > + qual =3D "const "; > + break; > + default: > + break; > + } > + > + val =3D db_get_value(addr, sizeof(db_addr_t), false); > + if (depth < max_depth) { > + /* Print contents of memory pointed to by this pointer. */ > + db_pprint_type(addr, ref_type, depth + 1); > + } else { > + name =3D db_ctf_stroff_to_str(&sym_data, ref_type->ctt_name); > + db_indent =3D depth; > + if (name !=3D NULL) > + db_printf("(%s%s *) 0x%lx", qual, name, val); > + else > + db_printf("0x%lx", val); > + } > +} > + > +/* > + * Pretty-print dispatching function. > + */ > +static void > +db_pprint_type(db_addr_t addr, struct ctf_type_v3 *type, u_int depth) > +{ > + > + if (db_pager_quit) { > + return; > + } > + if (type =3D=3D NULL) { > + db_printf("unknown type"); > + return; > + } > + > + switch (CTF_V3_INFO_KIND(type->ctt_info)) { > + case CTF_K_INTEGER: > + db_pprint_int(addr, type, depth); > + break; > + case CTF_K_UNION: > + case CTF_K_STRUCT: > + db_pprint_struct(addr, type, depth); > + break; > + case CTF_K_FUNCTION: > + case CTF_K_FLOAT: > + db_indent =3D depth; > + db_iprintf("0x%lx", addr); > + break; > + case CTF_K_POINTER: > + db_pprint_ptr(addr, type, depth); > + break; > + case CTF_K_TYPEDEF: > + case CTF_K_VOLATILE: > + case CTF_K_RESTRICT: > + case CTF_K_CONST: { > + struct ctf_type_v3 *ref_type =3D db_ctf_typeid_to_type(&sym_data, > + type->ctt_type); > + db_pprint_type(addr, ref_type, depth); > + break; > + } > + case CTF_K_ENUM: > + db_pprint_enum(addr, type, depth); > + break; > + case CTF_K_ARRAY: > + db_pprint_arr(addr, type, depth); > + break; > + case CTF_K_UNKNOWN: > + case CTF_K_FORWARD: > + default: > + break; > + } > +} > + > +/* > + * Symbol pretty-printing command. > + * Syntax: pprint [/d depth] > + */ > +static void > +db_pprint_symbol_cmd(const char *name) > +{ > + db_addr_t addr; > + int db_indent_old; > + const char *type_name =3D NULL; > + struct ctf_type_v3 *type =3D NULL; > + > + if (db_pager_quit) { > + return; > + } > + /* Clear symbol and CTF info */ > + memset(&sym_data, 0, sizeof(struct db_ctf_sym_data)); > + if (db_ctf_find_symbol(name, &sym_data) !=3D 0) { > + db_error("Symbol not found\n"); > + } > + if (ELF_ST_TYPE(sym_data.sym->st_info) !=3D STT_OBJECT) { > + db_error("Symbol is not a variable\n"); > + } > + addr =3D sym_data.sym->st_value; > + type =3D db_ctf_sym_to_type(&sym_data); > + if (type =3D=3D NULL) { > + db_error("Can't find CTF type info\n"); > + } > + type_name =3D db_ctf_stroff_to_str(&sym_data, type->ctt_name); > + if (type_name !=3D NULL) > + db_printf("%s ", type_name); > + db_printf("%s =3D ", name); > + > + db_indent_old =3D db_indent; > + db_pprint_type(addr, type, 0); > + db_indent =3D db_indent_old; > +} > + > +/* > + * Command for pretty-printing arbitrary addresses. > + * Syntax: pprint [/d depth] struct > + */ > +static void > +db_pprint_struct_cmd(db_expr_t addr, const char *struct_name) > +{ > + int db_indent_old; > + struct ctf_type_v3 *type =3D NULL; > + > + type =3D db_ctf_find_typename(&sym_data, struct_name); > + if (type =3D=3D NULL) { > + db_error("Can't find CTF type info\n"); > + return; > + } > + > + db_printf("struct %s ", struct_name); > + db_printf("%p =3D ", (void *)addr); > + > + db_indent_old =3D db_indent; > + db_pprint_type(addr, type, 0); > + db_indent =3D db_indent_old; > +} > + > +/* > + * Pretty print an address or a symbol. > + */ > +void > +db_pprint_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *mod= if) > +{ > + int t =3D 0; > + const char *name; > + > + /* Set default depth */ > + max_depth =3D DB_PPRINT_DEFAULT_DEPTH; > + /* Parse print modifiers */ > + t =3D db_read_token(); > + if (t =3D=3D tSLASH) { > + t =3D db_read_token(); > + if (t !=3D tIDENT) { > + db_error("Invalid flag passed\n"); > + } > + /* Parse desired depth level */ > + if (strcmp(db_tok_string, "d") =3D=3D 0) { > + t =3D db_read_token(); > + if (t !=3D tNUMBER) { > + db_error("Invalid depth provided\n"); > + } > + max_depth =3D db_tok_number; > + } else { > + db_error("Invalid flag passed\n"); > + } > + /* Fetch next token */ > + t =3D db_read_token(); > + } > + /* Parse subcomannd */ > + if (t =3D=3D tIDENT) { > + if (strcmp(db_tok_string, "struct") =3D=3D 0) { > + t =3D db_read_token(); > + > + if (t !=3D tIDENT) { > + db_error("Invalid struct type name provided\n"); > + } > + name =3D db_tok_string; > + > + if (db_expression(&addr) =3D=3D 0) { > + db_error("Address not provided\n"); > + } > + db_pprint_struct_cmd(addr, name); > + } else { > + name =3D db_tok_string; > + db_pprint_symbol_cmd(name); > + } > + } else { > + db_error("Invalid subcommand\n"); > + } > + db_skip_to_eol(); > +} > diff --git a/sys/ddb/ddb.h b/sys/ddb/ddb.h > index 1f388efcb389..bb92fef63e94 100644 > --- a/sys/ddb/ddb.h > +++ b/sys/ddb/ddb.h > @@ -297,6 +297,7 @@ db_cmdfcn_t db_trace_until_matching_cmd; > db_cmdfcn_t db_unscript_cmd; > db_cmdfcn_t db_watchpoint_cmd; > db_cmdfcn_t db_write_cmd; > +db_cmdfcn_t db_pprint_cmd; > =20 > /* > * Interface between DDB and the DDB output capture facility. > diff --git a/sys/kern/kern_ctf.c b/sys/kern/kern_ctf.c > index 748622653eb3..8a2106a15308 100644 > --- a/sys/kern/kern_ctf.c > *** 331 LINES SKIPPED *** >=20 --=20 O. Hartmann