我正在编写一个用于解析结构字段的 gcc 插件。但是我有问题如何获取结构中每个字段的偏移量?就像 gcc 中的偏移宏一样。
我在tree.h中看到DECL_FIELD_OFFSET
,但结果似乎不对。
我的代码遵循理查德·W·M·琼斯,https://rwmj.wordpress.com/2016/02/24/playing-with-gcc-plugins/
/* structsizes.cc plugin: public domain example code written by
* Richard W.M. Jones
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gcc-plugin.h>
#include <tree.h>
#include <print-tree.h>
int plugin_is_GPL_compatible;
static FILE *log_fp;
static void
plugin_finish_type (void *event_data, void *user_data)
{
tree type = (tree) event_data;
tree d, sz;
size_t size;
#if 1
/* This is useful for working out how to navigate the tree below. */
debug_tree (type);
#endif
/* We only care about structs, not any other type definition. */
if (TREE_CODE (type) == RECORD_TYPE) {
/* Struct name? */
tree name_tree = TYPE_NAME (type);
/* Ignore unnamed structs. */
if (!name_tree) {
fprintf (log_fp, "ignoring unnamed structn");
return;
}
const char *name;
if (TREE_CODE (name_tree) == IDENTIFIER_NODE)
name = IDENTIFIER_POINTER (name_tree);
else if (TREE_CODE (name_tree) == TYPE_DECL && DECL_NAME (name_tree))
name = IDENTIFIER_POINTER (DECL_NAME (name_tree));
else
name = "unknown struct name"; /* should never happen? */
/* If the type is not complete, we can't do anything. */
if (!COMPLETE_TYPE_P (type)) {
fprintf (log_fp, "struct '%s' has incomplete typen", name);
return;
}
for (d = TYPE_FIELDS(type); d != 0; d = TREE_CHAIN(d)) {
tree mtype = TREE_TYPE(d);
switch (TREE_CODE(d)) {
case TYPE_DECL:
printf("TYPE_DECL %dn", TREE_CODE(d));
printf("TREE_TYPE %sn", get_tree_code_name(TREE_CODE(TREE_TYPE(d))));
printf("TREE_TYPE %dn", (TREE_CODE(TREE_TYPE(d))));
printf("DECL_NAME = %pn", DECL_NAME(d));
if (DECL_NAME(d))
printf("IDENTIFIER_POINTER = %sn", IDENTIFIER_POINTER(DECL_NAME(d)));
break;
case FIELD_DECL:
printf("FIELD_DECL %dn", TREE_CODE(d));
printf("TREE_TYPE 1 %sn", get_tree_code_name(TREE_CODE(TREE_TYPE(d))));
printf("TREE_TYPE 1 %dn", (TREE_CODE(TREE_TYPE(d))));
sz = TYPE_SIZE(mtype);
if (TREE_CODE (sz) == INTEGER_CST &&
!TYPE_P (sz) && TREE_CONSTANT (sz)) {
size = TREE_INT_CST_LOW (sz);
printf ("TYPE_SIZE %zu [bits]n", size);
sz = TYPE_SIZE_UNIT(mtype);
size = TREE_INT_CST_LOW (sz);
printf ("TYPE_SIZE_UNIT %zu [bytes]n", size);
}
else
printf ("TYPE_SIZE has non-constant sizen");
sz = DECL_FIELD_OFFSET(d);
if (TREE_CODE (sz) == INTEGER_CST &&
!TYPE_P (sz) && TREE_CONSTANT (sz)) {
size = TREE_INT_CST_LOW(sz);
printf ("TYPE_OFFSET %zu [bits]n", size);
}
else
printf ("TYPE_OFFSET has non-constant sizen");
printf("DECL_NAME = %pn", DECL_NAME(d));
if (DECL_NAME(d))
printf("IDENTIFIER_POINTER = %sn", IDENTIFIER_POINTER(DECL_NAME(d)));
break;
default:
printf("default %dn", TREE_CODE(d));
break;
}
}
/* Get the size of the struct that has been defined. */
tree size_tree = TYPE_SIZE (type);
if (TREE_CODE (size_tree) == INTEGER_CST &&
!TYPE_P (size_tree) && TREE_CONSTANT (size_tree)) {
size = TREE_INT_CST_LOW (size_tree);
fprintf (log_fp, "struct '%s' has size %zu [bits]n", name, size);
}
else
fprintf (log_fp, "struct '%s' has non-constant sizen", name);
}
fflush (log_fp);
}
int
plugin_init (struct plugin_name_args *plugin_info,
struct plugin_gcc_version *version)
{
const char *logfile = NULL;
size_t i;
/* Open the log file. */
for (i = 0; i < plugin_info->argc; ++i) {
if (strcmp (plugin_info->argv[i].key, "log") == 0) {
logfile = plugin_info->argv[i].value;
}
}
if (!logfile) {
fprintf (stderr, "structsizes plugin: missing parameter: -fplugin-arg-structsizes-log=<logfile>n");
exit (EXIT_FAILURE);
}
log_fp = fopen (logfile, "a");
if (log_fp == NULL) {
perror (logfile);
exit (EXIT_FAILURE);
}
fprintf (log_fp, "Loaded structsizes plugin (GCC %s.%s.%s)n",
version->basever, version->devphase, version->revision);
register_callback (plugin_info->base_name, PLUGIN_FINISH_TYPE,
plugin_finish_type, NULL);
return 0;
}
测试源文件为:
struct TestType {
int test1;
char test2;
void *test3;
void *(*test4)(char, int);
char *test5;
char test6;
};
int main()
{
return 0;
}
但偏移量
TYPE_OFFSET 0
TYPE_OFFSET 0
TYPE_OFFSET 0
TYPE_OFFSET 16
TYPE_OFFSET 16
TYPE_OFFSET 32
不是正确的结果:
0
4
8
16
24
32
在询问gcc邮件列表后,Eric Botcazou给了我答案:https://gcc.gnu.org/ml/gcc/2018-02/msg00048.html
函数 bit_position 和 byte_position 可以给出结构中字段的偏移量。它们返回树类型数据结构,以便TREE_INT_CST_LOW可用于将它们转换为整数。