1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. 29 */ 30 31 /* 32 * Used to dump structures and unions in forth mode. 33 * 34 * structures and unions are a bit more complicated than enums. To make things 35 * just that much more interesting, we have to dump the members in reverse 36 * order, which is nice. But wait! It gets better! For compatibility reasons, 37 * we need to dump the members in reverse-offset order, even if member-specific 38 * mode was used to request the members in something other than that order. 39 * 40 * The header op prints the macro header and saves the type being printed. 41 * 42 * In member-specific mode, the member op will be invoked for each structure 43 * or union member. The member op adds the member name, format, type ID, 44 * and offset to a list, sorted in reverse order by offset. 45 * 46 * The trailer op is called when the structure or enum is complete. If no 47 * members were specifically requested, then the trailer iterates through all 48 * of the members of the structure, pretending they were. Each member is thus 49 * added, in reverse-offset order, to the list used in specific-member mode. 50 * Either way, we then proceed through the list, dumping each member out with 51 * fth_print_member. Structure and union members are printed out differently, 52 * depending on member type, as follows: 53 * 54 * Integer: 55 * Normal integers: ' <format> <offset> <type>-field <name> 56 * <format> defaults to ".d" for enums, ".x" for others 57 * <offset> is the member offset, in bytes. 58 * <type> is "byte", "short", "long", or "ext" for 8-, 16-, 32-, and 59 * 64-bit integers, respectively. 60 * <name> is the name of the member being printed 61 * 62 * Bitfields: ' <format> <shift> <mask> <offset> bits-field <name> 63 * <format> defaults to ".x" 64 * <shift> is the number of times to right-shift the masked value 65 * <mask> use to extract the bit-field value from the read value 66 * <offset> is the member offset, in bytes 67 * <name> is the name of the member being printed 68 * 69 * Float: Ignored 70 * 71 * Pointer: ' <format> <offset> ptr-field <name> 72 * <format> defaults to .x 73 * <offset> is in bytes 74 * <name> is the name of the member being printed 75 * 76 * Array: 77 * Arrays have a content-type-specific prefix, followed by an array 78 * suffix. The resulting line looks like this if the array contents 79 * type is an integer, a pointer, or an enum: 80 * 81 * ' <fldc> ' <fmt> <sz> <elsz> <off> array-field <name> 82 * 83 * The following is printed for array contents that are arrays: 84 * 85 * ' noop ' .x <sz> <elsz> <off> array-field <name> 86 * 87 * The following is printed for array contents that are structs: 88 * 89 * ' noop ' <fmt> <sz> <elsz> <off> array-field <name> 90 * 91 * <fldc> is "c@", "w@", "l@", or "x@", depending on whether array 92 * elements are 8, 16, 32 or 64 bits wide. 93 * <fmt> defaults to ".x" 94 * <sz> is the size of the array, in bytes 95 * <elsz> is the size of the array elements 96 * <off> is the member offset, in bytes 97 * <name> is the nam eof the member being printed 98 * 99 * Struct/Union: ' <format> <offset> struct-field <name> 100 * <format> defaults to ".x" 101 * <offset> is the member offset, in bytes 102 * <name> is the name of the member being printed 103 */ 104 105 #include <stdio.h> 106 #include <stdlib.h> 107 #include <string.h> 108 #include <sys/list.h> 109 110 #include "ctf_headers.h" 111 #include "forth.h" 112 #include "memory.h" 113 114 static ctf_id_t fth_str_curtid; 115 static list_t fth_str_curmems; 116 117 /* 118 * Node type for the member-storage list (fth_str_curmems) built by 119 * fth_struct_members() 120 */ 121 typedef struct fth_str_mem { 122 list_node_t fsm_node; 123 char *fsm_memname; 124 char *fsm_format; 125 ctf_id_t fsm_tid; 126 ulong_t fsm_off; 127 } fth_str_mem_t; 128 129 typedef struct fth_struct_members_data { 130 char *fsmd_strname; 131 char *fsmd_memfilter; 132 char *fsmd_format; 133 int fsmd_matched; 134 } fth_struct_members_data_t; 135 136 static int fth_print_member(fth_str_mem_t *, int); 137 138 /* Comparison routined used to insert members into the fth_str_curmems list */ 139 static int 140 fth_struct_memcmp(void *m1, void *m2) 141 { 142 fth_str_mem_t *mem1 = m1, *mem2 = m2; 143 144 if (mem1->fsm_off < mem2->fsm_off) 145 return (1); 146 else if (mem1->fsm_off > mem2->fsm_off) 147 return (-1); 148 else 149 return (0); 150 } 151 152 static void 153 fth_slist_add(fth_str_mem_t *mem) 154 { 155 fth_str_mem_t *l; 156 157 for (l = list_head(&fth_str_curmems); l != NULL; 158 l = list_next(&fth_str_curmems, l)) { 159 if (fth_struct_memcmp(l, mem) > 0) { 160 list_insert_before(&fth_str_curmems, l, mem); 161 return; 162 } 163 } 164 list_insert_tail(&fth_str_curmems, mem); 165 } 166 167 static void 168 fth_free_str_mem(fth_str_mem_t *mem) 169 { 170 free(mem->fsm_memname); 171 if (mem->fsm_format) 172 free(mem->fsm_format); 173 free(mem); 174 } 175 176 static int 177 fth_struct_header(ctf_id_t tid) 178 { 179 ssize_t sz; 180 181 fth_str_curtid = tid; 182 list_create(&fth_str_curmems, sizeof (fth_str_mem_t), 183 offsetof(fth_str_mem_t, fsm_node)); 184 185 if ((sz = ctf_type_size(ctf, fth_str_curtid)) == CTF_ERR) 186 return (parse_warn("Can't get size for %s", fth_curtype)); 187 188 (void) fprintf(out, "\n"); 189 (void) fprintf(out, "vocabulary %s-words\n", fth_curtype); 190 (void) fprintf(out, "h# %x constant %s-sz\n", sz, fth_curtype); 191 (void) fprintf(out, "%x ' %s-words c-struct .%s\n", sz, fth_curtype, 192 fth_curtype); 193 (void) fprintf(out, "also %s-words definitions\n\n", fth_curtype); 194 195 return (0); 196 } 197 198 /* Print the array prefix for integer and pointer members */ 199 static int 200 fth_print_level(uint_t bits, char *format) 201 { 202 if ((bits & (bits - 1)) != 0 ||(bits % 8) != 0 || bits > 64) { 203 return (parse_warn("Unexpected bit size %d in %s", 204 bits, fth_curtype)); 205 } 206 207 (void) fprintf(out, "' %c@ ' %s", " cw l x"[bits / 8], format); 208 209 return (0); 210 } 211 212 /* 213 * Return the format to be used to print the member. If one of the builtin 214 * formats "d" or "x" were specified, return ".d" or ".x", respectively. 215 * Otherwise, use the user-provided format as is, or use the default if none 216 * was provided. 217 */ 218 static char * 219 fth_convert_format(char *format, char *def) 220 { 221 static char dot[3] = "."; 222 223 if (format == NULL) 224 return (def); 225 else if (strlen(format) == 1) { 226 dot[1] = *format; 227 return (dot); 228 } else 229 return (format); 230 } 231 232 static int 233 fth_print_integer(const char *memname, ulong_t off, uint_t bits, char *format, 234 int level) 235 { 236 format = fth_convert_format(format, ".x"); 237 238 if (bits > 64) { 239 return (parse_warn("%s.%s is too large (>8 bytes)", 240 fth_curtype, memname)); 241 } 242 243 if (level != 0) 244 return (fth_print_level(bits, format)); 245 246 if ((bits % NBBY) != 0 || (bits & (bits - 1)) != 0) { 247 /* bit field */ 248 uint_t offset, shift, mask; 249 250 offset = (off / 32) * 4; 251 shift = 32 - ((off % 32) + bits); 252 mask = ((1 << bits) - 1) << shift; 253 254 (void) fprintf(out, "' %s %x %x %x bits-field %s\n", 255 format, shift, mask, offset, memname); 256 257 } else { 258 char *type[] = { 259 NULL, "byte", "short", NULL, "long", 260 NULL, NULL, NULL, "ext" 261 }; 262 263 (void) fprintf(out, "' %s %lx %s-field %s\n", format, off / 8, 264 type[bits / 8], memname); 265 } 266 267 return (0); 268 } 269 270 static int 271 fth_print_pointer(const char *memname, ulong_t off, uint_t bits, char *format, 272 int level) 273 { 274 format = fth_convert_format(format, ".x"); 275 276 if (level != 0) 277 return (fth_print_level(bits, format)); 278 279 (void) fprintf(out, "' %s %lx ptr-field %s\n", format, off / 8, 280 memname); 281 282 return (0); 283 } 284 285 static int 286 fth_print_struct(char *memname, ulong_t off, char *format, 287 int level) 288 { 289 format = fth_convert_format(format, ".x"); 290 291 if (level != 0) 292 (void) fprintf(out, "' noop ' %s", format); 293 else { 294 (void) fprintf(out, "' %s %lx struct-field %s\n", format, 295 off / 8, memname); 296 } 297 298 return (0); 299 } 300 301 static int 302 fth_print_enum(char *memname, ulong_t off, char *format, 303 int level) 304 { 305 format = fth_convert_format(format, ".d"); 306 307 if (level != 0) 308 (void) fprintf(out, "' l@ ' %s", format); 309 else { 310 (void) fprintf(out, "' %s %lx long-field %s\n", format, off / 8, 311 memname); 312 } 313 314 return (0); 315 } 316 317 static int 318 fth_print_array(char *memname, ctf_id_t tid, ulong_t off, ssize_t sz, 319 char *format, int level) 320 { 321 if (level != 0) 322 (void) fprintf(out, "' noop ' .x"); 323 else { 324 fth_str_mem_t mem; 325 ctf_arinfo_t ar; 326 327 /* 328 * print the prefix for the array contents type, then print 329 * the array macro 330 */ 331 332 if (ctf_array_info(ctf, tid, &ar) == CTF_ERR) { 333 return (parse_warn("Can't read array in %s.%s", 334 fth_curtype, memname)); 335 } 336 337 mem.fsm_memname = memname; 338 mem.fsm_format = format; 339 mem.fsm_tid = ar.ctr_contents; 340 mem.fsm_off = off; 341 342 if (fth_print_member(&mem, level + 1) < 0) 343 return (-1); 344 345 (void) fprintf(out, " %x %x %lx array-field %s\n", sz, 346 (sz / ar.ctr_nelems), off / 8, memname); 347 } 348 349 return (0); 350 } 351 352 /* dump a structure or union member */ 353 static int 354 fth_print_member(fth_str_mem_t *mem, int level) 355 { 356 ctf_encoding_t e; 357 ctf_id_t tid; 358 int kind; 359 ssize_t sz; 360 361 if ((tid = ctf_type_resolve(ctf, mem->fsm_tid)) == CTF_ERR) { 362 return (parse_warn("Can't resolve %s.%s", fth_curtype, 363 mem->fsm_memname)); 364 } 365 366 if ((kind = ctf_type_kind(ctf, tid)) == CTF_ERR) { 367 return (parse_warn("Can't get kind for %s.%s", 368 fth_curtype, mem->fsm_memname)); 369 } 370 371 if ((sz = ctf_type_size(ctf, tid)) == CTF_ERR) { 372 return (parse_warn("Can't get size for %s.%s", 373 fth_curtype, mem->fsm_memname)); 374 } 375 376 switch (kind) { 377 case CTF_K_INTEGER: 378 if (ctf_type_encoding(ctf, tid, &e) == CTF_ERR) 379 return (parse_warn("Can't get encoding for %ld", tid)); 380 381 return (fth_print_integer(mem->fsm_memname, mem->fsm_off, 382 e.cte_bits, mem->fsm_format, level)); 383 384 case CTF_K_FLOAT: 385 (void) parse_warn("Ignoring floating point member %s.%s", 386 fth_curtype, mem->fsm_memname); 387 return (0); 388 389 case CTF_K_POINTER: 390 return (fth_print_pointer(mem->fsm_memname, mem->fsm_off, 391 sz * 8, mem->fsm_format, level)); 392 393 case CTF_K_ARRAY: 394 return (fth_print_array(mem->fsm_memname, tid, mem->fsm_off, sz, 395 mem->fsm_format, level)); 396 397 case CTF_K_STRUCT: 398 case CTF_K_UNION: 399 return (fth_print_struct(mem->fsm_memname, mem->fsm_off, 400 mem->fsm_format, level)); 401 402 case CTF_K_ENUM: 403 return (fth_print_enum(mem->fsm_memname, mem->fsm_off, 404 mem->fsm_format, level)); 405 406 case CTF_K_FORWARD: 407 return (parse_warn("Type %ld in %s.%s is undefined", tid, 408 fth_curtype, mem->fsm_memname)); 409 410 default: 411 return (parse_warn("Unexpected kind %d for %s.%s", kind, 412 fth_curtype, mem->fsm_memname)); 413 } 414 } 415 416 /* 417 * Add a member to list of members to be printed (fth_str_curmems). If 418 * fsmd_memfilter is non-null, only add this member if its name matches that 419 * in the filter. 420 */ 421 static int 422 fth_struct_members_cb(const char *memname, ctf_id_t tid, ulong_t off, void *arg) 423 { 424 fth_struct_members_data_t *fsmd = arg; 425 fth_str_mem_t *mem; 426 427 if (fsmd->fsmd_memfilter != NULL && strcmp(fsmd->fsmd_memfilter, 428 memname) != 0) 429 return (0); 430 431 fsmd->fsmd_matched = 1; 432 433 mem = xcalloc(sizeof (fth_str_mem_t)); 434 mem->fsm_memname = xstrdup(memname); 435 if (fsmd->fsmd_format) 436 mem->fsm_format = xstrdup(fsmd->fsmd_format); 437 mem->fsm_tid = tid; 438 mem->fsm_off = off; 439 440 fth_slist_add(mem); 441 442 return (0); 443 } 444 445 /* 446 * If memfilter is non-null, iterate through the members of this type, causing 447 * every member to be added to the list. Otherwise, use the iterator and 448 * the callback to add only the specified member. 449 */ 450 static int 451 fth_struct_members(char *memfilter, char *format) 452 { 453 fth_struct_members_data_t fsmd; 454 455 fsmd.fsmd_strname = fth_curtype; 456 fsmd.fsmd_memfilter = memfilter; 457 fsmd.fsmd_format = format; 458 fsmd.fsmd_matched = 0; 459 460 if (ctf_member_iter(ctf, fth_str_curtid, fth_struct_members_cb, 461 &fsmd) != 0) 462 return (-1); 463 464 if (memfilter != NULL && fsmd.fsmd_matched == 0) { 465 return (parse_warn("Invalid member %s.%s", fth_curtype, 466 memfilter)); 467 } 468 469 return (0); 470 } 471 472 static int 473 fth_struct_trailer(void) 474 { 475 fth_str_mem_t *mem; 476 477 if (list_is_empty(&fth_str_curmems)) { 478 if (fth_struct_members(NULL, NULL) < 0) 479 return (-1); 480 } 481 482 while ((mem = list_remove_head(&fth_str_curmems)) != NULL) { 483 if (fth_print_member(mem, 0) < 0) 484 return (-1); 485 486 fth_free_str_mem(mem); 487 } 488 list_destroy(&fth_str_curmems); 489 490 (void) fprintf(out, "\n"); 491 (void) fprintf(out, "kdbg-words definitions\n"); 492 (void) fprintf(out, "previous\n"); 493 (void) fprintf(out, "\n"); 494 (void) fprintf(out, "\\ end %s section\n", fth_curtype); 495 (void) fprintf(out, "\n"); 496 497 return (0); 498 } 499 500 fth_type_ops_t fth_struct_ops = { 501 fth_struct_header, 502 fth_struct_members, 503 fth_struct_trailer 504 }; 505