Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F102074961
D37899.id127582.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
33 KB
Referenced Files
None
Subscribers
None
D37899.id127582.diff
View Options
diff --git a/share/man/man4/ddb.4 b/share/man/man4/ddb.4
--- a/share/man/man4/ddb.4
+++ b/share/man/man4/ddb.4
@@ -291,6 +291,32 @@
ecx = 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 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 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
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -734,6 +734,8 @@
ddb/db_variables.c optional ddb
ddb/db_watch.c optional ddb
ddb/db_write_cmd.c optional ddb
+ddb/db_pprint.c optional ddb
+ddb/db_ctf.c optional ddb
dev/aac/aac.c optional aac
dev/aac/aac_cam.c optional aacp aac
dev/aac/aac_debug.c optional aac
diff --git a/sys/ddb/db_command.c b/sys/ddb/db_command.c
--- a/sys/ddb/db_command.c
+++ b/sys/ddb/db_command.c
@@ -166,6 +166,7 @@
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 = LIST_HEAD_INITIALIZER(db_cmd_table);
diff --git a/sys/ddb/db_ctf.h b/sys/ddb/db_ctf.h
new file mode 100644
--- /dev/null
+++ b/sys/ddb/db_ctf.h
@@ -0,0 +1,64 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2023 Bojan Novković <bnovkov@freebsd.org>
+ *
+ * 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 distribution.
+ *
+ * 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 PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * 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 <sys/types.h>
+#include <sys/ctf.h>
+#include <sys/linker.h>
+
+#include <ddb/ddb.h>
+#include <ddb/db_sym.h>
+
+#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 files.
+ */
+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_ctf.c b/sys/ddb/db_ctf.c
new file mode 100644
--- /dev/null
+++ b/sys/ddb/db_ctf.c
@@ -0,0 +1,328 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2023 Bojan Novković <bnovkov@freebsd.org>
+ *
+ * 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 distribution.
+ *
+ * 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 PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * 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 <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/ctype.h>
+#include <sys/linker.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+
+#include <ddb/ddb.h>
+#include <ddb/db_ctf.h>
+
+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 scanning
+ * the CTF object section.
+ */
+static uint32_t
+sym_to_objtoff(linker_ctf_t *lc, const Elf_Sym *sym, const Elf_Sym *symtab,
+ const Elf_Sym *symtab_end)
+{
+ const ctf_header_t *hp = db_ctf_fetch_cth(lc);
+ uint32_t objtoff = hp->cth_objtoff;
+ const size_t idwidth = 4;
+
+ /* Ignore non-object symbols */
+ if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) {
+ return DB_CTF_INVALID_OFF;
+ }
+ /* Sanity check */
+ if (!(sym >= symtab && sym <= symtab_end)) {
+ return DB_CTF_INVALID_OFF;
+ }
+
+ for (const Elf_Sym *symp = symtab; symp < symtab_end; symp++) {
+ /* Make sure we do not go beyond the objtoff section */
+ if (objtoff >= hp->cth_funcoff) {
+ objtoff = DB_CTF_INVALID_OFF;
+ break;
+ }
+ if (symp->st_name == 0 || symp->st_shndx == SHN_UNDEF) {
+ continue;
+ }
+ if (symp->st_shndx == SHN_ABS && symp->st_value == 0) {
+ continue;
+ }
+
+ /* Skip non-object symbols */
+ if (ELF_ST_TYPE(symp->st_info) != STT_OBJECT) {
+ continue;
+ }
+ if (symp == sym) {
+ break;
+ }
+ objtoff += 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, type_struct_size, kind_size;
+
+ vlen = CTF_V3_INFO_VLEN(t->ctt_info);
+ kind = CTF_V3_INFO_KIND(t->ctt_info);
+ ssize = ((t->ctt_size == CTF_V3_LSIZE_SENT) ? CTF_TYPE_LSIZE(t) :
+ t->ctt_size);
+ type_struct_size = ((t->ctt_size == 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 = sizeof(uint32_t);
+ break;
+ case CTF_K_ARRAY:
+ kind_size = sizeof(struct ctf_array_v3);
+ break;
+ case CTF_K_UNION:
+ case CTF_K_STRUCT:
+ kind_size = vlen *
+ ((ssize < CTF_V3_LSTRUCT_THRESH) ?
+ sizeof(struct ctf_member_v3) :
+ sizeof(struct ctf_lmember_v3));
+ break;
+ case CTF_K_ENUM:
+ kind_size = vlen * sizeof(struct ctf_enum);
+ break;
+ case CTF_K_FUNCTION:
+ kind_size = 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 = 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 = db_ctf_fetch_cth(lc);
+ char *start, *cur, *end;
+ uint32_t stroff = hp->cth_stroff;
+ uint32_t typeoff = hp->cth_typeoff;
+ uint32_t name_stroff;
+ const uint8_t *ctfstart = (const uint8_t *)hp + sizeof(ctf_header_t);
+
+ u_int skiplen;
+
+ /* Scan ctf strtab for typename. */
+ start = cur = __DECONST(char *, hp) + sizeof(ctf_header_t) +
+ hp->cth_stroff;
+ end = cur + hp->cth_strlen;
+ while (cur < end) {
+ if (!strcmp(cur, name))
+ break;
+ cur += strlen(cur) + 1;
+ }
+ if (cur >= end)
+ return (NULL);
+ name_stroff = (uint32_t)(cur - start);
+
+ /* Scan for type containing the found stroff. */
+ while (typeoff < stroff) {
+ struct ctf_type_v3 *t =
+ (struct ctf_type_v3 *)(__DECONST(uint8_t *, ctfstart) +
+ typeoff);
+ /* We found the type struct */
+ if (t->ctt_name == name_stroff) {
+ break;
+ }
+ if ((skiplen = db_ctf_type_size(t)) == -1) {
+ return (NULL);
+ }
+ typeoff += 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 kernel
+ * modules.
+ */
+bool
+db_ctf_lookup_typename(linker_ctf_t *lc, const char *typename)
+{
+ return (db_ctf_typename_to_type(lc, typename) != 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 = db_ctf_fetch_cth(&sd->lc);
+ const uint8_t *ctfstart = (const uint8_t *)hp + sizeof(ctf_header_t);
+ uint32_t typeoff = hp->cth_typeoff;
+ uint32_t stroff = hp->cth_stroff;
+ /* CTF typeids start at 0x1 */
+ size_t cur_typeid = 1;
+ u_int skiplen;
+
+ /* Find corresponding type */
+ while (typeoff < stroff) {
+ struct ctf_type_v3 *t =
+ (struct ctf_type_v3 *)(__DECONST(uint8_t *, ctfstart) +
+ typeoff);
+
+ /* We found the type struct */
+ if (cur_typeid == typeid) {
+ break;
+ }
+ cur_typeid++;
+ if ((skiplen = db_ctf_type_size(t)) == -1) {
+ return (NULL);
+ }
+ typeoff += skiplen;
+ }
+ if (typeoff < stroff) {
+ return (struct ctf_type_v3 *)(__DECONST(uint8_t *, ctfstart) +
+ typeoff);
+ } else { /* A type struct was not found */
+ return (NULL);
+ }
+}
+
+/*
+ * Returns
+ */
+const char *
+db_ctf_stroff_to_str(db_ctf_sym_data_t sd, uint32_t off)
+{
+ const ctf_header_t *hp = db_ctf_fetch_cth(&sd->lc);
+ uint32_t stroff = hp->cth_stroff + off;
+ const char *ret;
+
+ if (stroff >= (hp->cth_stroff + hp->cth_strlen)) {
+ return "invalid";
+ }
+ ret = ((const char *)hp + sizeof(ctf_header_t)) + stroff;
+ if (*ret == '\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 == NULL) {
+ return (NULL);
+ }
+ symtab = sd->lc.symtab;
+ symtab_end = symtab + sd->lc.nsym;
+
+ objtoff = sym_to_objtoff(&sd->lc, sd->sym, symtab, symtab_end);
+ /* Sanity check - should not happen */
+ if (objtoff == DB_CTF_INVALID_OFF) {
+ db_printf("Could not find CTF object offset.\n");
+ return (NULL);
+ }
+
+ typeid = *(
+ 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 = NULL;
+
+ error = linker_ctf_lookup_sym_ddb(name, &lsym, &sd->lc);
+ if (error != 0) {
+ db_printf(
+ "failed to look up symbol and CTF info for %s: error %d\n",
+ name, error);
+ return (error);
+ }
+ sd->sym = __DECONST(Elf_Sym *, lsym);
+
+ return (0);
+}
+
+/*
+ * Scans the kernel file and all loaded module for type specified by 'typename'.
+ */
+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)) {
+ return (NULL);
+ }
+ return (db_ctf_typename_to_type(&sd->lc, typename));
+}
diff --git a/sys/ddb/db_pprint.c b/sys/ddb/db_pprint.c
new file mode 100644
--- /dev/null
+++ b/sys/ddb/db_pprint.c
@@ -0,0 +1,437 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2022 Bojan Novković <bnovkov@freebsd.org>
+ *
+ * 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 distribution.
+ *
+ * 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 PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * 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 <sys/param.h>
+#include <sys/systm.h>
+#include <sys/ctype.h>
+#include <sys/linker.h>
+
+#include <machine/stdarg.h>
+
+#include <ddb/ddb.h>
+#include <ddb/db_ctf.h>
+#include <ddb/db_lex.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_access.h>
+
+#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 = 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)
+{
+ size_t type_struct_size = ((type->ctt_size == CTF_V3_LSIZE_SENT) ?
+ sizeof(struct ctf_type_v3) :
+ sizeof(struct ctf_stype_v3));
+ uint32_t data = db_get_value((db_expr_t)type + type_struct_size,
+ sizeof(uint32_t), 0);
+ u_int bits = CTF_INT_BITS(data);
+ boolean_t sign = !!(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 = ((type->ctt_size == CTF_V3_LSIZE_SENT) ?
+ sizeof(struct ctf_type_v3) :
+ sizeof(struct ctf_stype_v3));
+ size_t struct_size = ((type->ctt_size == CTF_V3_LSIZE_SENT) ?
+ CTF_TYPE_LSIZE(type) :
+ type->ctt_size);
+ u_int vlen = CTF_V3_INFO_VLEN(type->ctt_info);
+ struct ctf_type_v3 *mtype;
+ const char *mname;
+ db_addr_t maddr;
+
+ 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 = (struct ctf_member_v3 *)((db_addr_t)type +
+ type_struct_size);
+ endp = mp + vlen;
+ for (; mp < endp; mp++) {
+ if (db_pager_quit) {
+ return;
+ }
+ mtype = db_ctf_typeid_to_type(&sym_data, mp->ctm_type);
+ maddr = addr + mp->ctm_offset;
+ mname = db_ctf_stroff_to_str(&sym_data, mp->ctm_name);
+ db_indent = depth;
+ if (mname) {
+ db_iprintf("%s = ", mname);
+ } else {
+ db_iprintf("");
+ }
+
+ db_pprint_type(maddr, mtype, depth + 1);
+ db_printf(",\n");
+ }
+ } else {
+ struct ctf_lmember_v3 *mp, *endp;
+
+ mp = (struct ctf_lmember_v3 *)((db_addr_t)type +
+ type_struct_size);
+ endp = mp + vlen;
+ for (; mp < endp; mp++) {
+ if (db_pager_quit) {
+ return;
+ }
+ mtype = db_ctf_typeid_to_type(&sym_data, mp->ctlm_type);
+ maddr = addr + CTF_LMEM_OFFSET(mp);
+ mname = db_ctf_stroff_to_str(&sym_data, mp->ctlm_name);
+ db_indent = depth;
+ if (mname) {
+ db_iprintf("%s = ", mname);
+ } else {
+ db_iprintf("");
+ }
+
+ db_pprint_type(maddr, mtype, depth + 1);
+ db_printf(",");
+ }
+ }
+ db_indent = depth - 1;
+ db_iprintf("}");
+}
+
+/*
+ * Pretty-prints an array. Each array member is printed out in a separate 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_array_v3 *arr;
+ struct ctf_type_v3 *elem_type;
+ db_addr_t elem_addr, end;
+ size_t elem_size;
+ size_t type_struct_size = ((type->ctt_size == CTF_V3_LSIZE_SENT) ?
+ sizeof(struct ctf_type_v3) :
+ sizeof(struct ctf_stype_v3));
+
+ arr = (struct ctf_array_v3 *)((db_addr_t)type + type_struct_size);
+ elem_type = db_ctf_typeid_to_type(&sym_data, arr->cta_contents);
+ elem_size = ((elem_type->ctt_size == CTF_V3_LSIZE_SENT) ?
+ CTF_TYPE_LSIZE(elem_type) :
+ elem_type->ctt_size);
+ elem_addr = addr;
+ end = addr + (arr->cta_nelems * elem_size);
+
+ db_indent = depth;
+ db_printf("[\n");
+ /* Loop through and print individual elements. */
+ for (; elem_addr < end; elem_addr += 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 = 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;
+ const char *valname;
+ u_int vlen = CTF_V3_INFO_VLEN(type->ctt_info);
+ db_expr_t val = db_get_value(addr, sizeof(int), 0);
+ size_t type_struct_size = ((type->ctt_size == CTF_V3_LSIZE_SENT) ?
+ sizeof(struct ctf_type_v3) :
+ sizeof(struct ctf_stype_v3));
+
+ if (db_pager_quit) {
+ return;
+ }
+ ep = (struct ctf_enum *)((db_addr_t)type + type_struct_size);
+ endp = ep + vlen;
+ for (; ep < endp; ep++) {
+ if (val == ep->cte_value) {
+ valname = db_ctf_stroff_to_str(&sym_data, ep->cte_name);
+ if (valname)
+ 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 contents 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)
+{
+ const char *qual = "";
+ const char *name;
+ struct ctf_type_v3 *ref_type;
+ u_int kind;
+ db_addr_t val;
+
+ ref_type = db_ctf_typeid_to_type(&sym_data, type->ctt_type);
+ kind = CTF_V3_INFO_KIND(ref_type->ctt_info);
+ switch (kind) {
+ case CTF_K_STRUCT:
+ qual = "struct ";
+ break;
+ case CTF_K_VOLATILE:
+ qual = "volatile ";
+ break;
+ case CTF_K_CONST:
+ qual = "const ";
+ break;
+ default:
+ break;
+ }
+
+ val = 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 = db_ctf_stroff_to_str(&sym_data, ref_type->ctt_name);
+ db_indent = depth;
+ if (name)
+ 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 == 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 = 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 = 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] <sym_name>
+ */
+static void
+db_pprint_symbol_cmd(const char *name)
+{
+ db_addr_t addr;
+ int db_indent_old;
+ struct ctf_type_v3 *type = NULL;
+ const char *type_name = NULL;
+
+ if (db_pager_quit) {
+ return;
+ }
+ if (db_ctf_find_symbol(name, &sym_data)) {
+ db_error("Symbol not found\n");
+ }
+ if (ELF_ST_TYPE(sym_data.sym->st_info) != STT_OBJECT) {
+ db_error("Symbol is not a variable\n");
+ }
+ addr = sym_data.sym->st_value;
+ type = db_ctf_sym_to_type(&sym_data);
+ if (!type) {
+ db_error("Can't find CTF type info\n");
+ }
+ type_name = db_ctf_stroff_to_str(&sym_data, type->ctt_name);
+ if (type_name)
+ db_printf("%s ", type_name);
+ db_printf("%s = ", name);
+
+ db_indent_old = db_indent;
+ db_pprint_type(addr, type, 0);
+ db_indent = db_indent_old;
+}
+
+/*
+ * Command for pretty-printing arbitrary addresses.
+ * Syntax: pprint [/d depth] struct <struct_name> <addr>
+ */
+static void
+db_pprint_struct_cmd(db_expr_t addr, const char *struct_name)
+{
+ int db_indent_old;
+ struct ctf_type_v3 *type = NULL;
+
+ // TODO: check whether rv is a struct type
+ type = db_ctf_find_typename(&sym_data, struct_name);
+ if (!type) {
+ db_error("Can't find CTF type info\n");
+ return;
+ }
+
+ db_printf("struct %s ", struct_name);
+ db_printf("%p = ", (void *)addr);
+
+ db_indent_old = db_indent;
+ db_pprint_type(addr, type, 0);
+ db_indent = 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 *modif)
+{
+ int t = 0;
+ const char *name;
+
+ /* Set default depth */
+ max_depth = DB_PPRINT_DEFAULT_DEPTH;
+ /* Clear symbol and CTF info */
+ bzero(&sym_data, sizeof(sym_data));
+ /* Parse print modifiers */
+ t = db_read_token();
+ if (t == tSLASH) {
+ t = db_read_token();
+ if (t != tIDENT) {
+ db_error("Invalid flag passed\n");
+ }
+ /* Parse desired depth level */
+ if (!strcmp(db_tok_string, "d")) {
+ t = db_read_token();
+ if (t != tNUMBER) {
+ db_error("Invalid depth provided\n");
+ }
+ max_depth = db_tok_number;
+ } else {
+ db_error("Invalid flag passed\n");
+ }
+ /* Fetch next token */
+ t = db_read_token();
+ }
+ /* Parse subcomannd */
+ if (t == tIDENT) {
+ if (!strcmp(db_tok_string, "struct")) {
+ t = db_read_token();
+
+ if (t != tIDENT) {
+ db_error("Invalid struct type name provided\n");
+ }
+ name = db_tok_string;
+
+ if (!db_expression(&addr)) {
+ db_error("Address not provided\n");
+ }
+ db_pprint_struct_cmd(addr, name);
+ } else {
+ name = db_tok_string;
+ db_pprint_symbol_cmd(name);
+ }
+ } else {
+ db_error("Invalid subcommand\n");
+ }
+}
diff --git a/sys/ddb/ddb.h b/sys/ddb/ddb.h
--- a/sys/ddb/ddb.h
+++ b/sys/ddb/ddb.h
@@ -299,6 +299,7 @@
db_cmdfcn_t db_unscript_cmd;
db_cmdfcn_t db_watchpoint_cmd;
db_cmdfcn_t db_write_cmd;
+db_cmdfcn_t db_pprint_cmd;
/*
* Interface between DDB and the DDB output capture facility.
diff --git a/sys/kern/kern_ctf.c b/sys/kern/kern_ctf.c
--- a/sys/kern/kern_ctf.c
+++ b/sys/kern/kern_ctf.c
@@ -29,6 +29,10 @@
*/
#include <sys/ctf.h>
+#include <sys/kdb.h>
+#include <sys/linker.h>
+
+#include <ddb/db_ctf.h>
/*
* Note this file is included by both link_elf.c and link_elf_obj.c.
@@ -88,6 +92,9 @@
return (0);
}
+ if (panicstr != NULL || kdb_active)
+ return (ENXIO);
+
/*
* We need to try reading the CTF data. Flag no CTF data present
* by default and if we actually succeed in reading it, we'll
@@ -290,3 +297,34 @@
return (error);
}
+
+static int
+link_elf_ctf_get_ddb(linker_file_t lf, linker_ctf_t *lc)
+{
+ elf_file_t ef = (elf_file_t)lf;
+
+ /* Check whether CTF data was loaded or if a previous loading attempt
+ * failed (ctfcnt == -1). */
+ if (ef->ctfcnt <= 0) {
+ return (ENOENT);
+ }
+
+ lc->ctftab = ef->ctftab;
+ lc->ctfcnt = ef->ctfcnt;
+ lc->symtab = ef->ddbsymtab;
+ lc->strtab = ef->ddbstrtab;
+ lc->strcnt = ef->ddbstrcnt;
+ lc->nsym = ef->ddbsymcnt;
+
+ return (0);
+}
+
+static int
+link_elf_ctf_lookup_typename(linker_file_t lf, linker_ctf_t *lc,
+ const char *typename)
+{
+ if (link_elf_ctf_get_ddb(lf, lc))
+ return (ENOENT);
+
+ return (db_ctf_lookup_typename(lc, typename) ? 0 : ENOENT);
+}
diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c
--- a/sys/kern/kern_linker.c
+++ b/sys/kern/kern_linker.c
@@ -330,6 +330,27 @@
sx_xlock(&kld_sx);
}
+/*
+ * Invoke the LINKER_CTF_GET implementation for this file. Existing
+ * implementations will load CTF info from the filesystem upon the first call
+ * and cache it in the kernel thereafter.
+ */
+static void
+linker_ctf_load_file(linker_file_t file)
+{
+ linker_ctf_t lc;
+ int error;
+
+ printf("%s:%d %s\n", __func__, __LINE__, file->filename);
+ error = linker_ctf_get(file, &lc);
+ if (error == 0)
+ return;
+ if (bootverbose) {
+ printf("failed to load CTF for %s: %d\n", file->filename,
+ error);
+ }
+}
+
static void
linker_file_enable_sysctls(linker_file_t lf)
{
@@ -486,6 +507,11 @@
return (ENOEXEC);
}
linker_file_enable_sysctls(lf);
+
+ /*
+ * Ask the linker to load CTF data for this file.
+ */
+ linker_ctf_load_file(lf);
EVENTHANDLER_INVOKE(kld_load, lf);
*result = lf;
return (0);
@@ -778,6 +804,35 @@
return (LINKER_CTF_GET(file, lc));
}
+int
+linker_ctf_lookup_typename_ddb(linker_ctf_t *lc, const char *typename)
+{
+#ifdef DDB
+ linker_file_t lf;
+
+ TAILQ_FOREACH (lf, &linker_files, link) {
+ if (LINKER_CTF_LOOKUP_TYPENAME(lf, lc, typename) == 0)
+ return (0);
+ }
+#endif
+ return (ENOENT);
+}
+
+int
+linker_ctf_lookup_sym_ddb(const char *symname, c_linker_sym_t *sym,
+ linker_ctf_t *lc)
+{
+#ifdef DDB
+ linker_file_t lf;
+
+ TAILQ_FOREACH (lf, &linker_files, link) {
+ if (LINKER_LOOKUP_DEBUG_SYMBOL_CTF(lf, symname, sym, lc) == 0)
+ return (0);
+ }
+#endif
+ return (ENOENT);
+}
+
static int
linker_file_add_dependency(linker_file_t file, linker_file_t dep)
{
@@ -1777,9 +1832,21 @@
sx_xunlock(&kld_sx);
/* woohoo! we made it! */
}
-
SYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, NULL);
+static void
+linker_mountroot(void *arg __unused)
+{
+ linker_file_t lf;
+
+ sx_xlock(&kld_sx);
+ TAILQ_FOREACH (lf, &linker_files, link) {
+ linker_ctf_load_file(lf);
+ }
+ sx_xunlock(&kld_sx);
+}
+EVENTHANDLER_DEFINE(mountroot, linker_mountroot, NULL, 0);
+
/*
* Handle preload files that failed to load any modules.
*/
diff --git a/sys/kern/link_elf.c b/sys/kern/link_elf.c
--- a/sys/kern/link_elf.c
+++ b/sys/kern/link_elf.c
@@ -71,6 +71,10 @@
#include "linker_if.h"
+#ifdef DDB_CTF
+#include <ddb/db_ctf.h>
+#endif
+
#define MAXSEGS 4
typedef struct elf_file {
@@ -144,6 +148,9 @@
c_linker_sym_t *);
static int link_elf_lookup_debug_symbol(linker_file_t, const char *,
c_linker_sym_t *);
+static int link_elf_lookup_debug_symbol_ctf(linker_file_t lf, const char *name,
+ c_linker_sym_t *sym, linker_ctf_t *lc);
+
static int link_elf_symbol_values(linker_file_t, c_linker_sym_t,
linker_symval_t *);
static int link_elf_debug_symbol_values(linker_file_t, c_linker_sym_t,
@@ -167,6 +174,7 @@
static kobj_method_t link_elf_methods[] = {
KOBJMETHOD(linker_lookup_symbol, link_elf_lookup_symbol),
KOBJMETHOD(linker_lookup_debug_symbol, link_elf_lookup_debug_symbol),
+ KOBJMETHOD(linker_lookup_debug_symbol_ctf, link_elf_lookup_debug_symbol_ctf),
KOBJMETHOD(linker_symbol_values, link_elf_symbol_values),
KOBJMETHOD(linker_debug_symbol_values, link_elf_debug_symbol_values),
KOBJMETHOD(linker_search_symbol, link_elf_search_symbol),
@@ -178,6 +186,7 @@
KOBJMETHOD(linker_each_function_name, link_elf_each_function_name),
KOBJMETHOD(linker_each_function_nameval, link_elf_each_function_nameval),
KOBJMETHOD(linker_ctf_get, link_elf_ctf_get),
+ KOBJMETHOD(linker_ctf_lookup_typename, link_elf_ctf_lookup_typename),
KOBJMETHOD(linker_symtab_get, link_elf_symtab_get),
KOBJMETHOD(linker_strtab_get, link_elf_strtab_get),
KOBJMETHOD_END
@@ -1582,6 +1591,34 @@
return (ENOENT);
}
+static int
+link_elf_lookup_debug_symbol_ctf(linker_file_t lf, const char *name,
+ c_linker_sym_t *sym, linker_ctf_t *lc)
+{
+ elf_file_t ef = (elf_file_t)lf;
+ const Elf_Sym *symp;
+ const char *strp;
+ int i;
+
+ for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) {
+ strp = ef->ddbstrtab + symp->st_name;
+ if (strcmp(name, strp) == 0) {
+ if (symp->st_shndx != SHN_UNDEF ||
+ (symp->st_value != 0 &&
+ (ELF_ST_TYPE(symp->st_info) == STT_FUNC ||
+ ELF_ST_TYPE(symp->st_info) ==
+ STT_GNU_IFUNC))) {
+ *sym = (c_linker_sym_t)symp;
+ break;
+ }
+ return (ENOENT);
+ }
+ }
+
+ /* Populate CTF info structure if symbol was found. */
+ return (i < ef->ddbsymcnt ? link_elf_ctf_get_ddb(lf, lc) : ENOENT);
+}
+
static int
link_elf_symbol_values1(linker_file_t lf, c_linker_sym_t sym,
linker_symval_t *symval, bool see_local)
diff --git a/sys/kern/link_elf_obj.c b/sys/kern/link_elf_obj.c
--- a/sys/kern/link_elf_obj.c
+++ b/sys/kern/link_elf_obj.c
@@ -134,6 +134,8 @@
c_linker_sym_t *);
static int link_elf_lookup_debug_symbol(linker_file_t, const char *,
c_linker_sym_t *);
+static int link_elf_lookup_debug_symbol_ctf(linker_file_t lf, const char *name,
+ c_linker_sym_t *sym, linker_ctf_t *lc);
static int link_elf_symbol_values(linker_file_t, c_linker_sym_t,
linker_symval_t *);
static int link_elf_debug_symbol_values(linker_file_t, c_linker_sym_t,
@@ -159,6 +161,7 @@
static kobj_method_t link_elf_methods[] = {
KOBJMETHOD(linker_lookup_symbol, link_elf_lookup_symbol),
KOBJMETHOD(linker_lookup_debug_symbol, link_elf_lookup_debug_symbol),
+ KOBJMETHOD(linker_lookup_debug_symbol_ctf, link_elf_lookup_debug_symbol_ctf),
KOBJMETHOD(linker_symbol_values, link_elf_symbol_values),
KOBJMETHOD(linker_debug_symbol_values, link_elf_debug_symbol_values),
KOBJMETHOD(linker_search_symbol, link_elf_search_symbol),
@@ -170,6 +173,7 @@
KOBJMETHOD(linker_each_function_name, link_elf_each_function_name),
KOBJMETHOD(linker_each_function_nameval, link_elf_each_function_nameval),
KOBJMETHOD(linker_ctf_get, link_elf_ctf_get),
+ KOBJMETHOD(linker_ctf_lookup_typename, link_elf_ctf_lookup_typename),
KOBJMETHOD(linker_symtab_get, link_elf_symtab_get),
KOBJMETHOD(linker_strtab_get, link_elf_strtab_get),
KOBJMETHOD_END
@@ -1472,6 +1476,16 @@
return (link_elf_lookup_symbol1(lf, name, sym, true));
}
+static int
+link_elf_lookup_debug_symbol_ctf(linker_file_t lf, const char *name,
+ c_linker_sym_t *sym, linker_ctf_t *lc)
+{
+ if (link_elf_lookup_debug_symbol(lf, name, sym))
+ return (ENOENT);
+
+ return (link_elf_ctf_get_ddb(lf, lc));
+}
+
static int
link_elf_symbol_values1(linker_file_t lf, c_linker_sym_t sym,
linker_symval_t *symval, bool see_local)
diff --git a/sys/kern/linker_if.m b/sys/kern/linker_if.m
--- a/sys/kern/linker_if.m
+++ b/sys/kern/linker_if.m
@@ -116,6 +116,29 @@
linker_ctf_t *lc;
};
+#
+# Look up a CTF type in the file's CTF section
+# and return CTF info in the linker CTF structure.
+# Return ENOENT if typename is not found, otherwise zero.
+#
+METHOD int ctf_lookup_typename {
+ linker_file_t file;
+ linker_ctf_t *lc;
+ const char *typename;
+};
+
+#
+# Lookup a symbol in the file's symbol table and the file's CTF info.
+# Return ENOENT if either the symbol or its CTF
+# data is not loaded, otherwise return zero.
+#
+METHOD int lookup_debug_symbol_ctf {
+ linker_file_t file;
+ const char *name;
+ c_linker_sym_t *sym;
+ linker_ctf_t *lc;
+};
+
#
# Get the symbol table, returning it in **symtab. Return the
# number of symbols, otherwise zero.
diff --git a/sys/sys/linker.h b/sys/sys/linker.h
--- a/sys/sys/linker.h
+++ b/sys/sys/linker.h
@@ -321,6 +321,9 @@
} linker_ctf_t;
int linker_ctf_get(linker_file_t, linker_ctf_t *);
+int linker_ctf_lookup_sym_ddb(const char *symname, c_linker_sym_t *sym,
+ linker_ctf_t *lc);
+int linker_ctf_lookup_typename_ddb(linker_ctf_t *lc, const char *typename);
int elf_cpu_load_file(linker_file_t);
int elf_cpu_unload_file(linker_file_t);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Nov 8, 7:40 AM (9 h, 38 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14530582
Default Alt Text
D37899.id127582.diff (33 KB)
Attached To
Mode
D37899: ddb: Add basic CTF support [2/2]
Attached
Detach File
Event Timeline
Log In to Comment