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 #include <sys/stdarg.h> 33 34 #include <ddb/ddb.h> 35 #include <ddb/db_ctf.h> 36 #include <ddb/db_lex.h> 37 #include <ddb/db_sym.h> 38 #include <ddb/db_access.h> 39 40 #define DB_PPRINT_DEFAULT_DEPTH 1 41 42 static void db_pprint_type(db_addr_t addr, struct ctf_type_v3 *type, 43 u_int depth); 44 45 static u_int max_depth = DB_PPRINT_DEFAULT_DEPTH; 46 static struct db_ctf_sym_data sym_data; 47 static const char *asteriskstr = "*****"; 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 / NBBY); 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) / NBBY); 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 uint32_t tid; 252 u_int kind; 253 int ptrcnt; 254 255 ptrcnt = 1; 256 tid = type->ctt_type; 257 again: 258 ref_type = db_ctf_typeid_to_type(&sym_data, tid); 259 kind = CTF_V3_INFO_KIND(ref_type->ctt_info); 260 switch (kind) { 261 case CTF_K_STRUCT: 262 qual = "struct "; 263 break; 264 case CTF_K_VOLATILE: 265 qual = "volatile "; 266 tid = ref_type->ctt_type; 267 goto again; 268 case CTF_K_CONST: 269 qual = "const "; 270 tid = ref_type->ctt_type; 271 goto again; 272 case CTF_K_RESTRICT: 273 qual = "restrict "; 274 tid = ref_type->ctt_type; 275 goto again; 276 case CTF_K_POINTER: 277 ptrcnt++; 278 tid = ref_type->ctt_type; 279 goto again; 280 case CTF_K_TYPEDEF: 281 tid = ref_type->ctt_type; 282 goto again; 283 default: 284 break; 285 } 286 287 ptrcnt = min(ptrcnt, strlen(asteriskstr)); 288 val = (addr != 0) ? db_get_value(addr, sizeof(db_addr_t), false) : 0; 289 if (depth < max_depth && (val != 0)) { 290 /* Print contents of memory pointed to by this pointer. */ 291 db_pprint_type(val, ref_type, depth + 1); 292 } else { 293 name = db_ctf_stroff_to_str(&sym_data, ref_type->ctt_name); 294 db_indent = depth; 295 if (name != NULL) 296 db_printf("(%s%s %.*s) 0x%lx", qual, name, ptrcnt, 297 asteriskstr, (long)val); 298 else 299 db_printf("(%s %.*s) 0x%lx", qual, ptrcnt, asteriskstr, 300 (long)val); 301 } 302 } 303 304 /* 305 * Pretty-print dispatching function. 306 */ 307 static void 308 db_pprint_type(db_addr_t addr, struct ctf_type_v3 *type, u_int depth) 309 { 310 311 if (db_pager_quit) { 312 return; 313 } 314 if (type == NULL) { 315 db_printf("unknown type"); 316 return; 317 } 318 319 switch (CTF_V3_INFO_KIND(type->ctt_info)) { 320 case CTF_K_INTEGER: 321 db_pprint_int(addr, type, depth); 322 break; 323 case CTF_K_UNION: 324 case CTF_K_STRUCT: 325 db_pprint_struct(addr, type, depth); 326 break; 327 case CTF_K_FUNCTION: 328 case CTF_K_FLOAT: 329 db_indent = depth; 330 db_iprintf("0x%lx", (long)addr); 331 break; 332 case CTF_K_POINTER: 333 db_pprint_ptr(addr, type, depth); 334 break; 335 case CTF_K_TYPEDEF: 336 case CTF_K_VOLATILE: 337 case CTF_K_RESTRICT: 338 case CTF_K_CONST: { 339 struct ctf_type_v3 *ref_type = db_ctf_typeid_to_type(&sym_data, 340 type->ctt_type); 341 db_pprint_type(addr, ref_type, depth); 342 break; 343 } 344 case CTF_K_ENUM: 345 db_pprint_enum(addr, type, depth); 346 break; 347 case CTF_K_ARRAY: 348 db_pprint_arr(addr, type, depth); 349 break; 350 case CTF_K_UNKNOWN: 351 case CTF_K_FORWARD: 352 default: 353 break; 354 } 355 } 356 357 /* 358 * Symbol pretty-printing command. 359 * Syntax: pprint [/d depth] <sym_name> 360 */ 361 static void 362 db_pprint_symbol_cmd(const char *name) 363 { 364 db_addr_t addr; 365 int db_indent_old; 366 const char *type_name = NULL; 367 struct ctf_type_v3 *type = NULL; 368 369 if (db_pager_quit) { 370 return; 371 } 372 /* Clear symbol and CTF info */ 373 memset(&sym_data, 0, sizeof(struct db_ctf_sym_data)); 374 if (db_ctf_find_symbol(name, &sym_data) != 0) { 375 db_error("Symbol not found\n"); 376 } 377 if (ELF_ST_TYPE(sym_data.sym->st_info) != STT_OBJECT) { 378 db_error("Symbol is not a variable\n"); 379 } 380 addr = sym_data.sym->st_value; 381 type = db_ctf_sym_to_type(&sym_data); 382 if (type == NULL) { 383 db_error("Can't find CTF type info\n"); 384 } 385 type_name = db_ctf_stroff_to_str(&sym_data, type->ctt_name); 386 if (type_name != NULL) 387 db_printf("%s ", type_name); 388 db_printf("%s = ", name); 389 390 db_indent_old = db_indent; 391 db_pprint_type(addr, type, 0); 392 db_indent = db_indent_old; 393 } 394 395 /* 396 * Command for pretty-printing arbitrary addresses. 397 * Syntax: pprint [/d depth] struct <struct_name> <addr> 398 */ 399 static void 400 db_pprint_struct_cmd(db_expr_t addr, const char *struct_name) 401 { 402 int db_indent_old; 403 struct ctf_type_v3 *type = NULL; 404 405 type = db_ctf_find_typename(&sym_data, struct_name); 406 if (type == NULL) { 407 db_error("Can't find CTF type info\n"); 408 return; 409 } 410 411 db_printf("struct %s ", struct_name); 412 db_printf("%p = ", (void *)addr); 413 414 db_indent_old = db_indent; 415 db_pprint_type(addr, type, 0); 416 db_indent = db_indent_old; 417 } 418 419 /* 420 * Pretty print an address or a symbol. 421 */ 422 void 423 db_pprint_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif) 424 { 425 int t = 0; 426 const char *name; 427 428 /* Set default depth */ 429 max_depth = DB_PPRINT_DEFAULT_DEPTH; 430 /* Parse print modifiers */ 431 t = db_read_token(); 432 if (t == tSLASH) { 433 t = db_read_token(); 434 if (t != tIDENT) { 435 db_error("Invalid flag passed\n"); 436 } 437 /* Parse desired depth level */ 438 if (strcmp(db_tok_string, "d") == 0) { 439 t = db_read_token(); 440 if (t != tNUMBER) { 441 db_error("Invalid depth provided\n"); 442 } 443 max_depth = db_tok_number; 444 } else { 445 db_error("Invalid flag passed\n"); 446 } 447 /* Fetch next token */ 448 t = db_read_token(); 449 } 450 /* Parse subcomannd */ 451 if (t == tIDENT) { 452 if (strcmp(db_tok_string, "struct") == 0) { 453 t = db_read_token(); 454 455 if (t != tIDENT) { 456 db_error("Invalid struct type name provided\n"); 457 } 458 name = db_tok_string; 459 460 if (db_expression(&addr) == 0) { 461 db_error("Address not provided\n"); 462 } 463 db_pprint_struct_cmd(addr, name); 464 } else { 465 name = db_tok_string; 466 db_pprint_symbol_cmd(name); 467 } 468 } else { 469 db_error("Invalid subcommand\n"); 470 } 471 db_skip_to_eol(); 472 } 473