/usr.bin/truss/amd64-linux32.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 329 lines · 199 code · 41 blank · 89 comment · 51 complexity · 99d3b7d48324a1054dddfc2c78f6d23b MD5 · raw file

  1. /*
  2. * Copyright 1997 Sean Eric Fagan
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. * 1. Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * 2. Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * 3. All advertising materials mentioning features or use of this software
  13. * must display the following acknowledgement:
  14. * This product includes software developed by Sean Eric Fagan
  15. * 4. Neither the name of the author may be used to endorse or promote
  16. * products derived from this software without specific prior written
  17. * permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  20. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  21. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  22. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  23. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  24. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  25. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  26. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  27. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  28. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  29. * SUCH DAMAGE.
  30. */
  31. #ifndef lint
  32. static const char rcsid[] =
  33. "$FreeBSD$";
  34. #endif /* not lint */
  35. /*
  36. * Linux/i386-specific system call handling. Given how much of this code
  37. * is taken from the freebsd equivalent, I can probably put even more of
  38. * it in support routines that can be used by any personality support.
  39. */
  40. #include <sys/types.h>
  41. #include <sys/ptrace.h>
  42. #include <machine/reg.h>
  43. #include <machine/psl.h>
  44. #include <errno.h>
  45. #include <fcntl.h>
  46. #include <signal.h>
  47. #include <stdio.h>
  48. #include <stdlib.h>
  49. #include <string.h>
  50. #include <time.h>
  51. #include <unistd.h>
  52. #include "truss.h"
  53. #include "syscall.h"
  54. #include "extern.h"
  55. #include "linux32_syscalls.h"
  56. static int nsyscalls =
  57. sizeof(linux32_syscallnames) / sizeof(linux32_syscallnames[0]);
  58. /*
  59. * This is what this particular file uses to keep track of a system call.
  60. * It is probably not quite sufficient -- I can probably use the same
  61. * structure for the various syscall personalities, and I also probably
  62. * need to nest system calls (for signal handlers).
  63. *
  64. * 'struct syscall' describes the system call; it may be NULL, however,
  65. * if we don't know about this particular system call yet.
  66. */
  67. struct linux_syscall {
  68. struct syscall *sc;
  69. const char *name;
  70. int number;
  71. unsigned long args[5];
  72. int nargs; /* number of arguments -- *not* number of words! */
  73. char **s_args; /* the printable arguments */
  74. };
  75. static struct linux_syscall *
  76. alloc_fsc(void)
  77. {
  78. return (malloc(sizeof(struct linux_syscall)));
  79. }
  80. /* Clear up and free parts of the fsc structure. */
  81. static void
  82. free_fsc(struct linux_syscall *fsc)
  83. {
  84. int i;
  85. if (fsc->s_args) {
  86. for (i = 0; i < fsc->nargs; i++)
  87. free(fsc->s_args[i]);
  88. free(fsc->s_args);
  89. }
  90. free(fsc);
  91. }
  92. /*
  93. * Called when a process has entered a system call. nargs is the
  94. * number of words, not number of arguments (a necessary distinction
  95. * in some cases). Note that if the STOPEVENT() code in i386/i386/trap.c
  96. * is ever changed these functions need to keep up.
  97. */
  98. void
  99. amd64_linux32_syscall_entry(struct trussinfo *trussinfo, int nargs)
  100. {
  101. struct reg regs;
  102. struct linux_syscall *fsc;
  103. struct syscall *sc;
  104. lwpid_t tid;
  105. int i, syscall_num;
  106. tid = trussinfo->curthread->tid;
  107. if (ptrace(PT_GETREGS, tid, (caddr_t)&regs, 0) < 0) {
  108. fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
  109. return;
  110. }
  111. syscall_num = regs.r_rax;
  112. fsc = alloc_fsc();
  113. if (fsc == NULL)
  114. return;
  115. fsc->number = syscall_num;
  116. fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ?
  117. NULL : linux32_syscallnames[syscall_num];
  118. if (!fsc->name) {
  119. fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n",
  120. syscall_num);
  121. }
  122. if (fsc->name && (trussinfo->flags & FOLLOWFORKS) &&
  123. (strcmp(fsc->name, "linux_fork") == 0 ||
  124. strcmp(fsc->name, "linux_vfork") == 0))
  125. trussinfo->curthread->in_fork = 1;
  126. if (nargs == 0)
  127. return;
  128. /*
  129. * Linux passes syscall arguments in registers, not
  130. * on the stack. Fortunately, we've got access to the
  131. * register set. Note that we don't bother checking the
  132. * number of arguments. And what does linux do for syscalls
  133. * that have more than five arguments?
  134. */
  135. fsc->args[0] = regs.r_rbx;
  136. fsc->args[1] = regs.r_rcx;
  137. fsc->args[2] = regs.r_rdx;
  138. fsc->args[3] = regs.r_rsi;
  139. fsc->args[4] = regs.r_rdi;
  140. sc = get_syscall(fsc->name);
  141. if (sc)
  142. fsc->nargs = sc->nargs;
  143. else {
  144. #if DEBUG
  145. fprintf(trussinfo->outfile, "unknown syscall %s -- setting "
  146. "args to %d\n", fsc->name, nargs);
  147. #endif
  148. fsc->nargs = nargs;
  149. }
  150. fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *));
  151. fsc->sc = sc;
  152. /*
  153. * At this point, we set up the system call arguments.
  154. * We ignore any OUT ones, however -- those are arguments that
  155. * are set by the system call, and so are probably meaningless
  156. * now. This doesn't currently support arguments that are
  157. * passed in *and* out, however.
  158. */
  159. if (fsc->name) {
  160. #if DEBUG
  161. fprintf(stderr, "syscall %s(", fsc->name);
  162. #endif
  163. for (i = 0; i < fsc->nargs; i++) {
  164. #if DEBUG
  165. fprintf(stderr, "0x%x%s", sc ?
  166. fsc->args[sc->args[i].offset] : fsc->args[i],
  167. i < (fsc->nargs - 1) ? "," : "");
  168. #endif
  169. if (sc && !(sc->args[i].type & OUT)) {
  170. fsc->s_args[i] = print_arg(&sc->args[i],
  171. fsc->args, 0, trussinfo);
  172. }
  173. }
  174. #if DEBUG
  175. fprintf(stderr, ")\n");
  176. #endif
  177. }
  178. #if DEBUG
  179. fprintf(trussinfo->outfile, "\n");
  180. #endif
  181. if (fsc->name != NULL && (strcmp(fsc->name, "linux_execve") == 0 ||
  182. strcmp(fsc->name, "exit") == 0)) {
  183. /*
  184. * XXX
  185. * This could be done in a more general
  186. * manner but it still wouldn't be very pretty.
  187. */
  188. if (strcmp(fsc->name, "linux_execve") == 0) {
  189. if ((trussinfo->flags & EXECVEARGS) == 0) {
  190. if (fsc->s_args[1]) {
  191. free(fsc->s_args[1]);
  192. fsc->s_args[1] = NULL;
  193. }
  194. }
  195. if ((trussinfo->flags & EXECVEENVS) == 0) {
  196. if (fsc->s_args[2]) {
  197. free(fsc->s_args[2]);
  198. fsc->s_args[2] = NULL;
  199. }
  200. }
  201. }
  202. }
  203. trussinfo->curthread->fsc = fsc;
  204. }
  205. /*
  206. * Linux syscalls return negative errno's, we do positive and map them
  207. */
  208. static const int bsd_to_linux_errno[] = {
  209. -0, -1, -2, -3, -4, -5, -6, -7, -8, -9,
  210. -10, -35, -12, -13, -14, -15, -16, -17, -18, -19,
  211. -20, -21, -22, -23, -24, -25, -26, -27, -28, -29,
  212. -30, -31, -32, -33, -34, -11,-115,-114, -88, -89,
  213. -90, -91, -92, -93, -94, -95, -96, -97, -98, -99,
  214. -100,-101,-102,-103,-104,-105,-106,-107,-108,-109,
  215. -110,-111, -40, -36,-112,-113, -39, -11, -87,-122,
  216. -116, -66, -6, -6, -6, -6, -6, -37, -38, -9,
  217. -6,
  218. };
  219. long
  220. amd64_linux32_syscall_exit(struct trussinfo *trussinfo,
  221. int syscall_num __unused)
  222. {
  223. struct reg regs;
  224. struct linux_syscall *fsc;
  225. struct syscall *sc;
  226. lwpid_t tid;
  227. long retval;
  228. int errorp, i;
  229. if (trussinfo->curthread->fsc == NULL)
  230. return (-1);
  231. tid = trussinfo->curthread->tid;
  232. if (ptrace(PT_GETREGS, tid, (caddr_t)&regs, 0) < 0) {
  233. fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
  234. return (-1);
  235. }
  236. retval = regs.r_rax;
  237. errorp = !!(regs.r_rflags & PSL_C);
  238. /*
  239. * This code, while simpler than the initial versions I used, could
  240. * stand some significant cleaning.
  241. */
  242. fsc = trussinfo->curthread->fsc;
  243. sc = fsc->sc;
  244. if (!sc) {
  245. for (i = 0; i < fsc->nargs; i++)
  246. asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]);
  247. } else {
  248. /*
  249. * Here, we only look for arguments that have OUT masked in --
  250. * otherwise, they were handled in the syscall_entry function.
  251. */
  252. for (i = 0; i < sc->nargs; i++) {
  253. char *temp;
  254. if (sc->args[i].type & OUT) {
  255. /*
  256. * If an error occurred, then don't bother
  257. * getting the data; it may not be valid.
  258. */
  259. if (errorp) {
  260. asprintf(&temp, "0x%lx",
  261. fsc->args[sc->args[i].offset]);
  262. } else {
  263. temp = print_arg(&sc->args[i],
  264. fsc->args, retval, trussinfo);
  265. }
  266. fsc->s_args[i] = temp;
  267. }
  268. }
  269. }
  270. /*
  271. * It would probably be a good idea to merge the error handling,
  272. * but that complicates things considerably.
  273. */
  274. if (errorp) {
  275. for (i = 0;
  276. (size_t)i < sizeof(bsd_to_linux_errno) / sizeof(int); i++) {
  277. if (retval == bsd_to_linux_errno[i])
  278. break;
  279. }
  280. }
  281. if (fsc->name != NULL && (strcmp(fsc->name, "linux_execve") == 0 ||
  282. strcmp(fsc->name, "exit") == 0))
  283. trussinfo->curthread->in_syscall = 1;
  284. print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp,
  285. errorp ? i : retval, fsc->sc);
  286. free_fsc(fsc);
  287. return (retval);
  288. }