logo

mstrace

Small Linux strace(1) implementationgit clone https://anongit.hacktivis.me/git/mstrace.git/

print_syscall.c (3270B)


  1. // SPDX-FileCopyrightText: 2024 Haelwenn (lanodan) Monnier <contact+mstrace@hacktivis.me>
  2. // SPDX-License-Identifier: MPL-2.0
  3. #define _DEFAULT_SOURCE
  4. #include "mstrace.h"
  5. #include "strsyscall.h"
  6. #include <assert.h>
  7. #include <inttypes.h> // PRIu64
  8. #include <limits.h> // PATH_MAX
  9. #include <linux/ptrace.h> // __u64
  10. #include <stdio.h> // fprintf
  11. #include <string.h> // memcpy
  12. #include <sys/ptrace.h> // ptrace()
  13. #include <sys/syscall.h> // SYS_*
  14. #include <time.h> // struct timespec
  15. #include <unistd.h> // pid_t
  16. extern pid_t child;
  17. union u8_timespec
  18. {
  19. struct timespec ts;
  20. uint8_t buf[sizeof(struct timespec)];
  21. };
  22. static char *
  23. read_str(intptr_t addr, size_t len)
  24. {
  25. static char str_buf[sizeof(unsigned long) * 128] = "";
  26. if(len == 0 || len > sizeof(unsigned long) * 128) len = sizeof(unsigned long) * 128;
  27. size_t i = 0;
  28. while(i < len)
  29. {
  30. unsigned long tmp = ptrace(PTRACE_PEEKDATA, child, addr + i);
  31. memcpy(str_buf + i, &tmp, sizeof(tmp));
  32. i += sizeof(tmp);
  33. if(memchr(&tmp, 0, sizeof(tmp)) != NULL) break;
  34. if(i > len)
  35. {
  36. str_buf[len - 1] = '\0';
  37. break;
  38. }
  39. }
  40. return str_buf;
  41. }
  42. static struct timespec *
  43. read_timespec(intptr_t addr)
  44. {
  45. static union u8_timespec local;
  46. for(size_t i = 0; i < sizeof(struct timespec);)
  47. {
  48. unsigned long tmp = ptrace(PTRACE_PEEKDATA, child, addr + i);
  49. memcpy(local.buf + i, &tmp, sizeof(tmp));
  50. i += sizeof(tmp);
  51. }
  52. return &(local.ts);
  53. }
  54. #define Pri_str "\"%s\""
  55. #define Pri_i "%" PRIi64
  56. #define Pri_u "%" PRIu64
  57. #define Pri_o "0o%" PRIo64
  58. #define Pri_x "0x%" PRIx64
  59. void
  60. print_syscall_entry(__u64 nr, __u64 args[6])
  61. {
  62. switch(nr)
  63. {
  64. case SYS_execve:
  65. fprintf(out,
  66. "<%s(" Pri_str ", " Pri_x ", " Pri_x ")\n",
  67. str_syscalls[nr],
  68. read_str(args[0], PATH_MAX),
  69. (int64_t)args[1],
  70. (int64_t)args[2]);
  71. return;
  72. case SYS_nanosleep:
  73. {
  74. struct timespec *rqtp = read_timespec(args[0]);
  75. struct timespec *rmtp = read_timespec(args[1]);
  76. fprintf(out,
  77. "<%s({tv_sec = " Pri_i ", tv_nsec = " Pri_i "}, {tv_sec = " Pri_i ", tv_nsec = " Pri_i
  78. "})\n",
  79. str_syscalls[nr],
  80. rqtp->tv_sec,
  81. rqtp->tv_nsec,
  82. rmtp->tv_sec,
  83. rmtp->tv_nsec);
  84. return;
  85. }
  86. }
  87. }
  88. void
  89. print_syscall_exit(__u64 nr, __u64 args[6])
  90. {
  91. switch(nr)
  92. {
  93. #include "syscalls_cases.h"
  94. case SYS_nanosleep:
  95. {
  96. struct timespec *rqtp = read_timespec(args[0]);
  97. struct timespec *rmtp = read_timespec(args[1]);
  98. fprintf(out,
  99. ">%s({tv_sec = " Pri_i ", tv_nsec = " Pri_i "}, {tv_sec = " Pri_i ", tv_nsec = " Pri_i
  100. "})",
  101. str_syscalls[nr],
  102. rqtp->tv_sec,
  103. rqtp->tv_nsec,
  104. rmtp->tv_sec,
  105. rmtp->tv_nsec);
  106. break;
  107. }
  108. // fallback
  109. default:
  110. assert(nr < SYSCALLS_MAX);
  111. if(str_syscalls[nr] != NULL)
  112. {
  113. fprintf(out, ">%s(", str_syscalls[nr]);
  114. }
  115. else
  116. {
  117. fprintf(out, ">syscall(%" PRIu64 ", ", (uint64_t)nr);
  118. }
  119. fprintf(out,
  120. "0x%" PRIx64 ", 0x%" PRIx64 ", 0x%" PRIx64 ", 0x%" PRIx64 ", 0x%" PRIx64 ", 0x%" PRIx64
  121. ")",
  122. (uint64_t)args[0],
  123. (uint64_t)args[1],
  124. (uint64_t)args[2],
  125. (uint64_t)args[3],
  126. (uint64_t)args[4],
  127. (uint64_t)args[5]);
  128. }
  129. }