Content1. 使用 od 命令 dump 文件内容 2. 文件内容解析 (1) file magic(2) version(3) time stamp(4) FUNCTION tag(5) COUNTER tag(6) OBJECT SUMMARY tag(7) PROGRAM SUMMARY tag(8) file end3. 文件读取函数及其调用过程 3.1 读取 / 写入相关调用 3.2 程序退出点 Appendix: gcov 文件格式定义 本文仍以 Linux 平台代码覆盖率测试工具 GCOV 简介 一文的例子为例,分析 gcda/gcno 的文件格式和读取 / 写入方法。 1. 使用 od 命令 dump 文件内容
# od -t x4 -w16 test.gcda 0000000 67636461 34303170 4e8eb3f0 01000000 //magic version stamp tag 0000020 00000002 00000003 eb65a768 01a10000 //length func_ident checksum tag0000040 0000000a 0000000a 00000000 00000000 //length 0000060 00000000 00000001 00000000 000000000000100 00000000 00000001 00000000 a1000000 //0xa1000000 is GCOV_TAG_OBJECT_SUMMARY0000120 00000009 00000000 00000005 00000001 //length0000140 0000000c 00000000 0000000a 000000000000160 0000000a 00000000 a3000000 00000009 //0xa3000000 is GCOV_TAG_PROGRAM_SUMMARY0000200 51924f98 00000005 00000001 0000000c //checksum number runs0000220 00000000 0000000a 00000000 0000000a0000240 00000000 00000000 0000250
od 命令的使用方法可参考其 manual 页。 2. 文件内容解析 (1) file magic 0x67636461 is file magic, that is, "gcda". 0x67636461 是怎么来的呢?细心的读者一定会发现,实际上就是 "g","c","d","a" 字符的 ASCII 码组成的,即 0x67,0x63,0x64,0x61 。即采用字符的 ASCII 码作为文件 magic 。可参考附录的解释。 defined as the following.
/* File suffixes. */#define GCOV_DATA_SUFFIX ".gcda"#define GCOV_NOTE_SUFFIX ".gcno" /* File magic. Must not be palindromes. */#define GCOV_DATA_MAGIC ((gcov_unsigned_t)0x67636461 ) /* "gcda" */#define GCOV_NOTE_MAGIC ((gcov_unsigned_t)0x67636e6f ) /* "gcno" */
(2) version 0x34303170 is the GCOV_VERSION, that is, 401p, 即 4.1.2p 该版本常量在 gcov_iov.h 文件中定义,如下。
/* Generated automatically by the program `./gcov-iov" from `4.1.2 (4 1) and p (p)". */ #define GCOV_VERSION ((gcov_unsigned_t)0x34303170 ) /* 401p */
然而,这个文件是在编译 GCC 时自动产生的;文件的内容,是有 gcov_iov 程序产生,该程序由 gcov_iov.c 编译得来, 我们可以直接在 gcc 源代码下的 gcc 目录编译该文件,例如。
# cd /home/abo/gcc-4.1.2/gcc# gcc -g -o gcov-iov gcov-iov.c# ./gcov-iov 4.1.2 p/* Generated automatically by the program `./gcov-iov" from `4.1.2 (4 1) and p (p)". */ #define GCOV_VERSION ((gcov_unsigned_t)0x34303170) /* 401p */ # ./gcov-iov 4.1 p/* Generated automatically by the program `./gcov-iov" from `4.1 (4 1) and p (p)". */ #define GCOV_VERSION ((gcov_unsigned_t)0x34303170) /* 401p */
同样的道理, 0x34303170 即为字符 "4","0","1","p" 的 ASCII 码组成。 "p" 代表 prerelease ,请参考附录。 (3) time stamp 0x4e8eb3f0=1317975024 is the time stamp from GreenWich, it will be read and discarded. 可以使用 date 名验证这个时间,如下。不过,数值上好像有些差异,至于原因,本文不再研究。 # date -d @1317975024 +"%F %T %z"2011-10-07 16:10:24 +0800# date --date="2011-04-13 11:13:07" +%s1302664387 (4) FUNCTION tag 0x01000000 is a FUNCTION tag, defined as follows.
/* The record tags. Values [1..3f] are for tags which may be in either file. Values [41..9f] for those in the note file and [a1..ff] for the data file. The tag value zero is used as an explicit end of file marker -- it is not required to be present. */# define GCOV_TAG_FUNCTION ((gcov_unsigned_t) 0x01000000 ) # define GCOV_TAG_FUNCTION_LENGTH ( 2 ) # define GCOV_TAG_BLOCKS ((gcov_unsigned_t) 0x01410000 ) # define GCOV_TAG_BLOCKS_LENGTH(NUM) (NUM) # define GCOV_TAG_BLOCKS_NUM(LENGTH) (LENGTH) # define GCOV_TAG_ARCS ((gcov_unsigned_t) 0x01430000 ) # define GCOV_TAG_ARCS_LENGTH(NUM) ( 1 + (NUM) * 2 ) # define GCOV_TAG_ARCS_NUM(LENGTH) (((LENGTH) - 1 ) / 2 ) # define GCOV_TAG_LINES ((gcov_unsigned_t) 0x01450000 ) # define GCOV_TAG_COUNTER_BASE ((gcov_unsigned_t) 0x01a10000 ) # define GCOV_TAG_COUNTER_LENGTH(NUM) ((NUM) * 2 ) # define GCOV_TAG_COUNTER_NUM(LENGTH) ((LENGTH) / 2 ) # define GCOV_TAG_OBJECT_SUMMARY ((gcov_unsigned_t) 0xa1000000 ) # define GCOV_TAG_PROGRAM_SUMMARY ((gcov_unsigned_t) 0xa3000000 ) # define GCOV_TAG_SUMMARY_LENGTH ( 1 + GCOV_COUNTERS_SUMMABLE * ( 2 + 3 * 2 ))
then, 0x00000002 is its length; and 0x00000003 is the function identifier. Next, 0xeb65a768 is the checksum. 注 1 :只有是 FUNCTION tag 时,才会有后续的 length, function identifier 和 checksum 。 FUNCTION 数据结构如下。
/* Information about a single function. This uses the trailing array idiom. The number of counters is determined from the counter_mask in gcov_info. We hold an array of function info, so have to explicitly calculate the correct array stride. */struct gcov_fn_info { gcov_unsigned_t ident; /* unique ident of function */ gcov_unsigned_t checksum; /* function checksum */ unsigned n_ctrs[0]; /* instrumented counters */};