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 static const char *asteriskstr = "*****"; 49 50 /* 51 * Pretty-prints a CTF_INT type. 52 */ 53 static inline void 54 db_pprint_int(db_addr_t addr, struct ctf_type_v3 *type, u_int depth) 55 { 56 uint32_t data; 57 size_t type_struct_size; 58 59 type_struct_size = (type->ctt_size == CTF_V3_LSIZE_SENT) ? 60 sizeof(struct ctf_type_v3) : 61 sizeof(struct ctf_stype_v3); 62 63 data = db_get_value((db_expr_t)type + type_struct_size, 64 sizeof(uint32_t), 0); 65 u_int bits = CTF_INT_BITS(data); 66 boolean_t sign = !!(CTF_INT_ENCODING(data) & CTF_INT_SIGNED); 67 68 if (db_pager_quit) { 69 return; 70 } 71 if (bits > 64) { 72 db_printf("Invalid size '%d' found for integer type\n", bits); 73 return; 74 } 75 db_printf("0x%lx", 76 (long)db_get_value(addr, (bits / 8) ? (bits / 8) : 1, sign)); 77 } 78 79 /* 80 * Pretty-prints a struct. Nested structs are pretty-printed up 'depth' nested 81 * levels. 82 */ 83 static inline void 84 db_pprint_struct(db_addr_t addr, struct ctf_type_v3 *type, u_int depth) 85 { 86 size_t type_struct_size; 87 size_t struct_size; 88 struct ctf_type_v3 *mtype; 89 const char *mname; 90 db_addr_t maddr; 91 u_int vlen; 92 93 type_struct_size = (type->ctt_size == CTF_V3_LSIZE_SENT) ? 94 sizeof(struct ctf_type_v3) : 95 sizeof(struct ctf_stype_v3); 96 struct_size = ((type->ctt_size == CTF_V3_LSIZE_SENT) ? 97 CTF_TYPE_LSIZE(type) : 98 type->ctt_size); 99 vlen = CTF_V3_INFO_VLEN(type->ctt_info); 100 101 if (db_pager_quit) { 102 return; 103 } 104 if (depth > max_depth) { 105 db_printf("{ ... }"); 106 return; 107 } 108 db_printf("{\n"); 109 110 if (struct_size < CTF_V3_LSTRUCT_THRESH) { 111 struct ctf_member_v3 *mp, *endp; 112 113 mp = (struct ctf_member_v3 *)((db_addr_t)type + 114 type_struct_size); 115 endp = mp + vlen; 116 for (; mp < endp; mp++) { 117 if (db_pager_quit) { 118 return; 119 } 120 mtype = db_ctf_typeid_to_type(&sym_data, mp->ctm_type); 121 maddr = addr + (mp->ctm_offset / NBBY); 122 mname = db_ctf_stroff_to_str(&sym_data, mp->ctm_name); 123 db_indent = depth; 124 if (mname != NULL) { 125 db_iprintf("%s = ", mname); 126 } else { 127 db_iprintf(""); 128 } 129 130 db_pprint_type(maddr, mtype, depth + 1); 131 db_printf(",\n"); 132 } 133 } else { 134 struct ctf_lmember_v3 *mp, *endp; 135 136 mp = (struct ctf_lmember_v3 *)((db_addr_t)type + 137 type_struct_size); 138 endp = mp + vlen; 139 for (; mp < endp; mp++) { 140 if (db_pager_quit) { 141 return; 142 } 143 mtype = db_ctf_typeid_to_type(&sym_data, mp->ctlm_type); 144 maddr = addr + (CTF_LMEM_OFFSET(mp) / NBBY); 145 mname = db_ctf_stroff_to_str(&sym_data, mp->ctlm_name); 146 db_indent = depth; 147 if (mname != NULL) { 148 db_iprintf("%s = ", mname); 149 } else { 150 db_iprintf(""); 151 } 152 153 db_pprint_type(maddr, mtype, depth + 1); 154 db_printf(","); 155 } 156 } 157 db_indent = depth - 1; 158 db_iprintf("}"); 159 } 160 161 /* 162 * Pretty-prints an array. Each array member is printed out in a separate line 163 * indented with 'depth' spaces. 164 */ 165 static inline void 166 db_pprint_arr(db_addr_t addr, struct ctf_type_v3 *type, u_int depth) 167 { 168 struct ctf_type_v3 *elem_type; 169 struct ctf_array_v3 *arr; 170 db_addr_t elem_addr, end; 171 size_t type_struct_size; 172 size_t elem_size; 173 174 type_struct_size = (type->ctt_size == CTF_V3_LSIZE_SENT) ? 175 sizeof(struct ctf_type_v3) : 176 sizeof(struct ctf_stype_v3); 177 arr = (struct ctf_array_v3 *)((db_addr_t)type + type_struct_size); 178 elem_type = db_ctf_typeid_to_type(&sym_data, arr->cta_contents); 179 elem_size = ((elem_type->ctt_size == CTF_V3_LSIZE_SENT) ? 180 CTF_TYPE_LSIZE(elem_type) : 181 elem_type->ctt_size); 182 elem_addr = addr; 183 end = addr + (arr->cta_nelems * elem_size); 184 185 db_indent = depth; 186 db_printf("[\n"); 187 /* Loop through and print individual elements. */ 188 for (; elem_addr < end; elem_addr += elem_size) { 189 if (db_pager_quit) { 190 return; 191 } 192 db_iprintf(""); 193 db_pprint_type(elem_addr, elem_type, depth); 194 if ((elem_addr + elem_size) < end) { 195 db_printf(",\n"); 196 } 197 } 198 db_printf("\n"); 199 db_indent = depth - 1; 200 db_iprintf("]"); 201 } 202 203 /* 204 * Pretty-prints an enum value. Also prints out symbolic name of value, if any. 205 */ 206 static inline void 207 db_pprint_enum(db_addr_t addr, struct ctf_type_v3 *type, u_int depth) 208 { 209 struct ctf_enum *ep, *endp; 210 size_t type_struct_size; 211 const char *valname; 212 db_expr_t val; 213 u_int vlen; 214 215 type_struct_size = (type->ctt_size == CTF_V3_LSIZE_SENT) ? 216 sizeof(struct ctf_type_v3) : 217 sizeof(struct ctf_stype_v3); 218 vlen = CTF_V3_INFO_VLEN(type->ctt_info); 219 val = db_get_value(addr, sizeof(int), 0); 220 221 if (db_pager_quit) { 222 return; 223 } 224 ep = (struct ctf_enum *)((db_addr_t)type + type_struct_size); 225 endp = ep + vlen; 226 for (; ep < endp; ep++) { 227 if (val == ep->cte_value) { 228 valname = db_ctf_stroff_to_str(&sym_data, ep->cte_name); 229 if (valname != NULL) { 230 db_printf("%s (0x%lx)", valname, (long)val); 231 break; 232 } 233 } 234 } 235 if (ep == endp) 236 db_printf("0x%lx", (long)val); 237 } 238 239 /* 240 * Pretty-prints a pointer. If the 'depth' parameter is less than the 241 * 'max_depth' global var, the pointer is "dereference", i.e. the contents of 242 * the memory it points to are also printed. The value of the pointer is printed 243 * otherwise. 244 */ 245 static inline void 246 db_pprint_ptr(db_addr_t addr, struct ctf_type_v3 *type, u_int depth) 247 { 248 struct ctf_type_v3 *ref_type; 249 const char *qual = ""; 250 const char *name; 251 db_addr_t val; 252 uint32_t tid; 253 u_int kind; 254 int ptrcnt; 255 256 ptrcnt = 1; 257 tid = type->ctt_type; 258 again: 259 ref_type = db_ctf_typeid_to_type(&sym_data, tid); 260 kind = CTF_V3_INFO_KIND(ref_type->ctt_info); 261 switch (kind) { 262 case CTF_K_STRUCT: 263 qual = "struct "; 264 break; 265 case CTF_K_VOLATILE: 266 qual = "volatile "; 267 tid = ref_type->ctt_type; 268 goto again; 269 case CTF_K_CONST: 270 qual = "const "; 271 tid = ref_type->ctt_type; 272 goto again; 273 case CTF_K_RESTRICT: 274 qual = "restrict "; 275 tid = ref_type->ctt_type; 276 goto again; 277 case CTF_K_POINTER: 278 ptrcnt++; 279 tid = ref_type->ctt_type; 280 goto again; 281 case CTF_K_TYPEDEF: 282 tid = ref_type->ctt_type; 283 goto again; 284 default: 285 break; 286 } 287 288 ptrcnt = min(ptrcnt, strlen(asteriskstr)); 289 val = (addr != 0) ? db_get_value(addr, sizeof(db_addr_t), false) : 0; 290 if (depth < max_depth && (val != 0)) { 291 /* Print contents of memory pointed to by this pointer. */ 292 db_pprint_type(val, ref_type, depth + 1); 293 } else { 294 name = db_ctf_stroff_to_str(&sym_data, ref_type->ctt_name); 295 db_indent = depth; 296 if (name != NULL) 297 db_printf("(%s%s %.*s) 0x%lx", qual, name, ptrcnt, 298 asteriskstr, (long)val); 299 else 300 db_printf("(%s %.*s) 0x%lx", qual, ptrcnt, asteriskstr, 301 (long)val); 302 } 303 } 304 305 /* 306 * Pretty-print dispatching function. 307 */ 308 static void 309 db_pprint_type(db_addr_t addr, struct ctf_type_v3 *type, u_int depth) 310 { 311 312 if (db_pager_quit) { 313 return; 314 } 315 if (type == NULL) { 316 db_printf("unknown type"); 317 return; 318 } 319 320 switch (CTF_V3_INFO_KIND(type->ctt_info)) { 321 case CTF_K_INTEGER: 322 db_pprint_int(addr, type, depth); 323 break; 324 case CTF_K_UNION: 325 case CTF_K_STRUCT: 326 db_pprint_struct(addr, type, depth); 327 break; 328 case CTF_K_FUNCTION: 329 case CTF_K_FLOAT: 330 db_indent = depth; 331 db_iprintf("0x%lx", (long)addr); 332 break; 333 case CTF_K_POINTER: 334 db_pprint_ptr(addr, type, depth); 335 break; 336 case CTF_K_TYPEDEF: 337 case CTF_K_VOLATILE: 338 case CTF_K_RESTRICT: 339 case CTF_K_CONST: { 340 struct ctf_type_v3 *ref_type = db_ctf_typeid_to_type(&sym_data, 341 type->ctt_type); 342 db_pprint_type(addr, ref_type, depth); 343 break; 344 } 345 case CTF_K_ENUM: 346 db_pprint_enum(addr, type, depth); 347 break; 348 case CTF_K_ARRAY: 349 db_pprint_arr(addr, type, depth); 350 break; 351 case CTF_K_UNKNOWN: 352 case CTF_K_FORWARD: 353 default: 354 break; 355 } 356 } 357 358 /* 359 * Symbol pretty-printing command. 360 * Syntax: pprint [/d depth] <sym_name> 361 */ 362 static void 363 db_pprint_symbol_cmd(const char *name) 364 { 365 db_addr_t addr; 366 int db_indent_old; 367 const char *type_name = NULL; 368 struct ctf_type_v3 *type = NULL; 369 370 if (db_pager_quit) { 371 return; 372 } 373 /* Clear symbol and CTF info */ 374 memset(&sym_data, 0, sizeof(struct db_ctf_sym_data)); 375 if (db_ctf_find_symbol(name, &sym_data) != 0) { 376 db_error("Symbol not found\n"); 377 } 378 if (ELF_ST_TYPE(sym_data.sym->st_info) != STT_OBJECT) { 379 db_error("Symbol is not a variable\n"); 380 } 381 addr = sym_data.sym->st_value; 382 type = db_ctf_sym_to_type(&sym_data); 383 if (type == NULL) { 384 db_error("Can't find CTF type info\n"); 385 } 386 type_name = db_ctf_stroff_to_str(&sym_data, type->ctt_name); 387 if (type_name != NULL) 388 db_printf("%s ", type_name); 389 db_printf("%s = ", name); 390 391 db_indent_old = db_indent; 392 db_pprint_type(addr, type, 0); 393 db_indent = db_indent_old; 394 } 395 396 /* 397 * Command for pretty-printing arbitrary addresses. 398 * Syntax: pprint [/d depth] struct <struct_name> <addr> 399 */ 400 static void 401 db_pprint_struct_cmd(db_expr_t addr, const char *struct_name) 402 { 403 int db_indent_old; 404 struct ctf_type_v3 *type = NULL; 405 406 type = db_ctf_find_typename(&sym_data, struct_name); 407 if (type == NULL) { 408 db_error("Can't find CTF type info\n"); 409 return; 410 } 411 412 db_printf("struct %s ", struct_name); 413 db_printf("%p = ", (void *)addr); 414 415 db_indent_old = db_indent; 416 db_pprint_type(addr, type, 0); 417 db_indent = db_indent_old; 418 } 419 420 /* 421 * Pretty print an address or a symbol. 422 */ 423 void 424 db_pprint_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif) 425 { 426 int t = 0; 427 const char *name; 428 429 /* Set default depth */ 430 max_depth = DB_PPRINT_DEFAULT_DEPTH; 431 /* Parse print modifiers */ 432 t = db_read_token(); 433 if (t == tSLASH) { 434 t = db_read_token(); 435 if (t != tIDENT) { 436 db_error("Invalid flag passed\n"); 437 } 438 /* Parse desired depth level */ 439 if (strcmp(db_tok_string, "d") == 0) { 440 t = db_read_token(); 441 if (t != tNUMBER) { 442 db_error("Invalid depth provided\n"); 443 } 444 max_depth = db_tok_number; 445 } else { 446 db_error("Invalid flag passed\n"); 447 } 448 /* Fetch next token */ 449 t = db_read_token(); 450 } 451 /* Parse subcomannd */ 452 if (t == tIDENT) { 453 if (strcmp(db_tok_string, "struct") == 0) { 454 t = db_read_token(); 455 456 if (t != tIDENT) { 457 db_error("Invalid struct type name provided\n"); 458 } 459 name = db_tok_string; 460 461 if (db_expression(&addr) == 0) { 462 db_error("Address not provided\n"); 463 } 464 db_pprint_struct_cmd(addr, name); 465 } else { 466 name = db_tok_string; 467 db_pprint_symbol_cmd(name); 468 } 469 } else { 470 db_error("Invalid subcommand\n"); 471 } 472 db_skip_to_eol(); 473 } 474