blob: b3b832a3be77c63da0b27b79fa4fd333efb3d98e [file] [log] [blame]
/*
Copyright (C) 2006 Mandriva Conectiva S.A.
Copyright (C) 2006 Arnaldo Carvalho de Melo <acme@mandriva.com>
Copyright (C) 2007 Red Hat Inc.
Copyright (C) 2007 Arnaldo Carvalho de Melo <acme@redhat.com>
This program is free software; you can redistribute it and/or modify it
under the terms of version 2 of the GNU General Public License as
published by the Free Software Foundation.
*/
#include <string.h>
#include "list.h"
#include "dwarves_emit.h"
#include "dwarves.h"
static void cus__add_definition(struct cus *self, struct type *type)
{
type->definition_emitted = 1;
if (!list_empty(&type->node))
list_del(&type->node);
list_add_tail(&type->node, self->definitions);
}
static void cus__add_fwd_decl(struct cus *self, struct type *type)
{
type->fwd_decl_emitted = 1;
if (list_empty(&type->node))
list_add_tail(&type->node, self->fwd_decls);
}
struct type *cus__find_definition(const struct cus *self, const char *name)
{
struct type *pos;
if (name == NULL)
return NULL;
list_for_each_entry(pos, self->definitions, node)
if (type__name(pos, NULL) != NULL &&
strcmp(type__name(pos, NULL), name) == 0)
return pos;
return NULL;
}
static struct type *cus__find_fwd_decl(const struct cus *self,
const char *name)
{
struct type *pos;
list_for_each_entry(pos, self->fwd_decls, node)
if (strcmp(type__name(pos, NULL), name) == 0)
return pos;
return NULL;
}
static int cus__emit_enumeration_definitions(struct cus *self, struct tag *tag,
const struct cu *cu,
const struct conf_fprintf *conf,
FILE *fp)
{
struct type *etype = tag__type(tag);
/* Have we already emitted this in this CU? */
if (etype->definition_emitted)
return 0;
/* Ok, lets look at the previous CUs: */
if (cus__find_definition(self, type__name(etype, cu)) != NULL) {
/*
* Yes, so lets mark it visited on this CU too,
* to speed up the lookup.
*/
etype->definition_emitted = 1;
return 0;
}
enumeration__fprintf(tag, cu, conf, fp);
fputs(";\n", fp);
cus__add_definition(self, etype);
return 1;
}
static int cus__emit_tag_definitions(struct cus *self, struct cu *cu,
struct tag *tag, FILE *fp);
static int cus__emit_typedef_definitions(struct cus *self, struct cu *cu,
struct tag *tdef, FILE *fp)
{
struct type *def = tag__type(tdef);
struct tag *type, *ptr_type;
int is_pointer = 0;
/* Have we already emitted this in this CU? */
if (def->definition_emitted)
return 0;
/* Ok, lets look at the previous CUs: */
if (cus__find_definition(self, type__name(def, cu)) != NULL) {
/*
* Yes, so lets mark it visited on this CU too,
* to speed up the lookup.
*/
def->definition_emitted = 1;
return 0;
}
type = cu__find_tag_by_id(cu, tdef->type);
switch (type->tag) {
case DW_TAG_array_type:
cus__emit_tag_definitions(self, cu, type, fp);
break;
case DW_TAG_typedef:
cus__emit_typedef_definitions(self, cu, type, fp);
break;
case DW_TAG_pointer_type:
ptr_type = cu__find_tag_by_id(cu, type->type);
if (ptr_type->tag != DW_TAG_subroutine_type)
break;
type = ptr_type;
is_pointer = 1;
/* Fall thru */
case DW_TAG_subroutine_type:
cus__emit_ftype_definitions(self, cu, tag__ftype(type), fp);
break;
case DW_TAG_enumeration_type: {
struct type *ctype = tag__type(type);
struct conf_fprintf conf = {
.suffix = NULL,
};
tag__fprintf_decl_info(type, fp);
if (type__name(ctype, cu) == NULL) {
fputs("typedef ", fp);
conf.suffix = type__name(def, cu);
cus__emit_enumeration_definitions(self, type, cu, &conf, fp);
goto out;
} else
cus__emit_enumeration_definitions(self, type, cu, &conf, fp);
}
break;
case DW_TAG_structure_type:
case DW_TAG_union_type: {
struct type *ctype = tag__type(type);
if (type__name(ctype, cu) == NULL) {
if (cus__emit_type_definitions(self, cu, type, fp))
type__emit(type, cu, "typedef",
type__name(def, cu), fp);
goto out;
} else if (cus__emit_type_definitions(self, cu, type, fp))
type__emit(type, cu, NULL, NULL, fp);
}
}
/*
* Recheck if the typedef was emitted, as there are cases, like
* wait_queue_t in the Linux kernel, that is against struct
* __wait_queue, that has a wait_queue_func_t member, a function
* typedef that has as one of its parameters a... wait_queue_t, that
* will thus be emitted before the function typedef, making a no go to
* redefine the typedef after struct __wait_queue.
*/
if (!def->definition_emitted) {
typedef__fprintf(tdef, cu, NULL, fp);
fputs(";\n", fp);
}
out:
cus__add_definition(self, def);
return 1;
}
int cus__emit_fwd_decl(struct cus *self, struct type *ctype,
const struct cu *cu, FILE *fp)
{
/* Have we already emitted this in this CU? */
if (ctype->fwd_decl_emitted)
return 0;
/* Ok, lets look at the previous CUs: */
if (cus__find_fwd_decl(self, type__name(ctype, cu)) != NULL) {
/*
* Yes, so lets mark it visited on this CU too,
* to speed up the lookup.
*/
ctype->fwd_decl_emitted = 1;
return 0;
}
fprintf(fp, "%s %s;\n",
tag__is_union(&ctype->namespace.tag) ? "union" : "struct",
type__name(ctype, cu));
cus__add_fwd_decl(self, ctype);
return 1;
}
static int cus__emit_tag_definitions(struct cus *self, struct cu *cu,
struct tag *tag, FILE *fp)
{
struct tag *type = cu__find_tag_by_id(cu, tag->type);
int pointer = 0;
if (type == NULL)
return 0;
next_indirection:
switch (type->tag) {
case DW_TAG_pointer_type:
case DW_TAG_reference_type:
pointer = 1;
/* Fall thru */
case DW_TAG_array_type:
case DW_TAG_const_type:
case DW_TAG_volatile_type:
type = cu__find_tag_by_id(cu, type->type);
if (type == NULL)
return 0;
goto next_indirection;
case DW_TAG_typedef:
return cus__emit_typedef_definitions(self, cu, type, fp);
case DW_TAG_enumeration_type:
if (type__name(tag__type(type), cu) != NULL) {
struct conf_fprintf conf = {
.suffix = NULL,
};
tag__fprintf_decl_info(type, fp);
return cus__emit_enumeration_definitions(self, type,
cu, &conf, fp);
}
break;
case DW_TAG_structure_type:
case DW_TAG_union_type:
if (pointer)
return cus__emit_fwd_decl(self, tag__type(type),
cu, fp);
if (cus__emit_type_definitions(self, cu, type, fp))
type__emit(type, cu, NULL, NULL, fp);
return 1;
case DW_TAG_subroutine_type:
return cus__emit_ftype_definitions(self, cu,
tag__ftype(type), fp);
}
return 0;
}
int cus__emit_ftype_definitions(struct cus *self, struct cu *cu,
struct ftype *ftype, FILE *fp)
{
struct parameter *pos;
/* First check the function return type */
int printed = cus__emit_tag_definitions(self, cu, &ftype->tag, fp);
/* Then its parameters */
list_for_each_entry(pos, &ftype->parms, tag.node)
if (cus__emit_tag_definitions(self, cu, &pos->tag, fp))
printed = 1;
if (printed)
fputc('\n', fp);
return printed;
}
int cus__emit_type_definitions(struct cus *self, struct cu *cu,
struct tag *tag, FILE *fp)
{
struct type *ctype = tag__type(tag);
struct class_member *pos;
if (ctype->definition_emitted)
return 0;
/* Ok, lets look at the previous CUs: */
if (cus__find_definition(self, type__name(ctype, cu)) != NULL) {
ctype->definition_emitted = 1;
return 0;
}
cus__add_definition(self, ctype);
type__for_each_member(ctype, pos)
if (cus__emit_tag_definitions(self, cu, &pos->tag, fp))
fputc('\n', fp);
return 1;
}
void type__emit(struct tag *tag_self, struct cu *cu,
const char *prefix, const char *suffix, FILE *fp)
{
struct type *ctype = tag__type(tag_self);
if (tag__is_struct(tag_self))
class__find_holes(tag__class(tag_self), cu);
if (type__name(ctype, cu) != NULL ||
suffix != NULL || prefix != NULL) {
struct conf_fprintf conf = {
.prefix = prefix,
.suffix = suffix,
.emit_stats = 1,
};
tag__fprintf(tag_self, cu, &conf, fp);
fputc('\n', fp);
}
}