1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #ifndef __LINUX_INSTRUMENTATION_H 3 #define __LINUX_INSTRUMENTATION_H 4 5 #if defined(CONFIG_DEBUG_ENTRY) && defined(CONFIG_STACK_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"); \ 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"); \ 54 }) 55 #define instrumentation_end() __instrumentation_end(__COUNTER__) 56 #else 57 # define instrumentation_begin() do { } while(0) 58 # define instrumentation_end() do { } while(0) 59 #endif 60 61 #endif /* __LINUX_INSTRUMENTATION_H */ 62