summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kernel/gcov/gcc_3_4.c88
-rw-r--r--kernel/gcov/gcov.h42
2 files changed, 111 insertions, 19 deletions
diff --git a/kernel/gcov/gcc_3_4.c b/kernel/gcov/gcc_3_4.c
index ae5bb4260033..d753d1152b7b 100644
--- a/kernel/gcov/gcc_3_4.c
+++ b/kernel/gcov/gcc_3_4.c
@@ -297,16 +297,30 @@ void gcov_iter_start(struct gcov_iterator *iter)
}
/* 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 +337,9 @@ int gcov_iter_next(struct gcov_iterator *iter)
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 +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 = 9;
+ iter->record = 12;
break;
}
/* Advance to next counter type */
@@ -340,9 +357,9 @@ int gcov_iter_next(struct gcov_iterator *iter)
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 +412,34 @@ static int seq_write_gcov_u64(struct seq_file *seq, u64 v)
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 +466,24 @@ int gcov_iter_write(struct gcov_iterator *iter, struct seq_file *seq)
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,
diff --git a/kernel/gcov/gcov.h b/kernel/gcov/gcov.h
index 060073ebf7a6..040c6980df0d 100644
--- 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,10 +35,38 @@ 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;
+ unsigned int num_cpp_includes;
+ unsigned int num_cl_args;
+ char *string_array[1];
+};
+
+
/**
* struct gcov_fn_info - profiling meta data per function
* @ident: object file-unique function identifier
- * @checksum: function checksum
+ * @lineno_checksum: function lineno checksum
+ * @cfg_checksum: function cfg checksum
+ * @dc_offset: direct call offset
+ * @name: function name
* @n_ctrs: number of values per counter type belonging to this function
*
* This data is generated by gcc during compilation and doesn't change
@@ -45,7 +74,10 @@ typedef long long gcov_type;
*/
struct gcov_fn_info {
unsigned int ident;
- unsigned int checksum;
+ unsigned int lineno_checksum;
+ unsigned int cfg_checksum;
+ unsigned int dc_offset;
+ const char *name;
unsigned int n_ctrs[0];
};
@@ -67,9 +99,11 @@ struct gcov_ctr_info {
/**
* struct gcov_info - profiling data per object file
* @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
* @n_functions: number of instrumented functions
* @functions: function data
* @ctr_mask: mask specifying which counter types are active
@@ -80,9 +114,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;