Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 #ifndef __LINUX_INSTRUMENTATION_H
0003 #define __LINUX_INSTRUMENTATION_H
0004 
0005 #ifdef CONFIG_NOINSTR_VALIDATION
0006 
0007 #include <linux/stringify.h>
0008 
0009 /* Begin/end of an instrumentation safe region */
0010 #define __instrumentation_begin(c) ({                   \
0011     asm volatile(__stringify(c) ": nop\n\t"             \
0012              ".pushsection .discard.instr_begin\n\t"        \
0013              ".long " __stringify(c) "b - .\n\t"        \
0014              ".popsection\n\t" : : "i" (c));            \
0015 })
0016 #define instrumentation_begin() __instrumentation_begin(__COUNTER__)
0017 
0018 /*
0019  * Because instrumentation_{begin,end}() can nest, objtool validation considers
0020  * _begin() a +1 and _end() a -1 and computes a sum over the instructions.
0021  * When the value is greater than 0, we consider instrumentation allowed.
0022  *
0023  * There is a problem with code like:
0024  *
0025  * noinstr void foo()
0026  * {
0027  *  instrumentation_begin();
0028  *  ...
0029  *  if (cond) {
0030  *      instrumentation_begin();
0031  *      ...
0032  *      instrumentation_end();
0033  *  }
0034  *  bar();
0035  *  instrumentation_end();
0036  * }
0037  *
0038  * If instrumentation_end() would be an empty label, like all the other
0039  * annotations, the inner _end(), which is at the end of a conditional block,
0040  * would land on the instruction after the block.
0041  *
0042  * If we then consider the sum of the !cond path, we'll see that the call to
0043  * bar() is with a 0-value, even though, we meant it to happen with a positive
0044  * value.
0045  *
0046  * To avoid this, have _end() be a NOP instruction, this ensures it will be
0047  * part of the condition block and does not escape.
0048  */
0049 #define __instrumentation_end(c) ({                 \
0050     asm volatile(__stringify(c) ": nop\n\t"             \
0051              ".pushsection .discard.instr_end\n\t"      \
0052              ".long " __stringify(c) "b - .\n\t"        \
0053              ".popsection\n\t" : : "i" (c));            \
0054 })
0055 #define instrumentation_end() __instrumentation_end(__COUNTER__)
0056 #else /* !CONFIG_NOINSTR_VALIDATION */
0057 # define instrumentation_begin()    do { } while(0)
0058 # define instrumentation_end()      do { } while(0)
0059 #endif /* CONFIG_NOINSTR_VALIDATION */
0060 
0061 #endif /* __LINUX_INSTRUMENTATION_H */