Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2019 Google, Inc.
0004  * modified from kernel/gcov/gcc_4_7.c
0005  *
0006  * This software is licensed under the terms of the GNU General Public
0007  * License version 2, as published by the Free Software Foundation, and
0008  * may be copied, distributed, and modified under those terms.
0009  *
0010  * This program is distributed in the hope that it will be useful,
0011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013  * GNU General Public License for more details.
0014  *
0015  *
0016  * LLVM uses profiling data that's deliberately similar to GCC, but has a
0017  * very different way of exporting that data.  LLVM calls llvm_gcov_init() once
0018  * per module, and provides a couple of callbacks that we can use to ask for
0019  * more data.
0020  *
0021  * We care about the "writeout" callback, which in turn calls back into
0022  * compiler-rt/this module to dump all the gathered coverage data to disk:
0023  *
0024  *    llvm_gcda_start_file()
0025  *      llvm_gcda_emit_function()
0026  *      llvm_gcda_emit_arcs()
0027  *      llvm_gcda_emit_function()
0028  *      llvm_gcda_emit_arcs()
0029  *      [... repeats for each function ...]
0030  *    llvm_gcda_summary_info()
0031  *    llvm_gcda_end_file()
0032  *
0033  * This design is much more stateless and unstructured than gcc's, and is
0034  * intended to run at process exit.  This forces us to keep some local state
0035  * about which module we're dealing with at the moment.  On the other hand, it
0036  * also means we don't depend as much on how LLVM represents profiling data
0037  * internally.
0038  *
0039  * See LLVM's lib/Transforms/Instrumentation/GCOVProfiling.cpp for more
0040  * details on how this works, particularly GCOVProfiler::emitProfileArcs(),
0041  * GCOVProfiler::insertCounterWriteout(), and
0042  * GCOVProfiler::insertFlush().
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, &current_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(&current_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  * gcov_info_filename - return info filename
0150  * @info: profiling data set
0151  */
0152 const char *gcov_info_filename(struct gcov_info *info)
0153 {
0154     return info->filename;
0155 }
0156 
0157 /**
0158  * gcov_info_version - return info version
0159  * @info: profiling data set
0160  */
0161 unsigned int gcov_info_version(struct gcov_info *info)
0162 {
0163     return info->version;
0164 }
0165 
0166 /**
0167  * gcov_info_next - return next profiling data set
0168  * @info: profiling data set
0169  *
0170  * Returns next gcov_info following @info or first gcov_info in the chain if
0171  * @info is %NULL.
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  * gcov_info_link - link/add profiling data set to the list
0185  * @info: profiling data set
0186  */
0187 void gcov_info_link(struct gcov_info *info)
0188 {
0189     list_add_tail(&info->head, &clang_gcov_list);
0190 }
0191 
0192 /**
0193  * gcov_info_unlink - unlink/remove profiling data set from the list
0194  * @prev: previous profiling data set
0195  * @info: profiling data set
0196  */
0197 void gcov_info_unlink(struct gcov_info *prev, struct gcov_info *info)
0198 {
0199     /* Generic code unlinks while iterating. */
0200     __list_del_entry(&info->head);
0201 }
0202 
0203 /**
0204  * gcov_info_within_module - check if a profiling data set belongs to a module
0205  * @info: profiling data set
0206  * @mod: module
0207  *
0208  * Returns true if profiling data belongs module, false otherwise.
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 /* Symbolic links to be created for each profiling data file. */
0216 const struct gcov_link gcov_link[] = {
0217     { OBJ_TREE, "gcno" },   /* Link to .gcno file in $(objtree). */
0218     { 0, NULL},
0219 };
0220 
0221 /**
0222  * gcov_info_reset - reset profiling data to zero
0223  * @info: profiling data set
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  * gcov_info_is_compatible - check if profiling data can be added
0236  * @info1: first profiling data set
0237  * @info2: second profiling data set
0238  *
0239  * Returns non-zero if profiling data can be added, zero otherwise.
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  * gcov_info_add - add up profiling data
0267  * @dest: profiling data set to which data is added
0268  * @source: profiling data set which is added
0269  *
0270  * Adds profiling counts of @source to @dest.
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; /* counter values 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  * gcov_info_dup - duplicate profiling data set
0309  * @info: profiling data set to duplicate
0310  *
0311  * Return newly allocated duplicate on success, %NULL on error.
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  * gcov_info_free - release memory for profiling data set duplicate
0344  * @info: profiling data set duplicate to free
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  * convert_to_gcda - convert profiling data set to gcda file format
0361  * @buffer: the buffer to store file data or %NULL if no data should be stored
0362  * @info: profiling data set to be converted
0363  *
0364  * Returns the number of bytes that were/would have been stored into the buffer.
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     /* File header. */
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 }