dwarves.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/6] improve expanded header
@ 2021-12-07 17:31 Douglas RAILLARD
  2021-12-07 17:31 ` [PATCH v2 1/6] Revert "fprintf: Allow making struct/enum/union anonymous" Douglas RAILLARD
                   ` (6 more replies)
  0 siblings, 7 replies; 17+ messages in thread
From: Douglas RAILLARD @ 2021-12-07 17:31 UTC (permalink / raw)
  To: acme; +Cc: dwarves, douglas.raillard

From: Douglas Raillard <douglas.raillard@arm.com>

Improve headers generated with -E in a few ways:

  * Print each type only once, to avoid redefinitions

  * --forward_decl: Generate forward declaration for struct and union so
    that uses of pointers will work.

  * --expanded_prefix: Allow prefixing names of types added by -E (all
    the ones not explicitly requested with -C) so they can be namespaced
    manually. This is important in order to be able to mix
    pahole-generated headers with existing headers without clash or
    maintenance.


types.txt:

  t1
  t4

Original printed type with "-C types.txt -E":

  struct t1 {
    struct t2 *a;
    struct t3 {
      int a;
    } b;
  };

  struct t4 {
    struct t3 {
      int a;
    } a;
  };

After this series and with
"-C types.txt -E --expanded_prefix __pahole --forward_decl":

  struct t1
  struct t2;
  struct t3;

  struct t1 {
    struct t2 *a;
    struct __pahole_t3 {
      int a;
    } b;
  };

  struct t4 {
    struct __pahole_t3 a;
  };


This header can be freely mixed with any other header as long as they
don't define t1 or t4 (if there is a clash, then pahole is not necessary
and the user can just use the header in the first place).

TODOs:

  * Define types on their first use even when they are first used as
    pointers. Currently, if a type is only used as pointer it will never
    get defined, which will still compile thanks to --forward_decl but
    won't allow easy use of the values.

  * The prefix system allocates memory to rename types and never frees
    it. I don't think it's a big issue for now as it's done inside
    pahole.c and type names are likely necessary until the end of the
    process anyway, but it makes valgrind angry and could therefore mask
    other problems. There is another implementation of prefix that
    modifies dwarves_fprintf.c instead of changing the name but it was
    very invasive and impossible to check if prefixable spots were
    missed.


This series is to be applied on the "next" branch as it includes reverts
of the --inner_anonymous series, which is dropped since it could not
cope with recursive types.


Douglas Raillard (6):
  Revert "fprintf: Allow making struct/enum/union anonymous"
  Revert "pahole.c: Add --inner_anonymous option"
  fprintf: Print types only once
  pahole.c: Add prefix to expanded type names
  pahole.c: Add --expanded_prefix option
  pahole.c: Add --forward_decl option

 dwarves.h          | 12 ++++--
 dwarves_emit.c     |  2 +-
 dwarves_fprintf.c  | 77 +++++++++++++++++-------------------
 man-pages/pahole.1 |  8 ++--
 pahole.c           | 98 ++++++++++++++++++++++++++++++++++------------
 5 files changed, 121 insertions(+), 76 deletions(-)

-- 
2.25.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v2 1/6] Revert "fprintf: Allow making struct/enum/union anonymous"
  2021-12-07 17:31 [PATCH v2 0/6] improve expanded header Douglas RAILLARD
@ 2021-12-07 17:31 ` Douglas RAILLARD
  2021-12-07 17:31 ` [PATCH v2 2/6] Revert "pahole.c: Add --inner_anonymous option" Douglas RAILLARD
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 17+ messages in thread
From: Douglas RAILLARD @ 2021-12-07 17:31 UTC (permalink / raw)
  To: acme; +Cc: dwarves, douglas.raillard

From: Douglas Raillard <douglas.raillard@arm.com>

This reverts commit 7c5e35b63bd26f1de0a22acb6319bf2b1a4166c1.

Signed-off-by: Douglas Raillard <douglas.raillard@arm.com>
---
 dwarves.h         |  4 +---
 dwarves_emit.c    |  2 +-
 dwarves_fprintf.c | 52 +++++++++++++++++------------------------------
 3 files changed, 21 insertions(+), 37 deletions(-)

diff --git a/dwarves.h b/dwarves.h
index 2fbeac3..52d162d 100644
--- a/dwarves.h
+++ b/dwarves.h
@@ -105,7 +105,6 @@ struct conf_fprintf {
 	uint8_t	   indent;
 	uint8_t	   expand_types:1;
 	uint8_t	   expand_pointers:1;
-	uint8_t	   inner_anonymous:1;
 	uint8_t    rel_offset:1;
 	uint8_t	   emit_stats:1;
 	uint8_t	   suppress_comments:1;
@@ -1372,8 +1371,7 @@ static inline const char *enumerator__name(const struct enumerator *enumerator)
 void enumeration__delete(struct type *type);
 void enumeration__add(struct type *type, struct enumerator *enumerator);
 size_t enumeration__fprintf(const struct tag *tag_enum,
-			    const struct conf_fprintf *conf, FILE *fp,
-			    bool anonymous);
+			    const struct conf_fprintf *conf, FILE *fp);
 
 int dwarves__init(void);
 void dwarves__exit(void);
diff --git a/dwarves_emit.c b/dwarves_emit.c
index 5c67559..5bf7946 100644
--- a/dwarves_emit.c
+++ b/dwarves_emit.c
@@ -91,7 +91,7 @@ static int enumeration__emit_definitions(struct tag *tag,
 		return 0;
 	}
 
-	enumeration__fprintf(tag, conf, fp, false);
+	enumeration__fprintf(tag, conf, fp);
 	fputs(";\n", fp);
 	type_emissions__add_definition(emissions, etype);
 	return 1;
diff --git a/dwarves_fprintf.c b/dwarves_fprintf.c
index ecb6c7f..c5921d7 100644
--- a/dwarves_fprintf.c
+++ b/dwarves_fprintf.c
@@ -198,8 +198,7 @@ size_t tag__fprintf_decl_info(const struct tag *tag,
 }
 
 static size_t __class__fprintf(struct class *class, const struct cu *cu,
-			       const struct conf_fprintf *conf, FILE *fp,
-			       bool anonymous);
+			       const struct conf_fprintf *conf, FILE *fp);
 static size_t type__fprintf(struct tag *type, const struct cu *cu,
 			    const char *name, const struct conf_fprintf *conf,
 			    FILE *fp);
@@ -331,7 +330,7 @@ size_t typedef__fprintf(const struct tag *tag, const struct cu *cu,
 		struct conf_fprintf tconf = *pconf;
 
 		tconf.suffix = type__name(type);
-		return fprintf(fp, "typedef ") + __class__fprintf(tag__class(tag_type), cu, &tconf, fp, false);
+		return fprintf(fp, "typedef ") + __class__fprintf(tag__class(tag_type), cu, &tconf, fp);
 	}
 	case DW_TAG_enumeration_type: {
 		struct type *ctype = tag__type(tag_type);
@@ -342,7 +341,7 @@ size_t typedef__fprintf(const struct tag *tag, const struct cu *cu,
 		struct conf_fprintf tconf = *pconf;
 
 		tconf.suffix = type__name(type);
-		return fprintf(fp, "typedef ") + enumeration__fprintf(tag_type, &tconf, fp, false);
+		return fprintf(fp, "typedef ") + enumeration__fprintf(tag_type, &tconf, fp);
 	}
 	}
 
@@ -395,16 +394,12 @@ out:
 	return type->max_tag_name_len;
 }
 
-size_t enumeration__fprintf(const struct tag *tag, const struct conf_fprintf *conf, FILE *fp, bool anonymous)
+size_t enumeration__fprintf(const struct tag *tag, const struct conf_fprintf *conf, FILE *fp)
 {
 	struct type *type = tag__type(tag);
 	struct enumerator *pos;
 	int max_entry_name_len = enumeration__max_entry_name_len(type);
-	size_t printed = fprintf(fp, "enum%s%s%s%s {\n",
-				 type__name(type) ? " " : "",
-				 type__name(type) && anonymous ? "/* " : "",
-				 type__name(type) ? type__name(type) : "",
-				 type__name(type) && anonymous ? " */" : "");
+	size_t printed = fprintf(fp, "enum%s%s {\n", type__name(type) ? " " : "", type__name(type) ?: "");
 	int indent = conf->indent;
 
 	if (indent >= (int)sizeof(tabs))
@@ -639,8 +634,7 @@ static size_t type__fprintf_stats(struct type *type, const struct cu *cu,
 }
 
 static size_t union__fprintf(struct type *type, const struct cu *cu,
-			     const struct conf_fprintf *conf, FILE *fp,
-			     bool anonymous);
+			     const struct conf_fprintf *conf, FILE *fp);
 
 static size_t type__fprintf(struct tag *type, const struct cu *cu,
 			    const char *name, const struct conf_fprintf *conf,
@@ -656,7 +650,6 @@ static size_t type__fprintf(struct tag *type, const struct cu *cu,
 	};
 	size_t printed = 0;
 	int expand_types = conf->expand_types;
-	int inner_anonymous = conf->inner_anonymous;
 	int suppress_offset_comment = conf->suppress_offset_comment;
 
 	if (type == NULL)
@@ -814,7 +807,7 @@ print_default:
 				class__find_holes(cclass);
 
 			tconf.type_spacing -= 8;
-			printed += __class__fprintf(cclass, cu, &tconf, fp, inner_anonymous);
+			printed += __class__fprintf(cclass, cu, &tconf, fp);
 		}
 		break;
 	case DW_TAG_union_type:
@@ -824,7 +817,7 @@ print_default:
 			printed += fprintf(fp, "union %-*s %s", tconf.type_spacing - 6, type__name(ctype), name ?: "");
 		} else {
 			tconf.type_spacing -= 8;
-			printed += union__fprintf(ctype, cu, &tconf, fp, inner_anonymous);
+			printed += union__fprintf(ctype, cu, &tconf, fp);
 		}
 		break;
 	case DW_TAG_enumeration_type:
@@ -833,7 +826,7 @@ print_default:
 		if (type__name(ctype) != NULL)
 			printed += fprintf(fp, "enum %-*s %s", tconf.type_spacing - 5, type__name(ctype), name ?: "");
 		else
-			printed += enumeration__fprintf(type, &tconf, fp, inner_anonymous);
+			printed += enumeration__fprintf(type, &tconf, fp);
 		break;
 	}
 out:
@@ -998,8 +991,7 @@ static size_t union_member__fprintf(struct class_member *member,
 }
 
 static size_t union__fprintf(struct type *type, const struct cu *cu,
-			     const struct conf_fprintf *conf, FILE *fp,
-			     bool anonymous)
+			     const struct conf_fprintf *conf, FILE *fp)
 {
 	struct class_member *pos;
 	size_t printed = 0;
@@ -1013,11 +1005,8 @@ static size_t union__fprintf(struct type *type, const struct cu *cu,
 
 	if (conf->prefix != NULL)
 		printed += fprintf(fp, "%s ", conf->prefix);
-	printed += fprintf(fp, "union%s%s%s%s {\n",
-			   type__name(type) ? " " : "",
-			   type__name(type) && anonymous ? "/* " : "",
-			   type__name(type) ?: "",
-			   type__name(type) && anonymous ? " */" : "");
+	printed += fprintf(fp, "union%s%s {\n", type__name(type) ? " " : "",
+			   type__name(type) ?: "");
 
 	uconf = *conf;
 	uconf.indent = indent + 1;
@@ -1375,8 +1364,7 @@ out:
 }
 
 static size_t __class__fprintf(struct class *class, const struct cu *cu,
-			       const struct conf_fprintf *conf, FILE *fp,
-			       bool anonymous)
+			       const struct conf_fprintf *conf, FILE *fp)
 {
 	struct type *type = &class->type;
 	size_t last_size = 0, size;
@@ -1396,16 +1384,14 @@ static size_t __class__fprintf(struct class *class, const struct cu *cu,
 	const char *current_accessibility = NULL;
 	struct conf_fprintf cconf = conf ? *conf : conf_fprintf__defaults;
 	const uint16_t t = type->namespace.tag.tag;
-	size_t printed = fprintf(fp, "%s%s%s%s%s%s%s",
+	size_t printed = fprintf(fp, "%s%s%s%s%s",
 				 cconf.prefix ?: "", cconf.prefix ? " " : "",
 				 ((cconf.classes_as_structs ||
 				   t == DW_TAG_structure_type) ? "struct" :
 				  t == DW_TAG_class_type ? "class" :
 							"interface"),
 				 type__name(type) ? " " : "",
-				 anonymous && type__name(type) ? "/* " : "",
-				 type__name(type) ?: "",
-				 anonymous && type__name(type) ? " */" : "");
+				 type__name(type) ?: "");
 	int indent = cconf.indent;
 
 	if (indent >= (int)sizeof(tabs))
@@ -1822,7 +1808,7 @@ out:
 
 size_t class__fprintf(struct class *class, const struct cu *cu, FILE *fp)
 {
-	return __class__fprintf(class, cu, NULL, fp, false);
+	return __class__fprintf(class, cu, NULL, fp);
 }
 
 static size_t variable__fprintf(const struct tag *tag, const struct cu *cu,
@@ -1909,7 +1895,7 @@ size_t tag__fprintf(struct tag *tag, const struct cu *cu,
 		printed += array_type__fprintf(tag, cu, "array", pconf, fp);
 		break;
 	case DW_TAG_enumeration_type:
-		printed += enumeration__fprintf(tag, pconf, fp, false);
+		printed += enumeration__fprintf(tag, pconf, fp);
 		break;
 	case DW_TAG_typedef:
 		printed += typedef__fprintf(tag, cu, pconf, fp);
@@ -1917,7 +1903,7 @@ size_t tag__fprintf(struct tag *tag, const struct cu *cu,
 	case DW_TAG_class_type:
 	case DW_TAG_interface_type:
 	case DW_TAG_structure_type:
-		printed += __class__fprintf(tag__class(tag), cu, pconf, fp, false);
+		printed += __class__fprintf(tag__class(tag), cu, pconf, fp);
 		break;
 	case DW_TAG_subroutine_type:
 		printed += ftype__fprintf(tag__ftype(tag), cu, NULL, false, false, 0, true, pconf, fp);
@@ -1929,7 +1915,7 @@ size_t tag__fprintf(struct tag *tag, const struct cu *cu,
 		printed += function__fprintf(tag, cu, pconf, fp);
 		break;
 	case DW_TAG_union_type:
-		printed += union__fprintf(tag__type(tag), cu, pconf, fp, false);
+		printed += union__fprintf(tag__type(tag), cu, pconf, fp);
 		break;
 	case DW_TAG_variable:
 		printed += variable__fprintf(tag, cu, pconf, fp);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 2/6] Revert "pahole.c: Add --inner_anonymous option"
  2021-12-07 17:31 [PATCH v2 0/6] improve expanded header Douglas RAILLARD
  2021-12-07 17:31 ` [PATCH v2 1/6] Revert "fprintf: Allow making struct/enum/union anonymous" Douglas RAILLARD
@ 2021-12-07 17:31 ` Douglas RAILLARD
  2021-12-07 17:31 ` [PATCH v2 3/6] fprintf: Print types only once Douglas RAILLARD
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 17+ messages in thread
From: Douglas RAILLARD @ 2021-12-07 17:31 UTC (permalink / raw)
  To: acme; +Cc: dwarves, douglas.raillard

From: Douglas Raillard <douglas.raillard@arm.com>

This reverts commit 6bf42c504b25f7daf9b601655ba1f8ba9ae3dd79.

Signed-off-by: Douglas Raillard <douglas.raillard@arm.com>
---
 man-pages/pahole.1 | 7 -------
 pahole.c           | 8 --------
 2 files changed, 15 deletions(-)

diff --git a/man-pages/pahole.1 b/man-pages/pahole.1
index 583e8a9..c1ec63e 100644
--- a/man-pages/pahole.1
+++ b/man-pages/pahole.1
@@ -122,13 +122,6 @@ Skip COUNT input records.
 Expand class members. Useful to find in what member of inner structs where an
 offset from the beginning of a struct is.
 
-.TP
-.B \-\-inner_anonymous
-Allow making inner structs, enums and unions anonymous, so that when using -E
-to expand types we don't end up with multiple definitions for the expanded
-inner structs/enums/unions, allowing the resulting expanded struct to be
-compilable.
-
 .TP
 .B \-F, \-\-format_path
 Allows specifying a list of debugging formats to try, in order. Right now this
diff --git a/pahole.c b/pahole.c
index 0f4ca57..f3a51cb 100644
--- a/pahole.c
+++ b/pahole.c
@@ -1127,7 +1127,6 @@ ARGP_PROGRAM_VERSION_HOOK_DEF = dwarves_print_version;
 #define ARGP_skip_encoding_btf_decl_tag 331
 #define ARGP_skip_missing          332
 #define ARGP_skip_encoding_btf_type_tag 333
-#define ARGP_inner_anonymous       334
 
 static const struct argp_option pahole__options[] = {
 	{
@@ -1235,11 +1234,6 @@ static const struct argp_option pahole__options[] = {
 		.key  = 'E',
 		.doc  = "expand class members",
 	},
-	{
-		.name = "inner_anonymous",
-		.key  = ARGP_inner_anonymous,
-		.doc  = "expanded class members are anonymous",
-	},
 	{
 		.name = "nr_members",
 		.key  = 'n',
@@ -1672,8 +1666,6 @@ static error_t pahole__options_parser(int key, char *arg,
 		conf_load.skip_missing = true;          break;
 	case ARGP_skip_encoding_btf_type_tag:
 		conf_load.skip_encoding_btf_type_tag = true;	break;
-	case ARGP_inner_anonymous:
-		conf.inner_anonymous = true;            break;
 	default:
 		return ARGP_ERR_UNKNOWN;
 	}
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 3/6] fprintf: Print types only once
  2021-12-07 17:31 [PATCH v2 0/6] improve expanded header Douglas RAILLARD
  2021-12-07 17:31 ` [PATCH v2 1/6] Revert "fprintf: Allow making struct/enum/union anonymous" Douglas RAILLARD
  2021-12-07 17:31 ` [PATCH v2 2/6] Revert "pahole.c: Add --inner_anonymous option" Douglas RAILLARD
@ 2021-12-07 17:31 ` Douglas RAILLARD
  2021-12-14 14:02   ` Arnaldo Carvalho de Melo
  2021-12-14 14:06   ` Arnaldo Carvalho de Melo
  2021-12-07 17:31 ` [PATCH v2 4/6] pahole.c: Add prefix to expanded type names Douglas RAILLARD
                   ` (3 subsequent siblings)
  6 siblings, 2 replies; 17+ messages in thread
From: Douglas RAILLARD @ 2021-12-07 17:31 UTC (permalink / raw)
  To: acme; +Cc: dwarves, douglas.raillard

From: Douglas Raillard <douglas.raillard@arm.com>

Use (struct tag).visited member to track what type has been printed
already to avoid printing it twice. This allows producing a valid C
header along with --expand_types.

Signed-off-by: Douglas Raillard <douglas.raillard@arm.com>
---
 dwarves.h         |  3 ++-
 dwarves_fprintf.c | 22 ++++++++++++++++------
 pahole.c          | 34 ++++++++++++++++++----------------
 3 files changed, 36 insertions(+), 23 deletions(-)

diff --git a/dwarves.h b/dwarves.h
index 52d162d..fc5b3fa 100644
--- a/dwarves.h
+++ b/dwarves.h
@@ -413,6 +413,7 @@ struct tag {
 	type_id_t	 type;
 	uint16_t	 tag;
 	bool		 visited;
+	bool		 printed;
 	bool		 top_level;
 	bool		 has_btf_type_tag;
 	uint16_t	 recursivity_level;
@@ -1370,7 +1371,7 @@ static inline const char *enumerator__name(const struct enumerator *enumerator)
 
 void enumeration__delete(struct type *type);
 void enumeration__add(struct type *type, struct enumerator *enumerator);
-size_t enumeration__fprintf(const struct tag *tag_enum,
+size_t enumeration__fprintf(struct tag *tag_enum,
 			    const struct conf_fprintf *conf, FILE *fp);
 
 int dwarves__init(void);
diff --git a/dwarves_fprintf.c b/dwarves_fprintf.c
index c5921d7..2c5dce6 100644
--- a/dwarves_fprintf.c
+++ b/dwarves_fprintf.c
@@ -278,8 +278,8 @@ size_t typedef__fprintf(const struct tag *tag, const struct cu *cu,
 {
 	struct type *type = tag__type(tag);
 	const struct conf_fprintf *pconf = conf ?: &conf_fprintf__defaults;
-	const struct tag *tag_type;
-	const struct tag *ptr_type;
+	struct tag *tag_type;
+	struct tag *ptr_type;
 	char bf[512];
 	int is_pointer = 0;
 	size_t printed;
@@ -394,13 +394,14 @@ out:
 	return type->max_tag_name_len;
 }
 
-size_t enumeration__fprintf(const struct tag *tag, const struct conf_fprintf *conf, FILE *fp)
+size_t enumeration__fprintf(struct tag *tag, const struct conf_fprintf *conf, FILE *fp)
 {
 	struct type *type = tag__type(tag);
 	struct enumerator *pos;
 	int max_entry_name_len = enumeration__max_entry_name_len(type);
 	size_t printed = fprintf(fp, "enum%s%s {\n", type__name(type) ? " " : "", type__name(type) ?: "");
 	int indent = conf->indent;
+	tag->printed = 1;
 
 	if (indent >= (int)sizeof(tabs))
 		indent = sizeof(tabs) - 1;
@@ -651,10 +652,14 @@ static size_t type__fprintf(struct tag *type, const struct cu *cu,
 	size_t printed = 0;
 	int expand_types = conf->expand_types;
 	int suppress_offset_comment = conf->suppress_offset_comment;
+	bool type_printed;
 
 	if (type == NULL)
 		goto out_type_not_found;
 
+	type_printed = type->printed;
+	type->printed = 1;
+
 	if (conf->expand_pointers) {
 		int nr_indirections = 0;
 
@@ -794,7 +799,7 @@ print_default:
 	case DW_TAG_structure_type:
 		ctype = tag__type(type);
 
-		if (type__name(ctype) != NULL && !expand_types) {
+		if (type__name(ctype) != NULL && (!expand_types || type_printed)) {
 			printed += fprintf(fp, "%s %-*s %s",
 					   (type->tag == DW_TAG_class_type &&
 					    !tconf.classes_as_structs) ? "class" : "struct",
@@ -813,7 +818,7 @@ print_default:
 	case DW_TAG_union_type:
 		ctype = tag__type(type);
 
-		if (type__name(ctype) != NULL && !expand_types) {
+		if (type__name(ctype) != NULL && (!expand_types || type_printed)) {
 			printed += fprintf(fp, "union %-*s %s", tconf.type_spacing - 6, type__name(ctype), name ?: "");
 		} else {
 			tconf.type_spacing -= 8;
@@ -823,7 +828,7 @@ print_default:
 	case DW_TAG_enumeration_type:
 		ctype = tag__type(type);
 
-		if (type__name(ctype) != NULL)
+		if (type__name(ctype) != NULL || type_printed)
 			printed += fprintf(fp, "enum %-*s %s", tconf.type_spacing - 5, type__name(ctype), name ?: "");
 		else
 			printed += enumeration__fprintf(type, &tconf, fp);
@@ -1000,6 +1005,8 @@ static size_t union__fprintf(struct type *type, const struct cu *cu,
 	uint32_t initial_union_cacheline;
 	uint32_t cacheline = 0; /* This will only be used if this is the outermost union */
 
+	type__tag(type)->printed = 1;
+
 	if (indent >= (int)sizeof(tabs))
 		indent = sizeof(tabs) - 1;
 
@@ -1394,6 +1401,8 @@ static size_t __class__fprintf(struct class *class, const struct cu *cu,
 				 type__name(type) ?: "");
 	int indent = cconf.indent;
 
+	class__tag(class)->printed = 1;
+
 	if (indent >= (int)sizeof(tabs))
 		indent = sizeof(tabs) - 1;
 
@@ -1856,6 +1865,7 @@ size_t tag__fprintf(struct tag *tag, const struct cu *cu,
 	size_t printed = 0;
 	struct conf_fprintf tconf;
 	const struct conf_fprintf *pconf = conf;
+	tag->printed = 1;
 
 	if (conf == NULL) {
 		tconf = conf_fprintf__defaults;
diff --git a/pahole.c b/pahole.c
index f3a51cb..42ba110 100644
--- a/pahole.c
+++ b/pahole.c
@@ -2964,22 +2964,24 @@ out_btf:
 			goto dump_it;
 		}
 
-		if (class)
-			class__find_holes(tag__class(class));
-		if (reorganize) {
-			if (class && tag__is_struct(class))
-				do_reorg(class, cu);
-		} else if (find_containers)
-			print_containers(cu, class_id, 0);
-		else if (find_pointers_in_structs)
-			print_structs_with_pointer_to(cu, class_id);
-		else if (class) {
-			/*
-			 * We don't need to print it for every compile unit
-			 * but the previous options need
-			 */
-			tag__fprintf(class, cu, &conf, stdout);
-			putchar('\n');
+		if (!class->printed) {
+			if (class)
+				class__find_holes(tag__class(class));
+			if (reorganize) {
+				if (class && tag__is_struct(class))
+					do_reorg(class, cu);
+			} else if (find_containers)
+				print_containers(cu, class_id, 0);
+			else if (find_pointers_in_structs)
+				print_structs_with_pointer_to(cu, class_id);
+			else if (class) {
+				/*
+				 * We don't need to print it for every compile unit
+				 * but the previous options need
+				 */
+				tag__fprintf(class, cu, &conf, stdout);
+				putchar('\n');
+			}
 		}
 	}
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 4/6] pahole.c: Add prefix to expanded type names
  2021-12-07 17:31 [PATCH v2 0/6] improve expanded header Douglas RAILLARD
                   ` (2 preceding siblings ...)
  2021-12-07 17:31 ` [PATCH v2 3/6] fprintf: Print types only once Douglas RAILLARD
@ 2021-12-07 17:31 ` Douglas RAILLARD
  2021-12-14 14:55   ` Arnaldo Carvalho de Melo
  2021-12-07 17:31 ` [PATCH v2 5/6] pahole.c: Add --expanded_prefix option Douglas RAILLARD
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 17+ messages in thread
From: Douglas RAILLARD @ 2021-12-07 17:31 UTC (permalink / raw)
  To: acme; +Cc: dwarves, douglas.raillard

From: Douglas Raillard <douglas.raillard@arm.com>

Add the prefix specified by --expanded_prefix to type names that have
not been specificaly requested using -C. This allows manual namespacing
so that these inner types will not conflict with existing headers.

Signed-off-by: Douglas Raillard <douglas.raillard@arm.com>
---
 dwarves.h |  1 +
 pahole.c  | 29 +++++++++++++++++++++++++++--
 2 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/dwarves.h b/dwarves.h
index fc5b3fa..0967e5c 100644
--- a/dwarves.h
+++ b/dwarves.h
@@ -90,6 +90,7 @@ struct conf_load {
  */
 struct conf_fprintf {
 	const char *prefix;
+	const char *name_prefix;
 	const char *suffix;
 	int32_t	   type_spacing;
 	int32_t	   name_spacing;
diff --git a/pahole.c b/pahole.c
index 42ba110..e0a1438 100644
--- a/pahole.c
+++ b/pahole.c
@@ -2882,6 +2882,33 @@ out_btf:
 
 	bool include_decls = find_pointers_in_structs != 0 || stats_formatter == nr_methods_formatter;
 	struct prototype *prototype, *n;
+	static type_id_t class_id;
+
+	uint32_t id;
+	struct tag *pos;
+	bool skip;
+	const char *prefix = conf_load->conf_fprintf->name_prefix;
+	const size_t prefix_len = prefix ? strlen(prefix) : 0;
+	cu__for_each_type(cu, id, pos) {
+		if (tag__is_type(pos)) {
+			const char *name = type__name(tag__type(pos));
+			if (name && prefix) {
+				skip = false;
+				list_for_each_entry_safe(prototype, n, &class_names, node) {
+					if (!strcmp(prototype->name, name)) {
+						skip = true;
+						break;
+					}
+				}
+				if (!skip) {
+					const size_t len = 1024 + prefix_len;
+					char *bf = malloc(len);
+					snprintf(bf, len, "%s%s", prefix, name);
+					tag__namespace(pos)->name = bf;
+				}
+			}
+		}
+	}
 
 	list_for_each_entry_safe(prototype, n, &class_names, node) {
 
@@ -2891,8 +2918,6 @@ out_btf:
 				prototype->type_enum_resolved = type__find_type_enum(tag__type(prototype->class), cu, prototype->type_enum) == 0;
 			continue;
 		}
-
-		static type_id_t class_id;
 		struct tag *class = cu__find_type_by_name(cu, prototype->name, include_decls, &class_id);
 
 		// couldn't find that class name in this CU, continue to the next one.
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 5/6] pahole.c: Add --expanded_prefix option
  2021-12-07 17:31 [PATCH v2 0/6] improve expanded header Douglas RAILLARD
                   ` (3 preceding siblings ...)
  2021-12-07 17:31 ` [PATCH v2 4/6] pahole.c: Add prefix to expanded type names Douglas RAILLARD
@ 2021-12-07 17:31 ` Douglas RAILLARD
  2021-12-07 17:31 ` [PATCH v2 6/6] pahole.c: Add --forward_decl option Douglas RAILLARD
  2021-12-08 11:55 ` [PATCH v2 0/6] improve expanded header Arnaldo Carvalho de Melo
  6 siblings, 0 replies; 17+ messages in thread
From: Douglas RAILLARD @ 2021-12-07 17:31 UTC (permalink / raw)
  To: acme; +Cc: dwarves, douglas.raillard

From: Douglas Raillard <douglas.raillard@arm.com>

Allow prefixing type names and enum members with an arbitrary string as
a way of creating a manual namespace for additional types displayed with
--expand_types.

Signed-off-by: Douglas Raillard <douglas.raillard@arm.com>
---
 man-pages/pahole.1 | 5 +++++
 pahole.c           | 9 +++++++++
 2 files changed, 14 insertions(+)

diff --git a/man-pages/pahole.1 b/man-pages/pahole.1
index c1ec63e..f845e24 100644
--- a/man-pages/pahole.1
+++ b/man-pages/pahole.1
@@ -122,6 +122,11 @@ Skip COUNT input records.
 Expand class members. Useful to find in what member of inner structs where an
 offset from the beginning of a struct is.
 
+.TP
+.B \-\-expanded_prefix
+Add prefix to type names that are not specified using --class_name. This helps
+avoiding conflicts with existing headers in types expanded by --expand_types.
+
 .TP
 .B \-F, \-\-format_path
 Allows specifying a list of debugging formats to try, in order. Right now this
diff --git a/pahole.c b/pahole.c
index e0a1438..e828c31 100644
--- a/pahole.c
+++ b/pahole.c
@@ -1127,6 +1127,7 @@ ARGP_PROGRAM_VERSION_HOOK_DEF = dwarves_print_version;
 #define ARGP_skip_encoding_btf_decl_tag 331
 #define ARGP_skip_missing          332
 #define ARGP_skip_encoding_btf_type_tag 333
+#define ARGP_expanded_prefix 334
 
 static const struct argp_option pahole__options[] = {
 	{
@@ -1234,6 +1235,12 @@ static const struct argp_option pahole__options[] = {
 		.key  = 'E',
 		.doc  = "expand class members",
 	},
+	{
+		.name = "expanded_prefix",
+		.key  = ARGP_expanded_prefix,
+		.arg  = "NAME_PREFIX",
+		.doc  = "Add prefix to all the nested types displayed with --expand_types",
+	},
 	{
 		.name = "nr_members",
 		.key  = 'n',
@@ -1666,6 +1673,8 @@ static error_t pahole__options_parser(int key, char *arg,
 		conf_load.skip_missing = true;          break;
 	case ARGP_skip_encoding_btf_type_tag:
 		conf_load.skip_encoding_btf_type_tag = true;	break;
+	case ARGP_expanded_prefix:
+		conf.name_prefix = arg;                 break;
 	default:
 		return ARGP_ERR_UNKNOWN;
 	}
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v2 6/6] pahole.c: Add --forward_decl option
  2021-12-07 17:31 [PATCH v2 0/6] improve expanded header Douglas RAILLARD
                   ` (4 preceding siblings ...)
  2021-12-07 17:31 ` [PATCH v2 5/6] pahole.c: Add --expanded_prefix option Douglas RAILLARD
@ 2021-12-07 17:31 ` Douglas RAILLARD
  2021-12-08 11:55 ` [PATCH v2 0/6] improve expanded header Arnaldo Carvalho de Melo
  6 siblings, 0 replies; 17+ messages in thread
From: Douglas RAILLARD @ 2021-12-07 17:31 UTC (permalink / raw)
  To: acme; +Cc: dwarves, douglas.raillard

From: Douglas Raillard <douglas.raillard@arm.com>

Print forward declaration for types supporting it. This allows creating
a self-contained header where it is guaranteed that union and struct
pointers will compile correctly regardless of their declaration order.

Signed-off-by: Douglas Raillard <douglas.raillard@arm.com>
---
 dwarves.h         |  4 ++++
 dwarves_fprintf.c |  5 +----
 pahole.c          | 22 ++++++++++++++++++++++
 3 files changed, 27 insertions(+), 4 deletions(-)

diff --git a/dwarves.h b/dwarves.h
index 0967e5c..3f4b31b 100644
--- a/dwarves.h
+++ b/dwarves.h
@@ -1046,6 +1046,10 @@ struct type {
 
 void __type__init(struct type *type);
 
+size_t type__fprintf(struct tag *type, const struct cu *cu,
+		     const char *name, const struct conf_fprintf *conf,
+		     FILE *fp);
+
 size_t tag__natural_alignment(struct tag *tag, const struct cu *cu);
 
 static inline struct class *type__class(const struct type *type)
diff --git a/dwarves_fprintf.c b/dwarves_fprintf.c
index 2c5dce6..c116184 100644
--- a/dwarves_fprintf.c
+++ b/dwarves_fprintf.c
@@ -199,9 +199,6 @@ size_t tag__fprintf_decl_info(const struct tag *tag,
 
 static size_t __class__fprintf(struct class *class, const struct cu *cu,
 			       const struct conf_fprintf *conf, FILE *fp);
-static size_t type__fprintf(struct tag *type, const struct cu *cu,
-			    const char *name, const struct conf_fprintf *conf,
-			    FILE *fp);
 
 static size_t array_type__fprintf(const struct tag *tag,
 				  const struct cu *cu, const char *name,
@@ -637,7 +634,7 @@ static size_t type__fprintf_stats(struct type *type, const struct cu *cu,
 static size_t union__fprintf(struct type *type, const struct cu *cu,
 			     const struct conf_fprintf *conf, FILE *fp);
 
-static size_t type__fprintf(struct tag *type, const struct cu *cu,
+size_t type__fprintf(struct tag *type, const struct cu *cu,
 			    const char *name, const struct conf_fprintf *conf,
 			    FILE *fp)
 {
diff --git a/pahole.c b/pahole.c
index e828c31..73579f5 100644
--- a/pahole.c
+++ b/pahole.c
@@ -59,6 +59,8 @@ static size_t cu__exclude_prefix_len;
 static char *decl_exclude_prefix;
 static size_t decl_exclude_prefix_len;
 
+static bool print_forward_decl;
+
 static uint16_t nr_holes;
 static uint16_t nr_bit_holes;
 static uint16_t hole_size_ge;
@@ -1128,6 +1130,7 @@ ARGP_PROGRAM_VERSION_HOOK_DEF = dwarves_print_version;
 #define ARGP_skip_missing          332
 #define ARGP_skip_encoding_btf_type_tag 333
 #define ARGP_expanded_prefix 334
+#define ARGP_forward_decl 335
 
 static const struct argp_option pahole__options[] = {
 	{
@@ -1241,6 +1244,11 @@ static const struct argp_option pahole__options[] = {
 		.arg  = "NAME_PREFIX",
 		.doc  = "Add prefix to all the nested types displayed with --expand_types",
 	},
+	{
+		.name = "forward_decl",
+		.key  = ARGP_forward_decl,
+		.doc  = "Print a forward declaration for types that support it",
+	},
 	{
 		.name = "nr_members",
 		.key  = 'n',
@@ -1675,6 +1683,8 @@ static error_t pahole__options_parser(int key, char *arg,
 		conf_load.skip_encoding_btf_type_tag = true;	break;
 	case ARGP_expanded_prefix:
 		conf.name_prefix = arg;                 break;
+	case ARGP_forward_decl:
+		print_forward_decl = true;                 break;
 	default:
 		return ARGP_ERR_UNKNOWN;
 	}
@@ -2898,6 +2908,10 @@ out_btf:
 	bool skip;
 	const char *prefix = conf_load->conf_fprintf->name_prefix;
 	const size_t prefix_len = prefix ? strlen(prefix) : 0;
+
+	struct conf_fprintf pconf = *conf_load->conf_fprintf;
+	pconf.expand_types = false;
+
 	cu__for_each_type(cu, id, pos) {
 		if (tag__is_type(pos)) {
 			const char *name = type__name(tag__type(pos));
@@ -2917,6 +2931,14 @@ out_btf:
 				}
 			}
 		}
+		if (print_forward_decl && (tag__is_union(pos) || tag__is_struct(pos))) {
+			const char *name = type__name(tag__type(pos));
+			if (name) {
+				type__fprintf(pos, cu, NULL, &pconf, stdout);
+				pos->printed = false;
+				printf(";\n");
+			}
+		}
 	}
 
 	list_for_each_entry_safe(prototype, n, &class_names, node) {
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [PATCH v2 0/6] improve expanded header
  2021-12-07 17:31 [PATCH v2 0/6] improve expanded header Douglas RAILLARD
                   ` (5 preceding siblings ...)
  2021-12-07 17:31 ` [PATCH v2 6/6] pahole.c: Add --forward_decl option Douglas RAILLARD
@ 2021-12-08 11:55 ` Arnaldo Carvalho de Melo
  6 siblings, 0 replies; 17+ messages in thread
From: Arnaldo Carvalho de Melo @ 2021-12-08 11:55 UTC (permalink / raw)
  To: Douglas RAILLARD; +Cc: acme, dwarves

Em Tue, Dec 07, 2021 at 05:31:45PM +0000, Douglas RAILLARD escreveu:
> From: Douglas Raillard <douglas.raillard@arm.com>
> 
> Improve headers generated with -E in a few ways:
> 
>   * Print each type only once, to avoid redefinitions
> 
>   * --forward_decl: Generate forward declaration for struct and union so
>     that uses of pointers will work.
> 
>   * --expanded_prefix: Allow prefixing names of types added by -E (all
>     the ones not explicitly requested with -C) so they can be namespaced
>     manually. This is important in order to be able to mix
>     pahole-generated headers with existing headers without clash or
>     maintenance.

Looks good from a very quick first view, I'll cut 1.23 today as the BPF
guys need a release with the new BTF tag feature and then will review
this patchset.

So I've applied so far only the reverts, since yesterday I had flipped
next to master.

- Arnaldo
 
> 
> types.txt:
> 
>   t1
>   t4
> 
> Original printed type with "-C types.txt -E":
> 
>   struct t1 {
>     struct t2 *a;
>     struct t3 {
>       int a;
>     } b;
>   };
> 
>   struct t4 {
>     struct t3 {
>       int a;
>     } a;
>   };
> 
> After this series and with
> "-C types.txt -E --expanded_prefix __pahole --forward_decl":
> 
>   struct t1
>   struct t2;
>   struct t3;
> 
>   struct t1 {
>     struct t2 *a;
>     struct __pahole_t3 {
>       int a;
>     } b;
>   };
> 
>   struct t4 {
>     struct __pahole_t3 a;
>   };
> 
> 
> This header can be freely mixed with any other header as long as they
> don't define t1 or t4 (if there is a clash, then pahole is not necessary
> and the user can just use the header in the first place).
> 
> TODOs:
> 
>   * Define types on their first use even when they are first used as
>     pointers. Currently, if a type is only used as pointer it will never
>     get defined, which will still compile thanks to --forward_decl but
>     won't allow easy use of the values.
> 
>   * The prefix system allocates memory to rename types and never frees
>     it. I don't think it's a big issue for now as it's done inside
>     pahole.c and type names are likely necessary until the end of the
>     process anyway, but it makes valgrind angry and could therefore mask
>     other problems. There is another implementation of prefix that
>     modifies dwarves_fprintf.c instead of changing the name but it was
>     very invasive and impossible to check if prefixable spots were
>     missed.
> 
> 
> This series is to be applied on the "next" branch as it includes reverts
> of the --inner_anonymous series, which is dropped since it could not
> cope with recursive types.
> 
> 
> Douglas Raillard (6):
>   Revert "fprintf: Allow making struct/enum/union anonymous"
>   Revert "pahole.c: Add --inner_anonymous option"
>   fprintf: Print types only once
>   pahole.c: Add prefix to expanded type names
>   pahole.c: Add --expanded_prefix option
>   pahole.c: Add --forward_decl option
> 
>  dwarves.h          | 12 ++++--
>  dwarves_emit.c     |  2 +-
>  dwarves_fprintf.c  | 77 +++++++++++++++++-------------------
>  man-pages/pahole.1 |  8 ++--
>  pahole.c           | 98 ++++++++++++++++++++++++++++++++++------------
>  5 files changed, 121 insertions(+), 76 deletions(-)
> 
> -- 
> 2.25.1

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v2 3/6] fprintf: Print types only once
  2021-12-07 17:31 ` [PATCH v2 3/6] fprintf: Print types only once Douglas RAILLARD
@ 2021-12-14 14:02   ` Arnaldo Carvalho de Melo
  2021-12-14 17:54     ` Douglas Raillard
  2021-12-14 14:06   ` Arnaldo Carvalho de Melo
  1 sibling, 1 reply; 17+ messages in thread
From: Arnaldo Carvalho de Melo @ 2021-12-14 14:02 UTC (permalink / raw)
  To: Douglas RAILLARD; +Cc: acme, dwarves

Em Tue, Dec 07, 2021 at 05:31:48PM +0000, Douglas RAILLARD escreveu:
> From: Douglas Raillard <douglas.raillard@arm.com>
> 
> Use (struct tag).visited member to track what type has been printed

This doesn't match the patch, where you ended up using a new tar.printed
field, have you tried with .visited and ended up finding out .printed
was needed?

- Arnaldo

> already to avoid printing it twice. This allows producing a valid C
> header along with --expand_types.
> 
> Signed-off-by: Douglas Raillard <douglas.raillard@arm.com>
> ---
>  dwarves.h         |  3 ++-
>  dwarves_fprintf.c | 22 ++++++++++++++++------
>  pahole.c          | 34 ++++++++++++++++++----------------
>  3 files changed, 36 insertions(+), 23 deletions(-)
> 
> diff --git a/dwarves.h b/dwarves.h
> index 52d162d..fc5b3fa 100644
> --- a/dwarves.h
> +++ b/dwarves.h
> @@ -413,6 +413,7 @@ struct tag {
>  	type_id_t	 type;
>  	uint16_t	 tag;
>  	bool		 visited;
> +	bool		 printed;
>  	bool		 top_level;
>  	bool		 has_btf_type_tag;
>  	uint16_t	 recursivity_level;
> @@ -1370,7 +1371,7 @@ static inline const char *enumerator__name(const struct enumerator *enumerator)
>  
>  void enumeration__delete(struct type *type);
>  void enumeration__add(struct type *type, struct enumerator *enumerator);
> -size_t enumeration__fprintf(const struct tag *tag_enum,
> +size_t enumeration__fprintf(struct tag *tag_enum,
>  			    const struct conf_fprintf *conf, FILE *fp);
>  
>  int dwarves__init(void);
> diff --git a/dwarves_fprintf.c b/dwarves_fprintf.c
> index c5921d7..2c5dce6 100644
> --- a/dwarves_fprintf.c
> +++ b/dwarves_fprintf.c
> @@ -278,8 +278,8 @@ size_t typedef__fprintf(const struct tag *tag, const struct cu *cu,
>  {
>  	struct type *type = tag__type(tag);
>  	const struct conf_fprintf *pconf = conf ?: &conf_fprintf__defaults;
> -	const struct tag *tag_type;
> -	const struct tag *ptr_type;
> +	struct tag *tag_type;
> +	struct tag *ptr_type;
>  	char bf[512];
>  	int is_pointer = 0;
>  	size_t printed;
> @@ -394,13 +394,14 @@ out:
>  	return type->max_tag_name_len;
>  }
>  
> -size_t enumeration__fprintf(const struct tag *tag, const struct conf_fprintf *conf, FILE *fp)
> +size_t enumeration__fprintf(struct tag *tag, const struct conf_fprintf *conf, FILE *fp)
>  {
>  	struct type *type = tag__type(tag);
>  	struct enumerator *pos;
>  	int max_entry_name_len = enumeration__max_entry_name_len(type);
>  	size_t printed = fprintf(fp, "enum%s%s {\n", type__name(type) ? " " : "", type__name(type) ?: "");
>  	int indent = conf->indent;
> +	tag->printed = 1;
>  
>  	if (indent >= (int)sizeof(tabs))
>  		indent = sizeof(tabs) - 1;
> @@ -651,10 +652,14 @@ static size_t type__fprintf(struct tag *type, const struct cu *cu,
>  	size_t printed = 0;
>  	int expand_types = conf->expand_types;
>  	int suppress_offset_comment = conf->suppress_offset_comment;
> +	bool type_printed;
>  
>  	if (type == NULL)
>  		goto out_type_not_found;
>  
> +	type_printed = type->printed;
> +	type->printed = 1;
> +
>  	if (conf->expand_pointers) {
>  		int nr_indirections = 0;
>  
> @@ -794,7 +799,7 @@ print_default:
>  	case DW_TAG_structure_type:
>  		ctype = tag__type(type);
>  
> -		if (type__name(ctype) != NULL && !expand_types) {
> +		if (type__name(ctype) != NULL && (!expand_types || type_printed)) {
>  			printed += fprintf(fp, "%s %-*s %s",
>  					   (type->tag == DW_TAG_class_type &&
>  					    !tconf.classes_as_structs) ? "class" : "struct",
> @@ -813,7 +818,7 @@ print_default:
>  	case DW_TAG_union_type:
>  		ctype = tag__type(type);
>  
> -		if (type__name(ctype) != NULL && !expand_types) {
> +		if (type__name(ctype) != NULL && (!expand_types || type_printed)) {
>  			printed += fprintf(fp, "union %-*s %s", tconf.type_spacing - 6, type__name(ctype), name ?: "");
>  		} else {
>  			tconf.type_spacing -= 8;
> @@ -823,7 +828,7 @@ print_default:
>  	case DW_TAG_enumeration_type:
>  		ctype = tag__type(type);
>  
> -		if (type__name(ctype) != NULL)
> +		if (type__name(ctype) != NULL || type_printed)
>  			printed += fprintf(fp, "enum %-*s %s", tconf.type_spacing - 5, type__name(ctype), name ?: "");
>  		else
>  			printed += enumeration__fprintf(type, &tconf, fp);
> @@ -1000,6 +1005,8 @@ static size_t union__fprintf(struct type *type, const struct cu *cu,
>  	uint32_t initial_union_cacheline;
>  	uint32_t cacheline = 0; /* This will only be used if this is the outermost union */
>  
> +	type__tag(type)->printed = 1;
> +
>  	if (indent >= (int)sizeof(tabs))
>  		indent = sizeof(tabs) - 1;
>  
> @@ -1394,6 +1401,8 @@ static size_t __class__fprintf(struct class *class, const struct cu *cu,
>  				 type__name(type) ?: "");
>  	int indent = cconf.indent;
>  
> +	class__tag(class)->printed = 1;
> +
>  	if (indent >= (int)sizeof(tabs))
>  		indent = sizeof(tabs) - 1;
>  
> @@ -1856,6 +1865,7 @@ size_t tag__fprintf(struct tag *tag, const struct cu *cu,
>  	size_t printed = 0;
>  	struct conf_fprintf tconf;
>  	const struct conf_fprintf *pconf = conf;
> +	tag->printed = 1;
>  
>  	if (conf == NULL) {
>  		tconf = conf_fprintf__defaults;
> diff --git a/pahole.c b/pahole.c
> index f3a51cb..42ba110 100644
> --- a/pahole.c
> +++ b/pahole.c
> @@ -2964,22 +2964,24 @@ out_btf:
>  			goto dump_it;
>  		}
>  
> -		if (class)
> -			class__find_holes(tag__class(class));
> -		if (reorganize) {
> -			if (class && tag__is_struct(class))
> -				do_reorg(class, cu);
> -		} else if (find_containers)
> -			print_containers(cu, class_id, 0);
> -		else if (find_pointers_in_structs)
> -			print_structs_with_pointer_to(cu, class_id);
> -		else if (class) {
> -			/*
> -			 * We don't need to print it for every compile unit
> -			 * but the previous options need
> -			 */
> -			tag__fprintf(class, cu, &conf, stdout);
> -			putchar('\n');
> +		if (!class->printed) {
> +			if (class)
> +				class__find_holes(tag__class(class));
> +			if (reorganize) {
> +				if (class && tag__is_struct(class))
> +					do_reorg(class, cu);
> +			} else if (find_containers)
> +				print_containers(cu, class_id, 0);
> +			else if (find_pointers_in_structs)
> +				print_structs_with_pointer_to(cu, class_id);
> +			else if (class) {
> +				/*
> +				 * We don't need to print it for every compile unit
> +				 * but the previous options need
> +				 */
> +				tag__fprintf(class, cu, &conf, stdout);
> +				putchar('\n');
> +			}
>  		}
>  	}
>  
> -- 
> 2.25.1

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v2 3/6] fprintf: Print types only once
  2021-12-07 17:31 ` [PATCH v2 3/6] fprintf: Print types only once Douglas RAILLARD
  2021-12-14 14:02   ` Arnaldo Carvalho de Melo
@ 2021-12-14 14:06   ` Arnaldo Carvalho de Melo
  2021-12-14 18:23     ` Douglas Raillard
  1 sibling, 1 reply; 17+ messages in thread
From: Arnaldo Carvalho de Melo @ 2021-12-14 14:06 UTC (permalink / raw)
  To: Douglas RAILLARD; +Cc: acme, dwarves

Em Tue, Dec 07, 2021 at 05:31:48PM +0000, Douglas RAILLARD escreveu:
> From: Douglas Raillard <douglas.raillard@arm.com>
> 
> Use (struct tag).visited member to track what type has been printed
> already to avoid printing it twice. This allows producing a valid C
> header along with --expand_types.

And here you changed the default, i.e. it is useful to have the current
--expand_types behaviour of expanding types as it traverse containers,
so I think this needs another option to ask for this new
behaviour, I think we can have that as --expand_types_once that would be
used instead of --expand_types, ok?

- Arnaldo
 
> Signed-off-by: Douglas Raillard <douglas.raillard@arm.com>
> ---
>  dwarves.h         |  3 ++-
>  dwarves_fprintf.c | 22 ++++++++++++++++------
>  pahole.c          | 34 ++++++++++++++++++----------------
>  3 files changed, 36 insertions(+), 23 deletions(-)
> 
> diff --git a/dwarves.h b/dwarves.h
> index 52d162d..fc5b3fa 100644
> --- a/dwarves.h
> +++ b/dwarves.h
> @@ -413,6 +413,7 @@ struct tag {
>  	type_id_t	 type;
>  	uint16_t	 tag;
>  	bool		 visited;
> +	bool		 printed;
>  	bool		 top_level;
>  	bool		 has_btf_type_tag;
>  	uint16_t	 recursivity_level;
> @@ -1370,7 +1371,7 @@ static inline const char *enumerator__name(const struct enumerator *enumerator)
>  
>  void enumeration__delete(struct type *type);
>  void enumeration__add(struct type *type, struct enumerator *enumerator);
> -size_t enumeration__fprintf(const struct tag *tag_enum,
> +size_t enumeration__fprintf(struct tag *tag_enum,
>  			    const struct conf_fprintf *conf, FILE *fp);
>  
>  int dwarves__init(void);
> diff --git a/dwarves_fprintf.c b/dwarves_fprintf.c
> index c5921d7..2c5dce6 100644
> --- a/dwarves_fprintf.c
> +++ b/dwarves_fprintf.c
> @@ -278,8 +278,8 @@ size_t typedef__fprintf(const struct tag *tag, const struct cu *cu,
>  {
>  	struct type *type = tag__type(tag);
>  	const struct conf_fprintf *pconf = conf ?: &conf_fprintf__defaults;
> -	const struct tag *tag_type;
> -	const struct tag *ptr_type;
> +	struct tag *tag_type;
> +	struct tag *ptr_type;
>  	char bf[512];
>  	int is_pointer = 0;
>  	size_t printed;
> @@ -394,13 +394,14 @@ out:
>  	return type->max_tag_name_len;
>  }
>  
> -size_t enumeration__fprintf(const struct tag *tag, const struct conf_fprintf *conf, FILE *fp)
> +size_t enumeration__fprintf(struct tag *tag, const struct conf_fprintf *conf, FILE *fp)
>  {
>  	struct type *type = tag__type(tag);
>  	struct enumerator *pos;
>  	int max_entry_name_len = enumeration__max_entry_name_len(type);
>  	size_t printed = fprintf(fp, "enum%s%s {\n", type__name(type) ? " " : "", type__name(type) ?: "");
>  	int indent = conf->indent;
> +	tag->printed = 1;
>  
>  	if (indent >= (int)sizeof(tabs))
>  		indent = sizeof(tabs) - 1;
> @@ -651,10 +652,14 @@ static size_t type__fprintf(struct tag *type, const struct cu *cu,
>  	size_t printed = 0;
>  	int expand_types = conf->expand_types;
>  	int suppress_offset_comment = conf->suppress_offset_comment;
> +	bool type_printed;
>  
>  	if (type == NULL)
>  		goto out_type_not_found;
>  
> +	type_printed = type->printed;
> +	type->printed = 1;
> +
>  	if (conf->expand_pointers) {
>  		int nr_indirections = 0;
>  
> @@ -794,7 +799,7 @@ print_default:
>  	case DW_TAG_structure_type:
>  		ctype = tag__type(type);
>  
> -		if (type__name(ctype) != NULL && !expand_types) {
> +		if (type__name(ctype) != NULL && (!expand_types || type_printed)) {
>  			printed += fprintf(fp, "%s %-*s %s",
>  					   (type->tag == DW_TAG_class_type &&
>  					    !tconf.classes_as_structs) ? "class" : "struct",
> @@ -813,7 +818,7 @@ print_default:
>  	case DW_TAG_union_type:
>  		ctype = tag__type(type);
>  
> -		if (type__name(ctype) != NULL && !expand_types) {
> +		if (type__name(ctype) != NULL && (!expand_types || type_printed)) {
>  			printed += fprintf(fp, "union %-*s %s", tconf.type_spacing - 6, type__name(ctype), name ?: "");
>  		} else {
>  			tconf.type_spacing -= 8;
> @@ -823,7 +828,7 @@ print_default:
>  	case DW_TAG_enumeration_type:
>  		ctype = tag__type(type);
>  
> -		if (type__name(ctype) != NULL)
> +		if (type__name(ctype) != NULL || type_printed)
>  			printed += fprintf(fp, "enum %-*s %s", tconf.type_spacing - 5, type__name(ctype), name ?: "");
>  		else
>  			printed += enumeration__fprintf(type, &tconf, fp);
> @@ -1000,6 +1005,8 @@ static size_t union__fprintf(struct type *type, const struct cu *cu,
>  	uint32_t initial_union_cacheline;
>  	uint32_t cacheline = 0; /* This will only be used if this is the outermost union */
>  
> +	type__tag(type)->printed = 1;
> +
>  	if (indent >= (int)sizeof(tabs))
>  		indent = sizeof(tabs) - 1;
>  
> @@ -1394,6 +1401,8 @@ static size_t __class__fprintf(struct class *class, const struct cu *cu,
>  				 type__name(type) ?: "");
>  	int indent = cconf.indent;
>  
> +	class__tag(class)->printed = 1;
> +
>  	if (indent >= (int)sizeof(tabs))
>  		indent = sizeof(tabs) - 1;
>  
> @@ -1856,6 +1865,7 @@ size_t tag__fprintf(struct tag *tag, const struct cu *cu,
>  	size_t printed = 0;
>  	struct conf_fprintf tconf;
>  	const struct conf_fprintf *pconf = conf;
> +	tag->printed = 1;
>  
>  	if (conf == NULL) {
>  		tconf = conf_fprintf__defaults;
> diff --git a/pahole.c b/pahole.c
> index f3a51cb..42ba110 100644
> --- a/pahole.c
> +++ b/pahole.c
> @@ -2964,22 +2964,24 @@ out_btf:
>  			goto dump_it;
>  		}
>  
> -		if (class)
> -			class__find_holes(tag__class(class));
> -		if (reorganize) {
> -			if (class && tag__is_struct(class))
> -				do_reorg(class, cu);
> -		} else if (find_containers)
> -			print_containers(cu, class_id, 0);
> -		else if (find_pointers_in_structs)
> -			print_structs_with_pointer_to(cu, class_id);
> -		else if (class) {
> -			/*
> -			 * We don't need to print it for every compile unit
> -			 * but the previous options need
> -			 */
> -			tag__fprintf(class, cu, &conf, stdout);
> -			putchar('\n');
> +		if (!class->printed) {
> +			if (class)
> +				class__find_holes(tag__class(class));
> +			if (reorganize) {
> +				if (class && tag__is_struct(class))
> +					do_reorg(class, cu);
> +			} else if (find_containers)
> +				print_containers(cu, class_id, 0);
> +			else if (find_pointers_in_structs)
> +				print_structs_with_pointer_to(cu, class_id);
> +			else if (class) {
> +				/*
> +				 * We don't need to print it for every compile unit
> +				 * but the previous options need
> +				 */
> +				tag__fprintf(class, cu, &conf, stdout);
> +				putchar('\n');
> +			}
>  		}
>  	}
>  
> -- 
> 2.25.1

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v2 4/6] pahole.c: Add prefix to expanded type names
  2021-12-07 17:31 ` [PATCH v2 4/6] pahole.c: Add prefix to expanded type names Douglas RAILLARD
@ 2021-12-14 14:55   ` Arnaldo Carvalho de Melo
  2021-12-14 17:50     ` Douglas Raillard
  0 siblings, 1 reply; 17+ messages in thread
From: Arnaldo Carvalho de Melo @ 2021-12-14 14:55 UTC (permalink / raw)
  To: Douglas RAILLARD; +Cc: acme, dwarves

Em Tue, Dec 07, 2021 at 05:31:49PM +0000, Douglas RAILLARD escreveu:
> From: Douglas Raillard <douglas.raillard@arm.com>
> 
> Add the prefix specified by --expanded_prefix to type names that have
> not been specificaly requested using -C. This allows manual namespacing
> so that these inner types will not conflict with existing headers.
> 
> Signed-off-by: Douglas Raillard <douglas.raillard@arm.com>
> ---
>  dwarves.h |  1 +
>  pahole.c  | 29 +++++++++++++++++++++++++++--
>  2 files changed, 28 insertions(+), 2 deletions(-)
> 
> diff --git a/dwarves.h b/dwarves.h
> index fc5b3fa..0967e5c 100644
> --- a/dwarves.h
> +++ b/dwarves.h
> @@ -90,6 +90,7 @@ struct conf_load {
>   */
>  struct conf_fprintf {
>  	const char *prefix;
> +	const char *name_prefix;
>  	const char *suffix;
>  	int32_t	   type_spacing;
>  	int32_t	   name_spacing;
> diff --git a/pahole.c b/pahole.c
> index 42ba110..e0a1438 100644
> --- a/pahole.c
> +++ b/pahole.c
> @@ -2882,6 +2882,33 @@ out_btf:
>  
>  	bool include_decls = find_pointers_in_structs != 0 || stats_formatter == nr_methods_formatter;
>  	struct prototype *prototype, *n;
> +	static type_id_t class_id;
> +
> +	uint32_t id;
> +	struct tag *pos;
> +	bool skip;
> +	const char *prefix = conf_load->conf_fprintf->name_prefix;
> +	const size_t prefix_len = prefix ? strlen(prefix) : 0;
> +	cu__for_each_type(cu, id, pos) {
> +		if (tag__is_type(pos)) {
> +			const char *name = type__name(tag__type(pos));
> +			if (name && prefix) {
> +				skip = false;
> +				list_for_each_entry_safe(prototype, n, &class_names, node) {
> +					if (!strcmp(prototype->name, name)) {
> +						skip = true;
> +						break;
> +					}
> +				}
> +				if (!skip) {
> +					const size_t len = 1024 + prefix_len;
> +					char *bf = malloc(len);
> +					snprintf(bf, len, "%s%s", prefix, name);
> +					tag__namespace(pos)->name = bf;
> +				}
> +			}
> +		}
> +	}

I don't like this change in place mode, but I understand it is easier to
do it here instead of in all types fprintf routines, but perhaps its
better that way, I'll check how big it would be.

>  
>  	list_for_each_entry_safe(prototype, n, &class_names, node) {
>  
> @@ -2891,8 +2918,6 @@ out_btf:
>  				prototype->type_enum_resolved = type__find_type_enum(tag__type(prototype->class), cu, prototype->type_enum) == 0;
>  			continue;
>  		}
> -
> -		static type_id_t class_id;
>  		struct tag *class = cu__find_type_by_name(cu, prototype->name, include_decls, &class_id);
>  
>  		// couldn't find that class name in this CU, continue to the next one.
> -- 
> 2.25.1

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v2 4/6] pahole.c: Add prefix to expanded type names
  2021-12-14 14:55   ` Arnaldo Carvalho de Melo
@ 2021-12-14 17:50     ` Douglas Raillard
  2021-12-14 19:13       ` Arnaldo Carvalho de Melo
  2021-12-14 19:18       ` Arnaldo Carvalho de Melo
  0 siblings, 2 replies; 17+ messages in thread
From: Douglas Raillard @ 2021-12-14 17:50 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo; +Cc: acme, dwarves

On 12/14/21 2:55 PM, Arnaldo Carvalho de Melo wrote:
> Em Tue, Dec 07, 2021 at 05:31:49PM +0000, Douglas RAILLARD escreveu:
>> From: Douglas Raillard <douglas.raillard@arm.com>
>>
>> Add the prefix specified by --expanded_prefix to type names that have
>> not been specificaly requested using -C. This allows manual namespacing
>> so that these inner types will not conflict with existing headers.
>>
>> Signed-off-by: Douglas Raillard <douglas.raillard@arm.com>
>> ---
>>   dwarves.h |  1 +
>>   pahole.c  | 29 +++++++++++++++++++++++++++--
>>   2 files changed, 28 insertions(+), 2 deletions(-)
>>
>> diff --git a/dwarves.h b/dwarves.h
>> index fc5b3fa..0967e5c 100644
>> --- a/dwarves.h
>> +++ b/dwarves.h
>> @@ -90,6 +90,7 @@ struct conf_load {
>>    */
>>   struct conf_fprintf {
>>   	const char *prefix;
>> +	const char *name_prefix;
>>   	const char *suffix;
>>   	int32_t	   type_spacing;
>>   	int32_t	   name_spacing;
>> diff --git a/pahole.c b/pahole.c
>> index 42ba110..e0a1438 100644
>> --- a/pahole.c
>> +++ b/pahole.c
>> @@ -2882,6 +2882,33 @@ out_btf:
>>   
>>   	bool include_decls = find_pointers_in_structs != 0 || stats_formatter == nr_methods_formatter;
>>   	struct prototype *prototype, *n;
>> +	static type_id_t class_id;
>> +
>> +	uint32_t id;
>> +	struct tag *pos;
>> +	bool skip;
>> +	const char *prefix = conf_load->conf_fprintf->name_prefix;
>> +	const size_t prefix_len = prefix ? strlen(prefix) : 0;
>> +	cu__for_each_type(cu, id, pos) {
>> +		if (tag__is_type(pos)) {
>> +			const char *name = type__name(tag__type(pos));
>> +			if (name && prefix) {
>> +				skip = false;
>> +				list_for_each_entry_safe(prototype, n, &class_names, node) {
>> +					if (!strcmp(prototype->name, name)) {
>> +						skip = true;
>> +						break;
>> +					}
>> +				}
>> +				if (!skip) {
>> +					const size_t len = 1024 + prefix_len;
>> +					char *bf = malloc(len);
>> +					snprintf(bf, len, "%s%s", prefix, name);
>> +					tag__namespace(pos)->name = bf;
>> +				}
>> +			}
>> +		}
>> +	}
> 
> I don't like this change in place mode, but I understand it is easier to
> do it here instead of in all types fprintf routines, but perhaps its
> better that way, I'll check how big it would be.

I don't really like it either but the alternative is something like that:
https://github.com/douglas-raillard-arm/pahole/commit/a3d4e224b2a0cb8196db0f8536bd77f976e364ca

The worst is not the size of the patch, it's the inability to check that it's actually complete.
Any spot where the prefix should be applied and where it is not will result in a broken header.
This also stands for any future addition to dwarves_fprintf.c.

One way to make the substitution safer is to completely ban direct access to the name and force
to go through an accessor that would apply the prefix, but this leads to either memory management
issue or inefficiency (as we would need to return copies so the caller can free it).

> 
>>   
>>   	list_for_each_entry_safe(prototype, n, &class_names, node) {
>>   
>> @@ -2891,8 +2918,6 @@ out_btf:
>>   				prototype->type_enum_resolved = type__find_type_enum(tag__type(prototype->class), cu, prototype->type_enum) == 0;
>>   			continue;
>>   		}
>> -
>> -		static type_id_t class_id;
>>   		struct tag *class = cu__find_type_by_name(cu, prototype->name, include_decls, &class_id);
>>   
>>   		// couldn't find that class name in this CU, continue to the next one.
>> -- 
>> 2.25.1
> 


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v2 3/6] fprintf: Print types only once
  2021-12-14 14:02   ` Arnaldo Carvalho de Melo
@ 2021-12-14 17:54     ` Douglas Raillard
  0 siblings, 0 replies; 17+ messages in thread
From: Douglas Raillard @ 2021-12-14 17:54 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo; +Cc: acme, dwarves

On 12/14/21 2:02 PM, Arnaldo Carvalho de Melo wrote:
> Em Tue, Dec 07, 2021 at 05:31:48PM +0000, Douglas RAILLARD escreveu:
>> From: Douglas Raillard <douglas.raillard@arm.com>
>>
>> Use (struct tag).visited member to track what type has been printed
> 
> This doesn't match the patch, where you ended up using a new tar.printed
> field, have you tried with .visited and ended up finding out .printed
> was needed?
> 

Indeed I forgot to update the commit message. I initially used "visited" but
decided to add a new member instead as "visited" is already used by other tools
for other purposes that should probably not impact printing. We can revert
to "visited" easily if needed.

> - Arnaldo
> 
>> already to avoid printing it twice. This allows producing a valid C
>> header along with --expand_types.
>>
>> Signed-off-by: Douglas Raillard <douglas.raillard@arm.com>
>> ---
>>   dwarves.h         |  3 ++-
>>   dwarves_fprintf.c | 22 ++++++++++++++++------
>>   pahole.c          | 34 ++++++++++++++++++----------------
>>   3 files changed, 36 insertions(+), 23 deletions(-)
>>
>> diff --git a/dwarves.h b/dwarves.h
>> index 52d162d..fc5b3fa 100644
>> --- a/dwarves.h
>> +++ b/dwarves.h
>> @@ -413,6 +413,7 @@ struct tag {
>>   	type_id_t	 type;
>>   	uint16_t	 tag;
>>   	bool		 visited;
>> +	bool		 printed;
>>   	bool		 top_level;
>>   	bool		 has_btf_type_tag;
>>   	uint16_t	 recursivity_level;
>> @@ -1370,7 +1371,7 @@ static inline const char *enumerator__name(const struct enumerator *enumerator)
>>   
>>   void enumeration__delete(struct type *type);
>>   void enumeration__add(struct type *type, struct enumerator *enumerator);
>> -size_t enumeration__fprintf(const struct tag *tag_enum,
>> +size_t enumeration__fprintf(struct tag *tag_enum,
>>   			    const struct conf_fprintf *conf, FILE *fp);
>>   
>>   int dwarves__init(void);
>> diff --git a/dwarves_fprintf.c b/dwarves_fprintf.c
>> index c5921d7..2c5dce6 100644
>> --- a/dwarves_fprintf.c
>> +++ b/dwarves_fprintf.c
>> @@ -278,8 +278,8 @@ size_t typedef__fprintf(const struct tag *tag, const struct cu *cu,
>>   {
>>   	struct type *type = tag__type(tag);
>>   	const struct conf_fprintf *pconf = conf ?: &conf_fprintf__defaults;
>> -	const struct tag *tag_type;
>> -	const struct tag *ptr_type;
>> +	struct tag *tag_type;
>> +	struct tag *ptr_type;
>>   	char bf[512];
>>   	int is_pointer = 0;
>>   	size_t printed;
>> @@ -394,13 +394,14 @@ out:
>>   	return type->max_tag_name_len;
>>   }
>>   
>> -size_t enumeration__fprintf(const struct tag *tag, const struct conf_fprintf *conf, FILE *fp)
>> +size_t enumeration__fprintf(struct tag *tag, const struct conf_fprintf *conf, FILE *fp)
>>   {
>>   	struct type *type = tag__type(tag);
>>   	struct enumerator *pos;
>>   	int max_entry_name_len = enumeration__max_entry_name_len(type);
>>   	size_t printed = fprintf(fp, "enum%s%s {\n", type__name(type) ? " " : "", type__name(type) ?: "");
>>   	int indent = conf->indent;
>> +	tag->printed = 1;
>>   
>>   	if (indent >= (int)sizeof(tabs))
>>   		indent = sizeof(tabs) - 1;
>> @@ -651,10 +652,14 @@ static size_t type__fprintf(struct tag *type, const struct cu *cu,
>>   	size_t printed = 0;
>>   	int expand_types = conf->expand_types;
>>   	int suppress_offset_comment = conf->suppress_offset_comment;
>> +	bool type_printed;
>>   
>>   	if (type == NULL)
>>   		goto out_type_not_found;
>>   
>> +	type_printed = type->printed;
>> +	type->printed = 1;
>> +
>>   	if (conf->expand_pointers) {
>>   		int nr_indirections = 0;
>>   
>> @@ -794,7 +799,7 @@ print_default:
>>   	case DW_TAG_structure_type:
>>   		ctype = tag__type(type);
>>   
>> -		if (type__name(ctype) != NULL && !expand_types) {
>> +		if (type__name(ctype) != NULL && (!expand_types || type_printed)) {
>>   			printed += fprintf(fp, "%s %-*s %s",
>>   					   (type->tag == DW_TAG_class_type &&
>>   					    !tconf.classes_as_structs) ? "class" : "struct",
>> @@ -813,7 +818,7 @@ print_default:
>>   	case DW_TAG_union_type:
>>   		ctype = tag__type(type);
>>   
>> -		if (type__name(ctype) != NULL && !expand_types) {
>> +		if (type__name(ctype) != NULL && (!expand_types || type_printed)) {
>>   			printed += fprintf(fp, "union %-*s %s", tconf.type_spacing - 6, type__name(ctype), name ?: "");
>>   		} else {
>>   			tconf.type_spacing -= 8;
>> @@ -823,7 +828,7 @@ print_default:
>>   	case DW_TAG_enumeration_type:
>>   		ctype = tag__type(type);
>>   
>> -		if (type__name(ctype) != NULL)
>> +		if (type__name(ctype) != NULL || type_printed)
>>   			printed += fprintf(fp, "enum %-*s %s", tconf.type_spacing - 5, type__name(ctype), name ?: "");
>>   		else
>>   			printed += enumeration__fprintf(type, &tconf, fp);
>> @@ -1000,6 +1005,8 @@ static size_t union__fprintf(struct type *type, const struct cu *cu,
>>   	uint32_t initial_union_cacheline;
>>   	uint32_t cacheline = 0; /* This will only be used if this is the outermost union */
>>   
>> +	type__tag(type)->printed = 1;
>> +
>>   	if (indent >= (int)sizeof(tabs))
>>   		indent = sizeof(tabs) - 1;
>>   
>> @@ -1394,6 +1401,8 @@ static size_t __class__fprintf(struct class *class, const struct cu *cu,
>>   				 type__name(type) ?: "");
>>   	int indent = cconf.indent;
>>   
>> +	class__tag(class)->printed = 1;
>> +
>>   	if (indent >= (int)sizeof(tabs))
>>   		indent = sizeof(tabs) - 1;
>>   
>> @@ -1856,6 +1865,7 @@ size_t tag__fprintf(struct tag *tag, const struct cu *cu,
>>   	size_t printed = 0;
>>   	struct conf_fprintf tconf;
>>   	const struct conf_fprintf *pconf = conf;
>> +	tag->printed = 1;
>>   
>>   	if (conf == NULL) {
>>   		tconf = conf_fprintf__defaults;
>> diff --git a/pahole.c b/pahole.c
>> index f3a51cb..42ba110 100644
>> --- a/pahole.c
>> +++ b/pahole.c
>> @@ -2964,22 +2964,24 @@ out_btf:
>>   			goto dump_it;
>>   		}
>>   
>> -		if (class)
>> -			class__find_holes(tag__class(class));
>> -		if (reorganize) {
>> -			if (class && tag__is_struct(class))
>> -				do_reorg(class, cu);
>> -		} else if (find_containers)
>> -			print_containers(cu, class_id, 0);
>> -		else if (find_pointers_in_structs)
>> -			print_structs_with_pointer_to(cu, class_id);
>> -		else if (class) {
>> -			/*
>> -			 * We don't need to print it for every compile unit
>> -			 * but the previous options need
>> -			 */
>> -			tag__fprintf(class, cu, &conf, stdout);
>> -			putchar('\n');
>> +		if (!class->printed) {
>> +			if (class)
>> +				class__find_holes(tag__class(class));
>> +			if (reorganize) {
>> +				if (class && tag__is_struct(class))
>> +					do_reorg(class, cu);
>> +			} else if (find_containers)
>> +				print_containers(cu, class_id, 0);
>> +			else if (find_pointers_in_structs)
>> +				print_structs_with_pointer_to(cu, class_id);
>> +			else if (class) {
>> +				/*
>> +				 * We don't need to print it for every compile unit
>> +				 * but the previous options need
>> +				 */
>> +				tag__fprintf(class, cu, &conf, stdout);
>> +				putchar('\n');
>> +			}
>>   		}
>>   	}
>>   
>> -- 
>> 2.25.1
> 


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v2 3/6] fprintf: Print types only once
  2021-12-14 14:06   ` Arnaldo Carvalho de Melo
@ 2021-12-14 18:23     ` Douglas Raillard
  2021-12-17 18:40       ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 17+ messages in thread
From: Douglas Raillard @ 2021-12-14 18:23 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo; +Cc: acme, dwarves

On 12/14/21 2:06 PM, Arnaldo Carvalho de Melo wrote:
> Em Tue, Dec 07, 2021 at 05:31:48PM +0000, Douglas RAILLARD escreveu:
>> From: Douglas Raillard <douglas.raillard@arm.com>
>>
>> Use (struct tag).visited member to track what type has been printed
>> already to avoid printing it twice. This allows producing a valid C
>> header along with --expand_types.
> 
> And here you changed the default, i.e. it is useful to have the current
> --expand_types behaviour of expanding types as it traverse containers,
> so I think this needs another option to ask for this new
> behaviour, I think we can have that as --expand_types_once that would be
> used instead of --expand_types, ok?

Changed it to have --expand_types_once in the next version I'll send.
  
> - Arnaldo
>   
>> Signed-off-by: Douglas Raillard <douglas.raillard@arm.com>
>> ---
>>   dwarves.h         |  3 ++-
>>   dwarves_fprintf.c | 22 ++++++++++++++++------
>>   pahole.c          | 34 ++++++++++++++++++----------------
>>   3 files changed, 36 insertions(+), 23 deletions(-)
>>
>> diff --git a/dwarves.h b/dwarves.h
>> index 52d162d..fc5b3fa 100644
>> --- a/dwarves.h
>> +++ b/dwarves.h
>> @@ -413,6 +413,7 @@ struct tag {
>>   	type_id_t	 type;
>>   	uint16_t	 tag;
>>   	bool		 visited;
>> +	bool		 printed;
>>   	bool		 top_level;
>>   	bool		 has_btf_type_tag;
>>   	uint16_t	 recursivity_level;
>> @@ -1370,7 +1371,7 @@ static inline const char *enumerator__name(const struct enumerator *enumerator)
>>   
>>   void enumeration__delete(struct type *type);
>>   void enumeration__add(struct type *type, struct enumerator *enumerator);
>> -size_t enumeration__fprintf(const struct tag *tag_enum,
>> +size_t enumeration__fprintf(struct tag *tag_enum,
>>   			    const struct conf_fprintf *conf, FILE *fp);
>>   
>>   int dwarves__init(void);
>> diff --git a/dwarves_fprintf.c b/dwarves_fprintf.c
>> index c5921d7..2c5dce6 100644
>> --- a/dwarves_fprintf.c
>> +++ b/dwarves_fprintf.c
>> @@ -278,8 +278,8 @@ size_t typedef__fprintf(const struct tag *tag, const struct cu *cu,
>>   {
>>   	struct type *type = tag__type(tag);
>>   	const struct conf_fprintf *pconf = conf ?: &conf_fprintf__defaults;
>> -	const struct tag *tag_type;
>> -	const struct tag *ptr_type;
>> +	struct tag *tag_type;
>> +	struct tag *ptr_type;
>>   	char bf[512];
>>   	int is_pointer = 0;
>>   	size_t printed;
>> @@ -394,13 +394,14 @@ out:
>>   	return type->max_tag_name_len;
>>   }
>>   
>> -size_t enumeration__fprintf(const struct tag *tag, const struct conf_fprintf *conf, FILE *fp)
>> +size_t enumeration__fprintf(struct tag *tag, const struct conf_fprintf *conf, FILE *fp)
>>   {
>>   	struct type *type = tag__type(tag);
>>   	struct enumerator *pos;
>>   	int max_entry_name_len = enumeration__max_entry_name_len(type);
>>   	size_t printed = fprintf(fp, "enum%s%s {\n", type__name(type) ? " " : "", type__name(type) ?: "");
>>   	int indent = conf->indent;
>> +	tag->printed = 1;
>>   
>>   	if (indent >= (int)sizeof(tabs))
>>   		indent = sizeof(tabs) - 1;
>> @@ -651,10 +652,14 @@ static size_t type__fprintf(struct tag *type, const struct cu *cu,
>>   	size_t printed = 0;
>>   	int expand_types = conf->expand_types;
>>   	int suppress_offset_comment = conf->suppress_offset_comment;
>> +	bool type_printed;
>>   
>>   	if (type == NULL)
>>   		goto out_type_not_found;
>>   
>> +	type_printed = type->printed;
>> +	type->printed = 1;
>> +
>>   	if (conf->expand_pointers) {
>>   		int nr_indirections = 0;
>>   
>> @@ -794,7 +799,7 @@ print_default:
>>   	case DW_TAG_structure_type:
>>   		ctype = tag__type(type);
>>   
>> -		if (type__name(ctype) != NULL && !expand_types) {
>> +		if (type__name(ctype) != NULL && (!expand_types || type_printed)) {
>>   			printed += fprintf(fp, "%s %-*s %s",
>>   					   (type->tag == DW_TAG_class_type &&
>>   					    !tconf.classes_as_structs) ? "class" : "struct",
>> @@ -813,7 +818,7 @@ print_default:
>>   	case DW_TAG_union_type:
>>   		ctype = tag__type(type);
>>   
>> -		if (type__name(ctype) != NULL && !expand_types) {
>> +		if (type__name(ctype) != NULL && (!expand_types || type_printed)) {
>>   			printed += fprintf(fp, "union %-*s %s", tconf.type_spacing - 6, type__name(ctype), name ?: "");
>>   		} else {
>>   			tconf.type_spacing -= 8;
>> @@ -823,7 +828,7 @@ print_default:
>>   	case DW_TAG_enumeration_type:
>>   		ctype = tag__type(type);
>>   
>> -		if (type__name(ctype) != NULL)
>> +		if (type__name(ctype) != NULL || type_printed)
>>   			printed += fprintf(fp, "enum %-*s %s", tconf.type_spacing - 5, type__name(ctype), name ?: "");
>>   		else
>>   			printed += enumeration__fprintf(type, &tconf, fp);
>> @@ -1000,6 +1005,8 @@ static size_t union__fprintf(struct type *type, const struct cu *cu,
>>   	uint32_t initial_union_cacheline;
>>   	uint32_t cacheline = 0; /* This will only be used if this is the outermost union */
>>   
>> +	type__tag(type)->printed = 1;
>> +
>>   	if (indent >= (int)sizeof(tabs))
>>   		indent = sizeof(tabs) - 1;
>>   
>> @@ -1394,6 +1401,8 @@ static size_t __class__fprintf(struct class *class, const struct cu *cu,
>>   				 type__name(type) ?: "");
>>   	int indent = cconf.indent;
>>   
>> +	class__tag(class)->printed = 1;
>> +
>>   	if (indent >= (int)sizeof(tabs))
>>   		indent = sizeof(tabs) - 1;
>>   
>> @@ -1856,6 +1865,7 @@ size_t tag__fprintf(struct tag *tag, const struct cu *cu,
>>   	size_t printed = 0;
>>   	struct conf_fprintf tconf;
>>   	const struct conf_fprintf *pconf = conf;
>> +	tag->printed = 1;
>>   
>>   	if (conf == NULL) {
>>   		tconf = conf_fprintf__defaults;
>> diff --git a/pahole.c b/pahole.c
>> index f3a51cb..42ba110 100644
>> --- a/pahole.c
>> +++ b/pahole.c
>> @@ -2964,22 +2964,24 @@ out_btf:
>>   			goto dump_it;
>>   		}
>>   
>> -		if (class)
>> -			class__find_holes(tag__class(class));
>> -		if (reorganize) {
>> -			if (class && tag__is_struct(class))
>> -				do_reorg(class, cu);
>> -		} else if (find_containers)
>> -			print_containers(cu, class_id, 0);
>> -		else if (find_pointers_in_structs)
>> -			print_structs_with_pointer_to(cu, class_id);
>> -		else if (class) {
>> -			/*
>> -			 * We don't need to print it for every compile unit
>> -			 * but the previous options need
>> -			 */
>> -			tag__fprintf(class, cu, &conf, stdout);
>> -			putchar('\n');
>> +		if (!class->printed) {
>> +			if (class)
>> +				class__find_holes(tag__class(class));
>> +			if (reorganize) {
>> +				if (class && tag__is_struct(class))
>> +					do_reorg(class, cu);
>> +			} else if (find_containers)
>> +				print_containers(cu, class_id, 0);
>> +			else if (find_pointers_in_structs)
>> +				print_structs_with_pointer_to(cu, class_id);
>> +			else if (class) {
>> +				/*
>> +				 * We don't need to print it for every compile unit
>> +				 * but the previous options need
>> +				 */
>> +				tag__fprintf(class, cu, &conf, stdout);
>> +				putchar('\n');
>> +			}
>>   		}
>>   	}
>>   
>> -- 
>> 2.25.1
> 


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v2 4/6] pahole.c: Add prefix to expanded type names
  2021-12-14 17:50     ` Douglas Raillard
@ 2021-12-14 19:13       ` Arnaldo Carvalho de Melo
  2021-12-14 19:18       ` Arnaldo Carvalho de Melo
  1 sibling, 0 replies; 17+ messages in thread
From: Arnaldo Carvalho de Melo @ 2021-12-14 19:13 UTC (permalink / raw)
  To: Douglas Raillard, Arnaldo Carvalho de Melo; +Cc: acme, dwarves



On December 14, 2021 2:50:15 PM GMT-03:00, Douglas Raillard <douglas.raillard@arm.com> wrote:
>On 12/14/21 2:55 PM, Arnaldo Carvalho de Melo wrote:
>> Em Tue, Dec 07, 2021 at 05:31:49PM +0000, Douglas RAILLARD escreveu:
>>> From: Douglas Raillard <douglas.raillard@arm.com>
>>>
>>> Add the prefix specified by --expanded_prefix to type names that have
>>> not been specificaly requested using -C. This allows manual namespacing
>>> so that these inner types will not conflict with existing headers.
>>>
>>> Signed-off-by: Douglas Raillard <douglas.raillard@arm.com>
>>> ---
>>>   dwarves.h |  1 +
>>>   pahole.c  | 29 +++++++++++++++++++++++++++--
>>>   2 files changed, 28 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/dwarves.h b/dwarves.h
>>> index fc5b3fa..0967e5c 100644
>>> --- a/dwarves.h
>>> +++ b/dwarves.h
>>> @@ -90,6 +90,7 @@ struct conf_load {
>>>    */
>>>   struct conf_fprintf {
>>>   	const char *prefix;
>>> +	const char *name_prefix;
>>>   	const char *suffix;
>>>   	int32_t	   type_spacing;
>>>   	int32_t	   name_spacing;
>>> diff --git a/pahole.c b/pahole.c
>>> index 42ba110..e0a1438 100644
>>> --- a/pahole.c
>>> +++ b/pahole.c
>>> @@ -2882,6 +2882,33 @@ out_btf:
>>>   
>>>   	bool include_decls = find_pointers_in_structs != 0 || stats_formatter == nr_methods_formatter;
>>>   	struct prototype *prototype, *n;
>>> +	static type_id_t class_id;
>>> +
>>> +	uint32_t id;
>>> +	struct tag *pos;
>>> +	bool skip;
>>> +	const char *prefix = conf_load->conf_fprintf->name_prefix;
>>> +	const size_t prefix_len = prefix ? strlen(prefix) : 0;
>>> +	cu__for_each_type(cu, id, pos) {
>>> +		if (tag__is_type(pos)) {
>>> +			const char *name = type__name(tag__type(pos));
>>> +			if (name && prefix) {
>>> +				skip = false;
>>> +				list_for_each_entry_safe(prototype, n, &class_names, node) {
>>> +					if (!strcmp(prototype->name, name)) {
>>> +						skip = true;
>>> +						break;
>>> +					}
>>> +				}
>>> +				if (!skip) {
>>> +					const size_t len = 1024 + prefix_len;
>>> +					char *bf = malloc(len);
>>> +					snprintf(bf, len, "%s%s", prefix, name);
>>> +					tag__namespace(pos)->name = bf;
>>> +				}
>>> +			}
>>> +		}
>>> +	}
>> 
>> I don't like this change in place mode, but I understand it is easier to
>> do it here instead of in all types fprintf routines, but perhaps its
>> better that way, I'll check how big it would be.
>
>I don't really like it either but the alternative is something like that:
>https://github.com/douglas-raillard-arm/pahole/commit/a3d4e224b2a0cb8196db0f8536bd77f976e364ca
>
>The worst is not the size of the patch, it's the inability to check that it's actually complete.
>Any spot where the prefix should be applied and where it is not will result in a broken header.
>This also stands for any future addition to dwarves_fprintf.c.
>
>One way to make the substitution safer is to completely ban direct access to the name and force
>to go through an accessor that would apply the prefix, 


I like this, and we have tag__name(), I'm AFK now, will check if it fits.

Looking at your patch in te link you just provided

- Arnaldo

> but this leads to either memory management
>issue or inefficiency (as we would need to return copies so the caller can free it).
>
>> 
>>>   
>>>   	list_for_each_entry_safe(prototype, n, &class_names, node) {
>>>   
>>> @@ -2891,8 +2918,6 @@ out_btf:
>>>   				prototype->type_enum_resolved = type__find_type_enum(tag__type(prototype->class), cu, prototype->type_enum) == 0;
>>>   			continue;
>>>   		}
>>> -
>>> -		static type_id_t class_id;
>>>   		struct tag *class = cu__find_type_by_name(cu, prototype->name, include_decls, &class_id);
>>>   
>>>   		// couldn't find that class name in this CU, continue to the next one.
>>> -- 
>>> 2.25.1
>> 
>

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v2 4/6] pahole.c: Add prefix to expanded type names
  2021-12-14 17:50     ` Douglas Raillard
  2021-12-14 19:13       ` Arnaldo Carvalho de Melo
@ 2021-12-14 19:18       ` Arnaldo Carvalho de Melo
  1 sibling, 0 replies; 17+ messages in thread
From: Arnaldo Carvalho de Melo @ 2021-12-14 19:18 UTC (permalink / raw)
  To: Douglas Raillard, Arnaldo Carvalho de Melo; +Cc: acme, dwarves



On December 14, 2021 2:50:15 PM GMT-03:00, Douglas Raillard <douglas.raillard@arm.com> wrote:
>On 12/14/21 2:55 PM, Arnaldo Carvalho de Melo wrote:
>> Em Tue, Dec 07, 2021 at 05:31:49PM +0000, Douglas RAILLARD escreveu:
>>> From: Douglas Raillard <douglas.raillard@arm.com>
>>>
>>> Add the prefix specified by --expanded_prefix to type names that have
>>> not been specificaly requested using -C. This allows manual namespacing
>>> so that these inner types will not conflict with existing headers.
>>>
>>> Signed-off-by: Douglas Raillard <douglas.raillard@arm.com>
>>> ---
>>>   dwarves.h |  1 +
>>>   pahole.c  | 29 +++++++++++++++++++++++++++--
>>>   2 files changed, 28 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/dwarves.h b/dwarves.h
>>> index fc5b3fa..0967e5c 100644
>>> --- a/dwarves.h
>>> +++ b/dwarves.h
>>> @@ -90,6 +90,7 @@ struct conf_load {
>>>    */
>>>   struct conf_fprintf {
>>>   	const char *prefix;
>>> +	const char *name_prefix;
>>>   	const char *suffix;
>>>   	int32_t	   type_spacing;
>>>   	int32_t	   name_spacing;
>>> diff --git a/pahole.c b/pahole.c
>>> index 42ba110..e0a1438 100644
>>> --- a/pahole.c
>>> +++ b/pahole.c
>>> @@ -2882,6 +2882,33 @@ out_btf:
>>>   
>>>   	bool include_decls = find_pointers_in_structs != 0 || stats_formatter == nr_methods_formatter;
>>>   	struct prototype *prototype, *n;
>>> +	static type_id_t class_id;
>>> +
>>> +	uint32_t id;
>>> +	struct tag *pos;
>>> +	bool skip;
>>> +	const char *prefix = conf_load->conf_fprintf->name_prefix;
>>> +	const size_t prefix_len = prefix ? strlen(prefix) : 0;
>>> +	cu__for_each_type(cu, id, pos) {
>>> +		if (tag__is_type(pos)) {
>>> +			const char *name = type__name(tag__type(pos));
>>> +			if (name && prefix) {
>>> +				skip = false;
>>> +				list_for_each_entry_safe(prototype, n, &class_names, node) {
>>> +					if (!strcmp(prototype->name, name)) {
>>> +						skip = true;
>>> +						break;
>>> +					}
>>> +				}
>>> +				if (!skip) {
>>> +					const size_t len = 1024 + prefix_len;
>>> +					char *bf = malloc(len);
>>> +					snprintf(bf, len, "%s%s", prefix, name);
>>> +					tag__namespace(pos)->name = bf;
>>> +				}
>>> +			}
>>> +		}
>>> +	}
>> 
>> I don't like this change in place mode, but I understand it is easier to
>> do it here instead of in all types fprintf routines, but perhaps its
>> better that way, I'll check how big it would be.
>
>I don't really like it either but the alternative is something like that:
>https://github.com/douglas-raillard-arm/pahole/commit/a3d4e224b2a0cb8196db0f8536bd77f976e364ca

A quick look at the above hints at passing con_fprintf + a buffer + size to either return the type name or use the buffer to concatenate the prefix + the type name, with the type_name() return being the only result to use.

- Arnaldo
>
>The worst is not the size of the patch, it's the inability to check that it's actually complete.
>Any spot where the prefix should be applied and where it is not will result in a broken header.
>This also stands for any future addition to dwarves_fprintf.c.
>
>One way to make the substitution safer is to completely ban direct access to the name and force
>to go through an accessor that would apply the prefix, but this leads to either memory management
>issue or inefficiency (as we would need to return copies so the caller can free it).
>
>> 
>>>   
>>>   	list_for_each_entry_safe(prototype, n, &class_names, node) {
>>>   
>>> @@ -2891,8 +2918,6 @@ out_btf:
>>>   				prototype->type_enum_resolved = type__find_type_enum(tag__type(prototype->class), cu, prototype->type_enum) == 0;
>>>   			continue;
>>>   		}
>>> -
>>> -		static type_id_t class_id;
>>>   		struct tag *class = cu__find_type_by_name(cu, prototype->name, include_decls, &class_id);
>>>   
>>>   		// couldn't find that class name in this CU, continue to the next one.
>>> -- 
>>> 2.25.1
>> 
>

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v2 3/6] fprintf: Print types only once
  2021-12-14 18:23     ` Douglas Raillard
@ 2021-12-17 18:40       ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 17+ messages in thread
From: Arnaldo Carvalho de Melo @ 2021-12-17 18:40 UTC (permalink / raw)
  To: Douglas Raillard; +Cc: acme, dwarves

Em Tue, Dec 14, 2021 at 06:23:07PM +0000, Douglas Raillard escreveu:
> On 12/14/21 2:06 PM, Arnaldo Carvalho de Melo wrote:
> > Em Tue, Dec 07, 2021 at 05:31:48PM +0000, Douglas RAILLARD escreveu:
> > > From: Douglas Raillard <douglas.raillard@arm.com>
> > > 
> > > Use (struct tag).visited member to track what type has been printed
> > > already to avoid printing it twice. This allows producing a valid C
> > > header along with --expand_types.
> > 
> > And here you changed the default, i.e. it is useful to have the current
> > --expand_types behaviour of expanding types as it traverse containers,
> > so I think this needs another option to ask for this new
> > behaviour, I think we can have that as --expand_types_once that would be
> > used instead of --expand_types, ok?
> 
> Changed it to have --expand_types_once in the next version I'll send.

Ok, just one other nit, to make the patch smaller, please just use
continue:

diff --git a/pahole.c b/pahole.c
index f3a51cb2fe74afd2..b8beb71ae2c6a0b0 100644
--- a/pahole.c
+++ b/pahole.c
@@ -2964,6 +2964,9 @@ out_btf:
                        goto dump_it;
                }

+               if (class && class->printed)
+                       continue;
+
                if (class)
                        class__find_holes(tag__class(class));
                if (reorganize) {

> > - Arnaldo
> > > Signed-off-by: Douglas Raillard <douglas.raillard@arm.com>
> > > ---
> > >   dwarves.h         |  3 ++-
> > >   dwarves_fprintf.c | 22 ++++++++++++++++------
> > >   pahole.c          | 34 ++++++++++++++++++----------------
> > >   3 files changed, 36 insertions(+), 23 deletions(-)
> > > 
> > > diff --git a/dwarves.h b/dwarves.h
> > > index 52d162d..fc5b3fa 100644
> > > --- a/dwarves.h
> > > +++ b/dwarves.h
> > > @@ -413,6 +413,7 @@ struct tag {
> > >   	type_id_t	 type;
> > >   	uint16_t	 tag;
> > >   	bool		 visited;
> > > +	bool		 printed;
> > >   	bool		 top_level;
> > >   	bool		 has_btf_type_tag;
> > >   	uint16_t	 recursivity_level;
> > > @@ -1370,7 +1371,7 @@ static inline const char *enumerator__name(const struct enumerator *enumerator)
> > >   void enumeration__delete(struct type *type);
> > >   void enumeration__add(struct type *type, struct enumerator *enumerator);
> > > -size_t enumeration__fprintf(const struct tag *tag_enum,
> > > +size_t enumeration__fprintf(struct tag *tag_enum,
> > >   			    const struct conf_fprintf *conf, FILE *fp);
> > >   int dwarves__init(void);
> > > diff --git a/dwarves_fprintf.c b/dwarves_fprintf.c
> > > index c5921d7..2c5dce6 100644
> > > --- a/dwarves_fprintf.c
> > > +++ b/dwarves_fprintf.c
> > > @@ -278,8 +278,8 @@ size_t typedef__fprintf(const struct tag *tag, const struct cu *cu,
> > >   {
> > >   	struct type *type = tag__type(tag);
> > >   	const struct conf_fprintf *pconf = conf ?: &conf_fprintf__defaults;
> > > -	const struct tag *tag_type;
> > > -	const struct tag *ptr_type;
> > > +	struct tag *tag_type;
> > > +	struct tag *ptr_type;
> > >   	char bf[512];
> > >   	int is_pointer = 0;
> > >   	size_t printed;
> > > @@ -394,13 +394,14 @@ out:
> > >   	return type->max_tag_name_len;
> > >   }
> > > -size_t enumeration__fprintf(const struct tag *tag, const struct conf_fprintf *conf, FILE *fp)
> > > +size_t enumeration__fprintf(struct tag *tag, const struct conf_fprintf *conf, FILE *fp)
> > >   {
> > >   	struct type *type = tag__type(tag);
> > >   	struct enumerator *pos;
> > >   	int max_entry_name_len = enumeration__max_entry_name_len(type);
> > >   	size_t printed = fprintf(fp, "enum%s%s {\n", type__name(type) ? " " : "", type__name(type) ?: "");
> > >   	int indent = conf->indent;
> > > +	tag->printed = 1;
> > >   	if (indent >= (int)sizeof(tabs))
> > >   		indent = sizeof(tabs) - 1;
> > > @@ -651,10 +652,14 @@ static size_t type__fprintf(struct tag *type, const struct cu *cu,
> > >   	size_t printed = 0;
> > >   	int expand_types = conf->expand_types;
> > >   	int suppress_offset_comment = conf->suppress_offset_comment;
> > > +	bool type_printed;
> > >   	if (type == NULL)
> > >   		goto out_type_not_found;
> > > +	type_printed = type->printed;
> > > +	type->printed = 1;
> > > +
> > >   	if (conf->expand_pointers) {
> > >   		int nr_indirections = 0;
> > > @@ -794,7 +799,7 @@ print_default:
> > >   	case DW_TAG_structure_type:
> > >   		ctype = tag__type(type);
> > > -		if (type__name(ctype) != NULL && !expand_types) {
> > > +		if (type__name(ctype) != NULL && (!expand_types || type_printed)) {
> > >   			printed += fprintf(fp, "%s %-*s %s",
> > >   					   (type->tag == DW_TAG_class_type &&
> > >   					    !tconf.classes_as_structs) ? "class" : "struct",
> > > @@ -813,7 +818,7 @@ print_default:
> > >   	case DW_TAG_union_type:
> > >   		ctype = tag__type(type);
> > > -		if (type__name(ctype) != NULL && !expand_types) {
> > > +		if (type__name(ctype) != NULL && (!expand_types || type_printed)) {
> > >   			printed += fprintf(fp, "union %-*s %s", tconf.type_spacing - 6, type__name(ctype), name ?: "");
> > >   		} else {
> > >   			tconf.type_spacing -= 8;
> > > @@ -823,7 +828,7 @@ print_default:
> > >   	case DW_TAG_enumeration_type:
> > >   		ctype = tag__type(type);
> > > -		if (type__name(ctype) != NULL)
> > > +		if (type__name(ctype) != NULL || type_printed)
> > >   			printed += fprintf(fp, "enum %-*s %s", tconf.type_spacing - 5, type__name(ctype), name ?: "");
> > >   		else
> > >   			printed += enumeration__fprintf(type, &tconf, fp);
> > > @@ -1000,6 +1005,8 @@ static size_t union__fprintf(struct type *type, const struct cu *cu,
> > >   	uint32_t initial_union_cacheline;
> > >   	uint32_t cacheline = 0; /* This will only be used if this is the outermost union */
> > > +	type__tag(type)->printed = 1;
> > > +
> > >   	if (indent >= (int)sizeof(tabs))
> > >   		indent = sizeof(tabs) - 1;
> > > @@ -1394,6 +1401,8 @@ static size_t __class__fprintf(struct class *class, const struct cu *cu,
> > >   				 type__name(type) ?: "");
> > >   	int indent = cconf.indent;
> > > +	class__tag(class)->printed = 1;
> > > +
> > >   	if (indent >= (int)sizeof(tabs))
> > >   		indent = sizeof(tabs) - 1;
> > > @@ -1856,6 +1865,7 @@ size_t tag__fprintf(struct tag *tag, const struct cu *cu,
> > >   	size_t printed = 0;
> > >   	struct conf_fprintf tconf;
> > >   	const struct conf_fprintf *pconf = conf;
> > > +	tag->printed = 1;
> > >   	if (conf == NULL) {
> > >   		tconf = conf_fprintf__defaults;
> > > diff --git a/pahole.c b/pahole.c
> > > index f3a51cb..42ba110 100644
> > > --- a/pahole.c
> > > +++ b/pahole.c
> > > @@ -2964,22 +2964,24 @@ out_btf:
> > >   			goto dump_it;
> > >   		}
> > > -		if (class)
> > > -			class__find_holes(tag__class(class));
> > > -		if (reorganize) {
> > > -			if (class && tag__is_struct(class))
> > > -				do_reorg(class, cu);
> > > -		} else if (find_containers)
> > > -			print_containers(cu, class_id, 0);
> > > -		else if (find_pointers_in_structs)
> > > -			print_structs_with_pointer_to(cu, class_id);
> > > -		else if (class) {
> > > -			/*
> > > -			 * We don't need to print it for every compile unit
> > > -			 * but the previous options need
> > > -			 */
> > > -			tag__fprintf(class, cu, &conf, stdout);
> > > -			putchar('\n');
> > > +		if (!class->printed) {
> > > +			if (class)
> > > +				class__find_holes(tag__class(class));
> > > +			if (reorganize) {
> > > +				if (class && tag__is_struct(class))
> > > +					do_reorg(class, cu);
> > > +			} else if (find_containers)
> > > +				print_containers(cu, class_id, 0);
> > > +			else if (find_pointers_in_structs)
> > > +				print_structs_with_pointer_to(cu, class_id);
> > > +			else if (class) {
> > > +				/*
> > > +				 * We don't need to print it for every compile unit
> > > +				 * but the previous options need
> > > +				 */
> > > +				tag__fprintf(class, cu, &conf, stdout);
> > > +				putchar('\n');
> > > +			}
> > >   		}
> > >   	}
> > > -- 
> > > 2.25.1
> > 

-- 

- Arnaldo

^ permalink raw reply related	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2021-12-17 18:40 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-07 17:31 [PATCH v2 0/6] improve expanded header Douglas RAILLARD
2021-12-07 17:31 ` [PATCH v2 1/6] Revert "fprintf: Allow making struct/enum/union anonymous" Douglas RAILLARD
2021-12-07 17:31 ` [PATCH v2 2/6] Revert "pahole.c: Add --inner_anonymous option" Douglas RAILLARD
2021-12-07 17:31 ` [PATCH v2 3/6] fprintf: Print types only once Douglas RAILLARD
2021-12-14 14:02   ` Arnaldo Carvalho de Melo
2021-12-14 17:54     ` Douglas Raillard
2021-12-14 14:06   ` Arnaldo Carvalho de Melo
2021-12-14 18:23     ` Douglas Raillard
2021-12-17 18:40       ` Arnaldo Carvalho de Melo
2021-12-07 17:31 ` [PATCH v2 4/6] pahole.c: Add prefix to expanded type names Douglas RAILLARD
2021-12-14 14:55   ` Arnaldo Carvalho de Melo
2021-12-14 17:50     ` Douglas Raillard
2021-12-14 19:13       ` Arnaldo Carvalho de Melo
2021-12-14 19:18       ` Arnaldo Carvalho de Melo
2021-12-07 17:31 ` [PATCH v2 5/6] pahole.c: Add --expanded_prefix option Douglas RAILLARD
2021-12-07 17:31 ` [PATCH v2 6/6] pahole.c: Add --forward_decl option Douglas RAILLARD
2021-12-08 11:55 ` [PATCH v2 0/6] improve expanded header Arnaldo Carvalho de Melo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).