GCC Coverage代码分析-gcov-dump原理分析

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

本博客(http://blog.csdn.net/livelylittlefish)贴出作者(阿波)相关研究、学习内容所做的笔记,欢迎广大朋友指正!

Content

1.

2. gcov-dump原理分析

2.1 gcov-dump程序结构

2.2 dump_file函数分析

2.3处理各种tagcallback定义

2.4基本读取函数gcov_read_words

2.5分配空间函数gcov_allocate

2.6重要数据结构gcov_var

3.处理tagcallback分析

3.1FUNCTION tag: tag_function()函数

3.2BLOCKS tag: tag_blocks()函数

3.3ARCS tag: tag_arcs()函数

3.4LINES tag: tag_lines()函数

3.5COUNTER tag: tag_counters()函数

3.6OBJECT/PROGRAM SUMMARY tag: tag_summary()函数

4.小结

 

 

1.

 

gcov的相关文件.gcda(data文件)/.gcno(note文件)文件是以二进制方式写入的(fwrite),普通编辑文件打开看到的只是乱码,用ultraedit打开也只是看到十六进制的数据。如果你了解.gcda/.gcno的文件格式(可以参考"Linux平台代码覆盖率测试工具GCOV相关文件分析"),看起来会好些;否则,看起来便不知所云,除非有一种工具或程序能将其内容按照有意义的(文件)格式dump出来,如果再加上一些提示,就更好了。

 

——这就是gcov-dump程序。

 

gcov-dump是一个dump程序,输入是一个gcov的文件,或者.gcda,即gcovdata文件;或者.gcno,即gcovnote文件。

 

有了"Linux平台代码覆盖率测试工具GCOV相关文件分析""Linux平台代码覆盖率测试-GCC如何编译生成gcov/gcov-dump程序及其bug分析"这两篇文章做基础,gcov-dump的原理就很好理解了。本文不予详细叙述,只做一些代码注释和简单记录,便于用到的时候查询。好头脑赶不上烂笔头嘛。

 

本文例子所用的gcov-dump程序来自"Linux平台代码覆盖率测试-GCC源码中抽取gcov/gcov-dump程序"一文。

 

2. gcov-dump原理分析

 

2.1 gcov-dump程序结构


图中实线表示调用,实线旁边的数字表示tag值。tag的值请参考gcov_io.h文件,或者"Linux平台代码覆盖率测试工具GCOV相关文件分析"

 

2.2 dump_file函数分析

 

gcov-dump程序的主函数main,是靠调用dump_file()函数来完成文件内容的输出。该函数定义如下。其中的注释为笔者所加。

static void

dump_file(const char *filename)

{

   unsigned tags[4];

   unsigned depth =;

 

   if (!gcov_open (filename,1))  /* it will open .gcda/.gcno file, and save information into gcov_var */

   {

       fprintf (stderr,"%s:cannot open/n",filename);

       return;

   }

 

   /* magic */

   {

       unsigned magic = gcov_read_unsigned();

       unsigned version;

       const char *type = NULL;

       int endianness =;

       char m[4],v[4];

 

       /***** compare magic read just now with "gcda" or "gcno" to confirm file type */

       if ((endianness= gcov_magic(magic,GCOV_DATA_MAGIC)))

           type = "data";

       else if ((endianness= gcov_magic(magic,GCOV_NOTE_MAGIC)))

           type= "note";

       else

       {

           printf ("%s:not a gcov file/n",filename);

           gcov_close ();

           return;

       }

       /***** read version, an unsigned word */

       version = gcov_read_unsigned();

 

       /***** Convert a magic or version number to a 4 character string with ASCII */

       GCOV_UNSIGNED2STRING (v,version);

       GCOV_UNSIGNED2STRING (m,magic);

       printf ("%s:%s:magic `%.4s':version `%.4s'%s/n",filename,type,

               m,v, endianness < 0 ? " (swapped endianness)" : "");

       if (version!= GCOV_VERSION)

       {

           chare[4];

           GCOV_UNSIGNED2STRING(e,GCOV_VERSION);

           printf ("%s⚠current version is `%.4s'/n",filename,e);

       }

   }

 

    /* stamp */

   {

       unsigned stamp = gcov_read_unsigned();

       printf ("%s:stamp %lu/n",filename, (unsigned long)stamp);

   }

 

   while (1)

   {

       gcov_position_t base,position =gcov_position ();

       unsigned tag,length;tag_format_t const *format;unsigned tag_depth;

       int error;

       unsigned mask;

 

        /***** read a tag, for example, 0x01000000, 0x01a10000, 0xa1000000, etc */

       tag =gcov_read_unsigned();

       if(!tag)/***** tag=0x00000000, then, to the end of file, break *****/

           break;

 

        /***** read its length tag */

       length =gcov_read_unsigned();

       base = gcov_position ();

 

        /***** for example, tag=0x01000000, then, tag- 1=0xFFFFFF,

          * then, GCOV_TAG_MASK (tag)=0x1FFFFFF, then, mask = 0x1FFFFFF/ 2 = 0xFFFFFF

        */

       mask = GCOV_TAG_MASK (tag)>> 1;

 

        /****** validate the tag */

       for (tag_depth= 4;mask; mask>>= 8)

       {

           if ((mask& 0xff)!= 0xff)

           {

               printf ("%s:tag `%08x' is invalid/n",filename,tag);

               break;

           }

           tag_depth--;

       }

 

        /***** find the tag in tag_table, if found, then call its procedure */

       for (format= tag_table;format- >name;format++)

           if (format- >tag ==tag)

               goto found;

       format = &tag_table[GCOV_TAG_IS_COUNTER(tag)? 2:1];

found:

       ;

       if (tag)

       {

           if (depth&& depth < tag_depth)

           {

               if (!GCOV_TAG_IS_SUBTAG (tags[depth- 1],tag))

               printf ("%s:tag `%08x' is incorrectly nested/n",

               filename,tag);

           }

           depth = tag_depth;

           tags[depth- 1]= tag;

       }

 

        /***** print some spaces to represent the depth level */

       print_prefix (filename,tag_depth, position);

       printf ("%08x:%4u:%s",tag, length,format- >name);

        /***** call the procedure of this tag stored in tag_table */

       if (format- >proc)

           (*format- >proc) (filename, tag, length); //此处调用相应的tag处理函数

 

       printf ("/n");

       if (flag_dump_contents&& format- >proc)

       {

           unsigned long actual_length= gcov_position () - base;

           if (actual_length> length)

               printf ("%s:record size mismatch %lu bytes overread/n",

                   filename,actual_length - length);

           else if (length> actual_length)

               printf ("%s:record size mismatch %lu bytes unread/n",

                   filename,length - actual_length);

       }

 

        /***** base stands for the base position of a tag, then, synchronize the pointer */

       gcov_sync (base,length);

       if ((error= gcov_is_error()))

       {

           printf (error< 0 ?"%s:counter overflow at %lu/n" :

               "%s:read error at %lu/n",filename,

               (long unsigned)gcov_position ());

           break;

       }

   }

   gcov_close ();

}

dump_file函数首先通过gcov_open打开.gcda/.gcno文件,将文件信息保存到全局变量gcov_var(稍后介绍该变量),接着读取文件头信息,包括magicversionstamp,然后循环读取每个taglength,并通过函数指针处理该tag,直到文件结束(0x00000000)。下面介绍各种tagcallback

 

2.3处理各种tagcallback定义

 

处理tagcallback函数定义如下。

static const tag_format_ttag_table[]=

{

   {,"NOP",NULL},

   {,"UNKNOWN",NULL},

   {,"COUNTERS",tag_counters},

   {GCOV_TAG_FUNCTION,"FUNCTION", tag_function},

   {GCOV_TAG_BLOCKS,  "BLOCKS",  tag_blocks},

   {GCOV_TAG_ARCS,    "ARCS",    tag_arcs},

   {GCOV_TAG_LINES,   "LINES",   tag_lines},

   {GCOV_TAG_OBJECT_SUMMARY, "OBJECT_SUMMARY", tag_summary},

   {GCOV_TAG_PROGRAM_SUMMARY,"PROGRAM_SUMMARY",tag_summary},

   {, NULL, NULL}

};

其类型tag_format_t为一个结构,分别由tag本身,tag name和处理该tag的函数指针组成,定义如下。

typedef struct tag_format

{

   unsigned    tag;

   char const *name;

   void (*proc) (const char *,unsigned, unsigned);

}tag_format_t;

2.4基本读取函数gcov_read_words

 

.gcda/.gcno文件的读取/写入,均以4字节(1words)为单位进行。下面分析从.gcda/.gcno文件中读取words的基本读取函数gcov_read_words。代码如下。其中的注释为笔者所加。

/ * Return a pointer to read BYTES bytes from the gcov file. Returns

    NULL on failure (read past EOF). */

static const gcov_unsigned_t *

gcov_read_words(unsigned words)

{

   const gcov_unsigned_t *result;

 

   /**excess is the number of words which can be excessed*/

   unsigned excess =gcov_var.length -gcov_var.offset;

 

   gcc_assert (gcov_var.mode >);

   if (excess< words)

   {

       gcov_var.start +=gcov_var.offset;

#ifIN_LIBGCOV

       if (excess)

       {

           gcc_assert (excess== 1);

           memcpy (gcov_var.buffer,gcov_var.buffer +gcov_var.offset,4);

       }

#else

       //gcov-dump程序中,执行memmove

       memmove (gcov_var.buffer,gcov_var.buffer +gcov_var.offset,excess *4);

#endif

       gcov_var.offset =;

       gcov_var.length =excess;

#ifIN_LIBGCOV

       gcc_assert (!gcov_var.length ||gcov_var.length ==1);

       excess = GCOV_BLOCK_SIZE;

#else

       //gcov-dump程序中,执行gcov_allocate

       if (gcov_var.length +words > gcov_var.alloc)

            /** allocate space, the space pointer is saved in gcov_var.buffer */

           gcov_allocate (gcov_var.length +words);

       excess = gcov_var.alloc - gcov_var.length;/** if program can run here, then, excess = 2050 */

#endif

 

       /*****

        * >>2, that is, divided by 4, it is for 4 Bytes as a unit.

        * for example, a file with 168B, then, will read 168B, but excess is 168/ 4=42.

        * gcov_var.buffer will save the file content.

        */

       excess= fread(gcov_var.buffer +gcov_var.length,1,excess<< 2,gcov_var.file)>> 2;

       gcov_var.length +=excess;

       if (gcov_var.length <words)

       {

           gcov_var.overread +=words - gcov_var.length;

           gcov_var.length =;

           return 0;

       }

   }

 

   /***** then, return an unsigned word */

   result = &gcov_var.buffer[gcov_var.offset];gcov_var.offset +=words;

   return result;

}

第一次调用该函数时,gcov_var.alloc=0,然后一定会调用gcov_allocate,调用gcov_allocate后,gcov_var.alloc=2050。跟踪执行发现,第一次调用fread之前,excess = gcov_var.alloc - gcov_var.length = 2050,调用fread后,仍以test.c产生的test.gcda为例(可参考前面的文章)excess=168/4=42。因为test.gcda较小,只有168字节,故调用fread后,gcov_var.buffer中就存放了整个文件的内容(168字节),如下所示,虽然为gcov_var.buffer分配了8200自己的空间。

(gdb) p gcov_var

$1 = {

 file = 0x810c008,       //文件指针

  start = 0,

  offset = 0,

  length = 0,

 overread = 4294967295,  //4294967295=0xffffffff=-1

  error = 0,

  mode = 1,

  endian = 0,

  alloc = 2050,

  buffer = 0x810c170

}

(gdb) x /42w 0x810c170   //查看buffer中的前42个字,共168字节,就是test.gcda文件的内容

0x810c170:     0x67636461      0x34303170     0xc5ecae39      0x01000000

0x810c180:     0x00000002      0x00000003      0xeb65a768     0x01a10000

0x810c190:     0x0000000a      0x0000000a      0x00000000     0x00000000

0x810c1a0:     0x00000000      0x00000001      0x00000000     0x00000000

0x810c1b0:     0x00000000      0x00000001      0x00000000     0xa1000000

0x810c1c0:     0x00000009      0x00000000      0x00000005     0x00000001

0x810c1d0:     0x0000000c      0x00000000      0x0000000a     0x00000000

0x810c1e0:     0x0000000a      0x00000000      0xa3000000     0x00000009

0x810c1f0:     0x51924f98      0x00000005      0x00000001     0x0000000c

0x810c200:     0x00000000      0x0000000a      0x00000000     0x0000000a

0x810c210:     0x00000000      0x00000000

其中,前3个字(4字节/)即为magic, version, stamp;蓝色部分即为tag,可以参考"Linux平台代码覆盖率测试-GCC如何编译生成gcov/gcov-dump程序及其bug分析"一文的3.33.4节,也可以参考本文第3节。

 

为什么为gcov_var.buffer分配了8200字节的空间?

——这就是gcov_allocate完成的。

 

2.5分配空间函数gcov_allocate

 

代码如下。其中的注释为笔者加入。

#if! IN_LIBGCOV

static void

gcov_allocate(unsigned length)

{

   size_t new_size =gcov_var.alloc;

 

   if (!new_size)

       new_size =GCOV_BLOCK_SIZE;/***** if new_size==0, then, new_size=1024(GCOV_BLOCK_SIZE=1024) */

   new_size += length; /***** if length==1, then, new_size=1025 */

   new_size *= 2;       /***** then, new_size=1025*2=2050 */

 

   gcov_var.alloc = new_size;

   gcov_var.buffer =xrealloc(gcov_var.buffer,new_size<< 2);/***** size=1025*4=8200 */

}

#endif

实际上gcov_var.alloc是一个内存block,以4字节为一个单位。由代码及其注释可以看出,当length=1时,gcov_var.alloc=2050,调用gcov_allocate后,实际上分配了2050*4=8200个字节的空间给gcov_var.buffer

 

此处,不得不介绍一下gcov_var

 

2.6重要数据结构gcov_var

 

gcov_var是个全局变量,其作用就是在gcov/gcov-dump程序运行期间保存操作的文件信息,例如,文件指针、某个blockstart/offset/length、文件内容buffer等信息,定义如下。

/* Optimum number of gcov_unsigned_t's read from or written to disk. */

#defineGCOV_BLOCK_SIZE(1<<10)

 

GCOV_LINKAGE struct gcov_var

{

   FILE *file;

   gcov_position_t start;  /* Position of first byte of block */

   unsigned offset;        /* Read/ write position within the block. */

   unsigned length;        /* Read limit in the block. */

   unsigned overread;      /* Number of words overread. */

   int error;              /* < 0 overflow, > 0 disk error. */

   int mode;               /* < 0 writing, > 0 reading */

#ifIN_LIBGCOV

   /* Holds one block plus 4 bytes, thus all coverage reads & writes

 fit within this buffer and we always can transfer GCOV_BLOCK_SIZE

 to and from the disk. libgcov never backtracks and only writes 4 or 8 byte objects. */

   gcov_unsigned_t buffer[GCOV_BLOCK_SIZE+ 1];

#else

   int endian;             /* Swap endianness. */

   /* Holds a variable length block, as the compiler can write strings and needs to backtrack. */

   size_t alloc;

   gcov_unsigned_t *buffer;

#endif

}gcov_varATTRIBUTE_HIDDEN;

gcov-dump程序中,sizeof(gcov_type)=sizeof(gcov_unsigned_t)=4sizeof(gcov_var)=40gcov_var的值一个例子可以参考2.4节,此处不再赘述。

 

3.处理tagcallback分析

 

3.1FUNCTION tag: tag_function()函数

static void

tag_function(const char *filenameATTRIBUTE_UNUSED,

unsigned tag ATTRIBUTE_UNUSED,unsigned lengthATTRIBUTE_UNUSED)

{

   unsigned long pos= gcov_position(); 

 

   /***** for function, it will print ident and checksum */

   printf (" ident=%u",gcov_read_unsigned ());

   printf (", checksum=0x%08x",gcov_read_unsigned ());

 

   if(gcov_position() -pos <length) //一般对于.gcno文件该条件才满足,才能执行该clause

   {

       const char *name;

       name = gcov_read_string();  //该函数读取length(4字节)lengthwords(4*length字节),读取函数名字

       printf (", `%s'",name ? name: "NULL");

       name = gcov_read_string();  //读取源文件名字

       printf (" %s",name ? name: "NULL");

       printf (":%u",gcov_read_unsigned());  //读取该函数在该源文件中的行号

   }

}

输出格式:

    .gcda文件输出:ident=3, checksum=0xeb65a768

    .gcno文件输出:ident=3, checksum=0xeb65a768, `main' test.c:4

其中,划线部分分别为:函数名源文件名:行号

 

3.2BLOCKS tag: tag_blocks()函数

static void

tag_blocks(const char *filenameATTRIBUTE_UNUSED,

unsigned tag ATTRIBUTE_UNUSED,unsigned lengthATTRIBUTE_UNUSED)

{

   unsigned n_blocks = GCOV_TAG_BLOCKS_NUM(length);

   printf (" %u blocks",n_blocks);

 

   if (flag_dump_contents)

   {

       unsigned ix;

       for (ix= ;ix != n_blocks;ix++)

       {

           if(!(ix& 7)) //如果blocks较多,则每8个为1行输出,且按816...输出序号

           {

               printf ("/n");

               print_prefix (filename,, gcov_position());

               printf ("/t/t%u",ix); //输出序号

           }

           printf (" %04x",gcov_read_unsigned ());

       }

   }

} 

其中,flag_dump_contents是打印开关,flag_dump_contents时将打印COUNTER的内容。

输出格式:

    n blocks

   0 block0 block1 ... block7   //81行输出,前面的表示序号

   8 block8 block9 ... block15  //前面的8表示序号

    ...

当然,需要注意前导符或者输出位置。

 

3.3ARCS tag: tag_arcs()函数

static void

tag_arcs(const char *filenameATTRIBUTE_UNUSED,

unsigned tag ATTRIBUTE_UNUSED,unsigned lengthATTRIBUTE_UNUSED)

{

   unsigned n_arcs =GCOV_TAG_ARCS_NUM (length);

   printf (" %u arcs",n_arcs); //输出提示信息,几个arcs

 

   if (flag_dump_contents)

   {

       unsigned ix;

       unsigned blockno = gcov_read_unsigned();

 

       for (ix= ;ix != n_arcs;ix++)

       {

           unsigned dst,flags;

           if(!(ix& 3)) //如果arcs较多,则每4个为1行输出,且每行前面输出blockno

           {

               printf ("/n");

               print_prefix (filename,, gcov_position());

               printf ("/tblock %u:",blockno);

           }

 

           dst =gcov_read_unsigned();   //读取目的blockno

           flags = gcov_read_unsigned ();

           printf (" %u:%04x",dst, flags);

       }

   }

}

输出格式:

   n arcs   //narcs,每4个为1行输出

    blockno: dst0:flags0 dst1:flags1 dst2:flags2 dst3:flags3

    blockno: dst4:flags4 dst5:flags5 dst6:flags6 dst7:flags7

    ...

同上,需要注意前导符或者输出位置。dst0, ...,表示目的blockblockno

 

3.4LINES tag: tag_lines()函数

static void

tag_lines(const char *filenameATTRIBUTE_UNUSED,

unsigned tag ATTRIBUTE_UNUSED,unsigned lengthATTRIBUTE_UNUSED)

{

   if (flag_dump_contents)

   {

       unsigned blockno= gcov_read_unsigned();

       char const *sep= NULL;

 

       while (1)

       {

           gcov_position_t position= gcov_position ();

           const char *source= NULL;

           unsigned lineno= gcov_read_unsigned();

 

           if (!lineno) //lineno=0时才会执行该clause,因此lineno=0即为以后的新的文件的标志

           {

               source= gcov_read_string();  //该函数读取length(4字节)lengthwords(4*length字节)

               if(!source)                 //source即为文件名,没有源文件了,就退出

                   break;

               sep= NULL;

           }

 

           if (!sep) //sep=NULL才会执行该clause,那么什么时候会为NULL呢?——就是新的文件开始,实际上就是lineno=0

           {

               printf("/n");

               print_prefix(filename,, position);

               printf("/tblock %u:",blockno);

               sep= "";

           }

 

           if (lineno)

           {

               printf("%s%u",sep, lineno);

               sep= ", ";

           }

            else

           {

               printf("%s`%s'",sep,source); //lineno=0时,输出该文件名,之后sep=":"

               sep= ":";

           }

       }

    }

}

输出格式:

    block blockno:'filename':lineno1, lineno2, ...

 

例如:block 1:'test.c':4, 7, 9

其中,前面的block为提示信息。同上,需要注意前导符或者输出位置。

 

3.5COUNTER tag: tag_counters()函数

static void

tag_counters(const char *filenameATTRIBUTE_UNUSED,

unsigned tag ATTRIBUTE_UNUSED,unsigned lengthATTRIBUTE_UNUSED)

{

   static const char *const counter_names[]= GCOV_COUNTER_NAMES;

   unsigned n_counts = GCOV_TAG_COUNTER_NUM(length);

 

   printf (" %s %u counts",

       counter_names[GCOV_COUNTER_FOR_TAG(tag)],n_counts);

   if (flag_dump_contents)

   {

       unsigned ix;

 

       for (ix= ;ix != n_counts;ix++)

       {

           gcov_type count;

           if(!(ix& 7)) //如果counter较多,则每81行输出,且按816...输出序号

           {

               printf ("/n");

               print_prefix (filename,, gcov_position());

               printf ("/t/t%u",ix); //输出序号

           }

 

           count = gcov_read_counter();  //读取该counter,读取8字节,但返回4字节

           printf (" ");

           printf (HOST_WIDEST_INT_PRINT_DEC,count);

       }

    }

}

关于GCOV_TAG_COUNTER_NUMGCOV_COUNTER_FOR_TAG,请参考源代码。

 

counter的名字定义如下。

/* A list of human readable names of the counters */

#defineGCOV_COUNTER_NAMES        {"arcs", "interval", "pow2", "single", "delta"}

输出格式:

   arcsn counts //arcs即为counter的名字,如上

   0 counter0 counter1 ... counter7   //81行输出,前面的表示序号

   8 counter8 counter9 ... counter15  //前面的8表示序号

    ...

同上,需要注意前导符或者输出位置。

 

3.6OBJECT/PROGRAM SUMMARY tag: tag_summary()函数

static void 

tag_summary(const char *filenameATTRIBUTE_UNUSED,

unsigned tag ATTRIBUTE_UNUSED,unsigned lengthATTRIBUTE_UNUSED)

{

   struct gcov_summary summary;

   unsigned ix;

 

   /***** initialize all members with 0 *****/

   memset(&summary,, sizeof(summary));

 

   unsigned count = gcov_read_summary(&summary); //读取该summary

   printf (" checksum=0x%08x",summary.checksum);

 

   /* for (ix = 0; ix ! = GCOV_COUNTERS; ix++) */ /* 原来的代码 */

   for (ix= ;ix < count;ix++)                 /* 应该如此修改*/

   {

       printf ("/n");

       print_prefix (filename,, );

       printf ("/t/tcounts=%u, runs=%u",summary.ctrs[ix].num,summary.ctrs[ix].runs);

       printf (", sum_all="HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT)summary.ctrs[ix].sum_all);

       printf (", run_max="HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT)summary.ctrs[ix].run_max);

       printf (", sum_max="HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT)summary.ctrs[ix].sum_max);

    }

}

输出格式:

   checksum=0x51924f98

   counts=5, runs=1, sum_all=12, run_max=10, sum_max=10

同上,也需要注意前导符或者输出位置。

 

其中,gcov_read_summary函数是修改后的函数,在"Linux平台代码覆盖率测试-GCC如何编译生成gcov/gcov-dump程序及其bug分析"一文没有列出该修改后的函数,其实这篇文章中的bug与该函数有关。此处列出其代码。

GCOV_LINKAGEunsigned

gcov_read_summary(structgcov_summary *summary)

{

   unsigned ix;

   struct gcov_ctr_summary *csum;

 

   summary- >checksum =gcov_read_unsigned ();/***** checksum is a words (4Bytes) *****/

 

   /***** that is, a summry is 32Bytes (sizeof(gcov_type)=4) or 20Bytes (sizeof(gcov_type)=8) *****/

   for (csum= summary- >ctrs,ix = GCOV_COUNTERS_SUMMABLE;ix-- ;csum++)

    {

       csum- >num =gcov_read_unsigned ();/***** 4Bytes *****/

       csum- >runs =gcov_read_unsigned ();/***** 4Bytes *****/

       csum- >sum_all =gcov_read_counter ();/***** 8Bytes, but return 4Bytes*****/

       csum- >run_max =gcov_read_counter ();/***** 8Bytes, but return 4Bytes*****/

       csum- >sum_max =gcov_read_counter ();/***** 8Bytes, but return 4Bytes*****/

    }

 

   return GCOV_COUNTERS_SUMMABLE;/* zubo modified to return the nubmer */

}

gcov_summarygcov_ctr_summary结构的定义可参考源代码或者"Linux平台代码覆盖率测试工具GCOV相关文件分析"

 

4.小结

 

本文详细叙述了gcov-dump程序的结构和实现原理。也从中学习了其处理各种tag用到的callback方法,如果你想深入跟踪或学习gcc源码,请注意callback的使用,因为gcc源码中大量地使用了callback

 

 

Reference

http://blog.csdn.net/livelylittlefish/archive/2011/04/13/6321909.aspx

http://blog.csdn.net/livelylittlefish/archive/2011/05/01/6382489.aspx

http://blog.csdn.net/livelylittlefish/archive/2011/05/26/6448799.aspx



Technorati 标签:


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