instrumentation.h 2.0 KB

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