logo

mstrace

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

print_syscall.c (3216B)


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