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.

desc.c 5.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. /*
  2. * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
  3. * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
  4. * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
  5. * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
  6. * Copyright (c) 1999-2019 The strace developers.
  7. * All rights reserved.
  8. *
  9. * SPDX-License-Identifier: LGPL-2.1-or-later
  10. */
  11. #include "defs.h"
  12. #include "xstring.h"
  13. SYS_FUNC(close)
  14. {
  15. printfd(tcp, tcp->u_arg[0]);
  16. return RVAL_DECODED;
  17. }
  18. SYS_FUNC(dup)
  19. {
  20. printfd(tcp, tcp->u_arg[0]);
  21. return RVAL_DECODED | RVAL_FD;
  22. }
  23. static int
  24. do_dup2(struct tcb *tcp, int flags_arg)
  25. {
  26. printfd(tcp, tcp->u_arg[0]);
  27. tprints(", ");
  28. printfd(tcp, tcp->u_arg[1]);
  29. if (flags_arg >= 0) {
  30. tprints(", ");
  31. printflags(open_mode_flags, tcp->u_arg[flags_arg], "O_???");
  32. }
  33. return RVAL_DECODED | RVAL_FD;
  34. }
  35. SYS_FUNC(dup2)
  36. {
  37. return do_dup2(tcp, -1);
  38. }
  39. SYS_FUNC(dup3)
  40. {
  41. return do_dup2(tcp, 2);
  42. }
  43. static int
  44. decode_select(struct tcb *const tcp, const kernel_ulong_t *const args,
  45. const print_obj_by_addr_fn print_tv_ts,
  46. const sprint_obj_by_addr_fn sprint_tv_ts)
  47. {
  48. int i, j;
  49. int nfds, fdsize;
  50. fd_set *fds = NULL;
  51. const char *sep;
  52. kernel_ulong_t addr;
  53. /* Kernel truncates args[0] to int, we do the same. */
  54. nfds = (int) args[0];
  55. /* Kernel rejects negative nfds, so we don't parse it either. */
  56. if (nfds < 0)
  57. nfds = 0;
  58. /* Beware of select(2^31-1, NULL, NULL, NULL) and similar... */
  59. if (nfds > 1024*1024)
  60. nfds = 1024*1024;
  61. /*
  62. * We had bugs a-la "while (j < args[0])" and "umoven(args[0])" below.
  63. * Instead of args[0], use nfds for fd count, fdsize for array lengths.
  64. */
  65. fdsize = (((nfds + 7) / 8) + current_wordsize-1) & -current_wordsize;
  66. if (entering(tcp)) {
  67. tprintf("%d", (int) args[0]);
  68. if (verbose(tcp) && fdsize > 0)
  69. fds = malloc(fdsize);
  70. for (i = 0; i < 3; i++) {
  71. addr = args[i+1];
  72. tprints(", ");
  73. if (!fds) {
  74. printaddr(addr);
  75. continue;
  76. }
  77. if (umoven_or_printaddr(tcp, addr, fdsize, fds))
  78. continue;
  79. tprints("[");
  80. for (j = 0, sep = "";; j++) {
  81. j = next_set_bit(fds, j, nfds);
  82. if (j < 0)
  83. break;
  84. tprints(sep);
  85. printfd(tcp, j);
  86. sep = " ";
  87. }
  88. tprints("]");
  89. }
  90. free(fds);
  91. tprints(", ");
  92. print_tv_ts(tcp, args[4]);
  93. } else {
  94. static char outstr[1024];
  95. char *outptr;
  96. #define end_outstr (outstr + sizeof(outstr))
  97. int ready_fds;
  98. if (syserror(tcp))
  99. return 0;
  100. ready_fds = tcp->u_rval;
  101. if (ready_fds == 0) {
  102. tcp->auxstr = "Timeout";
  103. return RVAL_STR;
  104. }
  105. fds = malloc(fdsize);
  106. outptr = outstr;
  107. sep = "";
  108. for (i = 0; i < 3 && ready_fds > 0; i++) {
  109. int first = 1;
  110. addr = args[i+1];
  111. if (!addr || !fds || umoven(tcp, addr, fdsize, fds) < 0)
  112. continue;
  113. for (j = 0;; j++) {
  114. j = next_set_bit(fds, j, nfds);
  115. if (j < 0)
  116. break;
  117. /* +2 chars needed at the end: ']',NUL */
  118. if (outptr < end_outstr - (sizeof(", except [") + sizeof(int)*3 + 2)) {
  119. if (first) {
  120. outptr = xappendstr(outstr,
  121. outptr,
  122. "%s%s [%u",
  123. sep,
  124. i == 0 ? "in" : i == 1 ? "out" : "except",
  125. j
  126. );
  127. first = 0;
  128. sep = ", ";
  129. } else {
  130. outptr = xappendstr(outstr,
  131. outptr,
  132. " %u", j);
  133. }
  134. }
  135. if (--ready_fds == 0)
  136. break;
  137. }
  138. if (outptr != outstr)
  139. *outptr++ = ']';
  140. }
  141. free(fds);
  142. /* This contains no useful information on SunOS. */
  143. if (args[4]) {
  144. const char *str = sprint_tv_ts(tcp, args[4]);
  145. if (outptr + sizeof("left ") + strlen(sep) + strlen(str) < end_outstr) {
  146. outptr = xappendstr(outstr, outptr,
  147. "%sleft %s", sep, str);
  148. }
  149. }
  150. *outptr = '\0';
  151. tcp->auxstr = outstr;
  152. return RVAL_STR;
  153. #undef end_outstr
  154. }
  155. return 0;
  156. }
  157. #if HAVE_ARCH_OLD_SELECT
  158. SYS_FUNC(oldselect)
  159. {
  160. kernel_ulong_t *args =
  161. fetch_indirect_syscall_args(tcp, tcp->u_arg[0], 5);
  162. if (args) {
  163. return decode_select(tcp, args, print_timeval, sprint_timeval);
  164. } else {
  165. if (entering(tcp))
  166. printaddr(tcp->u_arg[0]);
  167. return RVAL_DECODED;
  168. }
  169. }
  170. #endif /* HAVE_ARCH_OLD_SELECT */
  171. #ifdef ALPHA
  172. SYS_FUNC(osf_select)
  173. {
  174. return decode_select(tcp, tcp->u_arg, print_timeval32, sprint_timeval32);
  175. }
  176. #endif
  177. SYS_FUNC(select)
  178. {
  179. return decode_select(tcp, tcp->u_arg, print_timeval, sprint_timeval);
  180. }
  181. static int
  182. umove_kulong_array_or_printaddr(struct tcb *const tcp, const kernel_ulong_t addr,
  183. kernel_ulong_t *const ptr, const size_t n)
  184. {
  185. #ifndef current_klongsize
  186. if (current_klongsize < sizeof(*ptr)) {
  187. uint32_t ptr32[n];
  188. int r = umove_or_printaddr(tcp, addr, &ptr32);
  189. if (!r) {
  190. size_t i;
  191. for (i = 0; i < n; ++i)
  192. ptr[i] = ptr32[i];
  193. }
  194. return r;
  195. }
  196. #endif /* !current_klongsize */
  197. return umoven_or_printaddr(tcp, addr, n * sizeof(*ptr), ptr);
  198. }
  199. static int
  200. do_pselect6(struct tcb *const tcp, const print_obj_by_addr_fn print_ts,
  201. const sprint_obj_by_addr_fn sprint_ts)
  202. {
  203. int rc = decode_select(tcp, tcp->u_arg, print_ts, sprint_ts);
  204. if (entering(tcp)) {
  205. kernel_ulong_t data[2];
  206. tprints(", ");
  207. if (!umove_kulong_array_or_printaddr(tcp, tcp->u_arg[5],
  208. data, ARRAY_SIZE(data))) {
  209. tprints("{");
  210. /* NB: kernel requires data[1] == NSIG_BYTES */
  211. print_sigset_addr_len(tcp, data[0], data[1]);
  212. tprintf(", %" PRI_klu "}", data[1]);
  213. }
  214. }
  215. return rc;
  216. }
  217. #if HAVE_ARCH_TIME32_SYSCALLS
  218. SYS_FUNC(pselect6_time32)
  219. {
  220. return do_pselect6(tcp, print_timespec32, sprint_timespec32);
  221. }
  222. #endif
  223. SYS_FUNC(pselect6_time64)
  224. {
  225. return do_pselect6(tcp, print_timespec64, sprint_timespec64);
  226. }