Mirror of strace – the linux syscall tracer
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

userfaultfd.c 3.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /*
  2. * Copyright (c) 2015 Dmitry V. Levin <ldv@altlinux.org>
  3. * Copyright (c) 2015-2018 The strace developers.
  4. * All rights reserved.
  5. *
  6. * SPDX-License-Identifier: LGPL-2.1-or-later
  7. */
  8. #include "defs.h"
  9. #include "print_fields.h"
  10. #include <fcntl.h>
  11. #include "xlat/uffd_flags.h"
  12. SYS_FUNC(userfaultfd)
  13. {
  14. printflags(uffd_flags, tcp->u_arg[0], "UFFD_???");
  15. return RVAL_DECODED | RVAL_FD;
  16. }
  17. #ifdef HAVE_LINUX_USERFAULTFD_H
  18. # include <linux/ioctl.h>
  19. # include <linux/userfaultfd.h>
  20. # include "xlat/uffd_api_features.h"
  21. # include "xlat/uffd_api_flags.h"
  22. # include "xlat/uffd_copy_flags.h"
  23. # include "xlat/uffd_register_ioctl_flags.h"
  24. # include "xlat/uffd_register_mode_flags.h"
  25. # include "xlat/uffd_zeropage_flags.h"
  26. static void
  27. tprintf_uffdio_range(const struct uffdio_range *range)
  28. {
  29. PRINT_FIELD_X("{", *range, start);
  30. PRINT_FIELD_X(", ", *range, len);
  31. tprints("}");
  32. }
  33. # define PRINT_FIELD_UFFDIO_RANGE(prefix_, where_, field_) \
  34. do { \
  35. STRACE_PRINTF("%s%s=", (prefix_), #field_); \
  36. tprintf_uffdio_range(&(where_).field_); \
  37. } while (0)
  38. int
  39. uffdio_ioctl(struct tcb *const tcp, const unsigned int code,
  40. const kernel_ulong_t arg)
  41. {
  42. switch (code) {
  43. case UFFDIO_API: {
  44. uint64_t *entering_features;
  45. struct uffdio_api ua;
  46. if (entering(tcp)) {
  47. tprints(", ");
  48. if (umove_or_printaddr(tcp, arg, &ua))
  49. break;
  50. PRINT_FIELD_X("{", ua, api);
  51. PRINT_FIELD_FLAGS(", ", ua, features, uffd_api_features,
  52. "UFFD_FEATURE_???");
  53. entering_features = malloc(sizeof(*entering_features));
  54. if (entering_features) {
  55. *entering_features = ua.features;
  56. set_tcb_priv_data(tcp, entering_features, free);
  57. }
  58. return 0;
  59. }
  60. if (!syserror(tcp) && !umove(tcp, arg, &ua)) {
  61. entering_features = get_tcb_priv_data(tcp);
  62. if (!entering_features
  63. || *entering_features != ua.features) {
  64. PRINT_FIELD_FLAGS(" => ", ua, features,
  65. uffd_api_features,
  66. "UFFD_FEATURE_???");
  67. }
  68. PRINT_FIELD_FLAGS(", ", ua, ioctls, uffd_api_flags,
  69. "_UFFDIO_???");
  70. }
  71. tprints("}");
  72. break;
  73. }
  74. case UFFDIO_COPY: {
  75. struct uffdio_copy uc;
  76. if (entering(tcp)) {
  77. tprints(", ");
  78. if (umove_or_printaddr(tcp, arg, &uc))
  79. return RVAL_IOCTL_DECODED;
  80. PRINT_FIELD_X("{", uc, dst);
  81. PRINT_FIELD_X(", ", uc, src);
  82. PRINT_FIELD_X(", ", uc, len);
  83. PRINT_FIELD_FLAGS(", ", uc, mode, uffd_copy_flags,
  84. "UFFDIO_COPY_???");
  85. return 0;
  86. }
  87. if (!syserror(tcp) && !umove(tcp, arg, &uc))
  88. PRINT_FIELD_X(", ", uc, copy);
  89. tprints("}");
  90. break;
  91. }
  92. case UFFDIO_REGISTER: {
  93. struct uffdio_register ur;
  94. if (entering(tcp)) {
  95. tprints(", ");
  96. if (umove_or_printaddr(tcp, arg, &ur))
  97. return RVAL_IOCTL_DECODED;
  98. PRINT_FIELD_UFFDIO_RANGE("{", ur, range);
  99. PRINT_FIELD_FLAGS(", ", ur, mode,
  100. uffd_register_mode_flags,
  101. "UFFDIO_REGISTER_MODE_???");
  102. return 0;
  103. }
  104. if (!syserror(tcp) && !umove(tcp, arg, &ur)) {
  105. PRINT_FIELD_FLAGS(", ", ur, ioctls,
  106. uffd_register_ioctl_flags,
  107. "UFFDIO_???");
  108. }
  109. tprints("}");
  110. break;
  111. }
  112. case UFFDIO_UNREGISTER:
  113. case UFFDIO_WAKE: {
  114. struct uffdio_range ura;
  115. tprints(", ");
  116. if (!umove_or_printaddr(tcp, arg, &ura))
  117. tprintf_uffdio_range(&ura);
  118. break;
  119. }
  120. case UFFDIO_ZEROPAGE: {
  121. struct uffdio_zeropage uz;
  122. if (entering(tcp)) {
  123. tprints(", ");
  124. if (umove_or_printaddr(tcp, arg, &uz))
  125. return RVAL_IOCTL_DECODED;
  126. PRINT_FIELD_UFFDIO_RANGE("{", uz, range);
  127. PRINT_FIELD_FLAGS(", ", uz, mode, uffd_zeropage_flags,
  128. "UFFDIO_ZEROPAGE_???");
  129. return 0;
  130. }
  131. if (!syserror(tcp) && !umove(tcp, arg, &uz))
  132. PRINT_FIELD_X(", ", uz, zeropage);
  133. tprints("}");
  134. break;
  135. }
  136. default:
  137. return RVAL_DECODED;
  138. }
  139. return RVAL_IOCTL_DECODED;
  140. }
  141. #endif /* HAVE_LINUX_USERFAULTFD_H */