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