Control: tags -1 + patch

memcpy(0x7ffeae63e888, ".", 1)                                                  
                          = 0x7ffeae63e888
inotify_add_watch(3, ".", 
IN_MOVED_TO|IN_CREATE|IN_DELETE_SELF|IN_MOVE_SELF|IN_ONLYDIR|IN_EXCL_UNLINK)    
= 1
reallocarray(nil, 2, 8)                                                         
                          = 0x55fb0d39a2e0
From 6e26699817640d09fd0c493f5722dd9057212400 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=BD=D0=B0=D0=B1?= <[email protected]>
Date: Thu, 31 Jul 2025 21:27:08 +0200
Subject: [PATCH] Add typedef = bitenum() (Closes: #1110138)
X-Mutt-PGP: OS

---
 Makefile.am        |   2 +-
 lens_bitenum.c     | 145 +++++++++++++++++++++++++++++++++++++++++++++
 lens_bitenum.h     |  47 +++++++++++++++
 read_config_file.c | 118 ++++++++++++++++++++++++++++++++++++
 4 files changed, 311 insertions(+), 1 deletion(-)
 create mode 100644 lens_bitenum.c
 create mode 100644 lens_bitenum.h

diff --git a/Makefile.am b/Makefile.am
index 394d91c..df408bb 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -33,7 +33,7 @@ libltrace_la_SOURCES = bits.c breakpoints.c debug.c demangle.c dict.c	\
 	options.c output.c proc.c read_config_file.c summary.c		\
 	library.c filter.c glob.c type.c value.c value_dict.c expr.c	\
 	fetch.c vect.c param.c printf.c zero.c lens.c lens_default.c	\
-	lens_enum.c memstream.c prototype.c
+	lens_enum.c lens_bitenum.c memstream.c prototype.c
 if HAVE_LIBDW
 libltrace_la_SOURCES += dwarf_prototypes.c
 endif
diff --git a/lens_bitenum.c b/lens_bitenum.c
new file mode 100644
index 0000000..42a7581
--- /dev/null
+++ b/lens_bitenum.c
@@ -0,0 +1,145 @@
+/*
+ * This file is part of ltrace.
+ * Copyright (C) 2011, 2012 Petr Machata, Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+#include "lens_bitenum.h"
+#include "lens_default.h"
+#include "value.h"
+#include "type.h"
+
+struct bitenum_entry {
+	char *key;
+	uint64_t value;
+	bool own_key : 1;
+};
+static_assert(sizeof(uint64_t) == sizeof(long long), "");
+
+static void
+bitenum_entry_dtor(struct bitenum_entry *entry, void *data)
+{
+	if (entry->own_key)
+		free(entry->key);
+}
+
+static void
+bitenum_lens_destroy_cb(struct lens *lens)
+{
+	struct bitenum_lens *self = (void *)lens;
+
+	VECT_DESTROY(&self->entries, struct bitenum_entry,
+		     bitenum_entry_dtor, NULL);
+}
+
+struct consumestate {
+	uint64_t bits;
+	FILE *stream;
+	int wrote;
+};
+
+static enum callback_status
+bitenum_consume(const struct bitenum_entry *entry, void *data)
+{
+	struct consumestate *consumestate = data;
+
+	if ((consumestate->bits & entry->value) != entry->value)
+		return CBS_CONT;
+
+	if (consumestate->wrote) {
+		fputc('|', consumestate->stream);
+		++consumestate->wrote;
+	}
+
+	fputs(entry->key, consumestate->stream);
+	consumestate->wrote += strlen(entry->key);
+	consumestate->bits &= ~entry->value;
+
+	return CBS_CONT_IF(consumestate->bits);
+}
+
+static int
+bitenum_lens_format_cb(struct lens *lens, FILE *stream,
+		       struct value *value, struct value_dict *arguments)
+{
+	struct bitenum_lens *self = (void *)lens;
+
+	struct consumestate consumestate = { .stream = stream };
+	if (value_extract_word(value, (long long *)&consumestate.bits, NULL))
+	none:
+		return lens_format(&default_lens, stream, value, arguments);
+
+	VECT_EACH_CST(&self->entries, struct bitenum_entry, NULL, bitenum_consume, &consumestate);
+
+	if (!consumestate.wrote)
+		goto none;
+	if (!consumestate.bits)
+		return consumestate.wrote;
+
+	fputc('|', stream);
+	++consumestate.wrote;
+
+	struct value remainder;
+	value_init_detached(&remainder, NULL, value->type, false);
+	value_set_word(&remainder, consumestate.bits);
+	return consumestate.wrote + lens_format(&default_lens, stream, &remainder, arguments);
+}
+
+// Most-populated values first
+static int
+bitenum_lens_sort(const struct bitenum_entry *lhs,
+		  const struct bitenum_entry *rhs)
+{
+	return __builtin_popcount(rhs->value) - __builtin_popcount(lhs->value);
+}
+
+
+void
+lens_init_bitenum(struct bitenum_lens *lens)
+{
+	*lens = (struct bitenum_lens){
+		{
+			.format_cb = bitenum_lens_format_cb,
+			.destroy_cb = bitenum_lens_destroy_cb,
+		},
+	};
+	VECT_INIT(&lens->entries, struct bitenum_entry);
+}
+
+int
+lens_bitenum_add(struct bitenum_lens *lens,
+	         const char *key, int own_key,
+	         uint64_t value)
+{
+	struct bitenum_entry entry = { (char *)key, value, own_key };
+	if (VECT_PUSHBACK(&lens->entries, &entry))
+		return -1;
+	// TODO: this would be better-served as an insert-at-lower_bound(), but vect doesn't have this
+	VECT_QSORT(&lens->entries, struct bitenum_entry, bitenum_lens_sort);
+	return 0;
+}
+
+size_t
+lens_bitenum_size(struct bitenum_lens *lens)
+{
+	return vect_size(&lens->entries);
+}
diff --git a/lens_bitenum.h b/lens_bitenum.h
new file mode 100644
index 0000000..70eb92a
--- /dev/null
+++ b/lens_bitenum.h
@@ -0,0 +1,47 @@
+/*
+ * This file is part of ltrace.
+ * Copyright (C) 2011, 2012 Petr Machata, Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef LENS_BITENUM_H
+#define LENS_BITENUM_H
+
+#include <stdint.h>
+#include "lens.h"
+#include "vect.h"
+
+struct bitenum_lens {
+	struct lens super;
+	struct vect entries;
+};
+
+/* Init enumeration LENS.  */
+void lens_init_bitenum(struct bitenum_lens *lens);
+
+/* Push another member of the enumeration, named KEY, with given
+ * VALUE.  If OWN_KEY, KEY is owned and released after the type is
+ * destroyed.  KEY is typed as const char *, but note that if OWN_KEY,
+ * this value will be freed.  */
+int lens_bitenum_add(struct bitenum_lens *lens,
+		  const char *key, int own_key,
+		  uint64_t value);
+
+/* Return number of enum elements of type INFO.  */
+size_t lens_bitenum_size(struct bitenum_lens *lens);
+
+#endif /* LENS_BITENUM_H */
diff --git a/read_config_file.c b/read_config_file.c
index 9e1f65c..3f35ae4 100644
--- a/read_config_file.c
+++ b/read_config_file.c
@@ -42,6 +42,7 @@
 #include "lens.h"
 #include "lens_default.h"
 #include "lens_enum.h"
+#include "lens_bitenum.h"
 
 /* Lifted from GCC: The ctype functions are often implemented as
  * macros which do lookups in arrays using the parameter as the
@@ -80,6 +81,8 @@ static struct arg_type_info *parse_lens(struct protolib *plib,
 					bool *forwardp);
 static int parse_enum(struct protolib *plib, struct locus *loc,
 		      char **str, struct arg_type_info **retp, bool *ownp);
+static int parse_bitenum(struct protolib *plib, struct locus *loc,
+		      char **str, struct arg_type_info **retp, bool *ownp);
 
 static int try_parse_kwd(char **str, const char *kwd);
 
@@ -168,6 +171,22 @@ parse_int(struct locus *loc, char **str, long *ret)
 	return 0;
 }
 
+static int
+parse_u64(struct locus *loc, char **str, uint64_t *ret)
+{
+	char *end;
+	unsigned long long n = strtoull(*str, &end, 0);
+	if (end == *str) {
+		report_error(loc->filename, loc->line_no, "bad number");
+		return -1;
+	}
+
+	*str = end;
+	if (ret != NULL)
+		*ret = n;
+	return 0;
+}
+
 static int
 check_nonnegative(struct locus *loc, long l)
 {
@@ -717,6 +736,10 @@ parse_alias(struct protolib *plib, struct locus *loc,
 
 		return parse_enum(plib, loc, str, retp, ownp);
 
+	} else if (try_parse_kwd(str, "bitenum") >= 0) {
+
+		return parse_bitenum(plib, loc, str, retp, ownp);
+
 	} else {
 		*retp = NULL;
 		return 0;
@@ -862,6 +885,101 @@ parse_enum(struct protolib *plib, struct locus *loc, char **str,
 	return 0;
 }
 
+/* Syntax:
+ *   bitenum (keyname=value,keyname=value,... )
+ *   bitenum<type> (keyname=value,keyname=value,... )
+ */
+static int
+parse_bitenum(struct protolib *plib, struct locus *loc, char **str,
+	   struct arg_type_info **retp, bool *ownp)
+{
+	/* Optional type argument.  */
+	skip_whitespace(str);
+	if (**str == '[') {
+		parse_char(loc, str, '[');
+		skip_whitespace(str);
+		*retp = parse_nonpointer_type(plib, loc, str, NULL, 0, ownp, NULL);
+		if (*retp == NULL)
+			return -1;
+
+		if (!type_is_integral((*retp)->type)) {
+			report_error(loc->filename, loc->line_no,
+				     "integral type required as bitenum argument");
+		fail:
+			if (*ownp) {
+				/* This also releases associated lens
+				 * if any was set so far.  */
+				type_destroy(*retp);
+				free(*retp);
+			}
+			return -1;
+		}
+
+		skip_whitespace(str);
+		if (parse_char(loc, str, ']') < 0)
+			goto fail;
+
+	} else {
+		*retp = type_get_simple(ARGTYPE_INT);
+		*ownp = false;
+	}
+
+	/* We'll need to set the lens, so unshare.  */
+	if (unshare_type_info(loc, retp, ownp) < 0)
+		goto fail;
+
+	skip_whitespace(str);
+	if (parse_char(loc, str, '(') < 0)
+		goto fail;
+
+	struct bitenum_lens *lens = malloc(sizeof(*lens));
+	if (lens == NULL) {
+		report_error(loc->filename, loc->line_no,
+			     "malloc enum lens: %s", strerror(errno));
+		return -1;
+	}
+
+	lens_init_bitenum(lens);
+	(*retp)->lens = &lens->super;
+	(*retp)->own_lens = 1;
+
+	while (1) {
+		skip_whitespace(str);
+		if (**str == 0 || **str == ')') {
+			parse_char(loc, str, ')');
+			return 0;
+		}
+
+		/* Field delimiter.  XXX should we support the C
+		 * syntax, where the enumeration can end in pending
+		 * comma?  */
+		if (lens_bitenum_size(lens) > 0)
+			parse_char(loc, str, ',');
+
+		skip_whitespace(str);
+		char *key = parse_ident(loc, str);
+		if (key == NULL) {
+		err:
+			free(key);
+			goto fail;
+		}
+
+		if (**str != '=')
+			goto err;
+		++*str;
+		skip_whitespace(str);
+
+		uint64_t val;
+		if (parse_u64(loc, str, &val) < 0)
+			goto err;
+
+		if (lens_bitenum_add(lens, key, 1, val) < 0)
+			goto err;
+	}
+
+	return 0;
+}
+
 static struct arg_type_info *
 parse_nonpointer_type(struct protolib *plib, struct locus *loc,
 		      char **str, struct param **extra_param, size_t param_num,
-- 
2.39.5

Attachment: signature.asc
Description: PGP signature

Reply via email to