diff --git a/sys/ddb/db_ctf.c b/sys/ddb/db_ctf.c index 03145064885c..56a6086849e9 100644 --- a/sys/ddb/db_ctf.c +++ b/sys/ddb/db_ctf.c @@ -1,326 +1,326 @@ /*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2023 Bojan Novković * * 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 #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 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; u_int 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) == 0) 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); } } 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) != 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 index 6da5f76b6cf6..c4c977cb8205 100644 --- a/sys/ddb/db_ctf.h +++ b/sys/ddb/db_ctf.h @@ -1,64 +1,64 @@ /*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2023 Bojan Novković * * 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 #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 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_pprint.c b/sys/ddb/db_pprint.c index aae3d698e8ec..8aa14550f068 100644 --- a/sys/ddb/db_pprint.c +++ b/sys/ddb/db_pprint.c @@ -1,450 +1,450 @@ /*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2022 Bojan Novković * * 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 #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 = 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 = (type->ctt_size == CTF_V3_LSIZE_SENT) ? sizeof(struct ctf_type_v3) : sizeof(struct ctf_stype_v3); 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", (long)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 = (type->ctt_size == CTF_V3_LSIZE_SENT) ? sizeof(struct ctf_type_v3) : sizeof(struct ctf_stype_v3); struct_size = ((type->ctt_size == CTF_V3_LSIZE_SENT) ? CTF_TYPE_LSIZE(type) : type->ctt_size); vlen = 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 = (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 != NULL) { 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 != NULL) { 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_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 = (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; size_t type_struct_size; const char *valname; db_expr_t val; u_int vlen; type_struct_size = (type->ctt_size == CTF_V3_LSIZE_SENT) ? sizeof(struct ctf_type_v3) : sizeof(struct ctf_stype_v3); vlen = CTF_V3_INFO_VLEN(type->ctt_info); val = db_get_value(addr, sizeof(int), 0); 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 != NULL) db_printf("%s (0x%lx)", valname, (long)val); else db_printf("(0x%lx)", (long)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) { struct ctf_type_v3 *ref_type; const char *qual = ""; const char *name; db_addr_t val; u_int kind; 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 != NULL) db_printf("(%s%s *) 0x%lx", qual, name, (long)val); else db_printf("0x%lx", (long)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", (long)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] */ static void db_pprint_symbol_cmd(const char *name) { db_addr_t addr; int db_indent_old; const char *type_name = NULL; struct ctf_type_v3 *type = 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) != 0) { 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 == NULL) { db_error("Can't find CTF type info\n"); } type_name = db_ctf_stroff_to_str(&sym_data, type->ctt_name); if (type_name != NULL) 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 */ static void db_pprint_struct_cmd(db_expr_t addr, const char *struct_name) { int db_indent_old; struct ctf_type_v3 *type = NULL; type = db_ctf_find_typename(&sym_data, struct_name); if (type == NULL) { 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; /* 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") == 0) { 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") == 0) { t = db_read_token(); if (t != tIDENT) { db_error("Invalid struct type name provided\n"); } name = db_tok_string; if (db_expression(&addr) == 0) { 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"); } db_skip_to_eol(); }