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 完成的。
相关视频
相关阅读 盘古越狱原理分析(看清它如何越狱的!)茄子快传原理是什么 茄子快传的原理分析硬盘保护卡的原理分析更改IE标题栏和注册表的原理分析VBS脚本病毒原理分析与防范 (1)VBS脚本病毒原理分析与防范QQ尾巴病毒的发送原理分析Mac虚拟机安装Linux Ubuntu教程 Parallels desktop安装linux教程
热门文章 没有查询到任何记录。
最新文章
nginx-1.0.4的容器源码如何在xp系统用IIS搭建
nginx-1.0.4的容器源码分析—数组结构ngx_aPHP编程技巧提高PHP开发效率php站内全文搜索代码如何在xp系统用IIS搭建php环境
人气排行 如何在xp系统用IIS搭建php环境php输出内容乱码解决方法php站内全文搜索代码gcov-dump原理分析_Linux平台代码覆盖率测试如何架设PHP服务器nginx-1.0.4的容器源码分析—数组结构ngx_a用PHP实现文件管理系统PHP编程技巧提高PHP开发效率
查看所有0条评论>>