您的位置:首页 > 编程语言

GCC Coverage代码分析-从GCC源码中抽取gcov/gcov-dump程序

2011-05-26 23:35 866 查看
本博客(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 H***E_BOOST_FILESYSTEM_PATH_HPP 1
/* Define to 1 if you have the <boost/graph/graph_utility.hpp> header file. */
#define H***E_BOOST_GRAPH_GRAPH_UTILITY_HPP 1
/* Define to 1 if you have the <dlfcn.h> header file. */
#define H***E_DLFCN_H 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define H***E_INTTYPES_H 1
/* Define to 1 if you have the <memory.h> header file. */
#define H***E_MEMORY_H 1
/* Define to 1 if you have the <stdint.h> header file. */
#define H***E_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define H***E_STDLIB_H 1
/* Define to 1 if you have the <strings.h> header file. */
#define H***E_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define H***E_STRING_H 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#define H***E_SYS_STAT_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define H***E_SYS_TYPES_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define H***E_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 "livelylittlefish@gmail.com"
/* 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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: