gcov-kernel: Make gcov work on vanilla gcc again.
Tuomas Tynkkynen [Fri, 9 Nov 2012 16:20:44 +0000 (18:20 +0200)]
Commit "gcov-kernel: patch for Android toolchain 4.4.x support" broke
support for gcov on vanilla gcc. Introduce #ifdefs to make it work on
both of them.

Since the gcov ABI for Android gcc is different, the build system
must set CONFIG_GCOV_TOOLCHAIN_IS_ANDROID when compiling with an
Android toolchain.

Also remove a few magic numbers from the original gcov code and fix a
unused function warning.

Bug 1155439

Change-Id: I7c18938e5503df4ee1c3f8de2b6f5a99ceef7f71
Signed-off-by: Tuomas Tynkkynen <ttynkkynen@nvidia.com>
Reviewed-on: http://git-master/r/162711
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: Juha Tukkinen <jtukkinen@nvidia.com>

kernel/gcov/Kconfig
kernel/gcov/gcc_3_4.c
kernel/gcov/gcov.h

index 824b741..19c4ba7 100644 (file)
@@ -46,6 +46,17 @@ config GCOV_PROFILE_ALL
        larger and run slower. Also be sure to exclude files from profiling
        which are not linked to the kernel image to prevent linker errors.
 
+config GCOV_TOOLCHAIN_IS_ANDROID
+       bool "Use Android toolchain ABI for gcov instead of vanilla gcc ABI"
+       default n
+       ---help---
+       This option must be set if a gcov-enabled kernel is being built with an
+       Android toolchain. The gcov ABI in Android gcc is not compatible with
+       vanilla gcc, and choosing this option incorrectly might lead to kernel
+       panics during boot or when dumping the gcov data.
+
+       If unsure, say N.
+
 config GCOV_CTORS
        string
        depends on CONSTRUCTORS
index bc78336..e075a15 100644 (file)
@@ -349,7 +349,7 @@ int gcov_iter_next(struct gcov_iterator *iter)
                /* fall through */
        case RECORD_COUNT_LEN:
                if (iter->count < get_func(iter)->n_ctrs[iter->type]) {
-                       iter->record = 12;
+                       iter->record = RECORD_COUNT;
                        break;
                }
                /* Advance to next counter type */
@@ -359,7 +359,7 @@ int gcov_iter_next(struct gcov_iterator *iter)
                /* fall through */
        case RECORD_FUNCTION_NAME:
                if (iter->type < iter->num_types) {
-                       iter->record = 10;
+                       iter->record = RECORD_COUNT_TAG;
                        break;
                }
                /* Advance to next function */
@@ -368,7 +368,7 @@ int gcov_iter_next(struct gcov_iterator *iter)
                /* fall through */
        case RECORD_TIME_STAMP:
                if (iter->function < iter->info->n_functions)
-                       iter->record = 3;
+                       iter->record = RECORD_FUNCTION_TAG;
                else
                        iter->record = -1;
                break;
@@ -423,6 +423,9 @@ static int seq_write_gcov_u64(struct seq_file *seq, u64 v)
  * first.
  */
 static int seq_write_gcov_str(struct seq_file *seq, const char *str)
+       __attribute__ ((unused));
+
+static int seq_write_gcov_str(struct seq_file *seq, const char *str)
 {
        if (str) {
                size_t len;
@@ -450,7 +453,7 @@ static int seq_write_gcov_str(struct seq_file *seq, const char *str)
  */
 int gcov_iter_write(struct gcov_iterator *iter, struct seq_file *seq)
 {
-       int rc = -EINVAL;
+       int rc = 0;
 
        switch (iter->record) {
        case RECORD_FILE_MAGIC:
@@ -477,24 +480,26 @@ int gcov_iter_write(struct gcov_iterator *iter, struct seq_file *seq)
                rc = seq_write_gcov_u32(seq, get_func(iter)->ident);
                break;
        case RECORD_FUNCTION_CHECK_LINE:
+#ifdef CONFIG_GCOV_TOOLCHAIN_IS_ANDROID
                rc = seq_write_gcov_u32(seq, get_func(iter)->lineno_checksum);
+#else
+               rc = seq_write_gcov_u32(seq, get_func(iter)->checksum);
+#endif
                break;
        case RECORD_FUNCTION_CHECK_CFG:
+#ifdef CONFIG_GCOV_TOOLCHAIN_IS_ANDROID
                rc = seq_write_gcov_u32(seq, get_func(iter)->cfg_checksum);
+#endif
                break;
        case RECORD_FUNCTION_NAME_LEN:
 #ifdef GCOV_FN_INFO_HAS_NAME_FIELD
                rc = seq_write_gcov_u32(seq,
                        (sizeof_str(get_func(iter)->name) - 1));
-#else
-               rc = 0;
 #endif
                break;
        case RECORD_FUNCTION_NAME:
 #ifdef GCOV_FN_INFO_HAS_NAME_FIELD
                rc = seq_write_gcov_str(seq, get_func(iter)->name);
-#else
-               rc = 0;
 #endif
                break;
        case RECORD_COUNT_TAG:
@@ -510,6 +515,8 @@ int gcov_iter_write(struct gcov_iterator *iter, struct seq_file *seq)
                        iter->info->counts[iter->type].
                                values[iter->count + get_type(iter)->offset]);
                break;
+       default:
+               rc = -EINVAL;
        }
        return rc;
 }
index 8c5130a..3083b37 100644 (file)
 #include <linux/types.h>
 
 /*
- * GCC 4.6 drops the 'name' field from 'struct gcov_fn_info'.
+ * Profiling data types used for at least gcc 4.4 - these are defined by
+ * gcc and need to be kept as close to the original definition as possible to
+ * remain compatible.
+ *
+ * If compiling with an Android toolchain (from 4.4 to at least 4.6),
+ * CONFIG_GCOV_TOOLCHAIN_IS_ANDROID must be set, since it's not compatible
+ * with a vanilla gcc.
  */
-#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6)
-#define GCOV_FN_INFO_HAS_NAME_FIELD
-#endif
+
+#ifdef CONFIG_GCOV_TOOLCHAIN_IS_ANDROID
 
 /*
- * Profiling data types used for at least gcc 4.4 and 4.6 - these are defined by
- * gcc and need to be kept as close to the original definition as possible to
- * remain compatible.
+ * Android GCC 4.6 drops the 'name' field from 'struct gcov_fn_info'.
  */
+# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6)
+# define GCOV_FN_INFO_HAS_NAME_FIELD
+# endif
+
+# define GCOV_TAG_FUNCTION_LENGTH 3
+#else /* !CONFIG_GCOV_TOOLCHAIN_IS_ANDROID */
+# define GCOV_TAG_FUNCTION_LENGTH 2
+#endif
+
 #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))
@@ -44,7 +55,7 @@ typedef long long gcov_type;
 
 /*
  * Source module info. The data structure is used in both runtime and
- * profile-use phase.
+ * profile-use phase. Android toolchain only.
  */
 struct gcov_module_info {
        unsigned int ident;
@@ -70,10 +81,11 @@ struct gcov_module_info {
 /**
  * struct gcov_fn_info - profiling meta data per function
  * @ident: object file-unique function identifier
- * @lineno_checksum: function lineno checksum
- * @cfg_checksum: function cfg checksum
+ * @checksum: function checksum. Removed in Android GCC 4.4+
+ * @lineno_checksum: function lineno checksum. In Android GCC 4.4+
+ * @cfg_checksum: function cfg checksum. In Android GCC 4.4+
  * @dc_offset: direct call offset
- * @name: function name
+ * @name: function name. In Android GCC 4.4, removed from 4.6.
  * @n_ctrs: number of values per counter type belonging to this function
  *
  * This data is generated by gcc during compilation and doesn't change
@@ -81,11 +93,15 @@ struct gcov_module_info {
  */
 struct gcov_fn_info {
        unsigned int ident;
+#ifndef CONFIG_GCOV_TOOLCHAIN_IS_ANDROID
+       unsigned int checksum;
+#else
        unsigned int lineno_checksum;
        unsigned int cfg_checksum;
        unsigned int dc_offset;
-#ifdef GCOV_FN_INFO_HAS_NAME_FIELD
+# ifdef GCOV_FN_INFO_HAS_NAME_FIELD
        const char   *name;
+# endif
 #endif
        unsigned int n_ctrs[0];
 };
@@ -106,13 +122,13 @@ struct gcov_ctr_info {
 };
 
 /**
- * struct gcov_info - profiling data per object file
+ * struct gcov_info - profiling data per object file. In Android GCC 4.4+
  * @version: gcov version magic indicating the gcc version used for compilation
  * @modinfo: additional module information
  * @next: list head for a singly-linked list
  * @stamp: time stamp
  * @filename: name of the associated gcov data file
- * @eof_pos: end position of profile data
+ * @eof_pos: end position of profile data. In Android GCC 4.4+
  * @n_functions: number of instrumented functions
  * @functions: function data
  * @ctr_mask: mask specifying which counter types are active
@@ -123,11 +139,15 @@ struct gcov_ctr_info {
  */
 struct gcov_info {
        unsigned int                    version;
+#ifdef CONFIG_GCOV_TOOLCHAIN_IS_ANDROID
        struct gcov_module_info         *mod_info;
+#endif
        struct gcov_info                *next;
        unsigned int                    stamp;
        const char                      *filename;
+#ifdef CONFIG_GCOV_TOOLCHAIN_IS_ANDROID
        unsigned int                    eof_pos;
+#endif
        unsigned int                    n_functions;
        const struct gcov_fn_info       *functions;
        unsigned int                    ctr_mask;