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 else 231 db_printf("(0x%lx)", (long)val); 232 break; 233 } 234 } 235 } 236 237 /* 238 * Pretty-prints a pointer. If the 'depth' parameter is less than the 239 * 'max_depth' global var, the pointer is "dereference", i.e. the contents of 240 * the memory it points to are also printed. The value of the pointer is printed 241 * otherwise. 242 */ 243 static inline void 244 db_pprint_ptr(db_addr_t addr, struct ctf_type_v3 *type, u_int depth) 245 { 246 struct ctf_type_v3 *ref_type; 247 const char *qual = ""; 248 const char *name; 249 db_addr_t val; 250 u_int kind; 251 252 ref_type = db_ctf_typeid_to_type(&sym_data, type->ctt_type); 253 kind = CTF_V3_INFO_KIND(ref_type->ctt_info); 254 switch (kind) { 255 case CTF_K_STRUCT: 256 qual = "struct "; 257 break; 258 case CTF_K_VOLATILE: 259 qual = "volatile "; 260 break; 261 case CTF_K_CONST: 262 qual = "const "; 263 break; 264 default: 265 break; 266 } 267 268 val = db_get_value(addr, sizeof(db_addr_t), false); 269 if (depth < max_depth) { 270 /* Print contents of memory pointed to by this pointer. */ 271 db_pprint_type(addr, ref_type, depth + 1); 272 } else { 273 name = db_ctf_stroff_to_str(&sym_data, ref_type->ctt_name); 274 db_indent = depth; 275 if (name != NULL) 276 db_printf("(%s%s *) 0x%lx", qual, name, (long)val); 277 else 278 db_printf("0x%lx", (long)val); 279 } 280 } 281 282 /* 283 * Pretty-print dispatching function. 284 */ 285 static void 286 db_pprint_type(db_addr_t addr, struct ctf_type_v3 *type, u_int depth) 287 { 288 289 if (db_pager_quit) { 290 return; 291 } 292 if (type == NULL) { 293 db_printf("unknown type"); 294 return; 295 } 296 297 switch (CTF_V3_INFO_KIND(type->ctt_info)) { 298 case CTF_K_INTEGER: 299 db_pprint_int(addr, type, depth); 300 break; 301 case CTF_K_UNION: 302 case CTF_K_STRUCT: 303 db_pprint_struct(addr, type, depth); 304 break; 305 case CTF_K_FUNCTION: 306 case CTF_K_FLOAT: 307 db_indent = depth; 308 db_iprintf("0x%lx", (long)addr); 309 break; 310 case CTF_K_POINTER: 311 db_pprint_ptr(addr, type, depth); 312 break; 313 case CTF_K_TYPEDEF: 314 case CTF_K_VOLATILE: 315 case CTF_K_RESTRICT: 316 case CTF_K_CONST: { 317 struct ctf_type_v3 *ref_type = db_ctf_typeid_to_type(&sym_data, 318 type->ctt_type); 319 db_pprint_type(addr, ref_type, depth); 320 break; 321 } 322 case CTF_K_ENUM: 323 db_pprint_enum(addr, type, depth); 324 break; 325 case CTF_K_ARRAY: 326 db_pprint_arr(addr, type, depth); 327 break; 328 case CTF_K_UNKNOWN: 329 case CTF_K_FORWARD: 330 default: 331 break; 332 } 333 } 334 335 /* 336 * Symbol pretty-printing command. 337 * Syntax: pprint [/d depth] <sym_name> 338 */ 339 static void 340 db_pprint_symbol_cmd(const char *name) 341 { 342 db_addr_t addr; 343 int db_indent_old; 344 const char *type_name = NULL; 345 struct ctf_type_v3 *type = NULL; 346 347 if (db_pager_quit) { 348 return; 349 } 350 /* Clear symbol and CTF info */ 351 memset(&sym_data, 0, sizeof(struct db_ctf_sym_data)); 352 if (db_ctf_find_symbol(name, &sym_data) != 0) { 353 db_error("Symbol not found\n"); 354 } 355 if (ELF_ST_TYPE(sym_data.sym->st_info) != STT_OBJECT) { 356 db_error("Symbol is not a variable\n"); 357 } 358 addr = sym_data.sym->st_value; 359 type = db_ctf_sym_to_type(&sym_data); 360 if (type == NULL) { 361 db_error("Can't find CTF type info\n"); 362 } 363 type_name = db_ctf_stroff_to_str(&sym_data, type->ctt_name); 364 if (type_name != NULL) 365 db_printf("%s ", type_name); 366 db_printf("%s = ", name); 367 368 db_indent_old = db_indent; 369 db_pprint_type(addr, type, 0); 370 db_indent = db_indent_old; 371 } 372 373 /* 374 * Command for pretty-printing arbitrary addresses. 375 * Syntax: pprint [/d depth] struct <struct_name> <addr> 376 */ 377 static void 378 db_pprint_struct_cmd(db_expr_t addr, const char *struct_name) 379 { 380 int db_indent_old; 381 struct ctf_type_v3 *type = NULL; 382 383 type = db_ctf_find_typename(&sym_data, struct_name); 384 if (type == NULL) { 385 db_error("Can't find CTF type info\n"); 386 return; 387 } 388 389 db_printf("struct %s ", struct_name); 390 db_printf("%p = ", (void *)addr); 391 392 db_indent_old = db_indent; 393 db_pprint_type(addr, type, 0); 394 db_indent = db_indent_old; 395 } 396 397 /* 398 * Pretty print an address or a symbol. 399 */ 400 void 401 db_pprint_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif) 402 { 403 int t = 0; 404 const char *name; 405 406 /* Set default depth */ 407 max_depth = DB_PPRINT_DEFAULT_DEPTH; 408 /* Parse print modifiers */ 409 t = db_read_token(); 410 if (t == tSLASH) { 411 t = db_read_token(); 412 if (t != tIDENT) { 413 db_error("Invalid flag passed\n"); 414 } 415 /* Parse desired depth level */ 416 if (strcmp(db_tok_string, "d") == 0) { 417 t = db_read_token(); 418 if (t != tNUMBER) { 419 db_error("Invalid depth provided\n"); 420 } 421 max_depth = db_tok_number; 422 } else { 423 db_error("Invalid flag passed\n"); 424 } 425 /* Fetch next token */ 426 t = db_read_token(); 427 } 428 /* Parse subcomannd */ 429 if (t == tIDENT) { 430 if (strcmp(db_tok_string, "struct") == 0) { 431 t = db_read_token(); 432 433 if (t != tIDENT) { 434 db_error("Invalid struct type name provided\n"); 435 } 436 name = db_tok_string; 437 438 if (db_expression(&addr) == 0) { 439 db_error("Address not provided\n"); 440 } 441 db_pprint_struct_cmd(addr, name); 442 } else { 443 name = db_tok_string; 444 db_pprint_symbol_cmd(name); 445 } 446 } else { 447 db_error("Invalid subcommand\n"); 448 } 449 db_skip_to_eol(); 450 } 451