1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2022 Bojan Novković <bnovkov@freebsd.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/param.h> 29 #include <sys/systm.h> 30 #include <sys/ctype.h> 31 #include <sys/linker.h> 32 33 #include <machine/stdarg.h> 34 35 #include <ddb/ddb.h> 36 #include <ddb/db_ctf.h> 37 #include <ddb/db_lex.h> 38 #include <ddb/db_sym.h> 39 #include <ddb/db_access.h> 40 41 #define DB_PPRINT_DEFAULT_DEPTH 1 42 43 static void db_pprint_type(db_addr_t addr, struct ctf_type_v3 *type, 44 u_int depth); 45 46 static u_int max_depth = DB_PPRINT_DEFAULT_DEPTH; 47 static struct db_ctf_sym_data sym_data; 48 49 /* 50 * Pretty-prints a CTF_INT type. 51 */ 52 static inline void 53 db_pprint_int(db_addr_t addr, struct ctf_type_v3 *type, u_int depth) 54 { 55 uint32_t data; 56 size_t type_struct_size; 57 58 type_struct_size = (type->ctt_size == CTF_V3_LSIZE_SENT) ? 59 sizeof(struct ctf_type_v3) : 60 sizeof(struct ctf_stype_v3); 61 62 data = db_get_value((db_expr_t)type + type_struct_size, 63 sizeof(uint32_t), 0); 64 u_int bits = CTF_INT_BITS(data); 65 boolean_t sign = !!(CTF_INT_ENCODING(data) & CTF_INT_SIGNED); 66 67 if (db_pager_quit) { 68 return; 69 } 70 if (bits > 64) { 71 db_printf("Invalid size '%d' found for integer type\n", bits); 72 return; 73 } 74 db_printf("0x%lx", 75 (long)db_get_value(addr, (bits / 8) ? (bits / 8) : 1, sign)); 76 } 77 78 /* 79 * Pretty-prints a struct. Nested structs are pretty-printed up 'depth' nested 80 * levels. 81 */ 82 static inline void 83 db_pprint_struct(db_addr_t addr, struct ctf_type_v3 *type, u_int depth) 84 { 85 size_t type_struct_size; 86 size_t struct_size; 87 struct ctf_type_v3 *mtype; 88 const char *mname; 89 db_addr_t maddr; 90 u_int vlen; 91 92 type_struct_size = (type->ctt_size == CTF_V3_LSIZE_SENT) ? 93 sizeof(struct ctf_type_v3) : 94 sizeof(struct ctf_stype_v3); 95 struct_size = ((type->ctt_size == CTF_V3_LSIZE_SENT) ? 96 CTF_TYPE_LSIZE(type) : 97 type->ctt_size); 98 vlen = CTF_V3_INFO_VLEN(type->ctt_info); 99 100 if (db_pager_quit) { 101 return; 102 } 103 if (depth > max_depth) { 104 db_printf("{ ... }"); 105 return; 106 } 107 db_printf("{\n"); 108 109 if (struct_size < CTF_V3_LSTRUCT_THRESH) { 110 struct ctf_member_v3 *mp, *endp; 111 112 mp = (struct ctf_member_v3 *)((db_addr_t)type + 113 type_struct_size); 114 endp = mp + vlen; 115 for (; mp < endp; mp++) { 116 if (db_pager_quit) { 117 return; 118 } 119 mtype = db_ctf_typeid_to_type(&sym_data, mp->ctm_type); 120 maddr = addr + mp->ctm_offset; 121 mname = db_ctf_stroff_to_str(&sym_data, mp->ctm_name); 122 db_indent = depth; 123 if (mname != NULL) { 124 db_iprintf("%s = ", mname); 125 } else { 126 db_iprintf(""); 127 } 128 129 db_pprint_type(maddr, mtype, depth + 1); 130 db_printf(",\n"); 131 } 132 } else { 133 struct ctf_lmember_v3 *mp, *endp; 134 135 mp = (struct ctf_lmember_v3 *)((db_addr_t)type + 136 type_struct_size); 137 endp = mp + vlen; 138 for (; mp < endp; mp++) { 139 if (db_pager_quit) { 140 return; 141 } 142 mtype = db_ctf_typeid_to_type(&sym_data, mp->ctlm_type); 143 maddr = addr + CTF_LMEM_OFFSET(mp); 144 mname = db_ctf_stroff_to_str(&sym_data, mp->ctlm_name); 145 db_indent = depth; 146 if (mname != NULL) { 147 db_iprintf("%s = ", mname); 148 } else { 149 db_iprintf(""); 150 } 151 152 db_pprint_type(maddr, mtype, depth + 1); 153 db_printf(","); 154 } 155 } 156 db_indent = depth - 1; 157 db_iprintf("}"); 158 } 159 160 /* 161 * Pretty-prints an array. Each array member is printed out in a separate line 162 * indented with 'depth' spaces. 163 */ 164 static inline void 165 db_pprint_arr(db_addr_t addr, struct ctf_type_v3 *type, u_int depth) 166 { 167 struct ctf_type_v3 *elem_type; 168 struct ctf_array_v3 *arr; 169 db_addr_t elem_addr, end; 170 size_t type_struct_size; 171 size_t elem_size; 172 173 type_struct_size = (type->ctt_size == CTF_V3_LSIZE_SENT) ? 174 sizeof(struct ctf_type_v3) : 175 sizeof(struct ctf_stype_v3); 176 arr = (struct ctf_array_v3 *)((db_addr_t)type + type_struct_size); 177 elem_type = db_ctf_typeid_to_type(&sym_data, arr->cta_contents); 178 elem_size = ((elem_type->ctt_size == CTF_V3_LSIZE_SENT) ? 179 CTF_TYPE_LSIZE(elem_type) : 180 elem_type->ctt_size); 181 elem_addr = addr; 182 end = addr + (arr->cta_nelems * elem_size); 183 184 db_indent = depth; 185 db_printf("[\n"); 186 /* Loop through and print individual elements. */ 187 for (; elem_addr < end; elem_addr += elem_size) { 188 if (db_pager_quit) { 189 return; 190 } 191 db_iprintf(""); 192 db_pprint_type(elem_addr, elem_type, depth); 193 if ((elem_addr + elem_size) < end) { 194 db_printf(",\n"); 195 } 196 } 197 db_printf("\n"); 198 db_indent = depth - 1; 199 db_iprintf("]"); 200 } 201 202 /* 203 * Pretty-prints an enum value. Also prints out symbolic name of value, if any. 204 */ 205 static inline void 206 db_pprint_enum(db_addr_t addr, struct ctf_type_v3 *type, u_int depth) 207 { 208 struct ctf_enum *ep, *endp; 209 size_t type_struct_size; 210 const char *valname; 211 db_expr_t val; 212 u_int vlen; 213 214 type_struct_size = (type->ctt_size == CTF_V3_LSIZE_SENT) ? 215 sizeof(struct ctf_type_v3) : 216 sizeof(struct ctf_stype_v3); 217 vlen = CTF_V3_INFO_VLEN(type->ctt_info); 218 val = db_get_value(addr, sizeof(int), 0); 219 220 if (db_pager_quit) { 221 return; 222 } 223 ep = (struct ctf_enum *)((db_addr_t)type + type_struct_size); 224 endp = ep + vlen; 225 for (; ep < endp; ep++) { 226 if (val == ep->cte_value) { 227 valname = db_ctf_stroff_to_str(&sym_data, ep->cte_name); 228 if (valname != NULL) { 229 db_printf("%s (0x%lx)", valname, (long)val); 230 break; 231 } 232 } 233 } 234 if (ep == endp) 235 db_printf("0x%lx", (long)val); 236 } 237 238 /* 239 * Pretty-prints a pointer. If the 'depth' parameter is less than the 240 * 'max_depth' global var, the pointer is "dereference", i.e. the contents of 241 * the memory it points to are also printed. The value of the pointer is printed 242 * otherwise. 243 */ 244 static inline void 245 db_pprint_ptr(db_addr_t addr, struct ctf_type_v3 *type, u_int depth) 246 { 247 struct ctf_type_v3 *ref_type; 248 const char *qual = ""; 249 const char *name; 250 db_addr_t val; 251 u_int kind; 252 253 ref_type = db_ctf_typeid_to_type(&sym_data, type->ctt_type); 254 kind = CTF_V3_INFO_KIND(ref_type->ctt_info); 255 switch (kind) { 256 case CTF_K_STRUCT: 257 qual = "struct "; 258 break; 259 case CTF_K_VOLATILE: 260 qual = "volatile "; 261 break; 262 case CTF_K_CONST: 263 qual = "const "; 264 break; 265 default: 266 break; 267 } 268 269 val = db_get_value(addr, sizeof(db_addr_t), false); 270 if (depth < max_depth) { 271 /* Print contents of memory pointed to by this pointer. */ 272 db_pprint_type(addr, ref_type, depth + 1); 273 } else { 274 name = db_ctf_stroff_to_str(&sym_data, ref_type->ctt_name); 275 db_indent = depth; 276 if (name != NULL) 277 db_printf("(%s%s *) 0x%lx", qual, name, (long)val); 278 else 279 db_printf("(%s *) 0x%lx", qual, (long)val); 280 } 281 } 282 283 /* 284 * Pretty-print dispatching function. 285 */ 286 static void 287 db_pprint_type(db_addr_t addr, struct ctf_type_v3 *type, u_int depth) 288 { 289 290 if (db_pager_quit) { 291 return; 292 } 293 if (type == NULL) { 294 db_printf("unknown type"); 295 return; 296 } 297 298 switch (CTF_V3_INFO_KIND(type->ctt_info)) { 299 case CTF_K_INTEGER: 300 db_pprint_int(addr, type, depth); 301 break; 302 case CTF_K_UNION: 303 case CTF_K_STRUCT: 304 db_pprint_struct(addr, type, depth); 305 break; 306 case CTF_K_FUNCTION: 307 case CTF_K_FLOAT: 308 db_indent = depth; 309 db_iprintf("0x%lx", (long)addr); 310 break; 311 case CTF_K_POINTER: 312 db_pprint_ptr(addr, type, depth); 313 break; 314 case CTF_K_TYPEDEF: 315 case CTF_K_VOLATILE: 316 case CTF_K_RESTRICT: 317 case CTF_K_CONST: { 318 struct ctf_type_v3 *ref_type = db_ctf_typeid_to_type(&sym_data, 319 type->ctt_type); 320 db_pprint_type(addr, ref_type, depth); 321 break; 322 } 323 case CTF_K_ENUM: 324 db_pprint_enum(addr, type, depth); 325 break; 326 case CTF_K_ARRAY: 327 db_pprint_arr(addr, type, depth); 328 break; 329 case CTF_K_UNKNOWN: 330 case CTF_K_FORWARD: 331 default: 332 break; 333 } 334 } 335 336 /* 337 * Symbol pretty-printing command. 338 * Syntax: pprint [/d depth] <sym_name> 339 */ 340 static void 341 db_pprint_symbol_cmd(const char *name) 342 { 343 db_addr_t addr; 344 int db_indent_old; 345 const char *type_name = NULL; 346 struct ctf_type_v3 *type = NULL; 347 348 if (db_pager_quit) { 349 return; 350 } 351 /* Clear symbol and CTF info */ 352 memset(&sym_data, 0, sizeof(struct db_ctf_sym_data)); 353 if (db_ctf_find_symbol(name, &sym_data) != 0) { 354 db_error("Symbol not found\n"); 355 } 356 if (ELF_ST_TYPE(sym_data.sym->st_info) != STT_OBJECT) { 357 db_error("Symbol is not a variable\n"); 358 } 359 addr = sym_data.sym->st_value; 360 type = db_ctf_sym_to_type(&sym_data); 361 if (type == NULL) { 362 db_error("Can't find CTF type info\n"); 363 } 364 type_name = db_ctf_stroff_to_str(&sym_data, type->ctt_name); 365 if (type_name != NULL) 366 db_printf("%s ", type_name); 367 db_printf("%s = ", name); 368 369 db_indent_old = db_indent; 370 db_pprint_type(addr, type, 0); 371 db_indent = db_indent_old; 372 } 373 374 /* 375 * Command for pretty-printing arbitrary addresses. 376 * Syntax: pprint [/d depth] struct <struct_name> <addr> 377 */ 378 static void 379 db_pprint_struct_cmd(db_expr_t addr, const char *struct_name) 380 { 381 int db_indent_old; 382 struct ctf_type_v3 *type = NULL; 383 384 type = db_ctf_find_typename(&sym_data, struct_name); 385 if (type == NULL) { 386 db_error("Can't find CTF type info\n"); 387 return; 388 } 389 390 db_printf("struct %s ", struct_name); 391 db_printf("%p = ", (void *)addr); 392 393 db_indent_old = db_indent; 394 db_pprint_type(addr, type, 0); 395 db_indent = db_indent_old; 396 } 397 398 /* 399 * Pretty print an address or a symbol. 400 */ 401 void 402 db_pprint_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif) 403 { 404 int t = 0; 405 const char *name; 406 407 /* Set default depth */ 408 max_depth = DB_PPRINT_DEFAULT_DEPTH; 409 /* Parse print modifiers */ 410 t = db_read_token(); 411 if (t == tSLASH) { 412 t = db_read_token(); 413 if (t != tIDENT) { 414 db_error("Invalid flag passed\n"); 415 } 416 /* Parse desired depth level */ 417 if (strcmp(db_tok_string, "d") == 0) { 418 t = db_read_token(); 419 if (t != tNUMBER) { 420 db_error("Invalid depth provided\n"); 421 } 422 max_depth = db_tok_number; 423 } else { 424 db_error("Invalid flag passed\n"); 425 } 426 /* Fetch next token */ 427 t = db_read_token(); 428 } 429 /* Parse subcomannd */ 430 if (t == tIDENT) { 431 if (strcmp(db_tok_string, "struct") == 0) { 432 t = db_read_token(); 433 434 if (t != tIDENT) { 435 db_error("Invalid struct type name provided\n"); 436 } 437 name = db_tok_string; 438 439 if (db_expression(&addr) == 0) { 440 db_error("Address not provided\n"); 441 } 442 db_pprint_struct_cmd(addr, name); 443 } else { 444 name = db_tok_string; 445 db_pprint_symbol_cmd(name); 446 } 447 } else { 448 db_error("Invalid subcommand\n"); 449 } 450 db_skip_to_eol(); 451 } 452