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#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