linux/include/linux/instrumentation.h
<<
>>
Prefs
   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