cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

clang.c (10359B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 2019 Google, Inc.
      4 * modified from kernel/gcov/gcc_4_7.c
      5 *
      6 * This software is licensed under the terms of the GNU General Public
      7 * License version 2, as published by the Free Software Foundation, and
      8 * may be copied, distributed, and modified under those terms.
      9 *
     10 * This program is distributed in the hope that it will be useful,
     11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 * GNU General Public License for more details.
     14 *
     15 *
     16 * LLVM uses profiling data that's deliberately similar to GCC, but has a
     17 * very different way of exporting that data.  LLVM calls llvm_gcov_init() once
     18 * per module, and provides a couple of callbacks that we can use to ask for
     19 * more data.
     20 *
     21 * We care about the "writeout" callback, which in turn calls back into
     22 * compiler-rt/this module to dump all the gathered coverage data to disk:
     23 *
     24 *    llvm_gcda_start_file()
     25 *      llvm_gcda_emit_function()
     26 *      llvm_gcda_emit_arcs()
     27 *      llvm_gcda_emit_function()
     28 *      llvm_gcda_emit_arcs()
     29 *      [... repeats for each function ...]
     30 *    llvm_gcda_summary_info()
     31 *    llvm_gcda_end_file()
     32 *
     33 * This design is much more stateless and unstructured than gcc's, and is
     34 * intended to run at process exit.  This forces us to keep some local state
     35 * about which module we're dealing with at the moment.  On the other hand, it
     36 * also means we don't depend as much on how LLVM represents profiling data
     37 * internally.
     38 *
     39 * See LLVM's lib/Transforms/Instrumentation/GCOVProfiling.cpp for more
     40 * details on how this works, particularly GCOVProfiler::emitProfileArcs(),
     41 * GCOVProfiler::insertCounterWriteout(), and
     42 * GCOVProfiler::insertFlush().
     43 */
     44
     45#define pr_fmt(fmt)	"gcov: " fmt
     46
     47#include <linux/kernel.h>
     48#include <linux/list.h>
     49#include <linux/printk.h>
     50#include <linux/ratelimit.h>
     51#include <linux/slab.h>
     52#include <linux/mm.h>
     53#include "gcov.h"
     54
     55typedef void (*llvm_gcov_callback)(void);
     56
     57struct gcov_info {
     58	struct list_head head;
     59
     60	const char *filename;
     61	unsigned int version;
     62	u32 checksum;
     63
     64	struct list_head functions;
     65};
     66
     67struct gcov_fn_info {
     68	struct list_head head;
     69
     70	u32 ident;
     71	u32 checksum;
     72	u32 cfg_checksum;
     73
     74	u32 num_counters;
     75	u64 *counters;
     76};
     77
     78static struct gcov_info *current_info;
     79
     80static LIST_HEAD(clang_gcov_list);
     81
     82void llvm_gcov_init(llvm_gcov_callback writeout, llvm_gcov_callback flush)
     83{
     84	struct gcov_info *info = kzalloc(sizeof(*info), GFP_KERNEL);
     85
     86	if (!info)
     87		return;
     88
     89	INIT_LIST_HEAD(&info->head);
     90	INIT_LIST_HEAD(&info->functions);
     91
     92	mutex_lock(&gcov_lock);
     93
     94	list_add_tail(&info->head, &clang_gcov_list);
     95	current_info = info;
     96	writeout();
     97	current_info = NULL;
     98	if (gcov_events_enabled)
     99		gcov_event(GCOV_ADD, info);
    100
    101	mutex_unlock(&gcov_lock);
    102}
    103EXPORT_SYMBOL(llvm_gcov_init);
    104
    105void llvm_gcda_start_file(const char *orig_filename, u32 version, u32 checksum)
    106{
    107	current_info->filename = orig_filename;
    108	current_info->version = version;
    109	current_info->checksum = checksum;
    110}
    111EXPORT_SYMBOL(llvm_gcda_start_file);
    112
    113void llvm_gcda_emit_function(u32 ident, u32 func_checksum, u32 cfg_checksum)
    114{
    115	struct gcov_fn_info *info = kzalloc(sizeof(*info), GFP_KERNEL);
    116
    117	if (!info)
    118		return;
    119
    120	INIT_LIST_HEAD(&info->head);
    121	info->ident = ident;
    122	info->checksum = func_checksum;
    123	info->cfg_checksum = cfg_checksum;
    124	list_add_tail(&info->head, &current_info->functions);
    125}
    126EXPORT_SYMBOL(llvm_gcda_emit_function);
    127
    128void llvm_gcda_emit_arcs(u32 num_counters, u64 *counters)
    129{
    130	struct gcov_fn_info *info = list_last_entry(&current_info->functions,
    131			struct gcov_fn_info, head);
    132
    133	info->num_counters = num_counters;
    134	info->counters = counters;
    135}
    136EXPORT_SYMBOL(llvm_gcda_emit_arcs);
    137
    138void llvm_gcda_summary_info(void)
    139{
    140}
    141EXPORT_SYMBOL(llvm_gcda_summary_info);
    142
    143void llvm_gcda_end_file(void)
    144{
    145}
    146EXPORT_SYMBOL(llvm_gcda_end_file);
    147
    148/**
    149 * gcov_info_filename - return info filename
    150 * @info: profiling data set
    151 */
    152const char *gcov_info_filename(struct gcov_info *info)
    153{
    154	return info->filename;
    155}
    156
    157/**
    158 * gcov_info_version - return info version
    159 * @info: profiling data set
    160 */
    161unsigned int gcov_info_version(struct gcov_info *info)
    162{
    163	return info->version;
    164}
    165
    166/**
    167 * gcov_info_next - return next profiling data set
    168 * @info: profiling data set
    169 *
    170 * Returns next gcov_info following @info or first gcov_info in the chain if
    171 * @info is %NULL.
    172 */
    173struct gcov_info *gcov_info_next(struct gcov_info *info)
    174{
    175	if (!info)
    176		return list_first_entry_or_null(&clang_gcov_list,
    177				struct gcov_info, head);
    178	if (list_is_last(&info->head, &clang_gcov_list))
    179		return NULL;
    180	return list_next_entry(info, head);
    181}
    182
    183/**
    184 * gcov_info_link - link/add profiling data set to the list
    185 * @info: profiling data set
    186 */
    187void gcov_info_link(struct gcov_info *info)
    188{
    189	list_add_tail(&info->head, &clang_gcov_list);
    190}
    191
    192/**
    193 * gcov_info_unlink - unlink/remove profiling data set from the list
    194 * @prev: previous profiling data set
    195 * @info: profiling data set
    196 */
    197void gcov_info_unlink(struct gcov_info *prev, struct gcov_info *info)
    198{
    199	/* Generic code unlinks while iterating. */
    200	__list_del_entry(&info->head);
    201}
    202
    203/**
    204 * gcov_info_within_module - check if a profiling data set belongs to a module
    205 * @info: profiling data set
    206 * @mod: module
    207 *
    208 * Returns true if profiling data belongs module, false otherwise.
    209 */
    210bool gcov_info_within_module(struct gcov_info *info, struct module *mod)
    211{
    212	return within_module((unsigned long)info->filename, mod);
    213}
    214
    215/* Symbolic links to be created for each profiling data file. */
    216const struct gcov_link gcov_link[] = {
    217	{ OBJ_TREE, "gcno" },	/* Link to .gcno file in $(objtree). */
    218	{ 0, NULL},
    219};
    220
    221/**
    222 * gcov_info_reset - reset profiling data to zero
    223 * @info: profiling data set
    224 */
    225void gcov_info_reset(struct gcov_info *info)
    226{
    227	struct gcov_fn_info *fn;
    228
    229	list_for_each_entry(fn, &info->functions, head)
    230		memset(fn->counters, 0,
    231				sizeof(fn->counters[0]) * fn->num_counters);
    232}
    233
    234/**
    235 * gcov_info_is_compatible - check if profiling data can be added
    236 * @info1: first profiling data set
    237 * @info2: second profiling data set
    238 *
    239 * Returns non-zero if profiling data can be added, zero otherwise.
    240 */
    241int gcov_info_is_compatible(struct gcov_info *info1, struct gcov_info *info2)
    242{
    243	struct gcov_fn_info *fn_ptr1 = list_first_entry_or_null(
    244			&info1->functions, struct gcov_fn_info, head);
    245	struct gcov_fn_info *fn_ptr2 = list_first_entry_or_null(
    246			&info2->functions, struct gcov_fn_info, head);
    247
    248	if (info1->checksum != info2->checksum)
    249		return false;
    250	if (!fn_ptr1)
    251		return fn_ptr1 == fn_ptr2;
    252	while (!list_is_last(&fn_ptr1->head, &info1->functions) &&
    253		!list_is_last(&fn_ptr2->head, &info2->functions)) {
    254		if (fn_ptr1->checksum != fn_ptr2->checksum)
    255			return false;
    256		if (fn_ptr1->cfg_checksum != fn_ptr2->cfg_checksum)
    257			return false;
    258		fn_ptr1 = list_next_entry(fn_ptr1, head);
    259		fn_ptr2 = list_next_entry(fn_ptr2, head);
    260	}
    261	return list_is_last(&fn_ptr1->head, &info1->functions) &&
    262		list_is_last(&fn_ptr2->head, &info2->functions);
    263}
    264
    265/**
    266 * gcov_info_add - add up profiling data
    267 * @dest: profiling data set to which data is added
    268 * @source: profiling data set which is added
    269 *
    270 * Adds profiling counts of @source to @dest.
    271 */
    272void gcov_info_add(struct gcov_info *dst, struct gcov_info *src)
    273{
    274	struct gcov_fn_info *dfn_ptr;
    275	struct gcov_fn_info *sfn_ptr = list_first_entry_or_null(&src->functions,
    276			struct gcov_fn_info, head);
    277
    278	list_for_each_entry(dfn_ptr, &dst->functions, head) {
    279		u32 i;
    280
    281		for (i = 0; i < sfn_ptr->num_counters; i++)
    282			dfn_ptr->counters[i] += sfn_ptr->counters[i];
    283	}
    284}
    285
    286static struct gcov_fn_info *gcov_fn_info_dup(struct gcov_fn_info *fn)
    287{
    288	size_t cv_size; /* counter values size */
    289	struct gcov_fn_info *fn_dup = kmemdup(fn, sizeof(*fn),
    290			GFP_KERNEL);
    291	if (!fn_dup)
    292		return NULL;
    293	INIT_LIST_HEAD(&fn_dup->head);
    294
    295	cv_size = fn->num_counters * sizeof(fn->counters[0]);
    296	fn_dup->counters = kvmalloc(cv_size, GFP_KERNEL);
    297	if (!fn_dup->counters) {
    298		kfree(fn_dup);
    299		return NULL;
    300	}
    301
    302	memcpy(fn_dup->counters, fn->counters, cv_size);
    303
    304	return fn_dup;
    305}
    306
    307/**
    308 * gcov_info_dup - duplicate profiling data set
    309 * @info: profiling data set to duplicate
    310 *
    311 * Return newly allocated duplicate on success, %NULL on error.
    312 */
    313struct gcov_info *gcov_info_dup(struct gcov_info *info)
    314{
    315	struct gcov_info *dup;
    316	struct gcov_fn_info *fn;
    317
    318	dup = kmemdup(info, sizeof(*dup), GFP_KERNEL);
    319	if (!dup)
    320		return NULL;
    321	INIT_LIST_HEAD(&dup->head);
    322	INIT_LIST_HEAD(&dup->functions);
    323	dup->filename = kstrdup(info->filename, GFP_KERNEL);
    324	if (!dup->filename)
    325		goto err;
    326
    327	list_for_each_entry(fn, &info->functions, head) {
    328		struct gcov_fn_info *fn_dup = gcov_fn_info_dup(fn);
    329
    330		if (!fn_dup)
    331			goto err;
    332		list_add_tail(&fn_dup->head, &dup->functions);
    333	}
    334
    335	return dup;
    336
    337err:
    338	gcov_info_free(dup);
    339	return NULL;
    340}
    341
    342/**
    343 * gcov_info_free - release memory for profiling data set duplicate
    344 * @info: profiling data set duplicate to free
    345 */
    346void gcov_info_free(struct gcov_info *info)
    347{
    348	struct gcov_fn_info *fn, *tmp;
    349
    350	list_for_each_entry_safe(fn, tmp, &info->functions, head) {
    351		kvfree(fn->counters);
    352		list_del(&fn->head);
    353		kfree(fn);
    354	}
    355	kfree(info->filename);
    356	kfree(info);
    357}
    358
    359/**
    360 * convert_to_gcda - convert profiling data set to gcda file format
    361 * @buffer: the buffer to store file data or %NULL if no data should be stored
    362 * @info: profiling data set to be converted
    363 *
    364 * Returns the number of bytes that were/would have been stored into the buffer.
    365 */
    366size_t convert_to_gcda(char *buffer, struct gcov_info *info)
    367{
    368	struct gcov_fn_info *fi_ptr;
    369	size_t pos = 0;
    370
    371	/* File header. */
    372	pos += store_gcov_u32(buffer, pos, GCOV_DATA_MAGIC);
    373	pos += store_gcov_u32(buffer, pos, info->version);
    374	pos += store_gcov_u32(buffer, pos, info->checksum);
    375
    376	list_for_each_entry(fi_ptr, &info->functions, head) {
    377		u32 i;
    378
    379		pos += store_gcov_u32(buffer, pos, GCOV_TAG_FUNCTION);
    380		pos += store_gcov_u32(buffer, pos, 3);
    381		pos += store_gcov_u32(buffer, pos, fi_ptr->ident);
    382		pos += store_gcov_u32(buffer, pos, fi_ptr->checksum);
    383		pos += store_gcov_u32(buffer, pos, fi_ptr->cfg_checksum);
    384		pos += store_gcov_u32(buffer, pos, GCOV_TAG_COUNTER_BASE);
    385		pos += store_gcov_u32(buffer, pos, fi_ptr->num_counters * 2);
    386		for (i = 0; i < fi_ptr->num_counters; i++)
    387			pos += store_gcov_u64(buffer, pos, fi_ptr->counters[i]);
    388	}
    389
    390	return pos;
    391}