From: Peter O. <obe...@us...> - 2012-01-20 08:23:12
|
Update of /cvsroot/ltp/utils/analysis/gcov-kernel In directory vz-cvs-4.sog:/tmp/cvs-serv32403 Modified Files: linux-2.6.32-gcov-android-toolchain-4.4.0.patch Added Files: linux-3.2-gcov-android-toolchain-4.4.0.patch Log Message: gcov-kernel: fix broken gcov_persist mechanism for android There are changes in the data structures that need to be cloned by gcov-kernel when unloading/reloading modules while gcov_persist is on. Without these changes, attempts to access gcov data after module reload will fail. Fix this by implementing the correct gcov data clone function. --- NEW FILE: linux-3.2-gcov-android-toolchain-4.4.0.patch --- # # mk...@mo...: # This is motorola kernel team, we have found and fixed an issue in gcov # kernel patch when working with android toolchain 4.4.0. # # The new toolchain added new feature LIPO # http://gcc.gnu.org/wiki/LightweightIpo and Sampled FDO, David is the author # for thoes feature, those change are not in gcov kernel patch. With David # and peter's help, I updated gcov kernel patch, so that it could works with # new android toolchain. This patch should be useful for other android kernel # developers. # # Changes: # - 2012-01-20 Peter Oberparleiter <pet...@de...> # * fix gcov_persist mechanism # # kernel/gcov/gcc_3_4.c | 98 +++++++++++++++++++++++++++++++++++++++++--------- # kernel/gcov/gcov.h | 32 +++++++++++++++- # 2 files changed, 112 insertions(+), 18 deletions(-) # --- a/kernel/gcov/gcc_3_4.c +++ b/kernel/gcov/gcc_3_4.c @@ -146,6 +146,14 @@ struct gcov_info *gcov_info_dup(struct g get_fn_size(info), GFP_KERNEL); if (!dup->functions) goto err_free; + for (i = 0; i < info->n_functions; i++) { + struct gcov_fn_info *src_fn = get_fn_info(info, i); + struct gcov_fn_info *dst_fn = get_fn_info(dup, i); + + dst_fn->name = kstrdup(src_fn->name, GFP_KERNEL); + if (!dst_fn->name) + goto err_free; + } /* Duplicate counter arrays. */ for (i = 0; i < active ; i++) { struct gcov_ctr_info *ctr = &info->counts[i]; @@ -176,6 +184,8 @@ void gcov_info_free(struct gcov_info *in for (i = 0; i < active ; i++) vfree(info->counts[i].values); + for (i = 0; i < info->n_functions; i++) + kfree(get_fn_info(info, i)->name); kfree(info->functions); kfree(info->filename); kfree(info); @@ -297,16 +307,30 @@ void gcov_iter_start(struct gcov_iterato } /* Mapping of logical record number to actual file content. */ -#define RECORD_FILE_MAGIC 0 -#define RECORD_GCOV_VERSION 1 -#define RECORD_TIME_STAMP 2 -#define RECORD_FUNCTION_TAG 3 -#define RECORD_FUNCTON_TAG_LEN 4 -#define RECORD_FUNCTION_IDENT 5 -#define RECORD_FUNCTION_CHECK 6 -#define RECORD_COUNT_TAG 7 -#define RECORD_COUNT_LEN 8 -#define RECORD_COUNT 9 +#define RECORD_FILE_MAGIC 0 +#define RECORD_GCOV_VERSION 1 +#define RECORD_TIME_STAMP 2 +#define RECORD_FUNCTION_TAG 3 +#define RECORD_FUNCTON_TAG_LEN 4 +#define RECORD_FUNCTION_IDENT 5 +#define RECORD_FUNCTION_CHECK_LINE 6 +#define RECORD_FUNCTION_CHECK_CFG 7 +#define RECORD_FUNCTION_NAME_LEN 8 +#define RECORD_FUNCTION_NAME 9 +#define RECORD_COUNT_TAG 10 +#define RECORD_COUNT_LEN 11 +#define RECORD_COUNT 12 + +/* Return length of string encoded in GCOV format. */ +static size_t +sizeof_str(const char *str) +{ + size_t len; + len = (str) ? strlen(str) : 0; + if (len == 0) + return 1; + return 1 + ((len + 4) >> 2); +} /** * gcov_iter_next - advance file iterator to next logical record @@ -323,6 +347,9 @@ int gcov_iter_next(struct gcov_iterator case RECORD_FUNCTON_TAG_LEN: case RECORD_FUNCTION_IDENT: case RECORD_COUNT_TAG: + case RECORD_FUNCTION_CHECK_LINE: + case RECORD_FUNCTION_CHECK_CFG: + case RECORD_FUNCTION_NAME_LEN: /* Advance to next record */ iter->record++; break; @@ -332,7 +359,7 @@ int gcov_iter_next(struct gcov_iterator /* fall through */ case RECORD_COUNT_LEN: if (iter->count < get_func(iter)->n_ctrs[iter->type]) { - iter->record = 9; + iter->record = 12; break; } /* Advance to next counter type */ @@ -340,9 +367,9 @@ int gcov_iter_next(struct gcov_iterator iter->count = 0; iter->type++; /* fall through */ - case RECORD_FUNCTION_CHECK: + case RECORD_FUNCTION_NAME: if (iter->type < iter->num_types) { - iter->record = 7; + iter->record = 10; break; } /* Advance to next function */ @@ -395,6 +422,34 @@ static int seq_write_gcov_u64(struct seq data[1] = (v >> 32); return seq_write(seq, data, sizeof(data)); } +/** + * seq_write_gcov_str - write string in gcov format to seq_file + * @seq: seq_file handle + * @str: string to be stored + * + * Number format defined by gcc: numbers are recorded in the 32 bit + * unsigned binary form of the endianness of the machine generating the + * file. 64 bit numbers are stored as two 32 bit numbers, the low part + * first. + */ +static int seq_write_gcov_str(struct seq_file *seq, const char *str) +{ + if (str) { + size_t len; + int str_off; + u32 data; + len = strlen(str); + for (str_off = 0; str_off < (sizeof_str(str) - 2) ; str_off++) { + memcpy(&data, (str + str_off * 4), 4); + seq_write(seq, &data, sizeof(data)); + } + data = 0; + memcpy(&data, (str + str_off * 4), (len - str_off * 4)); + return seq_write(seq, &data, sizeof(data)); + } else { + return 0; + } +} /** * gcov_iter_write - write data for current pos to seq_file @@ -421,13 +476,24 @@ int gcov_iter_write(struct gcov_iterator rc = seq_write_gcov_u32(seq, GCOV_TAG_FUNCTION); break; case RECORD_FUNCTON_TAG_LEN: - rc = seq_write_gcov_u32(seq, 2); + rc = seq_write_gcov_u32(seq, GCOV_TAG_FUNCTION_LENGTH + + (sizeof_str(get_func(iter)->name))); break; case RECORD_FUNCTION_IDENT: rc = seq_write_gcov_u32(seq, get_func(iter)->ident); break; - case RECORD_FUNCTION_CHECK: - rc = seq_write_gcov_u32(seq, get_func(iter)->checksum); + case RECORD_FUNCTION_CHECK_LINE: + rc = seq_write_gcov_u32(seq, get_func(iter)->lineno_checksum); + break; + case RECORD_FUNCTION_CHECK_CFG: + rc = seq_write_gcov_u32(seq, get_func(iter)->cfg_checksum); + break; + case RECORD_FUNCTION_NAME_LEN: + rc = seq_write_gcov_u32(seq, + (sizeof_str(get_func(iter)->name) - 1)); + break; + case RECORD_FUNCTION_NAME: + rc = seq_write_gcov_str(seq, get_func(iter)->name); break; case RECORD_COUNT_TAG: rc = seq_write_gcov_u32(seq, --- a/kernel/gcov/gcov.h +++ b/kernel/gcov/gcov.h @@ -21,9 +21,10 @@ * gcc and need to be kept as close to the original definition as possible to * remain compatible. */ -#define GCOV_COUNTERS 5 +#define GCOV_COUNTERS 10 #define GCOV_DATA_MAGIC ((unsigned int) 0x67636461) #define GCOV_TAG_FUNCTION ((unsigned int) 0x01000000) +#define GCOV_TAG_FUNCTION_LENGTH 3 #define GCOV_TAG_COUNTER_BASE ((unsigned int) 0x01a10000) #define GCOV_TAG_FOR_COUNTER(count) \ (GCOV_TAG_COUNTER_BASE + ((unsigned int) (count) << 17)) @@ -34,6 +35,29 @@ typedef long gcov_type; typedef long long gcov_type; #endif +/* + * Source module info. The data structure is used in both runtime and + * profile-use phase. + */ +struct gcov_module_info { + unsigned int ident; +/* + * This is overloaded to mean two things: + * (1) means FDO/LIPO in instrumented binary. + * (2) means IS_PRIMARY in persistent file or memory copy used in profile-use. + */ + unsigned int is_primary; + unsigned int is_exported; + unsigned int lang; + char *da_filename; + char *source_filename; + unsigned int num_quote_paths; + unsigned int num_bracket_paths; + unsigned int num_cpp_defines; + char *string_array[1]; +}; + + /** * struct gcov_fn_info - profiling meta data per function * @ident: object file-unique function identifier @@ -45,7 +69,9 @@ typedef long long gcov_type; */ struct gcov_fn_info { unsigned int ident; - unsigned int checksum; + unsigned int lineno_checksum; + unsigned int cfg_checksum; /* function cfg checksum */ + const char *name; /* name of the function */ unsigned int n_ctrs[0]; }; @@ -80,9 +106,11 @@ struct gcov_ctr_info { */ struct gcov_info { unsigned int version; + struct gcov_module_info *mod_info; struct gcov_info *next; unsigned int stamp; const char *filename; + unsigned int eof_pos; unsigned int n_functions; const struct gcov_fn_info *functions; unsigned int ctr_mask; Index: linux-2.6.32-gcov-android-toolchain-4.4.0.patch =================================================================== RCS file: /cvsroot/ltp/utils/analysis/gcov-kernel/linux-2.6.32-gcov-android-toolchain-4.4.0.patch,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** linux-2.6.32-gcov-android-toolchain-4.4.0.patch 22 Nov 2010 14:57:19 -0000 1.1 --- linux-2.6.32-gcov-android-toolchain-4.4.0.patch 20 Jan 2012 08:23:10 -0000 1.2 *************** *** 11,22 **** # developers. # ! # kernel/gcov/gcc_3_4.c | 88 ++++++++++++++++++++++++++++++++++-------- ! # kernel/gcov/gcov.h | 32 ++++++++++++++- ! # 2 files changed, 102 insertions(+), 18 deletions(-) # --- a/kernel/gcov/gcc_3_4.c +++ b/kernel/gcov/gcc_3_4.c ! @@ -297,16 +297,30 @@ void gcov_iter_start(struct gcov_iterato } --- 11,50 ---- # developers. # ! # Changes: ! # - 2012-01-20 Peter Oberparleiter <pet...@de...> ! # * fix gcov_persist mechanism ! # ! # kernel/gcov/gcc_3_4.c | 98 +++++++++++++++++++++++++++++++++++++++++--------- ! # kernel/gcov/gcov.h | 32 +++++++++++++++- ! # 2 files changed, 112 insertions(+), 18 deletions(-) # --- a/kernel/gcov/gcc_3_4.c +++ b/kernel/gcov/gcc_3_4.c ! @@ -146,6 +146,14 @@ struct gcov_info *gcov_info_dup(struct g ! get_fn_size(info), GFP_KERNEL); ! if (!dup->functions) ! goto err_free; ! + for (i = 0; i < info->n_functions; i++) { ! + struct gcov_fn_info *src_fn = get_fn_info(info, i); ! + struct gcov_fn_info *dst_fn = get_fn_info(dup, i); ! + ! + dst_fn->name = kstrdup(src_fn->name, GFP_KERNEL); ! + if (!dst_fn->name) ! + goto err_free; ! + } ! /* Duplicate counter arrays. */ ! for (i = 0; i < active ; i++) { ! struct gcov_ctr_info *ctr = &info->counts[i]; ! @@ -176,6 +184,8 @@ void gcov_info_free(struct gcov_info *in ! ! for (i = 0; i < active ; i++) ! vfree(info->counts[i].values); ! + for (i = 0; i < info->n_functions; i++) ! + kfree(get_fn_info(info, i)->name); ! kfree(info->functions); ! kfree(info->filename); ! kfree(info); ! @@ -297,16 +307,30 @@ void gcov_iter_start(struct gcov_iterato } *************** *** 59,63 **** /** * gcov_iter_next - advance file iterator to next logical record ! @@ -323,6 +337,9 @@ int gcov_iter_next(struct gcov_iterator case RECORD_FUNCTON_TAG_LEN: case RECORD_FUNCTION_IDENT: --- 87,91 ---- /** * gcov_iter_next - advance file iterator to next logical record ! @@ -323,6 +347,9 @@ int gcov_iter_next(struct gcov_iterator case RECORD_FUNCTON_TAG_LEN: case RECORD_FUNCTION_IDENT: *************** *** 69,73 **** iter->record++; break; ! @@ -332,7 +349,7 @@ int gcov_iter_next(struct gcov_iterator /* fall through */ case RECORD_COUNT_LEN: --- 97,101 ---- iter->record++; break; ! @@ -332,7 +359,7 @@ int gcov_iter_next(struct gcov_iterator /* fall through */ case RECORD_COUNT_LEN: *************** *** 78,82 **** } /* Advance to next counter type */ ! @@ -340,9 +357,9 @@ int gcov_iter_next(struct gcov_iterator iter->count = 0; iter->type++; --- 106,110 ---- } /* Advance to next counter type */ ! @@ -340,9 +367,9 @@ int gcov_iter_next(struct gcov_iterator iter->count = 0; iter->type++; *************** *** 90,94 **** } /* Advance to next function */ ! @@ -395,6 +412,34 @@ static int seq_write_gcov_u64(struct seq data[1] = (v >> 32); return seq_write(seq, data, sizeof(data)); --- 118,122 ---- } /* Advance to next function */ ! @@ -395,6 +422,34 @@ static int seq_write_gcov_u64(struct seq data[1] = (v >> 32); return seq_write(seq, data, sizeof(data)); *************** *** 125,129 **** /** * gcov_iter_write - write data for current pos to seq_file ! @@ -421,13 +466,24 @@ int gcov_iter_write(struct gcov_iterator rc = seq_write_gcov_u32(seq, GCOV_TAG_FUNCTION); break; --- 153,157 ---- /** * gcov_iter_write - write data for current pos to seq_file ! @@ -421,13 +476,24 @@ int gcov_iter_write(struct gcov_iterator rc = seq_write_gcov_u32(seq, GCOV_TAG_FUNCTION); break; |