/usr.bin/truss/mips-fbsd.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 366 lines · 226 code · 41 blank · 99 comment · 56 complexity · 4221351b6fd0055e4d7038f6fa153066 MD5 · raw file

  1. /*
  2. * Copyright 1998 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. * FreeBSD/sparc64-specific system call handling. This is probably the most
  37. * complex part of the entire truss program, although I've got lots of
  38. * it handled relatively cleanly now. The system call names are generated
  39. * automatically, thanks to /usr/src/sys/kern/syscalls.master. The
  40. * names used for the various structures are confusing, I sadly admit.
  41. *
  42. * This file is almost nothing more than a slightly-edited i386-fbsd.c.
  43. */
  44. #include <sys/types.h>
  45. #include <sys/ptrace.h>
  46. #include <sys/syscall.h>
  47. #include <machine/frame.h>
  48. #include <machine/reg.h>
  49. #include <err.h>
  50. #include <errno.h>
  51. #include <fcntl.h>
  52. #include <signal.h>
  53. #include <stddef.h>
  54. #include <stdio.h>
  55. #include <stdlib.h>
  56. #include <string.h>
  57. #include <time.h>
  58. #include <unistd.h>
  59. #include "truss.h"
  60. #include "syscall.h"
  61. #include "extern.h"
  62. #include "syscalls.h"
  63. static int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]);
  64. /*
  65. * This is what this particular file uses to keep track of a system call.
  66. * It is probably not quite sufficient -- I can probably use the same
  67. * structure for the various syscall personalities, and I also probably
  68. * need to nest system calls (for signal handlers).
  69. *
  70. * 'struct syscall' describes the system call; it may be NULL, however,
  71. * if we don't know about this particular system call yet.
  72. */
  73. struct freebsd_syscall {
  74. struct syscall *sc;
  75. const char *name;
  76. int number;
  77. unsigned long *args;
  78. int nargs; /* number of arguments -- *not* number of words! */
  79. char **s_args; /* the printable arguments */
  80. };
  81. static struct freebsd_syscall *
  82. alloc_fsc(void)
  83. {
  84. return (malloc(sizeof(struct freebsd_syscall)));
  85. }
  86. /* Clear up and free parts of the fsc structure. */
  87. static void
  88. free_fsc(struct freebsd_syscall *fsc)
  89. {
  90. int i;
  91. free(fsc->args);
  92. if (fsc->s_args) {
  93. for (i = 0; i < fsc->nargs; i++)
  94. free(fsc->s_args[i]);
  95. free(fsc->s_args);
  96. }
  97. free(fsc);
  98. }
  99. /*
  100. * Called when a process has entered a system call. nargs is the
  101. * number of words, not number of arguments (a necessary distinction
  102. * in some cases). Note that if the STOPEVENT() code in sparc64/sparc64/trap.c
  103. * is ever changed these functions need to keep up.
  104. */
  105. void
  106. mips_syscall_entry(struct trussinfo *trussinfo, int nargs)
  107. {
  108. struct ptrace_io_desc iorequest;
  109. struct reg regs;
  110. struct freebsd_syscall *fsc;
  111. struct syscall *sc;
  112. lwpid_t tid;
  113. int i, syscall_num;
  114. int indir; /* indirect system call */
  115. tid = trussinfo->curthread->tid;
  116. if (ptrace(PT_GETREGS, tid, (caddr_t)&regs, 0) < 0) {
  117. fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
  118. return;
  119. }
  120. indir = 0;
  121. syscall_num = regs.r_regs[V0];
  122. if (syscall_num == SYS_syscall) {
  123. indir = 1;
  124. syscall_num = regs.r_regs[A0];
  125. }
  126. fsc = alloc_fsc();
  127. if (fsc == NULL)
  128. return;
  129. fsc->number = syscall_num;
  130. fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ?
  131. NULL : syscallnames[syscall_num];
  132. if (!fsc->name) {
  133. fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n",
  134. syscall_num);
  135. }
  136. if (fsc->name && (trussinfo->flags & FOLLOWFORKS) &&
  137. (strcmp(fsc->name, "fork") == 0 ||
  138. strcmp(fsc->name, "rfork") == 0 ||
  139. strcmp(fsc->name, "vfork") == 0))
  140. trussinfo->curthread->in_fork = 1;
  141. if (nargs == 0)
  142. return;
  143. fsc->args = malloc((1 + nargs) * sizeof(unsigned long));
  144. #if 0 // XXX
  145. iorequest.piod_op = PIOD_READ_D;
  146. iorequest.piod_offs = (void *)parm_offset;
  147. iorequest.piod_addr = fsc->args;
  148. iorequest.piod_len = (1 + nargs) * sizeof(unsigned long);
  149. ptrace(PT_IO, tid, (caddr_t)&iorequest, 0);
  150. if (iorequest.piod_len == 0)
  151. return;
  152. #else
  153. iorequest.piod_op = PIOD_READ_D;
  154. #endif
  155. switch (nargs) {
  156. default:
  157. /*
  158. * The OS doesn't seem to allow more than 10 words of
  159. * parameters (yay!). So we shouldn't be here.
  160. */
  161. warn("More than 10 words (%d) of arguments!\n", nargs);
  162. break;
  163. case 10:
  164. case 9:
  165. case 8:
  166. case 7:
  167. case 6:
  168. case 5:
  169. /*
  170. * If there are 7-10 words of arguments, they are placed
  171. * on the stack, as is normal for other processors.
  172. * The fall-through for all of these is deliberate!!!
  173. */
  174. // XXX BAD constant used here
  175. iorequest.piod_op = PIOD_READ_D;
  176. iorequest.piod_offs = (void *)(regs.r_regs[SP] +
  177. 4 * sizeof(uint32_t));
  178. iorequest.piod_addr = &fsc->args[4];
  179. iorequest.piod_len = (nargs - 4) * sizeof(fsc->args[0]);
  180. ptrace(PT_IO, tid, (caddr_t)&iorequest, 0);
  181. if (iorequest.piod_len == 0)
  182. return;
  183. case 4: fsc->args[3] = regs.r_regs[A3];
  184. case 3: fsc->args[2] = regs.r_regs[A2];
  185. case 2: fsc->args[1] = regs.r_regs[A1];
  186. case 1: fsc->args[0] = regs.r_regs[A0];
  187. case 0: break;
  188. }
  189. if (indir) {
  190. memmove(&fsc->args[0], &fsc->args[1],
  191. (nargs - 1) * sizeof(fsc->args[0]));
  192. }
  193. sc = get_syscall(fsc->name);
  194. if (sc)
  195. fsc->nargs = sc->nargs;
  196. else {
  197. #if DEBUG
  198. fprintf(trussinfo->outfile, "unknown syscall %s -- setting "
  199. "args to %d\n", fsc->name, nargs);
  200. #endif
  201. fsc->nargs = nargs;
  202. }
  203. fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *));
  204. fsc->sc = sc;
  205. /*
  206. * At this point, we set up the system call arguments.
  207. * We ignore any OUT ones, however -- those are arguments that
  208. * are set by the system call, and so are probably meaningless
  209. * now. This doesn't currently support arguments that are
  210. * passed in *and* out, however.
  211. */
  212. if (fsc->name) {
  213. #if DEBUG
  214. fprintf(stderr, "syscall %s(", fsc->name);
  215. #endif
  216. for (i = 0; i < fsc->nargs; i++) {
  217. #if DEBUG
  218. fprintf(stderr, "0x%x%s", sc ?
  219. fsc->args[sc->args[i].offset] : fsc->args[i],
  220. i < (fsc->nargs - 1) ? "," : "");
  221. #endif
  222. if (sc && !(sc->args[i].type & OUT)) {
  223. fsc->s_args[i] = print_arg(&sc->args[i],
  224. fsc->args, 0, trussinfo);
  225. }
  226. }
  227. #if DEBUG
  228. fprintf(stderr, ")\n");
  229. #endif
  230. }
  231. #if DEBUG
  232. fprintf(trussinfo->outfile, "\n");
  233. #endif
  234. if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 ||
  235. strcmp(fsc->name, "exit") == 0)) {
  236. /*
  237. * XXX
  238. * This could be done in a more general
  239. * manner but it still wouldn't be very pretty.
  240. */
  241. if (strcmp(fsc->name, "execve") == 0) {
  242. if ((trussinfo->flags & EXECVEARGS) == 0) {
  243. if (fsc->s_args[1]) {
  244. free(fsc->s_args[1]);
  245. fsc->s_args[1] = NULL;
  246. }
  247. }
  248. if ((trussinfo->flags & EXECVEENVS) == 0) {
  249. if (fsc->s_args[2]) {
  250. free(fsc->s_args[2]);
  251. fsc->s_args[2] = NULL;
  252. }
  253. }
  254. }
  255. }
  256. trussinfo->curthread->fsc = fsc;
  257. }
  258. /*
  259. * And when the system call is done, we handle it here.
  260. * Currently, no attempt is made to ensure that the system calls
  261. * match -- this needs to be fixed (and is, in fact, why S_SCX includes
  262. * the system call number instead of, say, an error status).
  263. */
  264. long
  265. mips_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
  266. {
  267. struct reg regs;
  268. struct freebsd_syscall *fsc;
  269. struct syscall *sc;
  270. lwpid_t tid;
  271. long retval;
  272. int errorp, i;
  273. if (trussinfo->curthread->fsc == NULL)
  274. return (-1);
  275. tid = trussinfo->curthread->tid;
  276. if (ptrace(PT_GETREGS, tid, (caddr_t)&regs, 0) < 0) {
  277. fprintf(trussinfo->outfile, "\n");
  278. return (-1);
  279. }
  280. retval = regs.r_regs[V0];
  281. errorp = !!regs.r_regs[A3];
  282. /*
  283. * This code, while simpler than the initial versions I used, could
  284. * stand some significant cleaning.
  285. */
  286. fsc = trussinfo->curthread->fsc;
  287. sc = fsc->sc;
  288. if (!sc) {
  289. for (i = 0; i < fsc->nargs; i++)
  290. asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]);
  291. } else {
  292. /*
  293. * Here, we only look for arguments that have OUT masked in --
  294. * otherwise, they were handled in the syscall_entry function.
  295. */
  296. for (i = 0; i < sc->nargs; i++) {
  297. char *temp;
  298. if (sc->args[i].type & OUT) {
  299. /*
  300. * If an error occurred, then don't bother
  301. * getting the data; it may not be valid.
  302. */
  303. if (errorp) {
  304. asprintf(&temp, "0x%lx",
  305. fsc->args[sc->args[i].offset]);
  306. } else {
  307. temp = print_arg(&sc->args[i],
  308. fsc->args, retval, trussinfo);
  309. }
  310. fsc->s_args[i] = temp;
  311. }
  312. }
  313. }
  314. if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 ||
  315. strcmp(fsc->name, "exit") == 0))
  316. trussinfo->curthread->in_syscall = 1;
  317. /*
  318. * It would probably be a good idea to merge the error handling,
  319. * but that complicates things considerably.
  320. */
  321. print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp,
  322. retval, fsc->sc);
  323. free_fsc(fsc);
  324. return (retval);
  325. }