3

我正在使用 gcc 的-finstrument-functions选项。为了最大限度地减少开销,我只想检测几个函数。但是,gcc 只允许您将函数列入黑名单(使用no_instrument_function属性,或通过提供路径列表)。它不允许您将功能列入白名单

所以我写了一个小gcc插件添加一个instrument_function属性。这让我可以为特定功能设置检测“标志”(或者,更确切地说,清除无检测标志):

tree handle_instrument_function_attribute(
    tree * node,
    tree name,
    tree args,
    int flags,
    bool * no_add_attrs)
{
    tree decl = *node;
    DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT(decl) = 0;
    return NULL_TREE;
}

但是,据我了解,这是行不通的。查看 gcc 源代码,要让这个标志真正做任何事情,您还需要使用-finstrument-functions. 见gcc/gimplify.c:14436

...
  /* If we're instrumenting function entry/exit, then prepend the call to
     the entry hook and wrap the whole function in a TRY_FINALLY_EXPR to
     catch the exit hook.  */
  /* ??? Add some way to ignore exceptions for this TFE.  */
  if (flag_instrument_function_entry_exit
      && !DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (fndecl)
      /* Do not instrument extern inline functions.  */
      && !(DECL_DECLARED_INLINE_P (fndecl)
       && DECL_EXTERNAL (fndecl)
       && DECL_DISREGARD_INLINE_LIMITS (fndecl))
      && !flag_instrument_functions_exclude_p (fndecl))
...

它首先检查-finstrument-functions是否启用了全局标志。然后它检查特定功能的标志,据我了解,默认情况下启用该标志。所以所有其他没有我的instrument_function属性的函数仍然会被检测。

有没有办法先清除所有函数的这个标志,然后处理我的instrument_function属性以只为这些函数设置标志?

4

1 回答 1

3

诀窍只是定义属性,而不是实际使用任何处理函数,而是在其他地方进行处理。

我们仍然-finstrument-functions首先使用为所有功能启用检测。我们可以为 注册一个回调PLUGIN_FINISH_PARSE_FUNCTION,它会检查所有内容。对于每个函数声明,它都会检查其属性。如果它具有该instrument_function属性,它将像往常一样设置稍后添加的检测的标志。如果该函数没有该属性,则清除该标志。

#include <stdio.h>

#include "gcc-plugin.h"
#include "plugin-version.h"
#include "tree.h"

int plugin_is_GPL_compatible;

static struct plugin_info info = {
    "0.0.1",
    "This plugin provides the instrument_function attribute.",
};

static struct attribute_spec instrument_function_attr =
{
    "instrument_function",
    0,
    -1,
    false,
    false,
    false,
    NULL,  // No need for a handling function
};

static void register_attributes(void * event_data, void * data)
{
    register_attribute(&instrument_function_attr);
}

void handle(void * event_data, void * data)
{
    tree fndecl = (tree) event_data;
    // Make sure it's a function
    if (TREE_CODE(fndecl) == FUNCTION_DECL)
    {
        // If the function has our attribute, enable instrumentation,
        // otherwise explicitly disable it
        if (lookup_attribute("instrument_function", DECL_ATTRIBUTES(fndecl)) != NULL_TREE)
        {
            printf("instrument_function: (%s:%d) %s\n",
                DECL_SOURCE_FILE(fndecl),
                DECL_SOURCE_LINE(fndecl),
                get_name(fndecl));
            DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT(fndecl) = 0;
        }
        else
        {
            DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT(fndecl) = 1;
        }
    }
}

int plugin_init(
    struct plugin_name_args * plugin_info,
    struct plugin_gcc_version * version)
{
    register_callback(
        plugin_info->base_name,
        PLUGIN_INFO,
        NULL,
        &info);

    register_callback(
        plugin_info->base_name,
        PLUGIN_FINISH_PARSE_FUNCTION,
        handle,
        NULL);

    register_callback(
        plugin_info->base_name,
        PLUGIN_ATTRIBUTES,
        register_attributes,
        NULL);
    return 0;
}
于 2019-07-28T15:19:39.970 回答