0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045 #define pr_fmt(fmt) "gcov: " fmt
0046
0047 #include <linux/kernel.h>
0048 #include <linux/list.h>
0049 #include <linux/printk.h>
0050 #include <linux/ratelimit.h>
0051 #include <linux/slab.h>
0052 #include <linux/mm.h>
0053 #include "gcov.h"
0054
0055 typedef void (*llvm_gcov_callback)(void);
0056
0057 struct gcov_info {
0058 struct list_head head;
0059
0060 const char *filename;
0061 unsigned int version;
0062 u32 checksum;
0063
0064 struct list_head functions;
0065 };
0066
0067 struct gcov_fn_info {
0068 struct list_head head;
0069
0070 u32 ident;
0071 u32 checksum;
0072 u32 cfg_checksum;
0073
0074 u32 num_counters;
0075 u64 *counters;
0076 };
0077
0078 static struct gcov_info *current_info;
0079
0080 static LIST_HEAD(clang_gcov_list);
0081
0082 void llvm_gcov_init(llvm_gcov_callback writeout, llvm_gcov_callback flush)
0083 {
0084 struct gcov_info *info = kzalloc(sizeof(*info), GFP_KERNEL);
0085
0086 if (!info)
0087 return;
0088
0089 INIT_LIST_HEAD(&info->head);
0090 INIT_LIST_HEAD(&info->functions);
0091
0092 mutex_lock(&gcov_lock);
0093
0094 list_add_tail(&info->head, &clang_gcov_list);
0095 current_info = info;
0096 writeout();
0097 current_info = NULL;
0098 if (gcov_events_enabled)
0099 gcov_event(GCOV_ADD, info);
0100
0101 mutex_unlock(&gcov_lock);
0102 }
0103 EXPORT_SYMBOL(llvm_gcov_init);
0104
0105 void llvm_gcda_start_file(const char *orig_filename, u32 version, u32 checksum)
0106 {
0107 current_info->filename = orig_filename;
0108 current_info->version = version;
0109 current_info->checksum = checksum;
0110 }
0111 EXPORT_SYMBOL(llvm_gcda_start_file);
0112
0113 void llvm_gcda_emit_function(u32 ident, u32 func_checksum, u32 cfg_checksum)
0114 {
0115 struct gcov_fn_info *info = kzalloc(sizeof(*info), GFP_KERNEL);
0116
0117 if (!info)
0118 return;
0119
0120 INIT_LIST_HEAD(&info->head);
0121 info->ident = ident;
0122 info->checksum = func_checksum;
0123 info->cfg_checksum = cfg_checksum;
0124 list_add_tail(&info->head, ¤t_info->functions);
0125 }
0126 EXPORT_SYMBOL(llvm_gcda_emit_function);
0127
0128 void llvm_gcda_emit_arcs(u32 num_counters, u64 *counters)
0129 {
0130 struct gcov_fn_info *info = list_last_entry(¤t_info->functions,
0131 struct gcov_fn_info, head);
0132
0133 info->num_counters = num_counters;
0134 info->counters = counters;
0135 }
0136 EXPORT_SYMBOL(llvm_gcda_emit_arcs);
0137
0138 void llvm_gcda_summary_info(void)
0139 {
0140 }
0141 EXPORT_SYMBOL(llvm_gcda_summary_info);
0142
0143 void llvm_gcda_end_file(void)
0144 {
0145 }
0146 EXPORT_SYMBOL(llvm_gcda_end_file);
0147
0148
0149
0150
0151
0152 const char *gcov_info_filename(struct gcov_info *info)
0153 {
0154 return info->filename;
0155 }
0156
0157
0158
0159
0160
0161 unsigned int gcov_info_version(struct gcov_info *info)
0162 {
0163 return info->version;
0164 }
0165
0166
0167
0168
0169
0170
0171
0172
0173 struct gcov_info *gcov_info_next(struct gcov_info *info)
0174 {
0175 if (!info)
0176 return list_first_entry_or_null(&clang_gcov_list,
0177 struct gcov_info, head);
0178 if (list_is_last(&info->head, &clang_gcov_list))
0179 return NULL;
0180 return list_next_entry(info, head);
0181 }
0182
0183
0184
0185
0186
0187 void gcov_info_link(struct gcov_info *info)
0188 {
0189 list_add_tail(&info->head, &clang_gcov_list);
0190 }
0191
0192
0193
0194
0195
0196
0197 void gcov_info_unlink(struct gcov_info *prev, struct gcov_info *info)
0198 {
0199
0200 __list_del_entry(&info->head);
0201 }
0202
0203
0204
0205
0206
0207
0208
0209
0210 bool gcov_info_within_module(struct gcov_info *info, struct module *mod)
0211 {
0212 return within_module((unsigned long)info->filename, mod);
0213 }
0214
0215
0216 const struct gcov_link gcov_link[] = {
0217 { OBJ_TREE, "gcno" },
0218 { 0, NULL},
0219 };
0220
0221
0222
0223
0224
0225 void gcov_info_reset(struct gcov_info *info)
0226 {
0227 struct gcov_fn_info *fn;
0228
0229 list_for_each_entry(fn, &info->functions, head)
0230 memset(fn->counters, 0,
0231 sizeof(fn->counters[0]) * fn->num_counters);
0232 }
0233
0234
0235
0236
0237
0238
0239
0240
0241 int gcov_info_is_compatible(struct gcov_info *info1, struct gcov_info *info2)
0242 {
0243 struct gcov_fn_info *fn_ptr1 = list_first_entry_or_null(
0244 &info1->functions, struct gcov_fn_info, head);
0245 struct gcov_fn_info *fn_ptr2 = list_first_entry_or_null(
0246 &info2->functions, struct gcov_fn_info, head);
0247
0248 if (info1->checksum != info2->checksum)
0249 return false;
0250 if (!fn_ptr1)
0251 return fn_ptr1 == fn_ptr2;
0252 while (!list_is_last(&fn_ptr1->head, &info1->functions) &&
0253 !list_is_last(&fn_ptr2->head, &info2->functions)) {
0254 if (fn_ptr1->checksum != fn_ptr2->checksum)
0255 return false;
0256 if (fn_ptr1->cfg_checksum != fn_ptr2->cfg_checksum)
0257 return false;
0258 fn_ptr1 = list_next_entry(fn_ptr1, head);
0259 fn_ptr2 = list_next_entry(fn_ptr2, head);
0260 }
0261 return list_is_last(&fn_ptr1->head, &info1->functions) &&
0262 list_is_last(&fn_ptr2->head, &info2->functions);
0263 }
0264
0265
0266
0267
0268
0269
0270
0271
0272 void gcov_info_add(struct gcov_info *dst, struct gcov_info *src)
0273 {
0274 struct gcov_fn_info *dfn_ptr;
0275 struct gcov_fn_info *sfn_ptr = list_first_entry_or_null(&src->functions,
0276 struct gcov_fn_info, head);
0277
0278 list_for_each_entry(dfn_ptr, &dst->functions, head) {
0279 u32 i;
0280
0281 for (i = 0; i < sfn_ptr->num_counters; i++)
0282 dfn_ptr->counters[i] += sfn_ptr->counters[i];
0283 }
0284 }
0285
0286 static struct gcov_fn_info *gcov_fn_info_dup(struct gcov_fn_info *fn)
0287 {
0288 size_t cv_size;
0289 struct gcov_fn_info *fn_dup = kmemdup(fn, sizeof(*fn),
0290 GFP_KERNEL);
0291 if (!fn_dup)
0292 return NULL;
0293 INIT_LIST_HEAD(&fn_dup->head);
0294
0295 cv_size = fn->num_counters * sizeof(fn->counters[0]);
0296 fn_dup->counters = kvmalloc(cv_size, GFP_KERNEL);
0297 if (!fn_dup->counters) {
0298 kfree(fn_dup);
0299 return NULL;
0300 }
0301
0302 memcpy(fn_dup->counters, fn->counters, cv_size);
0303
0304 return fn_dup;
0305 }
0306
0307
0308
0309
0310
0311
0312
0313 struct gcov_info *gcov_info_dup(struct gcov_info *info)
0314 {
0315 struct gcov_info *dup;
0316 struct gcov_fn_info *fn;
0317
0318 dup = kmemdup(info, sizeof(*dup), GFP_KERNEL);
0319 if (!dup)
0320 return NULL;
0321 INIT_LIST_HEAD(&dup->head);
0322 INIT_LIST_HEAD(&dup->functions);
0323 dup->filename = kstrdup(info->filename, GFP_KERNEL);
0324 if (!dup->filename)
0325 goto err;
0326
0327 list_for_each_entry(fn, &info->functions, head) {
0328 struct gcov_fn_info *fn_dup = gcov_fn_info_dup(fn);
0329
0330 if (!fn_dup)
0331 goto err;
0332 list_add_tail(&fn_dup->head, &dup->functions);
0333 }
0334
0335 return dup;
0336
0337 err:
0338 gcov_info_free(dup);
0339 return NULL;
0340 }
0341
0342
0343
0344
0345
0346 void gcov_info_free(struct gcov_info *info)
0347 {
0348 struct gcov_fn_info *fn, *tmp;
0349
0350 list_for_each_entry_safe(fn, tmp, &info->functions, head) {
0351 kvfree(fn->counters);
0352 list_del(&fn->head);
0353 kfree(fn);
0354 }
0355 kfree(info->filename);
0356 kfree(info);
0357 }
0358
0359
0360
0361
0362
0363
0364
0365
0366 size_t convert_to_gcda(char *buffer, struct gcov_info *info)
0367 {
0368 struct gcov_fn_info *fi_ptr;
0369 size_t pos = 0;
0370
0371
0372 pos += store_gcov_u32(buffer, pos, GCOV_DATA_MAGIC);
0373 pos += store_gcov_u32(buffer, pos, info->version);
0374 pos += store_gcov_u32(buffer, pos, info->checksum);
0375
0376 list_for_each_entry(fi_ptr, &info->functions, head) {
0377 u32 i;
0378
0379 pos += store_gcov_u32(buffer, pos, GCOV_TAG_FUNCTION);
0380 pos += store_gcov_u32(buffer, pos, 3);
0381 pos += store_gcov_u32(buffer, pos, fi_ptr->ident);
0382 pos += store_gcov_u32(buffer, pos, fi_ptr->checksum);
0383 pos += store_gcov_u32(buffer, pos, fi_ptr->cfg_checksum);
0384 pos += store_gcov_u32(buffer, pos, GCOV_TAG_COUNTER_BASE);
0385 pos += store_gcov_u32(buffer, pos, fi_ptr->num_counters * 2);
0386 for (i = 0; i < fi_ptr->num_counters; i++)
0387 pos += store_gcov_u64(buffer, pos, fi_ptr->counters[i]);
0388 }
0389
0390 return pos;
0391 }