Blame dwarves_emit.c

Packit Service 154b7f
/*
Packit Service 154b7f
  SPDX-License-Identifier: GPL-2.0-only
Packit Service 154b7f
Packit Service 154b7f
  Copyright (C) 2006 Mandriva Conectiva S.A.
Packit Service 154b7f
  Copyright (C) 2006 Arnaldo Carvalho de Melo <acme@mandriva.com>
Packit Service 154b7f
  Copyright (C) 2007 Red Hat Inc.
Packit Service 154b7f
  Copyright (C) 2007 Arnaldo Carvalho de Melo <acme@redhat.com>
Packit Service 154b7f
*/
Packit Service 154b7f
Packit Service 154b7f
#include <string.h>
Packit Service 154b7f
Packit Service 154b7f
#include "list.h"
Packit Service 154b7f
#include "dwarves_emit.h"
Packit Service 154b7f
#include "dwarves.h"
Packit Service 154b7f
Packit Service 154b7f
void type_emissions__init(struct type_emissions *emissions)
Packit Service 154b7f
{
Packit Service 154b7f
	INIT_LIST_HEAD(&emissions->definitions);
Packit Service 154b7f
	INIT_LIST_HEAD(&emissions->fwd_decls);
Packit Service 154b7f
}
Packit Service 154b7f
Packit Service 154b7f
static void type_emissions__add_definition(struct type_emissions *emissions,
Packit Service 154b7f
					   struct type *type)
Packit Service 154b7f
{
Packit Service 154b7f
	type->definition_emitted = 1;
Packit Service 154b7f
	if (!list_empty(&type->node))
Packit Service 154b7f
		list_del(&type->node);
Packit Service 154b7f
	list_add_tail(&type->node, &emissions->definitions);
Packit Service 154b7f
}
Packit Service 154b7f
Packit Service 154b7f
static void type_emissions__add_fwd_decl(struct type_emissions *emissions,
Packit Service 154b7f
					 struct type *type)
Packit Service 154b7f
{
Packit Service 154b7f
	type->fwd_decl_emitted = 1;
Packit Service 154b7f
	if (list_empty(&type->node))
Packit Service 154b7f
		list_add_tail(&type->node, &emissions->fwd_decls);
Packit Service 154b7f
}
Packit Service 154b7f
Packit Service 154b7f
struct type *type_emissions__find_definition(const struct type_emissions *emissions,
Packit Service 154b7f
					     const struct cu *cu,
Packit Service 154b7f
					     const char *name)
Packit Service 154b7f
{
Packit Service 154b7f
	struct type *pos;
Packit Service 154b7f
Packit Service 154b7f
	if (name == NULL)
Packit Service 154b7f
		return NULL;
Packit Service 154b7f
Packit Service 154b7f
	list_for_each_entry(pos, &emissions->definitions, node)
Packit Service 154b7f
		if (type__name(pos, cu) != NULL &&
Packit Service 154b7f
		    strcmp(type__name(pos, cu), name) == 0)
Packit Service 154b7f
			return pos;
Packit Service 154b7f
Packit Service 154b7f
	return NULL;
Packit Service 154b7f
}
Packit Service 154b7f
Packit Service 154b7f
static struct type *type_emissions__find_fwd_decl(const struct type_emissions *emissions,
Packit Service 154b7f
						  const struct cu *cu,
Packit Service 154b7f
						  const char *name)
Packit Service 154b7f
{
Packit Service 154b7f
	struct type *pos;
Packit Service 154b7f
Packit Service 154b7f
	if (name == NULL)
Packit Service 154b7f
		return NULL;
Packit Service 154b7f
Packit Service 154b7f
	list_for_each_entry(pos, &emissions->fwd_decls, node) {
Packit Service 154b7f
		const char *curr_name = type__name(pos, cu);
Packit Service 154b7f
Packit Service 154b7f
		if (curr_name && strcmp(curr_name, name) == 0)
Packit Service 154b7f
			return pos;
Packit Service 154b7f
	}
Packit Service 154b7f
Packit Service 154b7f
	return NULL;
Packit Service 154b7f
}
Packit Service 154b7f
Packit Service 154b7f
static int enumeration__emit_definitions(struct tag *tag, struct cu *cu,
Packit Service 154b7f
					 struct type_emissions *emissions,
Packit Service 154b7f
					 const struct conf_fprintf *conf,
Packit Service 154b7f
					 FILE *fp)
Packit Service 154b7f
{
Packit Service 154b7f
	struct type *etype = tag__type(tag);
Packit Service 154b7f
Packit Service 154b7f
	/* Have we already emitted this in this CU? */
Packit Service 154b7f
	if (etype->definition_emitted)
Packit Service 154b7f
		return 0;
Packit Service 154b7f
Packit Service 154b7f
	/* Ok, lets look at the previous CUs: */
Packit Service 154b7f
	if (type_emissions__find_definition(emissions, cu,
Packit Service 154b7f
					    type__name(etype, cu)) != NULL) {
Packit Service 154b7f
		/*
Packit Service 154b7f
		 * Yes, so lets mark it visited on this CU too,
Packit Service 154b7f
		 * to speed up the lookup.
Packit Service 154b7f
		 */
Packit Service 154b7f
		etype->definition_emitted = 1;
Packit Service 154b7f
		return 0;
Packit Service 154b7f
	}
Packit Service 154b7f
Packit Service 154b7f
	enumeration__fprintf(tag, cu, conf, fp);
Packit Service 154b7f
	fputs(";\n", fp);
Packit Service 154b7f
	type_emissions__add_definition(emissions, etype);
Packit Service 154b7f
	return 1;
Packit Service 154b7f
}
Packit Service 154b7f
Packit Service 154b7f
static int tag__emit_definitions(struct tag *tag, struct cu *cu,
Packit Service 154b7f
				 struct type_emissions *emissions, FILE *fp);
Packit Service 154b7f
Packit Service 154b7f
static int typedef__emit_definitions(struct tag *tdef, struct cu *cu,
Packit Service 154b7f
				     struct type_emissions *emissions, FILE *fp)
Packit Service 154b7f
{
Packit Service 154b7f
	struct type *def = tag__type(tdef);
Packit Service 154b7f
	struct tag *type, *ptr_type;
Packit Service 154b7f
Packit Service 154b7f
	/* Have we already emitted this in this CU? */
Packit Service 154b7f
	if (def->definition_emitted)
Packit Service 154b7f
		return 0;
Packit Service 154b7f
Packit Service 154b7f
	/* Ok, lets look at the previous CUs: */
Packit Service 154b7f
	if (type_emissions__find_definition(emissions, cu,
Packit Service 154b7f
					    type__name(def, cu)) != NULL) {
Packit Service 154b7f
		/*
Packit Service 154b7f
		 * Yes, so lets mark it visited on this CU too,
Packit Service 154b7f
		 * to speed up the lookup.
Packit Service 154b7f
		 */
Packit Service 154b7f
		def->definition_emitted = 1;
Packit Service 154b7f
		return 0;
Packit Service 154b7f
	}
Packit Service 154b7f
Packit Service 154b7f
	type = cu__type(cu, tdef->type);
Packit Service 154b7f
	tag__assert_search_result(type);
Packit Service 154b7f
Packit Service 154b7f
	switch (type->tag) {
Packit Service 154b7f
	case DW_TAG_array_type:
Packit Service 154b7f
		tag__emit_definitions(type, cu, emissions, fp);
Packit Service 154b7f
		break;
Packit Service 154b7f
	case DW_TAG_typedef:
Packit Service 154b7f
		typedef__emit_definitions(type, cu, emissions, fp);
Packit Service 154b7f
		break;
Packit Service 154b7f
	case DW_TAG_pointer_type:
Packit Service 154b7f
		ptr_type = cu__type(cu, type->type);
Packit Service 154b7f
		/* void ** can make ptr_type be NULL */
Packit Service 154b7f
		if (ptr_type == NULL)
Packit Service 154b7f
			break;
Packit Service 154b7f
		if (ptr_type->tag == DW_TAG_typedef) {
Packit Service 154b7f
			typedef__emit_definitions(ptr_type, cu, emissions, fp);
Packit Service 154b7f
			break;
Packit Service 154b7f
		} else if (ptr_type->tag != DW_TAG_subroutine_type)
Packit Service 154b7f
			break;
Packit Service 154b7f
		type = ptr_type;
Packit Service 154b7f
		/* Fall thru */
Packit Service 154b7f
	case DW_TAG_subroutine_type:
Packit Service 154b7f
		ftype__emit_definitions(tag__ftype(type), cu, emissions, fp);
Packit Service 154b7f
		break;
Packit Service 154b7f
	case DW_TAG_enumeration_type: {
Packit Service 154b7f
		struct type *ctype = tag__type(type);
Packit Service 154b7f
		struct conf_fprintf conf = {
Packit Service 154b7f
			.suffix = NULL,
Packit Service 154b7f
		};
Packit Service 154b7f
Packit Service 154b7f
		if (type__name(ctype, cu) == NULL) {
Packit Service 154b7f
			fputs("typedef ", fp);
Packit Service 154b7f
			conf.suffix = type__name(def, cu);
Packit Service 154b7f
			enumeration__emit_definitions(type, cu, emissions,
Packit Service 154b7f
						      &conf, fp);
Packit Service 154b7f
			goto out;
Packit Service 154b7f
		} else
Packit Service 154b7f
			enumeration__emit_definitions(type, cu, emissions,
Packit Service 154b7f
						      &conf, fp);
Packit Service 154b7f
	}
Packit Service 154b7f
		break;
Packit Service 154b7f
	case DW_TAG_structure_type:
Packit Service 154b7f
	case DW_TAG_union_type: {
Packit Service 154b7f
		struct type *ctype = tag__type(type);
Packit Service 154b7f
Packit Service 154b7f
		if (type__name(ctype, cu) == NULL) {
Packit Service 154b7f
			if (type__emit_definitions(type, cu, emissions, fp))
Packit Service 154b7f
				type__emit(type, cu, "typedef",
Packit Service 154b7f
					   type__name(def, cu), fp);
Packit Service 154b7f
			goto out;
Packit Service 154b7f
		} else if (type__emit_definitions(type, cu, emissions, fp))
Packit Service 154b7f
			type__emit(type, cu, NULL, NULL, fp);
Packit Service 154b7f
	}
Packit Service 154b7f
	}
Packit Service 154b7f
Packit Service 154b7f
	/*
Packit Service 154b7f
	 * Recheck if the typedef was emitted, as there are cases, like
Packit Service 154b7f
	 * wait_queue_t in the Linux kernel, that is against struct
Packit Service 154b7f
	 * __wait_queue, that has a wait_queue_func_t member, a function
Packit Service 154b7f
	 * typedef that has as one of its parameters a... wait_queue_t, that
Packit Service 154b7f
	 * will thus be emitted before the function typedef, making a no go to
Packit Service 154b7f
	 * redefine the typedef after struct __wait_queue.
Packit Service 154b7f
	 */
Packit Service 154b7f
	if (!def->definition_emitted) {
Packit Service 154b7f
		typedef__fprintf(tdef, cu, NULL, fp);
Packit Service 154b7f
		fputs(";\n", fp);
Packit Service 154b7f
	}
Packit Service 154b7f
out:
Packit Service 154b7f
	type_emissions__add_definition(emissions, def);
Packit Service 154b7f
	return 1;
Packit Service 154b7f
}
Packit Service 154b7f
Packit Service 154b7f
int type__emit_fwd_decl(struct type *ctype, const struct cu *cu,
Packit Service 154b7f
			struct type_emissions *emissions, FILE *fp)
Packit Service 154b7f
{
Packit Service 154b7f
	/* Have we already emitted this in this CU? */
Packit Service 154b7f
	if (ctype->fwd_decl_emitted)
Packit Service 154b7f
		return 0;
Packit Service 154b7f
Packit Service 154b7f
	const char *name = type__name(ctype, cu);
Packit Service 154b7f
	if (name == NULL)
Packit Service 154b7f
		return 0;
Packit Service 154b7f
Packit Service 154b7f
	/* Ok, lets look at the previous CUs: */
Packit Service 154b7f
	if (type_emissions__find_fwd_decl(emissions, cu, name) != NULL) {
Packit Service 154b7f
		/*
Packit Service 154b7f
		 * Yes, so lets mark it visited on this CU too,
Packit Service 154b7f
		 * to speed up the lookup.
Packit Service 154b7f
		 */
Packit Service 154b7f
		ctype->fwd_decl_emitted = 1;
Packit Service 154b7f
		return 0;
Packit Service 154b7f
	}
Packit Service 154b7f
Packit Service 154b7f
	fprintf(fp, "%s %s;\n",
Packit Service 154b7f
		tag__is_union(&ctype->namespace.tag) ? "union" : "struct",
Packit Service 154b7f
		type__name(ctype, cu));
Packit Service 154b7f
	type_emissions__add_fwd_decl(emissions, ctype);
Packit Service 154b7f
	return 1;
Packit Service 154b7f
}
Packit Service 154b7f
Packit Service 154b7f
static int tag__emit_definitions(struct tag *tag, struct cu *cu,
Packit Service 154b7f
				 struct type_emissions *emissions, FILE *fp)
Packit Service 154b7f
{
Packit Service 154b7f
	struct tag *type = cu__type(cu, tag->type);
Packit Service 154b7f
	int pointer = 0;
Packit Service 154b7f
Packit Service 154b7f
	if (type == NULL)
Packit Service 154b7f
		return 0;
Packit Service 154b7f
next_indirection:
Packit Service 154b7f
	switch (type->tag) {
Packit Service 154b7f
	case DW_TAG_pointer_type:
Packit Service 154b7f
	case DW_TAG_reference_type:
Packit Service 154b7f
		pointer = 1;
Packit Service 154b7f
		/* Fall thru */
Packit Service 154b7f
	case DW_TAG_array_type:
Packit Service 154b7f
	case DW_TAG_const_type:
Packit Service 154b7f
	case DW_TAG_volatile_type:
Packit Service 154b7f
		type = cu__type(cu, type->type);
Packit Service 154b7f
		if (type == NULL)
Packit Service 154b7f
			return 0;
Packit Service 154b7f
		goto next_indirection;
Packit Service 154b7f
	case DW_TAG_typedef:
Packit Service 154b7f
		return typedef__emit_definitions(type, cu, emissions, fp);
Packit Service 154b7f
	case DW_TAG_enumeration_type:
Packit Service 154b7f
		if (type__name(tag__type(type), cu) != NULL) {
Packit Service 154b7f
			struct conf_fprintf conf = {
Packit Service 154b7f
				.suffix = NULL,
Packit Service 154b7f
			};
Packit Service 154b7f
			return enumeration__emit_definitions(type, cu, emissions,
Packit Service 154b7f
							     &conf, fp);
Packit Service 154b7f
		}
Packit Service 154b7f
		break;
Packit Service 154b7f
	case DW_TAG_structure_type:
Packit Service 154b7f
	case DW_TAG_union_type:
Packit Service 154b7f
		if (pointer) {
Packit Service 154b7f
			/*
Packit Service 154b7f
			 * Struct defined inline, no name, need to have its
Packit Service 154b7f
			 * members types emitted.
Packit Service 154b7f
			 */
Packit Service 154b7f
			if (type__name(tag__type(type), cu) == NULL)
Packit Service 154b7f
				type__emit_definitions(type, cu, emissions, fp);
Packit Service 154b7f
Packit Service 154b7f
			return type__emit_fwd_decl(tag__type(type), cu,
Packit Service 154b7f
						   emissions, fp);
Packit Service 154b7f
		}
Packit Service 154b7f
		if (type__emit_definitions(type, cu, emissions, fp))
Packit Service 154b7f
			type__emit(type, cu, NULL, NULL, fp);
Packit Service 154b7f
		return 1;
Packit Service 154b7f
	case DW_TAG_subroutine_type:
Packit Service 154b7f
		return ftype__emit_definitions(tag__ftype(type), cu,
Packit Service 154b7f
					       emissions, fp);
Packit Service 154b7f
	}
Packit Service 154b7f
Packit Service 154b7f
	return 0;
Packit Service 154b7f
}
Packit Service 154b7f
Packit Service 154b7f
int ftype__emit_definitions(struct ftype *ftype, struct cu *cu,
Packit Service 154b7f
			    struct type_emissions *emissions, FILE *fp)
Packit Service 154b7f
{
Packit Service 154b7f
	struct parameter *pos;
Packit Service 154b7f
	/* First check the function return type */
Packit Service 154b7f
	int printed = tag__emit_definitions(&ftype->tag, cu, emissions, fp);
Packit Service 154b7f
Packit Service 154b7f
	/* Then its parameters */
Packit Service 154b7f
	list_for_each_entry(pos, &ftype->parms, tag.node)
Packit Service 154b7f
		if (tag__emit_definitions(&pos->tag, cu, emissions, fp))
Packit Service 154b7f
			printed = 1;
Packit Service 154b7f
Packit Service 154b7f
	if (printed)
Packit Service 154b7f
		fputc('\n', fp);
Packit Service 154b7f
	return printed;
Packit Service 154b7f
}
Packit Service 154b7f
Packit Service 154b7f
int type__emit_definitions(struct tag *tag, struct cu *cu,
Packit Service 154b7f
			   struct type_emissions *emissions, FILE *fp)
Packit Service 154b7f
{
Packit Service 154b7f
	struct type *ctype = tag__type(tag);
Packit Service 154b7f
	struct class_member *pos;
Packit Service 154b7f
Packit Service 154b7f
	if (ctype->definition_emitted)
Packit Service 154b7f
		return 0;
Packit Service 154b7f
Packit Service 154b7f
	/* Ok, lets look at the previous CUs: */
Packit Service 154b7f
	if (type_emissions__find_definition(emissions, cu,
Packit Service 154b7f
					    type__name(ctype, cu)) != NULL) {
Packit Service 154b7f
		ctype->definition_emitted = 1;
Packit Service 154b7f
		return 0;
Packit Service 154b7f
	}
Packit Service 154b7f
Packit Service 154b7f
	if (tag__is_typedef(tag))
Packit Service 154b7f
		return typedef__emit_definitions(tag, cu, emissions, fp);
Packit Service 154b7f
Packit Service 154b7f
	type_emissions__add_definition(emissions, ctype);
Packit Service 154b7f
Packit Service 154b7f
	type__check_structs_at_unnatural_alignments(ctype, cu);
Packit Service 154b7f
Packit Service 154b7f
	type__for_each_member(ctype, pos)
Packit Service 154b7f
		if (tag__emit_definitions(&pos->tag, cu, emissions, fp))
Packit Service 154b7f
			fputc('\n', fp);
Packit Service 154b7f
Packit Service 154b7f
	return 1;
Packit Service 154b7f
}
Packit Service 154b7f
Packit Service 154b7f
void type__emit(struct tag *tag, struct cu *cu,
Packit Service 154b7f
		const char *prefix, const char *suffix, FILE *fp)
Packit Service 154b7f
{
Packit Service 154b7f
	struct type *ctype = tag__type(tag);
Packit Service 154b7f
Packit Service 154b7f
	if (type__name(ctype, cu) != NULL ||
Packit Service 154b7f
	    suffix != NULL || prefix != NULL) {
Packit Service 154b7f
		struct conf_fprintf conf = {
Packit Service 154b7f
			.prefix	    = prefix,
Packit Service 154b7f
			.suffix	    = suffix,
Packit Service 154b7f
			.emit_stats = 1,
Packit Service 154b7f
		};
Packit Service 154b7f
		tag__fprintf(tag, cu, &conf, fp);
Packit Service 154b7f
		fputc('\n', fp);
Packit Service 154b7f
	}
Packit Service 154b7f
}