如何在C库中覆盖FPRINTF?如何将GCC选项添加到Toplevel cmakelists.txt



我知道如何在简单的样本中覆盖C-Lib函数。但是我需要的是一个真正的项目,该项目具有数百个调用fprintf的文件。

在每个文件中,有一个"#include < stdio.h >",而fprintf的数十个或数百个呼叫。我想让所有这些FPRINTF完成自己的工作。我无法删除"stdio.h"并放置一个"#include < myprint.h >",其中myprint.h定义了我自己工作的fprintf的真实功能或宏。"stdio.h"在项目中还有许多其他电话。我想要一个足够简单的解决方案。

谢谢!

我是否足够清楚我的问题?...

更新2014.03.08:首先向所有女性致敬...

请参阅下面的第二篇文章。

例如
gcc -include myheader.h -Dfprintf=myfprintf file.c

,这将包括 myheader.h,然后再在 file.c中包含标头之前,并将fprintf重新定义为myfprintf

您可以在此处找到更多详细信息

问题更新概述:我将gcc选项添加到cmake,但似乎不起作用。

========我的第一篇文章==========

嗨,

至于我的第一篇文章中的问题,我找到了一个挂钩解决方案,如下所示:

#define _GNU_SOURCE
// for time() and localtime()
#include <time.h>
// for fprintf/fwrite
#include <stdio.h>
// for va_* functions
#include <stdarg.h>
// for dlsym
#include <dlfcn.h>
// compile command line: gcc -shared -Wl,--no-as-needed -ldl -fPIC -Wall hooktest.c -o hooktest.so
// how to use: LD_PRELOAD=hooktest.so ./hooktestprog, where hooktestprog includes stdio.h and calls fprintf
// a helper function
void print_time(FILE *fp, const char *format, ...)
{
    va_list args;
    va_start(args, format);
    vfprintf(fp, format, args);
    va_end(args);
}
// GCC optimizes fprintf to fwrite
// to make original program use fprintf exactly, compile the program (not this library) with -fno-builtin-fprintf
int fprintf(FILE *stream, const char *format, ...)
{
    static int (*my_fprintf)(FILE *stream, const char *format, ...) = NULL;
    if (NULL == my_fprintf)
    {
        my_fprintf = (int (*)(FILE *stream, const char *format, ...))dlsym(RTLD_NEXT, "fprintf");
    }
    va_list args;
    va_start(args, format);
    time_t tNow = time(NULL);
    struct tm *tmNow = localtime(&tNow);
    print_time(stream, "%04d/%02d/%02d %02d:%02d:%02d === ", tmNow->tm_year+1900, tmNow->tm_mon+1, tmNow->tm_mday, tmNow->tm_hour, tmNow->tm_min, tmNow->tm_sec);
    my_fprintf(stream, format, args);
    va_end(args); 
    return 0;
}
// GCC optimizes fprintf to fwrite
// to make original program use fprintf exactly, compile the program (not this library) with -fno-builtin-fprintf
/* size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
{
    static size_t (*my_fwrite)(const void *, size_t, size_t, FILE *) = NULL;
    if (NULL == my_fwrite)
    {
        my_fwrite = (size_t (*)(const void *, size_t, size_t, FILE *))dlsym(RTLD_NEXT, "fwrite");
    }
    time_t tNow = time(NULL);
    struct tm *tmNow = localtime(&tNow);
    print_time(stream, "%04d/%02d/%02d %02d:%02d:%02d === ", tmNow->tm_year+1900, tmNow->tm_mon+1, tmNow->tm_mday, tmNow->tm_hour, tmNow->tm_min, tmNow->tm_sec);
    my_fwrite(ptr, size, nmemb, stream);
    FILE *fp = fopen("/home/idesclient/log_freerdp.log", "a");
    if (NULL != fp)
    {
        print_time(fp, "%04d/%02d/%02d %02d:%02d:%02d === ", tmNow->tm_year+1900, tmNow->tm_mon+1, tmNow->tm_mday, tmNow->tm_hour, tmNow->tm_min, tmNow->tm_sec);
        my_fwrite(ptr, size, nmemb, fp);
        fclose(fp);
    }
    return nmemb;
} */

我想覆盖fprintf,但GCC优化了FPRINTF到FWRITE。您可以通过编写调用FPRINTF,编译它并使用命令" NM Yoursample | GREP @glibc_2.0"的示例来检查此内容。您可以看到诸如" fwrite@glibc_2.0"之类的东西,并且没有" fprintf@glibc_2.0"。

但是我不能覆盖FWRITE,因为我的项目中还有其他FWRITE呼叫。如您所见,我评论了fwrite()。

我找到了另一个解决方案:在编译样本程序时,添加" -fno-Builtin-fprintf",现在样本可行。注意:只有样本起作用,而不是我的项目工作...命令行如下:

>gcc -shared -Wl,--no-as-needed -ldl -fPIC -Wall hooktest.c -o hooktest.so
>gcc -fno-builtin-fprintf sample.c -o sample # where sample.c calls fprintf
>LD_PRELOAD=./hooktest.so ./sample

现在我可以看到fprintf添加了时间信息-Fprintf已连接。

=========新问题从这里开始==========

到目前为止,看来我可以将" -fno-builtin-fprintf"添加到我的Toplevel cmakelists.txt(该项目有许多子目录,这是一个相当复杂的项目),并且每一个都应该使用。但是实际上,它不是。

我在高级cmakelists.txt中有以下几行:

if(CMAKE_COMPILER_IS_GNUCC)
    xxxxxx (this is the original definitions in my project)
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-builtin-fprintf")
endif()

但是,在我编译了项目后,请使用" ld_preload =/xxx/hooktest.so/xxx/project/bin/somebinary",fprintf不被挂钩。

我进行了另一个测试。在上面的C代码中,我对FPRINTF和UNCOMEMONT FWRITE进行了评论(GCC优化FPRINTF到FWRITE,请参阅上面的expaination),然后在Toplevel cmakelists.txt中删除" -fno-builtin-fprintf"。我可以看到fprintf迷上了我的代码中的fwrite,但是只有fprintf(stderr,xxx")被挂上,但是fprintf(stderr," xxx%s%d xxx",somestring,someingeger)并未挂钩。看来fprintf具有%和2个以上的参数。

请帮助调试。谢谢!

最新更新