PC6下载站

分类分类

gcov-dump原理分析_Linux平台代码覆盖率测试

关注+2011-07-12作者:清晨

13 页 处理各种 tag 的 callback 定义

 

2.3 处理各种 tag 的 callback 定义

 

处理 tag 的 callback 函数定义如下。

static const tag_format_t tag_table [] =

{

    { 0 , "NOP" , NULL },

    { 0 , "UNKNOWN" , NULL },

    { 0 , "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 },

    { 0 , 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 字节 (1 个 words) 为单位进行。下面分析从 .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 > 0 );

    if ( excess < words )

    {

        gcov_var .start += gcov_var .offset ;

#if IN_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 = 0 ;

        gcov_var .length = excess ;

#if IN_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="">> 2 ;

        gcov_var .length += excess ;

        if ( gcov_var .length < words )

        {

            gcov_var .overread += words - gcov_var .length ;

            gcov_var .length = 0 ;

            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.3 和 3.4 节,也可以参考本文第 3 节。

 

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

——这就是 gcov_allocate 完成的。

展开全部

相关文章

更多+相同厂商

热门推荐

  • 最新排行
  • 最热排行
  • 评分最高
排行榜

    点击查看更多

      点击查看更多

        点击查看更多

        说两句网友评论

          我要评论...
          取消