Index | Thread | Search

From:
Claudio Jeker <cjeker@diehard.n-r-g.com>
Subject:
ddb, pimp my show struct command
To:
tech@openbsd.org
Cc:
Martin Pieuchot <mpi@openbsd.org>
Date:
Wed, 21 Feb 2024 17:46:12 +0100

Download raw body.

Thread
  • Claudio Jeker:

    ddb, pimp my show struct command

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<PRIV,IE>

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