How to override fprintf in the C library? How to add GCC option to toplevel CMakeLists.txt?

☆樱花仙子☆ 提交于 2019-12-11 12:11:30

问题


I know how to overwrite C-lib functions in just simple sample. But what I need is IN A REAL PROJECT which has hundreds of files that call fprintf.

In each file, there's a "#include < stdio.h >", and tens or hundreds of calls of fprintf. I wanna make all these fprintf to do my own job. I cannot remove the "stdio.h" and put a "#include < myprint.h >", where myprint.h defines the real function or macro of fprintf that do my own job. "stdio.h" has many other calls in the project. I want a simple enough solution.

Thanks!

Do I make my question clear enough?...

Update on 2014.03.08: Salute to all women at first...

Please see my 2nd post below.


回答1:


If you are using gcc for example, you can invoke it in the following way:

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

And that will include myheader.h before every other include header in file.c and will redefine fprintf as myfprintf.

You can find more details here




回答2:


Question update overview: I added GCC option to CMAKE, but it seems not working.

====== SOLUTION TO MY FIRST POST ======

Hi all,

As for the question in my first post, I found a hook solution as follows:

#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;
} */

I wanna override fprintf, but GCC optimizes fprintf to fwrite. You can check this by writing a sample that calls fprintf, compile it, and use the command "nm yoursample | grep @GLIBC_2.0". you can see something like "fwrite@GLIBC_2.0", and there is NO "fprintf@GLIBC_2.0".

But I cannot override fwrite because there are other fwrite calls in my project. As you can see, I commented out fwrite().

I found another solution: add "-fno-builtin-fprintf" while compiling a sample program, and now the sample works. NOTE: only the sample works, not my project works... The command line is as follows:

>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

Now I can see fprintf adds time information - fprintf is hooked.

====== NEW QUESTION STARTS HERE ======

By now, it seems I can add "-fno-builtin-fprintf" to my toplevel CMakeLists.txt (the project has many subdirectories, it's quite a complex project), and everythind SHOULD work. But in real practice, it does not.

I have the following lines in my toplevel 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()

But after I compile the project, use "LD_PRELOAD=/xxx/hooktest.so /xxx/project/bin/somebinary", fprintf is not hooked.

I do another test. In my C code above, I comment fprintf and uncomment fwrite (GCC optimizes fprintf to fwrite, see expaination above), and remove the "-fno-builtin-fprintf" in the toplevel CMakeLists.txt. I can see fprintf hooked to fwrite in my code, but only fprintf(stderr, "xxx") hooked, but fprintf(stderr, "xxx %s %d xxx", somestring, someinteger) not hooked. It seems that fprintf with % and more than 2 arguments cannot be hooked.

Please help to debug this. Thanks!



来源:https://stackoverflow.com/questions/22241757/how-to-override-fprintf-in-the-c-library-how-to-add-gcc-option-to-toplevel-cmak

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!