我知道如何在简单的样本中覆盖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个以上的参数。
请帮助调试。谢谢!