freebsd-dev/usr.bin/truss/syscalls.c
Sean Eric Fagan 970649f9c9 First cut at printing out ioctl names intelligently. Note that this doesn't
handle linux ioctls (yet?).  This uses the mkioctl script from kdump,
bless its little heart.

Reviewed by:	Mike Smith
1997-12-06 06:51:14 +00:00

207 lines
4.5 KiB
C

/*
* This file has routines used to print out system calls and their
* arguments.
*/
/*
* $Id: syscalls.c,v 1.1 1997/12/06 05:23:10 sef Exp $
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include "syscall.h"
/*
* This should probably be in its own file.
*/
struct syscall syscalls[] = {
{ "readlink", 1, 3,
{ { String, 0 } , { String | OUT, 1 }, { Int, 2 }}},
{ "lseek", 2, 3,
{ { Int, 0 }, {Quad, 2 }, { Int, 4 }}},
{ "mmap", 2, 6,
{ { Hex, 0 }, {Int, 1}, {Hex, 2}, {Hex, 3}, {Int, 4}, {Quad, 6}}},
{ "open", 1, 3,
{ { String | IN, 0} , { Int, 1}, {Octal, 2}}},
{ "linux_open", 1, 3,
{ { String, 0 }, { Int, 1}, { Octal, 2 }}},
{ "close", 1, 1, { { Int, 0 } } },
{ "fstat", 1, 2,
{ { Int, 0}, {Ptr | OUT , 1 }}},
{ "stat", 1, 2,
{ { String | IN, 0 }, { Ptr | OUT, 1 }}},
{ "linux_newstat", 1, 2,
{ { String | IN, 0 }, { Ptr | OUT, 1 }}},
{ "linux_newfstat", 1, 2,
{ { Int, 0 }, { Ptr | OUT, 1 }}},
{ "write", 1, 3,
{ { Int, 0}, { Ptr | IN, 1 }, { Int, 2 }}},
{ "ioctl", 1, 3,
{ { Int, 0}, { Ioctl, 1 }, { Hex, 2 }}},
{ "break", 1, 1, { { Hex, 0 }}},
{ "exit", 0, 1, { { Hex, 0 }}},
{ 0, 0, 0, { 0, 0 } },
};
/*
* If/when the list gets big, it might be desirable to do it
* as a hash table or binary search.
*/
struct syscall *
get_syscall(const char *name) {
struct syscall *sc = syscalls;
while (sc->name) {
if (!strcmp(name, sc->name))
return sc;
sc++;
}
return NULL;
}
/*
* get_string
* Copy a string from the process. Note that it is
* expected to be a C string, but if max is set, it will
* only get that much.
*/
char *
get_string(int procfd, void *offset, int max) {
char *buf, *tmp;
int size, len, c;
FILE *p;
if ((p = fdopen(procfd, "r")) == NULL) {
perror("fdopen");
exit(1);
}
buf = malloc( size = (max ? max : 64 ) );
len = 0;
fseek(p, (long)offset, SEEK_SET);
while ((c = fgetc(p)) != EOF) {
buf[len++] = c;
if (c == 0 || len == max) {
buf[len] = 0;
break;
}
if (len == size) {
char *tmp = buf;
tmp = realloc(buf, size+64);
if (tmp == NULL) {
buf[len] = 0;
return buf;
}
size += 64;
}
}
return buf;
}
/*
* Gag. This is really unportable. Multiplication is more portable.
* But slower, from the code I saw.
*/
static long long
make_quad(unsigned long p1, unsigned long p2) {
union {
long long ll;
unsigned long l[2];
} t;
t.l[0] = p1;
t.l[1] = p2;
return t.ll;
}
/*
* print_arg
* Converts a syscall argument into a string. Said string is
* allocated via malloc(), so needs to be free()'d. The file
* descriptor is for the process' memory (via /proc), and is used
* to get any data (where the argument is a pointer). sc is
* a pointer to the syscall description (see above); args is
* an array of all of the system call arguments.
*/
char *
print_arg(int fd, struct syscall_args *sc, unsigned long *args) {
char *tmp;
switch (sc->type & ARG_MASK) {
case Hex:
tmp = malloc(12);
sprintf(tmp, "0x%x", args[sc->offset]);
break;
case Octal:
tmp = malloc(13);
sprintf(tmp, "0%o", args[sc->offset]);
break;
case Int:
tmp = malloc(12);
sprintf(tmp, "%d", args[sc->offset]);
break;
case String:
{
char *tmp2;
tmp2 = get_string(fd, (void*)args[sc->offset], 0);
tmp = malloc(strlen(tmp2) + 3);
sprintf(tmp, "\"%s\"", tmp2);
free(tmp2);
}
break;
case Quad:
{
unsigned long long t;
unsigned long l1, l2;
l1 = args[sc->offset];
l2 = args[sc->offset+1];
t = make_quad(l1, l2);
tmp = malloc(24);
sprintf(tmp, "0x%qx", t);
break;
}
case Ptr:
tmp = malloc(12);
sprintf(tmp, "0x%x", args[sc->offset]);
break;
case Ioctl:
{
char *temp = ioctlname(args[sc->offset]);
if (temp)
tmp = strdup(temp);
else {
tmp = malloc(12);
sprintf(tmp, "0x%x", args[sc->offset]);
}
}
}
return tmp;
}
/*
* print_syscall
* Print (to outfile) the system call and its arguments. Note that
* nargs is the number of arguments (not the number of words; this is
* potentially confusing, I know).
*/
void
print_syscall(FILE *outfile, const char *name, int nargs, char **s_args) {
int i;
fprintf(outfile, "syscall %s(", name);
for (i = 0; i < nargs; i++) {
if (s_args[i])
fprintf(outfile, "%s", s_args[i]);
else
fprintf(outfile, "<missing argument>");
fprintf(outfile, "%s", i < (nargs - 1) ? "," : "");
}
fprintf(outfile, ")\n\t");
}