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

晨曦之光 发布于 2012/03/09 14:16
阅读 421
收藏 0

【Gopher China万字分享】华为云的Go语言云原生实战经验!>>>

本博客(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 "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,即gcovdata文件;或者.gcno,即gcovnote文件。它需要的文件与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

 

抽取并生成gcovgcov-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,即gcovdata文件;或者.gcno,即gcovnote文件。

 

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 标签:


原文链接:http://blog.csdn.net/livelylittlefish/article/details/6448799
加载中
返回顶部
顶部