From: Claudio Jeker Subject: ddb, pimp my show struct command To: tech@openbsd.org Cc: Martin Pieuchot Date: Wed, 21 Feb 2024 17:46:12 +0100 This started because of bluhm hitting a trap on sparc64 with show struct ether_header 0x4005c58e820 struct ether_header at 0x4005c58e820 (14 bytes) {ether_dhost = 4399299083592, ether_shost = panic: trap type 0x34 (mem address not aligned): pc=133240c npc=1332410 pstate=44820006 So the problem is that CTF_K_ARRAY is not correctly implemented and instead the addr is dumped as unsigned long via dereference. That is no good on strict alignment systems. After fixing various issues in our ctfconv tool this is now more or less working. I added support for CTF_K_ARRAY and CTF_K_ENUM and fixed the CTF_K_INTEGER case. One major setback is that db_get_value() does not handle uint64_t on 32bit archs :( I also did not use db_format() to print the CTF_K_INTEGER values. Again 32bit archs can't use db_format() to print a 64bit number :( CTF_K_FLOAT and CTF_K_FUNCTION are still in a sad state. But this diff already adds enough bikesheds. Right now I only tested this on amd64. -- :wq Claudio Index: db_ctf.c =================================================================== RCS file: /cvs/src/sys/ddb/db_ctf.c,v diff -u -p -r1.33 db_ctf.c --- db_ctf.c 14 Aug 2022 14:57:38 -0000 1.33 +++ db_ctf.c 21 Feb 2024 15:26:03 -0000 @@ -55,11 +55,14 @@ static const char *db_ctf_off2name(uint3 static Elf_Sym *db_ctf_idx2sym(size_t *, uint8_t); static char *db_ctf_decompress(const char *, size_t, size_t); +uint32_t db_ctf_type_len(const struct ctf_type *); +size_t db_ctf_type_size(const struct ctf_type *); const struct ctf_type *db_ctf_type_by_name(const char *, unsigned int); const struct ctf_type *db_ctf_type_by_symbol(Elf_Sym *); const struct ctf_type *db_ctf_type_by_index(uint16_t); void db_ctf_pprint(const struct ctf_type *, vaddr_t); void db_ctf_pprint_struct(const struct ctf_type *, vaddr_t); +void db_ctf_pprint_enum(const struct ctf_type *, vaddr_t); void db_ctf_pprint_ptr(const struct ctf_type *, vaddr_t); /* @@ -242,6 +245,68 @@ db_ctf_type_len(const struct ctf_type *c } /* + * Return the size of the type. + */ +size_t +db_ctf_type_size(const struct ctf_type *ctt) +{ + vaddr_t taddr = (vaddr_t)ctt; + const struct ctf_type *ref; + const struct ctf_array *arr; + size_t tlen = 0; + uint16_t kind; + uint32_t toff; + uint64_t size; + + kind = CTF_INFO_KIND(ctt->ctt_info); + + if (ctt->ctt_size <= CTF_MAX_SIZE) { + size = ctt->ctt_size; + toff = sizeof(struct ctf_stype); + } else { + size = CTF_TYPE_LSIZE(ctt); + toff = sizeof(struct ctf_type); + } + + switch (kind) { + case CTF_K_UNKNOWN: + case CTF_K_FORWARD: + break; + case CTF_K_INTEGER: + case CTF_K_FLOAT: + tlen = size; + break; + case CTF_K_ARRAY: + arr = (struct ctf_array *)(taddr + toff); + ref = db_ctf_type_by_index(arr->cta_contents); + tlen = arr->cta_nelems * db_ctf_type_size(ref); + break; + case CTF_K_FUNCTION: + tlen = 0; + break; + case CTF_K_STRUCT: + case CTF_K_UNION: + case CTF_K_ENUM: + tlen = size; + break; + case CTF_K_POINTER: + tlen = sizeof(void *); + break; + case CTF_K_TYPEDEF: + case CTF_K_VOLATILE: + case CTF_K_CONST: + case CTF_K_RESTRICT: + ref = db_ctf_type_by_index(ctt->ctt_type); + tlen = db_ctf_type_size(ref); + break; + default: + return 0; + } + + return tlen; +} + +/* * Return the CTF type associated to an ELF symbol. */ const struct ctf_type * @@ -347,8 +412,14 @@ db_ctf_pprint(const struct ctf_type *ctt { vaddr_t taddr = (vaddr_t)ctt; const struct ctf_type *ref; + const struct ctf_array *arr; uint16_t kind; - uint32_t eob, toff; + uint32_t eob, toff, i; + db_expr_t val; + size_t elm_size; + + if (ctt == NULL) + return; kind = CTF_INFO_KIND(ctt->ctt_info); if (ctt->ctt_size <= CTF_MAX_SIZE) @@ -357,20 +428,58 @@ db_ctf_pprint(const struct ctf_type *ctt toff = sizeof(struct ctf_type); switch (kind) { - case CTF_K_FLOAT: - case CTF_K_ENUM: case CTF_K_ARRAY: + arr = (struct ctf_array *)(taddr + toff); + ref = db_ctf_type_by_index(arr->cta_contents); + elm_size = db_ctf_type_size(ref); + db_printf("["); + for (i = 0; i < arr->cta_nelems; i++) { + db_ctf_pprint(ref, addr + i * elm_size); + if (i + 1 < arr->cta_nelems) + db_printf(","); + } + db_printf("]"); + break; + case CTF_K_ENUM: + db_ctf_pprint_enum(ctt, addr); + break; + case CTF_K_FLOAT: case CTF_K_FUNCTION: - db_printf("%lu", *((unsigned long *)addr)); + val = db_get_value(addr, sizeof(val), 0); + db_printf("%lx", (unsigned long)val); break; case CTF_K_INTEGER: eob = db_get_value((taddr + toff), sizeof(eob), 0); switch (CTF_INT_BITS(eob)) { - case 64: - db_printf("0x%llx", *((long long *)addr)); +#ifndef __LP64__ + case 64: { + uint64_t val64; +#if BYTE_ORDER == LITTLE_ENDIAN + val64 = db_get_value(addr + 4, CTF_INT_BITS(eob) / 8, + CTF_INT_ENCODING(eob) & CTF_INT_SIGNED); + val64 <<= 32; + val64 |= db_get_value(addr, CTF_INT_BITS(eob) / 8, 0); +#else + val64 = db_get_value(addr, CTF_INT_BITS(eob) / 8, + CTF_INT_ENCODING(eob) & CTF_INT_SIGNED); + val64 <<= 32; + val64 |= db_get_value(addr + 4, CTF_INT_BITS(eob) / 8, + 0); +#endif + if (CTF_INT_ENCODING(eob) & CTF_INT_SIGNED) + db_printf("%lld", val64); + else + db_printf("%llu", val64); break; + } +#endif default: - db_printf("0x%x", *((int *)addr)); + val = db_get_value(addr, CTF_INT_BITS(eob) / 8, + CTF_INT_ENCODING(eob) & CTF_INT_SIGNED); + if (CTF_INT_ENCODING(eob) & CTF_INT_SIGNED) + db_printf("%ld", val); + else + db_printf("%lu", val); break; } break; @@ -416,7 +525,6 @@ db_ctf_pprint_struct(const struct ctf_ty db_printf("{"); if (size < CTF_LSTRUCT_THRESH) { - for (i = 0; i < vlen; i++) { struct ctf_member *ctm; @@ -449,6 +557,35 @@ db_ctf_pprint_struct(const struct ctf_ty } } db_printf("}"); +} + +void +db_ctf_pprint_enum(const struct ctf_type *ctt, vaddr_t addr) +{ + const char *name = NULL, *p = (const char *)ctt; + struct ctf_enum *cte; + uint32_t toff; + int32_t val; + uint16_t i, vlen; + + vlen = CTF_INFO_VLEN(ctt->ctt_info); + toff = sizeof(struct ctf_stype); + + val = (int32_t)db_get_value(addr, sizeof(val), 1); + for (i = 0; i < vlen; i++) { + cte = (struct ctf_enum *)(p + toff); + toff += sizeof(*cte); + + if (val == cte->cte_value) { + name = db_ctf_off2name(cte->cte_name); + break; + } + } + + if (name != NULL) + db_printf("%s", name); + else + db_printf("#%d", val); } void