instrumentation.h (2002B)
1/* SPDX-License-Identifier: GPL-2.0 */ 2#ifndef __LINUX_INSTRUMENTATION_H 3#define __LINUX_INSTRUMENTATION_H 4 5#ifdef CONFIG_NOINSTR_VALIDATION 6 7#include <linux/stringify.h> 8 9/* Begin/end of an instrumentation safe region */ 10#define __instrumentation_begin(c) ({ \ 11 asm volatile(__stringify(c) ": nop\n\t" \ 12 ".pushsection .discard.instr_begin\n\t" \ 13 ".long " __stringify(c) "b - .\n\t" \ 14 ".popsection\n\t" : : "i" (c)); \ 15}) 16#define instrumentation_begin() __instrumentation_begin(__COUNTER__) 17 18/* 19 * Because instrumentation_{begin,end}() can nest, objtool validation considers 20 * _begin() a +1 and _end() a -1 and computes a sum over the instructions. 21 * When the value is greater than 0, we consider instrumentation allowed. 22 * 23 * There is a problem with code like: 24 * 25 * noinstr void foo() 26 * { 27 * instrumentation_begin(); 28 * ... 29 * if (cond) { 30 * instrumentation_begin(); 31 * ... 32 * instrumentation_end(); 33 * } 34 * bar(); 35 * instrumentation_end(); 36 * } 37 * 38 * If instrumentation_end() would be an empty label, like all the other 39 * annotations, the inner _end(), which is at the end of a conditional block, 40 * would land on the instruction after the block. 41 * 42 * If we then consider the sum of the !cond path, we'll see that the call to 43 * bar() is with a 0-value, even though, we meant it to happen with a positive 44 * value. 45 * 46 * To avoid this, have _end() be a NOP instruction, this ensures it will be 47 * part of the condition block and does not escape. 48 */ 49#define __instrumentation_end(c) ({ \ 50 asm volatile(__stringify(c) ": nop\n\t" \ 51 ".pushsection .discard.instr_end\n\t" \ 52 ".long " __stringify(c) "b - .\n\t" \ 53 ".popsection\n\t" : : "i" (c)); \ 54}) 55#define instrumentation_end() __instrumentation_end(__COUNTER__) 56#else /* !CONFIG_NOINSTR_VALIDATION */ 57# define instrumentation_begin() do { } while(0) 58# define instrumentation_end() do { } while(0) 59#endif /* CONFIG_NOINSTR_VALIDATION */ 60 61#endif /* __LINUX_INSTRUMENTATION_H */