0

我正在编写一个用于解析结构字段的 gcc 插件。但是我有问题如何获取结构中每个字段的偏移量?就像 gcc 中的 offsetof 宏一样。

DECL_FIELD_OFFSET在 tree.h 中看到,但结果似乎不对。

我的代码来自 Richard WM Jones,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 struct\n");
            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 type\n", 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 %d\n", TREE_CODE(d));
                    printf("TREE_TYPE %s\n", get_tree_code_name(TREE_CODE(TREE_TYPE(d))));
                    printf("TREE_TYPE %d\n", (TREE_CODE(TREE_TYPE(d))));
                    printf("DECL_NAME = %p\n", DECL_NAME(d));
                    if (DECL_NAME(d))
                        printf("IDENTIFIER_POINTER = %s\n", IDENTIFIER_POINTER(DECL_NAME(d)));
                    break;
                case FIELD_DECL:
                    printf("FIELD_DECL %d\n", TREE_CODE(d));
                    printf("TREE_TYPE 1 %s\n", get_tree_code_name(TREE_CODE(TREE_TYPE(d))));
                    printf("TREE_TYPE 1 %d\n", (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 size\n");

                    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 size\n");

                    printf("DECL_NAME = %p\n", DECL_NAME(d));
                    if (DECL_NAME(d))
                        printf("IDENTIFIER_POINTER = %s\n", IDENTIFIER_POINTER(DECL_NAME(d)));
                    break;
                default:
                    printf("default %d\n", 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 size\n", 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
4

1 回答 1

0

在询问 gcc 邮件列表后,Eric Botcazou 给了我答案: https ://gcc.gnu.org/ml/gcc/2018-02/msg00048.html

函数 bit_position 和 byte_position 可以给出 struct 中字段的偏移量。它们返回树型数据结构,因此可以使用 TREE_INT_CST_LOW 将它们转换为整数。

于 2018-02-07T15:28:00.953 回答