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