1*949c1c4eSmiod /* $OpenBSD: db_ctf.c,v 1.35 2024/11/07 16:02:29 miod Exp $ */ 2fd68ecf3Sjasper 3fd68ecf3Sjasper /* 48cd47547Smpi * Copyright (c) 2016-2017 Martin Pieuchot 5fd68ecf3Sjasper * Copyright (c) 2016 Jasper Lievisse Adriaanse <jasper@openbsd.org> 6fd68ecf3Sjasper * 7fd68ecf3Sjasper * Permission to use, copy, modify, and distribute this software for any 8fd68ecf3Sjasper * purpose with or without fee is hereby granted, provided that the above 9fd68ecf3Sjasper * copyright notice and this permission notice appear in all copies. 10fd68ecf3Sjasper * 11fd68ecf3Sjasper * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12fd68ecf3Sjasper * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13fd68ecf3Sjasper * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14fd68ecf3Sjasper * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15fd68ecf3Sjasper * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16fd68ecf3Sjasper * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17fd68ecf3Sjasper * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18fd68ecf3Sjasper */ 19fd68ecf3Sjasper 20fd68ecf3Sjasper #include <sys/param.h> 21b27348b2Sderaadt #include <sys/stdint.h> 22fd68ecf3Sjasper #include <sys/systm.h> 23fd68ecf3Sjasper #include <sys/exec.h> 24fd68ecf3Sjasper 25fd68ecf3Sjasper #include <machine/db_machdep.h> 26fd68ecf3Sjasper 27fd68ecf3Sjasper #include <ddb/db_extern.h> 28ad205586Smpi #include <ddb/db_command.h> 29fd68ecf3Sjasper #include <ddb/db_elf.h> 30ad205586Smpi #include <ddb/db_lex.h> 31fd68ecf3Sjasper #include <ddb/db_output.h> 32ad205586Smpi #include <ddb/db_sym.h> 330488a471Sdlg #include <ddb/db_access.h> 34fd68ecf3Sjasper 35fd68ecf3Sjasper #include <sys/exec_elf.h> 362c89ed74Sjasper #include <sys/ctf.h> 37fd68ecf3Sjasper #include <sys/malloc.h> 38fd68ecf3Sjasper #include <lib/libz/zlib.h> 39fd68ecf3Sjasper 40fd68ecf3Sjasper extern db_symtab_t db_symtab; 41fd68ecf3Sjasper 42fd68ecf3Sjasper struct ddb_ctf { 43fd68ecf3Sjasper struct ctf_header *cth; 44b42aa555Smpi const char *rawctf; /* raw .SUNW_ctf section */ 45b42aa555Smpi size_t rawctflen; /* raw .SUNW_ctf section size */ 46b42aa555Smpi const char *data; /* decompressed CTF data */ 47b42aa555Smpi size_t dlen; /* decompressed CTF data size */ 48*949c1c4eSmiod const char *strtab; /* ELF string table */ 49ba42e451Smpi uint32_t ctf_found; 50fd68ecf3Sjasper }; 51fd68ecf3Sjasper 52fd68ecf3Sjasper struct ddb_ctf db_ctf; 53fd68ecf3Sjasper 54ad205586Smpi static const char *db_ctf_off2name(uint32_t); 553dc63949Smpi static Elf_Sym *db_ctf_idx2sym(size_t *, uint8_t); 5627fc743bSmillert static char *db_ctf_decompress(const char *, size_t, size_t); 57fd68ecf3Sjasper 58609e0b1cSclaudio uint32_t db_ctf_type_len(const struct ctf_type *); 59609e0b1cSclaudio size_t db_ctf_type_size(const struct ctf_type *); 60266ad235Sdlg const struct ctf_type *db_ctf_type_by_name(const char *, unsigned int); 61ad205586Smpi const struct ctf_type *db_ctf_type_by_symbol(Elf_Sym *); 62ad205586Smpi const struct ctf_type *db_ctf_type_by_index(uint16_t); 638c31a435Sjasper void db_ctf_pprint(const struct ctf_type *, vaddr_t); 64ad205586Smpi void db_ctf_pprint_struct(const struct ctf_type *, vaddr_t); 65609e0b1cSclaudio void db_ctf_pprint_enum(const struct ctf_type *, vaddr_t); 66bebdad71Smpi void db_ctf_pprint_ptr(const struct ctf_type *, vaddr_t); 67ad205586Smpi 68fd68ecf3Sjasper /* 69fd68ecf3Sjasper * Entrypoint to verify CTF presence, initialize the header, decompress 70fd68ecf3Sjasper * the data, etc. 71fd68ecf3Sjasper */ 72fd68ecf3Sjasper void 73fd68ecf3Sjasper db_ctf_init(void) 74fd68ecf3Sjasper { 75fd68ecf3Sjasper db_symtab_t *stab = &db_symtab; 76b42aa555Smpi size_t rawctflen; 77fd68ecf3Sjasper 78fd68ecf3Sjasper /* Assume nothing was correct found until proven otherwise. */ 79fd68ecf3Sjasper db_ctf.ctf_found = 0; 80fd68ecf3Sjasper 81b42aa555Smpi if (stab->private == NULL) 82fd68ecf3Sjasper return; 83fd68ecf3Sjasper 84b42aa555Smpi db_ctf.strtab = db_elf_find_strtab(stab); 85b42aa555Smpi if (db_ctf.strtab == NULL) 86b42aa555Smpi return; 87b42aa555Smpi 884916abc8Smpi db_ctf.rawctf = db_elf_find_section(stab, &rawctflen, ELF_CTF); 89b42aa555Smpi if (db_ctf.rawctf == NULL) 90b42aa555Smpi return; 91b42aa555Smpi 92b42aa555Smpi db_ctf.rawctflen = rawctflen; 93b42aa555Smpi db_ctf.cth = (struct ctf_header *)db_ctf.rawctf; 94fd68ecf3Sjasper db_ctf.dlen = db_ctf.cth->cth_stroff + db_ctf.cth->cth_strlen; 95fd68ecf3Sjasper 96b42aa555Smpi if ((db_ctf.cth->cth_flags & CTF_F_COMPRESS) == 0) { 971c302ed1Sjasper db_printf("unsupported non-compressed CTF section\n"); 98fd68ecf3Sjasper return; 99fd68ecf3Sjasper } 100fd68ecf3Sjasper 101b42aa555Smpi /* Now decompress the section, take into account to skip the header */ 102b42aa555Smpi db_ctf.data = db_ctf_decompress(db_ctf.rawctf + sizeof(*db_ctf.cth), 103b42aa555Smpi db_ctf.rawctflen - sizeof(*db_ctf.cth), db_ctf.dlen); 104b42aa555Smpi if (db_ctf.data == NULL) 105fd68ecf3Sjasper return; 106fd68ecf3Sjasper 107fd68ecf3Sjasper /* We made it this far, everything seems fine. */ 108fd68ecf3Sjasper db_ctf.ctf_found = 1; 109fd68ecf3Sjasper } 110fd68ecf3Sjasper 111fd68ecf3Sjasper /* 112fd68ecf3Sjasper * Convert an index to a symbol name while ensuring the type is matched. 113fd68ecf3Sjasper * It must be noted this only works if the CTF table has the same order 114fd68ecf3Sjasper * as the symbol table. 115fd68ecf3Sjasper */ 1163dc63949Smpi Elf_Sym * 117ba42e451Smpi db_ctf_idx2sym(size_t *idx, uint8_t type) 118fd68ecf3Sjasper { 119b42aa555Smpi Elf_Sym *symp, *symtab_start, *symtab_end; 120b42aa555Smpi size_t i = *idx + 1; 121fd68ecf3Sjasper 122b42aa555Smpi symtab_start = STAB_TO_SYMSTART(&db_symtab); 123b42aa555Smpi symtab_end = STAB_TO_SYMEND(&db_symtab); 124fd68ecf3Sjasper 125b42aa555Smpi for (symp = &symtab_start[i]; symp < symtab_end; i++, symp++) { 126b42aa555Smpi if (ELF_ST_TYPE(symp->st_info) != type) 127fd68ecf3Sjasper continue; 128fd68ecf3Sjasper 129fd68ecf3Sjasper *idx = i; 1303dc63949Smpi return symp; 131fd68ecf3Sjasper } 132fd68ecf3Sjasper 133b42aa555Smpi return NULL; 134fd68ecf3Sjasper } 135fd68ecf3Sjasper 136fd68ecf3Sjasper /* 137fd68ecf3Sjasper * For a given function name, return the number of arguments. 138fd68ecf3Sjasper */ 139fd68ecf3Sjasper int 14062781896Smpi db_ctf_func_numargs(Elf_Sym *st) 141fd68ecf3Sjasper { 142ad205586Smpi Elf_Sym *symp; 143b42aa555Smpi uint16_t *fstart, *fend; 144ba42e451Smpi uint16_t *fsp, kind, vlen; 145b42aa555Smpi size_t i, idx = 0; 146fd68ecf3Sjasper 147ad205586Smpi if (!db_ctf.ctf_found || st == NULL) 148ed3d2e34Smpi return -1; 149fd68ecf3Sjasper 150b42aa555Smpi fstart = (uint16_t *)(db_ctf.data + db_ctf.cth->cth_funcoff); 151b42aa555Smpi fend = (uint16_t *)(db_ctf.data + db_ctf.cth->cth_typeoff); 152fd68ecf3Sjasper 153b42aa555Smpi fsp = fstart; 154b42aa555Smpi while (fsp < fend) { 1553dc63949Smpi symp = db_ctf_idx2sym(&idx, STT_FUNC); 1563dc63949Smpi if (symp == NULL) 157b42aa555Smpi break; 158fd68ecf3Sjasper 159fd68ecf3Sjasper kind = CTF_INFO_KIND(*fsp); 160fd68ecf3Sjasper vlen = CTF_INFO_VLEN(*fsp); 161fd68ecf3Sjasper fsp++; 162fd68ecf3Sjasper 163fd68ecf3Sjasper if (kind == CTF_K_UNKNOWN && vlen == 0) 164fd68ecf3Sjasper continue; 165fd68ecf3Sjasper 166b42aa555Smpi /* Skip return type */ 167b42aa555Smpi fsp++; 168b42aa555Smpi 169b42aa555Smpi /* Skip argument types */ 170b42aa555Smpi for (i = 0; i < vlen; i++) 171b42aa555Smpi fsp++; 172b42aa555Smpi 173ad205586Smpi if (symp == st) 174b42aa555Smpi return vlen; 175fd68ecf3Sjasper } 176b42aa555Smpi 1773998cbb6Smpi return 0; 178fd68ecf3Sjasper } 179fd68ecf3Sjasper 180ad205586Smpi /* 181ad205586Smpi * Return the length of the type record in the CTF section. 182ad205586Smpi */ 183ad205586Smpi uint32_t 184ad205586Smpi db_ctf_type_len(const struct ctf_type *ctt) 185ad205586Smpi { 186ad205586Smpi uint16_t kind, vlen, i; 187ad205586Smpi uint32_t tlen; 188ad205586Smpi uint64_t size; 189ad205586Smpi 190ad205586Smpi kind = CTF_INFO_KIND(ctt->ctt_info); 191ad205586Smpi vlen = CTF_INFO_VLEN(ctt->ctt_info); 192ad205586Smpi 193ad205586Smpi if (ctt->ctt_size <= CTF_MAX_SIZE) { 194ad205586Smpi size = ctt->ctt_size; 195ad205586Smpi tlen = sizeof(struct ctf_stype); 196ad205586Smpi } else { 197ad205586Smpi size = CTF_TYPE_LSIZE(ctt); 198ad205586Smpi tlen = sizeof(struct ctf_type); 199ad205586Smpi } 200ad205586Smpi 201ad205586Smpi switch (kind) { 202ad205586Smpi case CTF_K_UNKNOWN: 203ad205586Smpi case CTF_K_FORWARD: 204ad205586Smpi break; 205ad205586Smpi case CTF_K_INTEGER: 206ad205586Smpi tlen += sizeof(uint32_t); 207ad205586Smpi break; 208ad205586Smpi case CTF_K_FLOAT: 209ad205586Smpi tlen += sizeof(uint32_t); 210ad205586Smpi break; 211ad205586Smpi case CTF_K_ARRAY: 212ad205586Smpi tlen += sizeof(struct ctf_array); 213ad205586Smpi break; 214ad205586Smpi case CTF_K_FUNCTION: 215ad205586Smpi tlen += (vlen + (vlen & 1)) * sizeof(uint16_t); 216ad205586Smpi break; 217ad205586Smpi case CTF_K_STRUCT: 218ad205586Smpi case CTF_K_UNION: 219ad205586Smpi if (size < CTF_LSTRUCT_THRESH) { 220ad205586Smpi for (i = 0; i < vlen; i++) { 221ad205586Smpi tlen += sizeof(struct ctf_member); 222ad205586Smpi } 223ad205586Smpi } else { 224ad205586Smpi for (i = 0; i < vlen; i++) { 225ad205586Smpi tlen += sizeof(struct ctf_lmember); 226ad205586Smpi } 227ad205586Smpi } 228ad205586Smpi break; 229ad205586Smpi case CTF_K_ENUM: 230ad205586Smpi for (i = 0; i < vlen; i++) { 231ad205586Smpi tlen += sizeof(struct ctf_enum); 232ad205586Smpi } 233ad205586Smpi break; 234ad205586Smpi case CTF_K_POINTER: 235ad205586Smpi case CTF_K_TYPEDEF: 236ad205586Smpi case CTF_K_VOLATILE: 237ad205586Smpi case CTF_K_CONST: 238ad205586Smpi case CTF_K_RESTRICT: 239ad205586Smpi break; 240ad205586Smpi default: 241ad205586Smpi return 0; 242ad205586Smpi } 243ad205586Smpi 244ad205586Smpi return tlen; 245ad205586Smpi } 246ad205586Smpi 2478cd47547Smpi /* 248609e0b1cSclaudio * Return the size of the type. 249609e0b1cSclaudio */ 250609e0b1cSclaudio size_t 251609e0b1cSclaudio db_ctf_type_size(const struct ctf_type *ctt) 252609e0b1cSclaudio { 253609e0b1cSclaudio vaddr_t taddr = (vaddr_t)ctt; 254609e0b1cSclaudio const struct ctf_type *ref; 255609e0b1cSclaudio const struct ctf_array *arr; 256609e0b1cSclaudio size_t tlen = 0; 257609e0b1cSclaudio uint16_t kind; 258609e0b1cSclaudio uint32_t toff; 259609e0b1cSclaudio uint64_t size; 260609e0b1cSclaudio 261609e0b1cSclaudio kind = CTF_INFO_KIND(ctt->ctt_info); 262609e0b1cSclaudio 263609e0b1cSclaudio if (ctt->ctt_size <= CTF_MAX_SIZE) { 264609e0b1cSclaudio size = ctt->ctt_size; 265609e0b1cSclaudio toff = sizeof(struct ctf_stype); 266609e0b1cSclaudio } else { 267609e0b1cSclaudio size = CTF_TYPE_LSIZE(ctt); 268609e0b1cSclaudio toff = sizeof(struct ctf_type); 269609e0b1cSclaudio } 270609e0b1cSclaudio 271609e0b1cSclaudio switch (kind) { 272609e0b1cSclaudio case CTF_K_UNKNOWN: 273609e0b1cSclaudio case CTF_K_FORWARD: 274609e0b1cSclaudio break; 275609e0b1cSclaudio case CTF_K_INTEGER: 276609e0b1cSclaudio case CTF_K_FLOAT: 277609e0b1cSclaudio tlen = size; 278609e0b1cSclaudio break; 279609e0b1cSclaudio case CTF_K_ARRAY: 280609e0b1cSclaudio arr = (struct ctf_array *)(taddr + toff); 281609e0b1cSclaudio ref = db_ctf_type_by_index(arr->cta_contents); 282609e0b1cSclaudio tlen = arr->cta_nelems * db_ctf_type_size(ref); 283609e0b1cSclaudio break; 284609e0b1cSclaudio case CTF_K_FUNCTION: 285609e0b1cSclaudio tlen = 0; 286609e0b1cSclaudio break; 287609e0b1cSclaudio case CTF_K_STRUCT: 288609e0b1cSclaudio case CTF_K_UNION: 289609e0b1cSclaudio case CTF_K_ENUM: 290609e0b1cSclaudio tlen = size; 291609e0b1cSclaudio break; 292609e0b1cSclaudio case CTF_K_POINTER: 293609e0b1cSclaudio tlen = sizeof(void *); 294609e0b1cSclaudio break; 295609e0b1cSclaudio case CTF_K_TYPEDEF: 296609e0b1cSclaudio case CTF_K_VOLATILE: 297609e0b1cSclaudio case CTF_K_CONST: 298609e0b1cSclaudio case CTF_K_RESTRICT: 299609e0b1cSclaudio ref = db_ctf_type_by_index(ctt->ctt_type); 300609e0b1cSclaudio tlen = db_ctf_type_size(ref); 301609e0b1cSclaudio break; 302609e0b1cSclaudio default: 303609e0b1cSclaudio return 0; 304609e0b1cSclaudio } 305609e0b1cSclaudio 306609e0b1cSclaudio return tlen; 307609e0b1cSclaudio } 308609e0b1cSclaudio 309609e0b1cSclaudio /* 3108cd47547Smpi * Return the CTF type associated to an ELF symbol. 3118cd47547Smpi */ 312ad205586Smpi const struct ctf_type * 313ad205586Smpi db_ctf_type_by_symbol(Elf_Sym *st) 314ad205586Smpi { 315ad205586Smpi Elf_Sym *symp; 316ece49713Sjasper uint32_t objtoff; 317ad205586Smpi uint16_t *dsp; 318ad205586Smpi size_t idx = 0; 319ad205586Smpi 32016be3460Smpi if (!db_ctf.ctf_found || st == NULL) 32116be3460Smpi return NULL; 32216be3460Smpi 323ece49713Sjasper objtoff = db_ctf.cth->cth_objtoff; 324ece49713Sjasper 325ad205586Smpi while (objtoff < db_ctf.cth->cth_funcoff) { 326ad205586Smpi dsp = (uint16_t *)(db_ctf.data + objtoff); 327ad205586Smpi 328ad205586Smpi symp = db_ctf_idx2sym(&idx, STT_OBJECT); 329ad205586Smpi if (symp == NULL) 330ad205586Smpi break; 331ad205586Smpi if (symp == st) 332ad205586Smpi return db_ctf_type_by_index(*dsp); 333ad205586Smpi 334ad205586Smpi objtoff += sizeof(*dsp); 335ad205586Smpi } 336ad205586Smpi 337ad205586Smpi return NULL; 338ad205586Smpi } 339ad205586Smpi 340266ad235Sdlg const struct ctf_type * 341266ad235Sdlg db_ctf_type_by_name(const char *name, unsigned int kind) 342266ad235Sdlg { 343266ad235Sdlg struct ctf_header *cth; 344266ad235Sdlg const struct ctf_type *ctt; 345266ad235Sdlg const char *tname; 346266ad235Sdlg uint32_t off, toff; 347266ad235Sdlg 348266ad235Sdlg if (!db_ctf.ctf_found) 349266ad235Sdlg return (NULL); 350266ad235Sdlg 351266ad235Sdlg cth = db_ctf.cth; 352266ad235Sdlg 353266ad235Sdlg for (off = cth->cth_typeoff; off < cth->cth_stroff; off += toff) { 354266ad235Sdlg ctt = (struct ctf_type *)(db_ctf.data + off); 355266ad235Sdlg toff = db_ctf_type_len(ctt); 356266ad235Sdlg if (toff == 0) { 357266ad235Sdlg db_printf("incorrect type at offset %u", off); 358266ad235Sdlg break; 359266ad235Sdlg } 360266ad235Sdlg 361266ad235Sdlg if (CTF_INFO_KIND(ctt->ctt_info) != kind) 362266ad235Sdlg continue; 363266ad235Sdlg 364266ad235Sdlg tname = db_ctf_off2name(ctt->ctt_name); 365266ad235Sdlg if (tname == NULL) 366266ad235Sdlg continue; 367266ad235Sdlg 368266ad235Sdlg if (strcmp(name, tname) == 0) 369266ad235Sdlg return (ctt); 370266ad235Sdlg } 371266ad235Sdlg 372266ad235Sdlg return (NULL); 373266ad235Sdlg } 374266ad235Sdlg 3758cd47547Smpi /* 3768cd47547Smpi * Return the CTF type corresponding to a given index in the type section. 3778cd47547Smpi */ 378ad205586Smpi const struct ctf_type * 379ad205586Smpi db_ctf_type_by_index(uint16_t index) 380ad205586Smpi { 381ad205586Smpi uint32_t offset = db_ctf.cth->cth_typeoff; 382ad205586Smpi uint16_t idx = 1; 383ad205586Smpi 384ad205586Smpi if (!db_ctf.ctf_found) 385ad205586Smpi return NULL; 386ad205586Smpi 387ad205586Smpi while (offset < db_ctf.cth->cth_stroff) { 388ad205586Smpi const struct ctf_type *ctt; 389ad205586Smpi uint32_t toff; 390ad205586Smpi 391ad205586Smpi ctt = (struct ctf_type *)(db_ctf.data + offset); 392ad205586Smpi if (idx == index) 393ad205586Smpi return ctt; 394ad205586Smpi 395ad205586Smpi toff = db_ctf_type_len(ctt); 396ad205586Smpi if (toff == 0) { 397ad205586Smpi db_printf("incorrect type at offset %u", offset); 398ad205586Smpi break; 399ad205586Smpi } 400ad205586Smpi offset += toff; 401ad205586Smpi idx++; 402ad205586Smpi } 403ad205586Smpi 404ad205586Smpi return NULL; 405ad205586Smpi } 406ad205586Smpi 4078cd47547Smpi /* 4088cd47547Smpi * Pretty print `addr'. 4098cd47547Smpi */ 410ad205586Smpi void 41192b2adbfSuwe db_ctf_pprint(const struct ctf_type *ctt, vaddr_t addr) 412ad205586Smpi { 41308f058f8Smpi vaddr_t taddr = (vaddr_t)ctt; 414ad205586Smpi const struct ctf_type *ref; 415609e0b1cSclaudio const struct ctf_array *arr; 416ad205586Smpi uint16_t kind; 417609e0b1cSclaudio uint32_t eob, toff, i; 418609e0b1cSclaudio db_expr_t val; 419609e0b1cSclaudio size_t elm_size; 420609e0b1cSclaudio 421609e0b1cSclaudio if (ctt == NULL) 422609e0b1cSclaudio return; 423ad205586Smpi 424ad205586Smpi kind = CTF_INFO_KIND(ctt->ctt_info); 425ab77b743Smpi if (ctt->ctt_size <= CTF_MAX_SIZE) 426ab77b743Smpi toff = sizeof(struct ctf_stype); 427ab77b743Smpi else 428ab77b743Smpi toff = sizeof(struct ctf_type); 429ad205586Smpi 430ad205586Smpi switch (kind) { 431ad205586Smpi case CTF_K_ARRAY: 432609e0b1cSclaudio arr = (struct ctf_array *)(taddr + toff); 433609e0b1cSclaudio ref = db_ctf_type_by_index(arr->cta_contents); 434609e0b1cSclaudio elm_size = db_ctf_type_size(ref); 435609e0b1cSclaudio db_printf("["); 436609e0b1cSclaudio for (i = 0; i < arr->cta_nelems; i++) { 437609e0b1cSclaudio db_ctf_pprint(ref, addr + i * elm_size); 438609e0b1cSclaudio if (i + 1 < arr->cta_nelems) 439609e0b1cSclaudio db_printf(","); 440609e0b1cSclaudio } 441609e0b1cSclaudio db_printf("]"); 442609e0b1cSclaudio break; 443609e0b1cSclaudio case CTF_K_ENUM: 444609e0b1cSclaudio db_ctf_pprint_enum(ctt, addr); 445609e0b1cSclaudio break; 446609e0b1cSclaudio case CTF_K_FLOAT: 447ad205586Smpi case CTF_K_FUNCTION: 448609e0b1cSclaudio val = db_get_value(addr, sizeof(val), 0); 449609e0b1cSclaudio db_printf("%lx", (unsigned long)val); 450ad205586Smpi break; 451ad205586Smpi case CTF_K_INTEGER: 452ab77b743Smpi eob = db_get_value((taddr + toff), sizeof(eob), 0); 453ab77b743Smpi switch (CTF_INT_BITS(eob)) { 454609e0b1cSclaudio #ifndef __LP64__ 455609e0b1cSclaudio case 64: { 456609e0b1cSclaudio uint64_t val64; 457609e0b1cSclaudio #if BYTE_ORDER == LITTLE_ENDIAN 458609e0b1cSclaudio val64 = db_get_value(addr + 4, CTF_INT_BITS(eob) / 8, 459609e0b1cSclaudio CTF_INT_ENCODING(eob) & CTF_INT_SIGNED); 460609e0b1cSclaudio val64 <<= 32; 461609e0b1cSclaudio val64 |= db_get_value(addr, CTF_INT_BITS(eob) / 8, 0); 462609e0b1cSclaudio #else 463609e0b1cSclaudio val64 = db_get_value(addr, CTF_INT_BITS(eob) / 8, 464609e0b1cSclaudio CTF_INT_ENCODING(eob) & CTF_INT_SIGNED); 465609e0b1cSclaudio val64 <<= 32; 466609e0b1cSclaudio val64 |= db_get_value(addr + 4, CTF_INT_BITS(eob) / 8, 467609e0b1cSclaudio 0); 468609e0b1cSclaudio #endif 469609e0b1cSclaudio if (CTF_INT_ENCODING(eob) & CTF_INT_SIGNED) 470609e0b1cSclaudio db_printf("%lld", val64); 471609e0b1cSclaudio else 472609e0b1cSclaudio db_printf("%llu", val64); 473ab77b743Smpi break; 474609e0b1cSclaudio } 475609e0b1cSclaudio #endif 476ab77b743Smpi default: 477609e0b1cSclaudio val = db_get_value(addr, CTF_INT_BITS(eob) / 8, 478609e0b1cSclaudio CTF_INT_ENCODING(eob) & CTF_INT_SIGNED); 479609e0b1cSclaudio if (CTF_INT_ENCODING(eob) & CTF_INT_SIGNED) 480609e0b1cSclaudio db_printf("%ld", val); 481609e0b1cSclaudio else 482609e0b1cSclaudio db_printf("%lu", val); 483ab77b743Smpi break; 484ab77b743Smpi } 485ad205586Smpi break; 486ad205586Smpi case CTF_K_STRUCT: 487ad205586Smpi case CTF_K_UNION: 488ad205586Smpi db_ctf_pprint_struct(ctt, addr); 489ad205586Smpi break; 490ad205586Smpi case CTF_K_POINTER: 491bebdad71Smpi db_ctf_pprint_ptr(ctt, addr); 492ad205586Smpi break; 493ad205586Smpi case CTF_K_TYPEDEF: 494ad205586Smpi case CTF_K_VOLATILE: 495ad205586Smpi case CTF_K_CONST: 496ad205586Smpi case CTF_K_RESTRICT: 497ad205586Smpi ref = db_ctf_type_by_index(ctt->ctt_type); 49892b2adbfSuwe db_ctf_pprint(ref, addr); 499ad205586Smpi break; 500ad205586Smpi case CTF_K_UNKNOWN: 501ad205586Smpi case CTF_K_FORWARD: 502ad205586Smpi default: 503ad205586Smpi break; 504ad205586Smpi } 505ad205586Smpi } 506ad205586Smpi 507ad205586Smpi void 508ad205586Smpi db_ctf_pprint_struct(const struct ctf_type *ctt, vaddr_t addr) 509ad205586Smpi { 510ad205586Smpi const char *name, *p = (const char *)ctt; 511ad205586Smpi const struct ctf_type *ref; 512ad205586Smpi uint32_t toff; 513ad205586Smpi uint64_t size; 514ad205586Smpi uint16_t i, vlen; 515ad205586Smpi 516ad205586Smpi vlen = CTF_INFO_VLEN(ctt->ctt_info); 517ad205586Smpi 518ad205586Smpi if (ctt->ctt_size <= CTF_MAX_SIZE) { 519ad205586Smpi size = ctt->ctt_size; 520ad205586Smpi toff = sizeof(struct ctf_stype); 521ad205586Smpi } else { 522ad205586Smpi size = CTF_TYPE_LSIZE(ctt); 523ad205586Smpi toff = sizeof(struct ctf_type); 524ad205586Smpi } 525ad205586Smpi 526ad205586Smpi db_printf("{"); 527ad205586Smpi if (size < CTF_LSTRUCT_THRESH) { 528ad205586Smpi for (i = 0; i < vlen; i++) { 529ad205586Smpi struct ctf_member *ctm; 530ad205586Smpi 531ad205586Smpi ctm = (struct ctf_member *)(p + toff); 532ad205586Smpi toff += sizeof(struct ctf_member); 533ad205586Smpi 534ad205586Smpi name = db_ctf_off2name(ctm->ctm_name); 535ad205586Smpi if (name != NULL) 536ad205586Smpi db_printf("%s = ", name); 537ad205586Smpi ref = db_ctf_type_by_index(ctm->ctm_type); 53892b2adbfSuwe db_ctf_pprint(ref, addr + ctm->ctm_offset / 8); 539ad205586Smpi if (i < vlen - 1) 540ad205586Smpi db_printf(", "); 541ad205586Smpi } 542ad205586Smpi } else { 543ad205586Smpi for (i = 0; i < vlen; i++) { 544ad205586Smpi struct ctf_lmember *ctlm; 545ad205586Smpi 546ad205586Smpi ctlm = (struct ctf_lmember *)(p + toff); 547ad205586Smpi toff += sizeof(struct ctf_lmember); 548ad205586Smpi 549ad205586Smpi name = db_ctf_off2name(ctlm->ctlm_name); 550ad205586Smpi if (name != NULL) 551ad205586Smpi db_printf("%s = ", name); 552ad205586Smpi ref = db_ctf_type_by_index(ctlm->ctlm_type); 55392b2adbfSuwe db_ctf_pprint(ref, addr + 554ad205586Smpi CTF_LMEM_OFFSET(ctlm) / 8); 555ad205586Smpi if (i < vlen - 1) 556ad205586Smpi db_printf(", "); 557ad205586Smpi } 558ad205586Smpi } 559ad205586Smpi db_printf("}"); 560ad205586Smpi } 561ad205586Smpi 562bebdad71Smpi void 563609e0b1cSclaudio db_ctf_pprint_enum(const struct ctf_type *ctt, vaddr_t addr) 564609e0b1cSclaudio { 565609e0b1cSclaudio const char *name = NULL, *p = (const char *)ctt; 566609e0b1cSclaudio struct ctf_enum *cte; 567609e0b1cSclaudio uint32_t toff; 568609e0b1cSclaudio int32_t val; 569609e0b1cSclaudio uint16_t i, vlen; 570609e0b1cSclaudio 571609e0b1cSclaudio vlen = CTF_INFO_VLEN(ctt->ctt_info); 572609e0b1cSclaudio toff = sizeof(struct ctf_stype); 573609e0b1cSclaudio 574609e0b1cSclaudio val = (int32_t)db_get_value(addr, sizeof(val), 1); 575609e0b1cSclaudio for (i = 0; i < vlen; i++) { 576609e0b1cSclaudio cte = (struct ctf_enum *)(p + toff); 577609e0b1cSclaudio toff += sizeof(*cte); 578609e0b1cSclaudio 579609e0b1cSclaudio if (val == cte->cte_value) { 580609e0b1cSclaudio name = db_ctf_off2name(cte->cte_name); 581609e0b1cSclaudio break; 582609e0b1cSclaudio } 583609e0b1cSclaudio } 584609e0b1cSclaudio 585609e0b1cSclaudio if (name != NULL) 586609e0b1cSclaudio db_printf("%s", name); 587609e0b1cSclaudio else 588609e0b1cSclaudio db_printf("#%d", val); 589609e0b1cSclaudio } 590609e0b1cSclaudio 591609e0b1cSclaudio void 592bebdad71Smpi db_ctf_pprint_ptr(const struct ctf_type *ctt, vaddr_t addr) 593bebdad71Smpi { 594bebdad71Smpi const char *name, *modif = ""; 595bebdad71Smpi const struct ctf_type *ref; 596bebdad71Smpi uint16_t kind; 5970488a471Sdlg unsigned long ptr; 598bebdad71Smpi 599bebdad71Smpi ref = db_ctf_type_by_index(ctt->ctt_type); 600bebdad71Smpi kind = CTF_INFO_KIND(ref->ctt_info); 601bebdad71Smpi 602bebdad71Smpi switch (kind) { 603bebdad71Smpi case CTF_K_VOLATILE: 604bebdad71Smpi modif = "volatile "; 605bebdad71Smpi ref = db_ctf_type_by_index(ref->ctt_type); 606bebdad71Smpi break; 607bebdad71Smpi case CTF_K_CONST: 608bebdad71Smpi modif = "const "; 609bebdad71Smpi ref = db_ctf_type_by_index(ref->ctt_type); 610bebdad71Smpi break; 611bebdad71Smpi case CTF_K_STRUCT: 612bebdad71Smpi modif = "struct "; 613bebdad71Smpi break; 614bebdad71Smpi case CTF_K_UNION: 615bebdad71Smpi modif = "union "; 616bebdad71Smpi break; 617bebdad71Smpi default: 618bebdad71Smpi break; 619bebdad71Smpi } 620bebdad71Smpi 621bebdad71Smpi name = db_ctf_off2name(ref->ctt_name); 622bebdad71Smpi if (name != NULL) 623bebdad71Smpi db_printf("(%s%s *)", modif, name); 624bebdad71Smpi 625c0dc0921Sdlg ptr = (unsigned long)db_get_value(addr, sizeof(ptr), 0); 6260488a471Sdlg 6270488a471Sdlg db_printf("0x%lx", ptr); 628bebdad71Smpi } 629bebdad71Smpi 630fd68ecf3Sjasper static const char * 631ad205586Smpi db_ctf_off2name(uint32_t offset) 632fd68ecf3Sjasper { 633fd68ecf3Sjasper const char *name; 634fd68ecf3Sjasper 635ece49713Sjasper if (!db_ctf.ctf_found) 636ece49713Sjasper return NULL; 637ece49713Sjasper 638fd68ecf3Sjasper if (CTF_NAME_STID(offset) != CTF_STRTAB_0) 639fd68ecf3Sjasper return "external"; 640fd68ecf3Sjasper 641fd68ecf3Sjasper if (CTF_NAME_OFFSET(offset) >= db_ctf.cth->cth_strlen) 642fd68ecf3Sjasper return "exceeds strlab"; 643fd68ecf3Sjasper 644fd68ecf3Sjasper if (db_ctf.cth->cth_stroff + CTF_NAME_OFFSET(offset) >= db_ctf.dlen) 645fd68ecf3Sjasper return "invalid"; 646fd68ecf3Sjasper 647fd68ecf3Sjasper name = db_ctf.data + db_ctf.cth->cth_stroff + CTF_NAME_OFFSET(offset); 648fd68ecf3Sjasper if (*name == '\0') 649ad205586Smpi return NULL; 650fd68ecf3Sjasper 651fd68ecf3Sjasper return name; 652fd68ecf3Sjasper } 653fd68ecf3Sjasper 654fd68ecf3Sjasper static char * 65527fc743bSmillert db_ctf_decompress(const char *buf, size_t size, size_t len) 656fd68ecf3Sjasper { 657fd68ecf3Sjasper z_stream stream; 658fd68ecf3Sjasper char *data; 659fd68ecf3Sjasper int error; 660fd68ecf3Sjasper 661fd68ecf3Sjasper data = malloc(len, M_TEMP, M_WAITOK|M_ZERO|M_CANFAIL); 662b42aa555Smpi if (data == NULL) 663b42aa555Smpi return NULL; 664fd68ecf3Sjasper 665fd68ecf3Sjasper memset(&stream, 0, sizeof(stream)); 666fd68ecf3Sjasper stream.next_in = (void *)buf; 667fd68ecf3Sjasper stream.avail_in = size; 668fd68ecf3Sjasper stream.next_out = data; 669fd68ecf3Sjasper stream.avail_out = len; 670fd68ecf3Sjasper 671fd68ecf3Sjasper if ((error = inflateInit(&stream)) != Z_OK) { 672fd68ecf3Sjasper db_printf("zlib inflateInit failed: %s", zError(error)); 673fd68ecf3Sjasper goto exit; 674fd68ecf3Sjasper } 675fd68ecf3Sjasper 676fd68ecf3Sjasper if ((error = inflate(&stream, Z_FINISH)) != Z_STREAM_END) { 677fd68ecf3Sjasper db_printf("zlib inflate failed: %s", zError(error)); 678fd68ecf3Sjasper inflateEnd(&stream); 679fd68ecf3Sjasper goto exit; 680fd68ecf3Sjasper } 681fd68ecf3Sjasper 682fd68ecf3Sjasper if ((error = inflateEnd(&stream)) != Z_OK) { 683fd68ecf3Sjasper db_printf("zlib inflateEnd failed: %s", zError(error)); 684fd68ecf3Sjasper goto exit; 685fd68ecf3Sjasper } 686fd68ecf3Sjasper 68727fc743bSmillert if (stream.total_out != len) { 68827fc743bSmillert db_printf("decompression failed: %lu != %zu", 689fd68ecf3Sjasper stream.total_out, len); 690fd68ecf3Sjasper goto exit; 691fd68ecf3Sjasper } 692fd68ecf3Sjasper 693b42aa555Smpi return data; 694fd68ecf3Sjasper 695fd68ecf3Sjasper exit: 69685e04346Sbluhm free(data, M_DEVBUF, len); 697b42aa555Smpi return NULL; 698fd68ecf3Sjasper } 699ad205586Smpi 700ad205586Smpi /* 7012b6c37f3Suwe * pprint <symbol name> 702ad205586Smpi */ 703ad205586Smpi void 70416be3460Smpi db_ctf_pprint_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 705ad205586Smpi { 706ad205586Smpi Elf_Sym *st; 707ad205586Smpi const struct ctf_type *ctt; 708ad205586Smpi int t; 709ad205586Smpi 7101c302ed1Sjasper if (!db_ctf.ctf_found) { 7111c302ed1Sjasper db_printf("No CTF data found\n"); 7121c302ed1Sjasper db_flush_lex(); 7130938eda0Sjasper return; 7141c302ed1Sjasper } 7151c302ed1Sjasper 716ad205586Smpi /* 717ad205586Smpi * Read the struct name from the debugger input. 718ad205586Smpi */ 719ad205586Smpi t = db_read_token(); 720ad205586Smpi if (t != tIDENT) { 721ad205586Smpi db_printf("Bad symbol name\n"); 722ad205586Smpi db_flush_lex(); 723ad205586Smpi return; 724ad205586Smpi } 725ad205586Smpi 726ad205586Smpi if ((st = db_symbol_by_name(db_tok_string, &addr)) == NULL) { 727ad205586Smpi db_printf("Symbol not found %s\n", db_tok_string); 728ad205586Smpi db_flush_lex(); 729ad205586Smpi return; 730ad205586Smpi } 731ad205586Smpi 732ad205586Smpi if ((ctt = db_ctf_type_by_symbol(st)) == NULL) { 73316be3460Smpi modif[0] = '\0'; 73416be3460Smpi db_print_cmd(addr, 0, 0, modif); 735ad205586Smpi db_flush_lex(); 736ad205586Smpi return; 737ad205586Smpi } 738ad205586Smpi 739ad205586Smpi db_printf("%s:\t", db_tok_string); 74092b2adbfSuwe db_ctf_pprint(ctt, addr); 741ad205586Smpi db_printf("\n"); 742ad205586Smpi } 743266ad235Sdlg 744266ad235Sdlg /* 745266ad235Sdlg * show struct <struct name> [addr]: displays the data starting at addr 746266ad235Sdlg * (`dot' if unspecified) as a struct of the given type. 747266ad235Sdlg */ 748266ad235Sdlg void 749266ad235Sdlg db_ctf_show_struct(db_expr_t addr, int have_addr, db_expr_t count, 750266ad235Sdlg char *modifiers) 751266ad235Sdlg { 752266ad235Sdlg const struct ctf_type *ctt; 753266ad235Sdlg const char *name; 754266ad235Sdlg uint64_t sz; 755266ad235Sdlg int t; 756266ad235Sdlg 757266ad235Sdlg /* 758266ad235Sdlg * Read the struct name from the debugger input. 759266ad235Sdlg */ 760266ad235Sdlg t = db_read_token(); 761266ad235Sdlg if (t != tIDENT) { 762266ad235Sdlg db_printf("Bad struct name\n"); 763266ad235Sdlg db_flush_lex(); 764266ad235Sdlg return; 765266ad235Sdlg } 766266ad235Sdlg name = db_tok_string; 767266ad235Sdlg 768266ad235Sdlg ctt = db_ctf_type_by_name(name, CTF_K_STRUCT); 769266ad235Sdlg if (ctt == NULL) { 770266ad235Sdlg db_printf("unknown struct %s\n", name); 771266ad235Sdlg db_flush_lex(); 772266ad235Sdlg return; 773266ad235Sdlg } 774266ad235Sdlg 775266ad235Sdlg /* 776266ad235Sdlg * Read the address, if any, from the debugger input. 777266ad235Sdlg * In that case, update `dot' value. 778266ad235Sdlg */ 779266ad235Sdlg if (db_expression(&addr)) { 78008f058f8Smpi db_dot = (vaddr_t)addr; 781266ad235Sdlg db_last_addr = db_dot; 782266ad235Sdlg } else 783266ad235Sdlg addr = (db_expr_t)db_dot; 784266ad235Sdlg 785266ad235Sdlg db_skip_to_eol(); 786266ad235Sdlg 787266ad235Sdlg /* 788266ad235Sdlg * Display the structure contents. 789266ad235Sdlg */ 790266ad235Sdlg sz = (ctt->ctt_size <= CTF_MAX_SIZE) ? 791266ad235Sdlg ctt->ctt_size : CTF_TYPE_LSIZE(ctt); 792266ad235Sdlg db_printf("struct %s at %p (%llu bytes) ", name, (void *)addr, sz); 793266ad235Sdlg db_ctf_pprint_struct(ctt, addr); 794266ad235Sdlg } 795