Stop core dump if an ioctl trace has fewer than expected arguments.

- Check names of system calls (for special treatment) because emulations
  might use different numbers.
- Report an error if arguments to -p or -m non-numeric.
- Just take last of -x and -Xvalue, stop -X0x80000000 being valid (core dumps).
- Keep 'last used' emulation_ctx at top of list, create on lookup (usually
  EMUL anyway), delete when exit called (doesn't return).
- Slightly improve hack to get correct system call name in execve return
  when emulation has changed.
- Rename global variables 'current'/'previous' to 'cur_emul'/'prev_emul'.
(TODO: save system call type (and maybe an argument) per pid so GIO trace
format can depend on the actual system call.)
Fixes part of PR sparc64/23473 - but system call arguments will still not be
displayed correctly.
This commit is contained in:
dsl 2003-11-18 13:21:53 +00:00
parent ccd8c9e649
commit 3433691e60
3 changed files with 159 additions and 125 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: kdump.c,v 1.66 2003/11/16 21:52:33 manu Exp $ */
/* $NetBSD: kdump.c,v 1.67 2003/11/18 13:21:53 dsl Exp $ */
/*-
* Copyright (c) 1988, 1993
@ -39,7 +39,7 @@ __COPYRIGHT("@(#) Copyright (c) 1988, 1993\n\
#if 0
static char sccsid[] = "@(#)kdump.c 8.4 (Berkeley) 4/28/95";
#else
__RCSID("$NetBSD: kdump.c,v 1.66 2003/11/16 21:52:33 manu Exp $");
__RCSID("$NetBSD: kdump.c,v 1.67 2003/11/18 13:21:53 dsl Exp $");
#endif
#endif /* not lint */
@ -128,7 +128,7 @@ main(argc, argv)
int col;
char *cp;
while ((ch = getopt(argc, argv, "e:f:dlm:Nnp:RTt:xX:")) != -1)
while ((ch = getopt(argc, argv, "e:f:dlm:Nnp:RTt:xX:")) != -1) {
switch (ch) {
case 'e':
emul_name = strdup(optarg); /* it's safer to copy it */
@ -143,10 +143,14 @@ main(argc, argv)
tail = 1;
break;
case 'p':
do_pid = atoi(optarg);
do_pid = strtoul(optarg, &cp, 0);
if (*cp != 0)
errx(1,"invalid number %s", optarg);
break;
case 'm':
maxdata = atoi(optarg);
maxdata = strtoul(optarg, &cp, 0);
if (*cp != 0)
errx(1,"invalid number %s", optarg);
break;
case 'N':
numeric++;
@ -167,22 +171,19 @@ main(argc, argv)
errx(1, "unknown trace point in %s", optarg);
break;
case 'x':
if (word_size != 0)
errx(1, "-x and -X are mutually exclusive");
word_size = 1;
break;
case 'X':
if (word_size != 0)
errx(1, "-x and -X are mutually exclusive");
word_size = strtoul(optarg, &cp, 0);
if (*cp != 0 || word_size & (word_size - 1) ||
word_size > 16 || word_size == 0)
word_size > 16 || word_size <= 0)
errx(1, "argument to -X must be "
"1, 2, 4, 8 or 16");
break;
default:
usage();
}
}
argv += optind;
argc -= optind;
@ -378,41 +379,61 @@ void
ktrsyscall(ktr)
struct ktr_syscall *ktr;
{
int argsize = ktr->ktr_argsize;
const struct emulation *revelant = current;
int argcount = ktr->ktr_argsize / sizeof (register_t);
const struct emulation *emul = cur_emul;
register_t *ap;
if (((ktr->ktr_code >= revelant->nsysnames || ktr->ktr_code < 0)
&& (mach_traps_dispatch(&ktr->ktr_code, &revelant) == 0)) ||
numeric)
(void)printf("[%d]", ktr->ktr_code);
else
(void)printf("%s", revelant->sysnames[ktr->ktr_code]);
ap = (register_t *)((char *)ktr + sizeof(struct ktr_syscall));
if (argsize) {
char c = '(';
if (!plain) {
char c;
char *cp;
const char *sys_name;
switch (ktr->ktr_code) {
case SYS_ioctl:
if (decimal)
emul_changed = 0;
if (((ktr->ktr_code >= emul->nsysnames || ktr->ktr_code < 0)
&& (mach_traps_dispatch(&ktr->ktr_code, &emul) == 0)) ||
numeric) {
sys_name = "?";
(void)printf("[%d]", ktr->ktr_code);
} else {
sys_name = emul->sysnames[ktr->ktr_code];
(void)printf("%s", sys_name);
}
ap = (register_t *)((char *)ktr + sizeof(struct ktr_syscall));
if (argcount) {
c = '(';
if (plain) {
;
} else if (strcmp(sys_name, "exit") == 0) {
ectx_delete();
} else if (strcmp(sys_name, "ioctl") == 0 && argcount >= 2 ) {
if (decimal || *ap <= 9)
(void)printf("(%ld", (long)*ap);
else
(void)printf("(%#lx", (long)*ap);
ap++;
argsize -= sizeof(register_t);
argcount--;
if ((cp = ioctlname(*ap)) != NULL)
(void)printf(",%s", cp);
else
ioctldecode(*ap);
c = ',';
ap++;
argsize -= sizeof(register_t);
break;
argcount--;
c = ',';
case SYS_ptrace:
if (strcmp(revelant->name, "linux") == 0) {
} else if (strcmp(sys_name, "kill") == 0 && argcount >= 2) {
if (decimal || *ap <= 9)
(void)printf("(%ld, SIG%s",
(long)ap[0], signame(ap[1], 1));
else
(void)printf("(%#lx, SIG%s",
(long)ap[0], signame(ap[1], 1));
ap += 2;
argcount -= 2;
c = ',';
} else if (strcmp(sys_name, "ptrace") == 0 && argcount >= 1) {
if (strcmp(emul->name, "linux") == 0) {
if (*ap >= 0 && *ap <=
sizeof(linux_ptrace_ops) /
sizeof(linux_ptrace_ops[0]))
@ -427,35 +448,19 @@ ktrsyscall(ktr)
else
(void)printf("(%ld", (long)*ap);
}
c = ',';
ap++;
argsize -= sizeof(register_t);
break;
argcount--;
c = ',';
case SYS_kill:
if (decimal)
(void)printf("(%ld, SIG%s",
(long)ap[0], signame(ap[1], 1));
else
(void)printf("(%#lx, SIG%s",
(long)ap[0], signame(ap[1], 1));
ap += 2;
argsize -= 2 * sizeof(register_t);
break;
default:
/* No special handling */
break;
}
}
while (argsize) {
if (decimal)
while (argcount > 0) {
if (decimal || *ap <= 9)
(void)printf("%c%ld", c, (long)*ap);
else
(void)printf("%c%#lx", c, (long)*ap);
c = ',';
ap++;
argsize -= sizeof(register_t);
argcount--;
c = ',';
}
(void)putchar(')');
}
@ -467,21 +472,22 @@ ktrsysret(ktr, len)
struct ktr_sysret *ktr;
int len;
{
const struct emulation *revelant;
const struct emulation *emul;
int error = ktr->ktr_error;
int code = ktr->ktr_code;
if (emul_changed)
revelant = previous;
else
revelant = current;
if (emul_changed) {
/* In order to get system call name right in execve return */
emul = prev_emul;
emul_changed = 0;
} else
emul = cur_emul;
if ((code >= revelant->nsysnames || code < 0 || plain > 1)
&& (mach_traps_dispatch(&code, &revelant) == 0))
if ((code >= emul->nsysnames || code < 0 || plain > 1)
&& (mach_traps_dispatch(&code, &emul) == 0))
(void)printf("[%d] ", code);
else
(void)printf("%s ", revelant->sysnames[code]);
(void)printf("%s ", emul->sysnames[code]);
switch (error) {
case 0:
@ -508,7 +514,7 @@ rprint(register_t ret)
if (ret < 0 || ret > 9)
(void)printf("/%#lx", (long)ret);
} else {
if (decimal)
if (decimal || ret <= 9)
(void)printf("%ld", (long)ret);
else
(void)printf("%#lx", (long)ret);
@ -525,18 +531,18 @@ eprint(e)
{
int i = e;
if (current->errnomap) {
if (cur_emul->errnomap) {
/* No remapping for ERESTART and EJUSTRETURN */
/* Kludge for linux that has negative error numbers */
if (current->errnomap[2] > 0 && e < 0)
if (cur_emul->errnomap[2] > 0 && e < 0)
goto normal;
for (i = 0; i < current->nerrnomap; i++)
if (e == current->errnomap[i])
for (i = 0; i < cur_emul->nerrnomap; i++)
if (e == cur_emul->errnomap[i])
break;
if (i == current->nerrnomap) {
if (i == cur_emul->nerrnomap) {
printf("-1 unknown errno %d", e);
return;
}
@ -638,7 +644,7 @@ hexdump_buf(vdp, datalen, word_sz)
*cp++ = isgraph(c) ? c : '.';
};
printf("\t%3.3x %.*s%.*s\n", off, width, bytes, l, chars);
printf("\t%-5.3x%.*s%.*s\n", off, width, bytes, l, chars);
}
}
@ -885,8 +891,8 @@ signame(long sig, int xlat)
(void)snprintf(buf, sizeof(buf), "*unknown %ld*", sig);
return buf;
} else
return sys_signame[(xlat && current->signalmap != NULL) ?
current->signalmap[sig] : sig];
return sys_signame[(xlat && cur_emul->signalmap != NULL) ?
cur_emul->signalmap[sig] : sig];
}
void

View File

@ -1,4 +1,4 @@
/* $NetBSD: setemul.c,v 1.17 2003/11/15 23:10:31 manu Exp $ */
/* $NetBSD: setemul.c,v 1.18 2003/11/18 13:21:54 dsl Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
@ -69,7 +69,7 @@
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: setemul.c,v 1.17 2003/11/15 23:10:31 manu Exp $");
__RCSID("$NetBSD: setemul.c,v 1.18 2003/11/18 13:21:54 dsl Exp $");
#endif /* not lint */
#include <sys/param.h>
@ -238,17 +238,18 @@ struct emulation_ctx {
struct emulation_ctx *next;
};
const struct emulation *current;
const struct emulation *previous;
const struct emulation *cur_emul;
const struct emulation *prev_emul;
/* Mach emulation require extra emulation contexts */
static const struct emulation *mach;
static const struct emulation *mach_ppccalls;
static const struct emulation *mach_fasttraps;
static const struct emulation *default_emul = NULL;
static const struct emulation *default_emul = &emulations[0];
struct emulation_ctx *current_ctx;
struct emulation_ctx *emul_ctx = NULL;
static struct emulation_ctx emul_0 = {0, &emulations[0], NULL};
struct emulation_ctx *emul_ctx = &emul_0;
static struct emulation_ctx *ectx_find(pid_t);
static void ectx_update(pid_t, const struct emulation *);
@ -273,22 +274,24 @@ setemul(const char *name, pid_t pid, int update_ectx)
if (update_ectx)
ectx_update(pid, match);
if (!default_emul)
else
default_emul = match;
if (current != NULL)
previous = current;
if (cur_emul != NULL)
prev_emul = cur_emul;
else
previous = match;
prev_emul = match;
current = match;
cur_emul = match;
}
/*
* Emulation context list is very simple chained list, not even hashed.
* We expect the number of separate traced contexts/processes to be
* fairly low, so it's not worth it to optimize this.
* MMMmmmm not when I use it, it is only bounded PID_MAX!
* Requeue looked up item at start of list to cache result since the
* trace file tendes to have a burst of calls for a single process.
*/
/*
@ -297,14 +300,32 @@ setemul(const char *name, pid_t pid, int update_ectx)
static struct emulation_ctx *
ectx_find(pid_t pid)
{
struct emulation_ctx *ctx;
struct emulation_ctx *ctx, **pctx;
for(ctx = emul_ctx; ctx != NULL; ctx = ctx->next) {
if (ctx->pid == pid)
return ctx;
/* Top of list is almost always right... (and list is never empty) */
if (emul_ctx->pid == pid)
return emul_ctx;
for (pctx = &emul_ctx; ; pctx = &ctx->next) {
ctx = *pctx;
if (ctx == NULL) {
/* create entry with default emulation */
ctx = malloc(sizeof *ctx);
if (ctx == NULL)
err(1, "malloc emul context");
ctx->pid = pid;
ctx->emulation = default_emul;
break;
}
return NULL;
if (ctx->pid != pid)
continue;
/* Cut out of chain */
*pctx = ctx->next;
}
/* Add at chain head */
ctx->next = emul_ctx;
emul_ctx = ctx;
return ctx;
}
/*
@ -316,22 +337,8 @@ ectx_update(pid_t pid, const struct emulation *emul)
{
struct emulation_ctx *ctx;
if ((ctx = ectx_find(pid)) != NULL) {
/* found and entry, ensure the emulation is right (exec!) */
ctx = ectx_find(pid);
ctx->emulation = emul;
return;
}
ctx = malloc(sizeof(*ctx));
if (ctx == NULL)
err(1, NULL);
ctx->pid = pid;
ctx->emulation = emul;
/* put the entry on start of emul_ctx chain */
ctx->next = emul_ctx;
emul_ctx = ctx;
}
/*
@ -342,12 +349,32 @@ ectx_sanify(pid_t pid)
{
struct emulation_ctx *ctx;
if ((ctx = ectx_find(pid)) != NULL)
current = ctx->emulation;
else if (default_emul)
current = default_emul;
else
current = &emulations[0]; /* NetBSD */
ctx = ectx_find(pid);
cur_emul = ctx->emulation;
}
/*
* Delete emulation context for current pid.
* (eg when tracing exit())
* Defer delete just in case we've cached a pointer...
*/
void
ectx_delete(void)
{
static struct emulation_ctx *ctx;
struct emulation_ctx *nctx;
if (ctx != NULL)
free(ctx);
nctx = emul_ctx->next;
if (nctx == NULL) {
/* sanity - last item on list should never be killed */
ctx = NULL;
return;
}
ctx = emul_ctx;
emul_ctx = nctx;
}
/*

View File

@ -1,4 +1,4 @@
/* $NetBSD: setemul.h,v 1.10 2003/11/15 23:10:31 manu Exp $ */
/* $NetBSD: setemul.h,v 1.11 2003/11/18 13:21:54 dsl Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
@ -79,11 +79,12 @@ struct emulation {
int nsignalmap; /* number of elements in array */
};
extern const struct emulation *current;
extern const struct emulation *previous;
extern const struct emulation *cur_emul;
extern const struct emulation *prev_emul;
void setemul(const char *, pid_t, int);
void ectx_sanify(pid_t);
void ectx_delete(void);
int mach_traps_dispatch(int *, const struct emulation **);
void mach_lookup_emul(void);
const char *mach_service_name(int);