本博客(http://blog.csdn.net/livelylittlefish)贴出作者(阿波)相关研究、学习内容所做的笔记,欢迎广大朋友指正!
Content
0.序
1. gcov
1.1 gcov必须的文件
(1) 实现文件
(2) 版本文件
(3) 配置文件
(4) 系统文件
1.2如何编译生成gcov
2. gcov-dump
3. gcov-tools
4. 小结
Reference
附:本文代码下载地址
0.序
若想研究gcov/gcov-dump原理或者代码,深入函数内部跟踪调试是最好的理解方式,但gcc的源代码毕竟比较庞大,欲从中抽丝剥茧,往往会被gcc的庞大源代码吓住。那么,有没有一种方式,允许我们从gcc的源代码中抽取想要研究的程序或代码?
有!
本文以gcov程序为例,说明如何从GCC源代码中抽取gcov/gcov-dump程序并编译生成可执行的程序。有了这个独立的gcov/gcov-dump,研究、调试很方便。想搞清楚gcc的内部机理,并非一朝一夕之功,本文只是一种探索,希望对一些想研究gcc coverage test的朋友有些帮助。余愿足矣。
本文gcc源代码版本为gcc-4.1.2,其位置在/usr/src/gcc-4.1.2目录,.表示/usr/src/gcc-4.1.2。
1. gcov
gcov程序的输入是一个.c文件,前提是已经编译生成了.gcno文件并运行可执行程序生成.gcda文件;gcov根据.c文件相应的.gcda文件和.gcno文件生成相应的.c.gcov并报告覆盖率测试结果。
1.1 gcov必须的文件
(1)实现文件
根据"Linux平台代码覆盖率测试-GCC如何编译生成gcov/gcov-dump程序及其bug分析"一文的讨论,gcov所需的.c文件有gcov.c, gcov-io.c, intl.c, error.c, version.c。
注:gcov-io.c在编译gcov时并没有显示被编译(成.o文件),实际上,gcov-io.c被包含进了gcov.c文件中,请参考gcov.c代码。
因此,我们需要将这些.c文件及其.h文件抽取出来。
(2)版本文件
gcov-iov.h:该文件的内容由./gcc/gcov-iov程序生成。请参考"Linux平台代码覆盖率测试工具GCOV相关文件分析"一文。内容如下。
/* Generated automatically by the program `./gcov-iov' from `4.1.2 (4 1) and p (p)'. */ #define GCOV_VERSION ((gcov_unsigned_t)0x34303170) /* 401p */
(3)配置文件
auto-host.h
config.h
其中,
auto-host.h文件可以使用./gcc/configure程序自动生成,当然,这里的auto-host.h文件只需要包含在gcov程序中需要的常量,且有些常量需要修改,内容如下。
/* auto-host.h. Generated from auto-host.h.in by configure. */ /* auto-host.h.in. Generated from configure.ac by autoheader. */ /* Define to 1 if you have the <boost/filesystem/path.hpp> header file. */ #define HAVE_BOOST_FILESYSTEM_PATH_HPP 1 /* Define to 1 if you have the <boost/graph/graph_utility.hpp> header file. */ #define HAVE_BOOST_GRAPH_GRAPH_UTILITY_HPP 1 /* Define to 1 if you have the <dlfcn.h> header file. */ #define HAVE_DLFCN_H 1 /* Define to 1 if you have the <inttypes.h> header file. */ #define HAVE_INTTYPES_H 1 /* Define to 1 if you have the <memory.h> header file. */ #define HAVE_MEMORY_H 1 /* Define to 1 if you have the <stdint.h> header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the <stdlib.h> header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the <strings.h> header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the <string.h> header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the <sys/stat.h> header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the <sys/types.h> header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the <unistd.h> header file. */ #define HAVE_UNISTD_H 1 /* Name of package */ #define PACKAGE "gcov" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "[email protected]" /* Define to the full name of this package. */ #define PACKAGE_NAME "gcov" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "gcov 1.0" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "gcov" /* Define to the version of this package. */ #define PACKAGE_VERSION "1.0" /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Version number of package */ #define VERSION "1.0"
config.h文件也可以参考./gcc/build/config.h(该文件是在编译gcc时自动生成的),也可自己手写,内容如下。
#ifndef _GCOV_DUMP_CONFIG_H_ #define _GCOV_DUMP_CONFIG_H_ #define ATTRIBUTE_NORETURN #define ATTRIBUTE_UNUSED #define ATTRIBUTE_PRINTF_1 #define ATTRIBUTE_PRINTF_2 /** * this macro definition is for the following warning. * In file included from gcov.c:62: * gcov-io.c: In function ‘gcov_allocate’: * gcov-io.c:204: warning: implicit declaration of function ‘xrealloc’ * gcov-io.c:204: warning: assignment makes pointer from integer without a cast */ #define xrealloc realloc #include "auto-host.h" #ifdef IN_GCC /* # include "ansidecl.h" */ #endif #endif /* _GCOV_DUMP_CONFIG_H_ */
(4)系统文件
以下4个文件均是gcc的源代码文件,可以直接从gcc源代码中拷贝出来。
system.h
safe-ctype.h
hwint.h
filenames.h
但需要对system.h做少量的修改:
修改1:加入如下函数的声明,以通过编译或者消除一些warning
FILE *fopen_unlocked (const char *, const char *);
void unlock_std_streams (void);
void *xcalloc (size_t nelem, size_t elsize);
void *xmalloc (size_t size);
char *xstrdup (const char * s);
实际上,从"Linux平台代码覆盖率测试-GCC如何编译生成gcov/gcov-dump程序及其bug分析"一文中,可以看出,gcov对静态库libiberty.a的依赖,但gcov对该库的依赖仅限于以上几个文件操作或内存操作函数,因libiberty.a是被安装到系统的静态库(/usr/lib/libiberty.a),不如直接用它。因此,在system.h文件中,只需加入声明,链接的时候要将libiberty.a一起链接。
这一点从1.2节的makefile文件也能看出。
修改2:删除一些不必要的包含头文件
删除如下头文件。
/* #include */
/* #include "libiberty.h" */
修改后的system.h文件请参考http://download.csdn.net/source/3235106。
1.2如何编译生成gcov
本文从gcc源代码中抽取gcov程序,重点是如何编写makefile文件。可以参考./gcc/build/makefile文件中gcov程序,或者参考"Linux平台代码覆盖率测试-GCC如何编译生成gcov/gcov-dump程序及其bug分析"一文。
笔者编写的makefile文件如下。
CC = gcc
CXXFLAGS += -g -Wall -Wextra
TARGET = gcov
CLEANUP = rm -f $(TARGET) *.o
all : $(TARGET)
clean :
$(CLEANUP)
LIBIBERTY = /usr/lib/libiberty.a
gcov.o: gcov.c
$(CC) $(CXXFLAGS) -c $^
intl.o: intl.c
$(CC) $(CXXFLAGS) -c $^
version.o: version.c
$(CC) $(CXXFLAGS) -c $^
errors.o : errors.c
$(CC) $(CXXFLAGS) -c $^
$(TARGET): version.o errors.o intl.o gcov.o
$(CC) $(CXXFLAGS) $^ $(LIBIBERTY) -o $@
至此,gcov程序即从庞大的GCC源代码中抽取出来。如果只是研究gcov本身,这就足够了。
2. gcov-dump
gcov-dump是一个dump程序,输入是一个gcov的文件,或者.gcda,即gcov的data文件;或者.gcno,即gcov的note文件。它需要的文件与gcov程序唯一不同的是gcov-dump.c,而gcov的实现是gcov.c。
笔者为gcov-dump编写的makefile文件如下。
CC = gcc
CXXFLAGS += -g -Wall -Wextra
TARGET = gcov-dump
CLEANUP = rm -f $(TARGET) *.o
all : $(TARGET)
clean :
$(CLEANUP)
LIBIBERTY = /usr/lib/libiberty.a
gcov-dump.o: gcov-dump.c
$(CC) $(CXXFLAGS) -c $^
version.o: version.c
$(CC) $(CXXFLAGS) -c $^
errors.o : errors.c
$(CC) $(CXXFLAGS) -c $^
$(TARGET): version.o errors.o gcov-dump.o
$(CC) $(CXXFLAGS) $^ $(LIBIBERTY) -o $@
3. gcov-tools
抽取并生成gcov和gcov-dump程序后,笔者发现可将二者结合到一起,这就是gcov-tools,因为他们需要很多共同的文件。其makefile文件如下。
CC = gcc
CXXFLAGS += -g -Wall -Wextra
TARGET = gcov gcov-dump
CLEANUP = rm -f $(TARGET) *.o
all : $(TARGET)
clean :
$(CLEANUP)
LIBIBERTY = /usr/lib/libiberty.a
gcov-dump.o: gcov-dump.c
$(CC) $(CXXFLAGS) -c $^
gcov.o: gcov.c
$(CC) $(CXXFLAGS) -c $^
intl.o: intl.c
$(CC) $(CXXFLAGS) -c $^
version.o: version.c
$(CC) $(CXXFLAGS) -c $^
errors.o : errors.c
$(CC) $(CXXFLAGS) -c $^
all:
gcov: version.o errors.o intl.o gcov.o
$(CC) $(CXXFLAGS) $^ $(LIBIBERTY) -o $@
gcov-dump: version.o errors.o gcov-dump.o
$(CC) $(CXXFLAGS) $^ $(LIBIBERTY) -o $@
4.小结
gcov-dump是一个dump程序,输入是一个gcov的文件,或者.gcda,即gcov的data文件;或者.gcno,即gcov的note文件。
gcov的输入是一个.c文件,前提是已经编译生成了.gcno文件并运行可执行程序生成.gcda文件;gcov根据.c文件相应的.gcda文件和.gcno文件生成相应的.c.gcov并报告覆盖率测试结果。
从GCC源代码中抽取gcov/gcov-dump相关代码并生成,重点是编写makefile文件。
Reference
./gcc/build/makefile
http://blog.csdn.net/livelylittlefish/archive/2011/05/01/6382489.aspx
附:本文代码下载地址
根据本文抽取出的gcov/gcov-dump程序代码已经打包并上传到CSDN的资源,欢迎下载、指正。
gcov-dump-1.0.tar.gz :http://download.csdn.net/source/3235106
gcov-1.0.tar.gz : http://download.csdn.net/source/3235119
gcov-tools-1.0.tar.gz:http://download.csdn.net/source/3235127
Technorati 标签: 覆盖率测试,GCC,GCOV,GCOV-DUMP