2007-05-06 19:50:28 +02:00
|
|
|
/*
|
2019-01-15 18:28:24 +01:00
|
|
|
SPDX-License-Identifier: GPL-2.0-only
|
|
|
|
|
2007-05-06 19:50:28 +02:00
|
|
|
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>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "list.h"
|
|
|
|
#include "dwarves_emit.h"
|
|
|
|
#include "dwarves.h"
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
void type_emissions__init(struct type_emissions *emissions)
|
2008-10-01 17:51:58 +02:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
INIT_LIST_HEAD(&emissions->definitions);
|
|
|
|
INIT_LIST_HEAD(&emissions->fwd_decls);
|
2008-10-01 17:51:58 +02:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void type_emissions__add_definition(struct type_emissions *emissions,
|
2008-10-01 17:43:01 +02:00
|
|
|
struct type *type)
|
2007-05-06 19:50:28 +02:00
|
|
|
{
|
|
|
|
type->definition_emitted = 1;
|
|
|
|
if (!list_empty(&type->node))
|
|
|
|
list_del(&type->node);
|
2012-08-17 23:47:15 +02:00
|
|
|
list_add_tail(&type->node, &emissions->definitions);
|
2007-05-06 19:50:28 +02:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static void type_emissions__add_fwd_decl(struct type_emissions *emissions,
|
2008-10-01 17:43:01 +02:00
|
|
|
struct type *type)
|
2007-05-06 19:50:28 +02:00
|
|
|
{
|
|
|
|
type->fwd_decl_emitted = 1;
|
|
|
|
if (list_empty(&type->node))
|
2012-08-17 23:47:15 +02:00
|
|
|
list_add_tail(&type->node, &emissions->fwd_decls);
|
2007-05-06 19:50:28 +02:00
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
struct type *type_emissions__find_definition(const struct type_emissions *emissions,
|
2009-04-02 22:54:43 +02:00
|
|
|
const struct cu *cu,
|
2008-10-01 17:43:01 +02:00
|
|
|
const char *name)
|
2007-05-06 19:50:28 +02:00
|
|
|
{
|
|
|
|
struct type *pos;
|
|
|
|
|
|
|
|
if (name == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
list_for_each_entry(pos, &emissions->definitions, node)
|
2009-04-02 22:54:43 +02:00
|
|
|
if (type__name(pos, cu) != NULL &&
|
|
|
|
strcmp(type__name(pos, cu), name) == 0)
|
2007-05-06 19:50:28 +02:00
|
|
|
return pos;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static struct type *type_emissions__find_fwd_decl(const struct type_emissions *emissions,
|
2009-04-02 22:54:43 +02:00
|
|
|
const struct cu *cu,
|
2008-10-01 17:43:01 +02:00
|
|
|
const char *name)
|
2007-05-06 19:50:28 +02:00
|
|
|
{
|
|
|
|
struct type *pos;
|
|
|
|
|
2019-04-16 01:51:20 +02:00
|
|
|
if (name == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
list_for_each_entry(pos, &emissions->fwd_decls, node) {
|
|
|
|
const char *curr_name = type__name(pos, cu);
|
|
|
|
|
|
|
|
if (curr_name && strcmp(curr_name, name) == 0)
|
2007-05-06 19:50:28 +02:00
|
|
|
return pos;
|
2019-04-16 01:51:20 +02:00
|
|
|
}
|
2007-05-06 19:50:28 +02:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static int enumeration__emit_definitions(struct tag *tag, struct cu *cu,
|
2008-10-01 17:43:01 +02:00
|
|
|
struct type_emissions *emissions,
|
|
|
|
const struct conf_fprintf *conf,
|
|
|
|
FILE *fp)
|
2007-05-06 19:50:28 +02:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
struct type *etype = tag__type(tag);
|
2007-05-06 19:50:28 +02:00
|
|
|
|
|
|
|
/* Have we already emitted this in this CU? */
|
|
|
|
if (etype->definition_emitted)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Ok, lets look at the previous CUs: */
|
2009-04-02 22:54:43 +02:00
|
|
|
if (type_emissions__find_definition(emissions, cu,
|
|
|
|
type__name(etype, cu)) != NULL) {
|
2007-05-06 19:50:28 +02:00
|
|
|
/*
|
|
|
|
* Yes, so lets mark it visited on this CU too,
|
|
|
|
* to speed up the lookup.
|
|
|
|
*/
|
|
|
|
etype->definition_emitted = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
enumeration__fprintf(tag, cu, conf, fp);
|
2007-11-15 18:17:01 +01:00
|
|
|
fputs(";\n", fp);
|
2008-10-01 17:43:01 +02:00
|
|
|
type_emissions__add_definition(emissions, etype);
|
2007-05-06 19:50:28 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2008-10-01 17:43:01 +02:00
|
|
|
static int tag__emit_definitions(struct tag *tag, struct cu *cu,
|
|
|
|
struct type_emissions *emissions, FILE *fp);
|
2007-05-06 19:50:28 +02:00
|
|
|
|
2008-10-01 17:43:01 +02:00
|
|
|
static int typedef__emit_definitions(struct tag *tdef, struct cu *cu,
|
|
|
|
struct type_emissions *emissions, FILE *fp)
|
2009-03-14 17:50:36 +01:00
|
|
|
{
|
2007-05-06 19:50:28 +02:00
|
|
|
struct type *def = tag__type(tdef);
|
|
|
|
struct tag *type, *ptr_type;
|
|
|
|
|
|
|
|
/* Have we already emitted this in this CU? */
|
|
|
|
if (def->definition_emitted)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Ok, lets look at the previous CUs: */
|
2009-04-02 22:54:43 +02:00
|
|
|
if (type_emissions__find_definition(emissions, cu,
|
|
|
|
type__name(def, cu)) != NULL) {
|
2007-05-06 19:50:28 +02:00
|
|
|
/*
|
|
|
|
* Yes, so lets mark it visited on this CU too,
|
|
|
|
* to speed up the lookup.
|
|
|
|
*/
|
|
|
|
def->definition_emitted = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-03-18 16:17:07 +01:00
|
|
|
type = cu__type(cu, tdef->type);
|
2008-04-20 23:56:36 +02:00
|
|
|
tag__assert_search_result(type);
|
2007-05-06 19:50:28 +02:00
|
|
|
|
|
|
|
switch (type->tag) {
|
|
|
|
case DW_TAG_array_type:
|
2008-10-01 17:43:01 +02:00
|
|
|
tag__emit_definitions(type, cu, emissions, fp);
|
2007-05-06 19:50:28 +02:00
|
|
|
break;
|
|
|
|
case DW_TAG_typedef:
|
2008-10-01 17:43:01 +02:00
|
|
|
typedef__emit_definitions(type, cu, emissions, fp);
|
2007-05-06 19:50:28 +02:00
|
|
|
break;
|
|
|
|
case DW_TAG_pointer_type:
|
2009-03-18 16:17:07 +01:00
|
|
|
ptr_type = cu__type(cu, type->type);
|
2019-04-11 16:19:32 +02:00
|
|
|
/* void ** can make ptr_type be NULL */
|
2019-04-16 18:49:29 +02:00
|
|
|
if (ptr_type == NULL)
|
|
|
|
break;
|
|
|
|
if (ptr_type->tag == DW_TAG_typedef) {
|
|
|
|
typedef__emit_definitions(ptr_type, cu, emissions, fp);
|
|
|
|
break;
|
|
|
|
} else if (ptr_type->tag != DW_TAG_subroutine_type)
|
2007-05-06 19:50:28 +02:00
|
|
|
break;
|
|
|
|
type = ptr_type;
|
|
|
|
/* Fall thru */
|
|
|
|
case DW_TAG_subroutine_type:
|
2008-10-01 17:43:01 +02:00
|
|
|
ftype__emit_definitions(tag__ftype(type), cu, emissions, fp);
|
2007-05-06 19:50:28 +02:00
|
|
|
break;
|
|
|
|
case DW_TAG_enumeration_type: {
|
2007-05-24 23:45:34 +02:00
|
|
|
struct type *ctype = tag__type(type);
|
2007-05-06 19:50:28 +02:00
|
|
|
struct conf_fprintf conf = {
|
|
|
|
.suffix = NULL,
|
|
|
|
};
|
|
|
|
|
2009-04-02 22:54:43 +02:00
|
|
|
if (type__name(ctype, cu) == NULL) {
|
2007-05-06 19:50:28 +02:00
|
|
|
fputs("typedef ", fp);
|
2009-04-02 22:54:43 +02:00
|
|
|
conf.suffix = type__name(def, cu);
|
|
|
|
enumeration__emit_definitions(type, cu, emissions,
|
|
|
|
&conf, fp);
|
2007-05-06 19:50:28 +02:00
|
|
|
goto out;
|
2009-03-14 17:50:36 +01:00
|
|
|
} else
|
2009-04-02 22:54:43 +02:00
|
|
|
enumeration__emit_definitions(type, cu, emissions,
|
|
|
|
&conf, fp);
|
2007-05-06 19:50:28 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case DW_TAG_structure_type:
|
|
|
|
case DW_TAG_union_type: {
|
2007-05-24 23:45:34 +02:00
|
|
|
struct type *ctype = tag__type(type);
|
2007-05-06 19:50:28 +02:00
|
|
|
|
2009-04-02 22:54:43 +02:00
|
|
|
if (type__name(ctype, cu) == NULL) {
|
2008-10-01 17:43:01 +02:00
|
|
|
if (type__emit_definitions(type, cu, emissions, fp))
|
2007-05-24 23:45:34 +02:00
|
|
|
type__emit(type, cu, "typedef",
|
2009-04-02 22:54:43 +02:00
|
|
|
type__name(def, cu), fp);
|
2007-05-06 19:50:28 +02:00
|
|
|
goto out;
|
2008-10-01 17:43:01 +02:00
|
|
|
} else if (type__emit_definitions(type, cu, emissions, fp))
|
2007-05-06 19:50:28 +02:00
|
|
|
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) {
|
2007-07-02 01:04:19 +02:00
|
|
|
typedef__fprintf(tdef, cu, NULL, fp);
|
2007-05-06 19:50:28 +02:00
|
|
|
fputs(";\n", fp);
|
|
|
|
}
|
|
|
|
out:
|
2008-10-01 17:43:01 +02:00
|
|
|
type_emissions__add_definition(emissions, def);
|
2007-05-06 19:50:28 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2009-04-02 22:54:43 +02:00
|
|
|
int type__emit_fwd_decl(struct type *ctype, const struct cu *cu,
|
2008-10-01 17:43:01 +02:00
|
|
|
struct type_emissions *emissions, FILE *fp)
|
2007-05-06 19:50:28 +02:00
|
|
|
{
|
|
|
|
/* Have we already emitted this in this CU? */
|
|
|
|
if (ctype->fwd_decl_emitted)
|
|
|
|
return 0;
|
|
|
|
|
2019-04-16 19:34:04 +02:00
|
|
|
const char *name = type__name(ctype, cu);
|
|
|
|
if (name == NULL)
|
|
|
|
return 0;
|
|
|
|
|
2007-05-06 19:50:28 +02:00
|
|
|
/* Ok, lets look at the previous CUs: */
|
2019-04-16 19:34:04 +02:00
|
|
|
if (type_emissions__find_fwd_decl(emissions, cu, name) != NULL) {
|
2007-05-06 19:50:28 +02:00
|
|
|
/*
|
|
|
|
* 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",
|
2007-05-31 07:21:36 +02:00
|
|
|
tag__is_union(&ctype->namespace.tag) ? "union" : "struct",
|
2009-04-02 22:54:43 +02:00
|
|
|
type__name(ctype, cu));
|
2008-10-01 17:43:01 +02:00
|
|
|
type_emissions__add_fwd_decl(emissions, ctype);
|
2007-05-06 19:50:28 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
static int tag__emit_definitions(struct tag *tag, struct cu *cu,
|
2008-10-01 17:43:01 +02:00
|
|
|
struct type_emissions *emissions, FILE *fp)
|
2007-05-06 19:50:28 +02:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
struct tag *type = cu__type(cu, tag->type);
|
2007-05-06 19:50:28 +02:00
|
|
|
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:
|
2009-03-18 16:17:07 +01:00
|
|
|
type = cu__type(cu, type->type);
|
2007-05-06 19:50:28 +02:00
|
|
|
if (type == NULL)
|
|
|
|
return 0;
|
|
|
|
goto next_indirection;
|
|
|
|
case DW_TAG_typedef:
|
2008-10-01 17:43:01 +02:00
|
|
|
return typedef__emit_definitions(type, cu, emissions, fp);
|
2007-05-06 19:50:28 +02:00
|
|
|
case DW_TAG_enumeration_type:
|
2009-04-02 22:54:43 +02:00
|
|
|
if (type__name(tag__type(type), cu) != NULL) {
|
2007-11-12 17:01:08 +01:00
|
|
|
struct conf_fprintf conf = {
|
|
|
|
.suffix = NULL,
|
|
|
|
};
|
2009-04-02 22:54:43 +02:00
|
|
|
return enumeration__emit_definitions(type, cu, emissions,
|
2008-10-01 17:43:01 +02:00
|
|
|
&conf, fp);
|
2007-05-06 19:50:28 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case DW_TAG_structure_type:
|
|
|
|
case DW_TAG_union_type:
|
2019-04-16 19:47:53 +02:00
|
|
|
if (pointer) {
|
|
|
|
/*
|
|
|
|
* Struct defined inline, no name, need to have its
|
|
|
|
* members types emitted.
|
|
|
|
*/
|
|
|
|
if (type__name(tag__type(type), cu) == NULL)
|
|
|
|
type__emit_definitions(type, cu, emissions, fp);
|
|
|
|
|
2009-04-02 22:54:43 +02:00
|
|
|
return type__emit_fwd_decl(tag__type(type), cu,
|
2008-10-01 17:43:01 +02:00
|
|
|
emissions, fp);
|
2019-04-16 19:47:53 +02:00
|
|
|
}
|
2008-10-01 17:43:01 +02:00
|
|
|
if (type__emit_definitions(type, cu, emissions, fp))
|
2007-05-06 19:50:28 +02:00
|
|
|
type__emit(type, cu, NULL, NULL, fp);
|
|
|
|
return 1;
|
|
|
|
case DW_TAG_subroutine_type:
|
2008-10-01 17:43:01 +02:00
|
|
|
return ftype__emit_definitions(tag__ftype(type), cu,
|
|
|
|
emissions, fp);
|
2007-05-06 19:50:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
int ftype__emit_definitions(struct ftype *ftype, struct cu *cu,
|
2008-10-01 17:43:01 +02:00
|
|
|
struct type_emissions *emissions, FILE *fp)
|
2007-05-06 19:50:28 +02:00
|
|
|
{
|
|
|
|
struct parameter *pos;
|
|
|
|
/* First check the function return type */
|
2012-08-17 23:47:15 +02:00
|
|
|
int printed = tag__emit_definitions(&ftype->tag, cu, emissions, fp);
|
2007-05-06 19:50:28 +02:00
|
|
|
|
|
|
|
/* Then its parameters */
|
2012-08-17 23:47:15 +02:00
|
|
|
list_for_each_entry(pos, &ftype->parms, tag.node)
|
2008-10-01 17:43:01 +02:00
|
|
|
if (tag__emit_definitions(&pos->tag, cu, emissions, fp))
|
2007-05-06 19:50:28 +02:00
|
|
|
printed = 1;
|
|
|
|
|
|
|
|
if (printed)
|
|
|
|
fputc('\n', fp);
|
|
|
|
return printed;
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
int type__emit_definitions(struct tag *tag, struct cu *cu,
|
2008-10-01 17:43:01 +02:00
|
|
|
struct type_emissions *emissions, FILE *fp)
|
2007-05-06 19:50:28 +02:00
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
struct type *ctype = tag__type(tag);
|
2007-05-06 19:50:28 +02:00
|
|
|
struct class_member *pos;
|
|
|
|
|
|
|
|
if (ctype->definition_emitted)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Ok, lets look at the previous CUs: */
|
2009-04-02 22:54:43 +02:00
|
|
|
if (type_emissions__find_definition(emissions, cu,
|
|
|
|
type__name(ctype, cu)) != NULL) {
|
2007-05-06 19:50:28 +02:00
|
|
|
ctype->definition_emitted = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-04-04 22:40:22 +02:00
|
|
|
if (tag__is_typedef(tag))
|
|
|
|
return typedef__emit_definitions(tag, cu, emissions, fp);
|
|
|
|
|
2008-10-01 17:43:01 +02:00
|
|
|
type_emissions__add_definition(emissions, ctype);
|
2007-05-06 19:50:28 +02:00
|
|
|
|
core: Use unnatural alignment of struct embedded in another to infer __packed__
Since we don't have something like DW_AT_alignment for
__attribute__((__packed__)), we need to use whatever hints that are
there in the alignments to figure out if a naturally packed struct has
the __attribute__((packed)) in the original sources, because that is
needed to waiver its natural alignment requisites.
For instance,
/* Used at: btrfs.c */
/* <1e7b> /home/acme/git/pahole/btrfs.c:199 */
struct btrfs_block_group_cache {
struct btrfs_key key; /* 0 17 */
struct btrfs_block_group_item item; /* 17 24 */
/* XXX 7 bytes hole, try to pack */
struct btrfs_fs_info * fs_info; /* 48 8 */
struct inode * inode; /* 56 8 */
In the original source code, btrfs_block_group_item is marked
__packed__, and being so, even seemingly unnecessarily, makes it, when
embedded in another struct, like the above, forfeit its natural
alingment, that would be 8 bytes, and instead appear right at the 17th
byte offset...
struct btrfs_block_group_item {
__le64 used; /* 0 8 */
__le64 chunk_objectid; /* 8 8 */
__le64 flags; /* 16 8 */
/* size: 24, cachelines: 1, members: 3 */
/* last cacheline: 24 bytes */
} __attribute__((__packed__));
So we need to, seeing its use at a unnatural offset, go backwards to the
btrfs_block_group_item pahole internal data structure, 'struct type' and
mark is_packed field as 'true', despite it not looking like a packed
struct.
Same thing with:
struct ieee80211_mcs_info {
u8 rx_mask[10]; /* 0 10 */
__le16 rx_highest; /* 10 2 */
u8 tx_params; /* 12 1 */
u8 reserved[3]; /* 13 3 */
/* size: 16, cachelines: 1, members: 4 */
/* last cacheline: 16 bytes */
};
That is naturally aligned and as 16 bytes, a power of two, then when it appears at the end of:
$ pahole -IC ieee80211_sta_ht_cap vht.o
/* Used at: vht.c */
/* <31ea> /home/acme/git/pahole/vht.c:1769 */
struct ieee80211_sta_ht_cap {
u16 cap; /* 0 2 */
bool ht_supported; /* 2 1 */
u8 ampdu_factor; /* 3 1 */
u8 ampdu_density; /* 4 1 */
/* XXX 1 byte hole, try to pack */
struct ieee80211_mcs_info mcs; /* 6 16 */
/* size: 22, cachelines: 1, members: 5 */
/* sum members: 21, holes: 1, sum holes: 1 */
/* last cacheline: 22 bytes */
};
$
We get that one byte hole if ieee80211_mcs_info isn't marked __packed__, as soon as we mark it:
$ pahole -IC ieee80211_sta_ht_cap vht.o
/* Used at: vht.c */
/* <31ea> /home/acme/git/pahole/vht.c:1769 */
struct ieee80211_sta_ht_cap {
u16 cap; /* 0 2 */
bool ht_supported; /* 2 1 */
u8 ampdu_factor; /* 3 1 */
u8 ampdu_density; /* 4 1 */
struct ieee80211_mcs_info mcs; /* 5 16 */
/* size: 22, cachelines: 1, members: 5 */
/* padding: 1 */
/* last cacheline: 22 bytes */
};
[acme@quaco pahole]$
It works, so __packed__ in this case just says: trow away the natural
alignment, make it 1 in whatever container structs.
So, before emitting the types for some struct, we go back looking at
each of its members and checking for such unnatural offsets, marking the
types as __packed__. Now:
$ pfunct --compile /home/acme/git/build/v5.1-rc4+/net/mac80211/vht.o | grep "^struct ieee80211_mcs_info" -A8
struct ieee80211_mcs_info {
u8 rx_mask[10]; /* 0 10 */
__le16 rx_highest; /* 10 2 */
u8 tx_params; /* 12 1 */
u8 reserved[3]; /* 13 3 */
/* size: 16, cachelines: 1, members: 4 */
/* last cacheline: 16 bytes */
} __attribute__((__packed__));
$
$ pfunct --compile /home/acme/git/build/v5.1-rc4+/fs/btrfs/free-space-tree.o | grep "^struct btrfs_block_group_item" -A7
struct btrfs_block_group_item {
__le64 used; /* 0 8 */
__le64 chunk_objectid; /* 8 8 */
__le64 flags; /* 16 8 */
/* size: 24, cachelines: 1, members: 3 */
/* last cacheline: 24 bytes */
} __attribute__((__packed__));
$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-15 20:51:16 +02:00
|
|
|
type__check_structs_at_unnatural_alignments(ctype, cu);
|
|
|
|
|
2007-05-24 02:43:01 +02:00
|
|
|
type__for_each_member(ctype, pos)
|
2008-10-01 17:43:01 +02:00
|
|
|
if (tag__emit_definitions(&pos->tag, cu, emissions, fp))
|
2007-11-15 18:17:01 +01:00
|
|
|
fputc('\n', fp);
|
2007-05-06 19:50:28 +02:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-08-17 23:47:15 +02:00
|
|
|
void type__emit(struct tag *tag, struct cu *cu,
|
2007-05-06 19:50:28 +02:00
|
|
|
const char *prefix, const char *suffix, FILE *fp)
|
|
|
|
{
|
2012-08-17 23:47:15 +02:00
|
|
|
struct type *ctype = tag__type(tag);
|
2007-05-06 19:50:28 +02:00
|
|
|
|
2009-04-02 22:54:43 +02:00
|
|
|
if (type__name(ctype, cu) != NULL ||
|
2007-05-24 23:45:34 +02:00
|
|
|
suffix != NULL || prefix != NULL) {
|
2007-05-06 19:50:28 +02:00
|
|
|
struct conf_fprintf conf = {
|
|
|
|
.prefix = prefix,
|
|
|
|
.suffix = suffix,
|
|
|
|
.emit_stats = 1,
|
|
|
|
};
|
2012-08-17 23:47:15 +02:00
|
|
|
tag__fprintf(tag, cu, &conf, fp);
|
2007-05-06 19:50:28 +02:00
|
|
|
fputc('\n', fp);
|
|
|
|
}
|
|
|
|
}
|