Subject: bin/1545: self-contained ktrace files
To: None <gnats-bugs@gnats.netbsd.org>
From: Niklas Hallqvist <niklas@appli.se>
List: netbsd-bugs
Date: 09/29/1995 14:31:17
>Number:         1545
>Category:       bin
>Synopsis:       Ktrace doesn't produce self-contained output files
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    bin-bug-people (Utility Bug People)
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Fri Sep 29 15:50:01 1995
>Last-Modified:
>Originator:     Niklas Hallqvist
>Organization:
	Applitron Datasystem AB
>Release:        950907
>Environment:
System: NetBSD nettan.appli.se 1.0A NetBSD 1.0A (NETTAN) #13: Fri Aug 25 11:45:40 PDT 1995 niklas@nettan.appli.se:/u6/NetBSD/src/sys/arch/i386/compile/NETTAN i386


>Description:
	Today ktrace/kdump doesn't know anything about what emulations
	and options are used in a kernel which is traced.  This leads
	to things like "unimplemented syscalls" in the trace output.
	Another problem is when moving around trace files to machines which
	aren't based on equal kernel sources.  Emulations/syscall sets may
	vary over time, so kdump may produce confusing results.

>How-To-Repeat:
	Ktrace a Linux (or other new emulation) binary on a current system
	move the ktrace.out to an older system and kdump it.  Ktrace a SVR4
	binary using SYSV IPC (shared mem etc) and kdump it, watch for
	"unimplemented" in the output, even when the kernel has it enabled.

>Fix:
	The patchfile below changes the kernel to keep track of the syscall
	sets for each emulation and makes them exportable to userlevel via
	the sysctl interface.  Also new versions of sysctl, ktrace and kdump
	are there to use this kernel feature.  Besides ktrace puts the syscall
	tables in the output file unless appending, so kdump can use them for
	printing purposes.  If kdump gets an old trace file it will work as
	before.  A magic entry is also contributed for file(1) to recognize
	our new ktrace file format.

*** old-NetBSD/src/lib/libc/gen/sysctl.3
--- NetBSD/src/lib/libc/gen/sysctl.3
***************
*** 223,230 ****
  privilege may change the value.
  The types of data currently available are process information,
  system vnodes, the open file entries, routing table entries,
! virtual memory statistics, load average history, and clock rate
! information.
  .Bl -column "KERNXCHOWNXRESTRICTEDXXX" "struct clockrateXXX" -offset indent
  .It Sy Pa Second level name	Type	Changeable
  .It KERN\_ARGMAX	integer	no
--- 223,230 ----
  privilege may change the value.
  The types of data currently available are process information,
  system vnodes, the open file entries, routing table entries,
! virtual memory statistics, load average history, clock rate
! information and emulation information.
  .Bl -column "KERNXCHOWNXRESTRICTEDXXX" "struct clockrateXXX" -offset indent
  .It Sy Pa Second level name	Type	Changeable
  .It KERN\_ARGMAX	integer	no
***************
*** 232,237 ****
--- 232,238 ----
  .It KERN\_CHOWN\_RESTRICTED	integer	no
  .It KERN\_CLOCKRATE	struct clockinfo	no
  .It KERN\_DOMAINNAME	string	yes
+ .It KERN\_EMUL	node	not applicable
  .It KERN\_FILE	struct file	no
  .It KERN\_HOSTID	integer	yes
  .It KERN\_HOSTNAME	string	yes
***************
*** 244,249 ****
--- 245,251 ----
  .It KERN\_MAX\_CANON	integer	no
  .It KERN\_MAX\_INPUT	integer	no
  .It KERN\_NAME\_MAX	integer	no
+ .It KERN\_NEMUL	integer	no
  .It KERN\_NGROUPS	integer	no
  .It KERN\_NO\_TRUNC	integer	no
  .It KERN\_OSRELEASE	string	no
***************
*** 284,289 ****
--- 286,313 ----
  skew rate.
  .It Li KERN_DOMAINNAME
  Get or set the YP domain name.
+ .It Li KERN_EMUL
+ Return emulation information about the kernel.
+ The third level name is the offset into the emulsw table and the fourth
+ level names are detailed below.
+ No values in this hierachy is changeable.
+ .Bl -column "KERNXEMULXMAXSYSCALLXXX" -offset indent
+ .It Sy Pa Fourth level name	Type
+ .It KERN\_EMUL\_NAME	string
+ .It KERN\_EMUL\_MAXSYSCALL	integer
+ .It KERN\_EMUL\_SYSCALL	node
+ .El
+ .Pp
+ The variables are as follows:
+ .Bl -tag -width "123456"
+ .It Li KERN_EMUL_NAME
+ Returns the name of the emulation.
+ .It Li KERN_EMUL_MAXSYSCALL
+ Returns the number of system calls in this emulation.
+ .It Li KERN_EMUL_SYSCALL
+ Returns the individual system call names.
+ The fifth level name is the system call number.
+ .El
  .It Li KERN_FILE
  Return the entire file table.
  The returned data consists of a single
***************
*** 314,319 ****
--- 338,345 ----
  a terminal input queue.
  .It Li KERN_NAME_MAX
  The maximum number of bytes in a file name.
+ .It Li KERN_NEMUL
+ The number of entries in the emulsw table.
  .It Li KERN_NGROUPS
  The maximum number of supplemental groups.
  .It Li KERN_NO_TRUNC
*** old-NetBSD/src/sys/conf/files
--- NetBSD/src/sys/conf/files
***************
*** 71,76 ****
--- 71,77 ----
  file isofs/cd9660/cd9660_util.c		cd9660
  file isofs/cd9660/cd9660_vfsops.c	cd9660
  file isofs/cd9660/cd9660_vnops.c	cd9660
+ file kern/emul_conf.c
  file kern/exec_aout.c
  file kern/exec_conf.c
  file kern/exec_ecoff.c			compat_ultrix compat_osf1
***************
*** 108,114 ****
  file kern/sys_generic.c
  file kern/sys_process.c
  file kern/sys_socket.c
! file kern/syscalls.c			syscall_debug
  file kern/sysv_ipc.c			sysvshm sysvsem sysvmsg
  file kern/sysv_msg.c			sysvmsg
  file kern/sysv_sem.c			sysvsem
--- 109,115 ----
  file kern/sys_generic.c
  file kern/sys_process.c
  file kern/sys_socket.c
! file kern/syscalls.c
  file kern/sysv_ipc.c			sysvshm sysvsem sysvmsg
  file kern/sysv_msg.c			sysvmsg
  file kern/sysv_sem.c			sysvsem
*** old-NetBSD/src/sys/conf/files.oldconf
--- NetBSD/src/sys/conf/files.oldconf
***************
*** 64,70 ****
  kern/sys_generic.c	standard
  kern/sys_process.c	standard
  kern/sys_socket.c	standard
! kern/syscalls.c		optional syscall_debug
  kern/sysv_ipc.c		optional sysvmsg or sysvsem or sysvshm
  kern/sysv_msg.c		optional sysvmsg
  kern/sysv_sem.c		optional sysvsem
--- 64,70 ----
  kern/sys_generic.c	standard
  kern/sys_process.c	standard
  kern/sys_socket.c	standard
! kern/syscalls.c		standard
  kern/sysv_ipc.c		optional sysvmsg or sysvsem or sysvshm
  kern/sysv_msg.c		optional sysvmsg
  kern/sysv_sem.c		optional sysvsem
*** /dev/null
--- NetBSD/src/sys/kern/emul_conf.c
***************
*** 0 ****
--- 1,113 ----
+ /*	$NetBSD: emul_conf.c,v 1.1 1995/08/26 11:00:47 niklas Exp $	*/
+ 
+ /*
+  * Copyright (c) 1995 Niklas Hallqvist
+  * All rights reserved.
+  *
+  * Redistribution and use in source and binary forms, with or without
+  * modification, are permitted provided that the following conditions
+  * are met:
+  * 1. Redistributions of source code must retain the above copyright
+  *    notice, this list of conditions and the following disclaimer.
+  * 2. Redistributions in binary form must reproduce the above copyright
+  *    notice, this list of conditions and the following disclaimer in the
+  *    documentation and/or other materials provided with the distribution.
+  * 3. All advertising materials mentioning features or use of this software
+  *    must display the following acknowledgement:
+  *      This product includes software developed by Christopher G. Demetriou.
+  * 4. The name of the author may not be used to endorse or promote products
+  *    derived from this software without specific prior written permission
+  *
+  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  */
+ 
+ #include <sys/param.h>
+ #include <sys/emul.h>
+ #include <sys/syscall.h>
+ #ifdef COMPAT_HPUX
+ #include <compat/hpux/hpux_syscall.h>
+ #endif
+ #ifdef COMPAT_IBCS2
+ #include <compat/ibcs2/ibcs2_syscall.h>
+ #endif
+ #ifdef COMPAT_LINUX
+ #include <compat/linux/linux_syscall.h>
+ #endif
+ #ifdef COMPAT_HPUX
+ #include <compat/osf1/osf1_syscall.h>
+ #endif
+ #ifdef COMPAT_SUNOS
+ #include <compat/sunos/sunos_syscall.h>
+ #endif
+ #ifdef COMPAT_SVR4
+ #include <compat/svr4/svr4_syscall.h>
+ #endif
+ #ifdef COMPAT_ULTRIX
+ #include <compat/ultrix/ultrix_syscall.h>
+ #endif
+ 
+ extern char *syscallnames[];
+ #ifdef COMPAT_HPUX
+ extern char *hpux_syscalls[];
+ #endif
+ #ifdef COMPAT_IBCS2
+ extern char *ibcs2_syscalls[];
+ #endif
+ #ifdef COMPAT_LINUX
+ extern char *linux_syscalls[];
+ #endif
+ #ifdef COMPAT_HPUX
+ extern char *osf1_syscalls[];
+ #endif
+ #ifdef COMPAT_SUNOS
+ extern char *sunos_syscalls[];
+ #endif
+ #ifdef COMPAT_SVR4
+ extern char *svr4_syscalls[];
+ #endif
+ #ifdef COMPAT_ULTRIX
+ extern char *ultrix_syscalls[];
+ #endif
+ 
+ struct emulsw emulsw[] = {
+ 	{ "netbsd", SYS_MAXSYSCALL, syscallnames, },
+ #ifdef COMPAT_HPUX
+ 	{ "hpux", HPUX_SYS_MAXSYSCALL, hpux_syscalls, },
+ #endif
+ #ifdef COMPAT_IBCS2
+ 	{ "ibcs2", IBCS2_SYS_MAXSYSCALL, ibcs2_syscalls, },
+ #endif
+ #ifdef COMPAT_LINUX
+ 	{ "linux", LINUX_SYS_MAXSYSCALL, linux_syscalls, },
+ #endif
+ #ifdef COMPAT_HPUX
+ 	{ "osf1", OSF1_SYS_MAXSYSCALL, osf1_syscalls, },
+ #endif
+ #ifdef COMPAT_SUNOS
+ 	{ "sunos", SUNOS_SYS_MAXSYSCALL, sunos_syscalls, },
+ #endif
+ #ifdef COMPAT_SVR4
+ 	{ "svr4", SVR4_SYS_MAXSYSCALL, svr4_syscalls, },
+ #endif
+ #ifdef COMPAT_ULTRIX
+ 	{ "ultrix", ULTRIX_SYS_MAXSYSCALL, ultrix_syscalls, },
+ #endif
+ #ifdef LKM
+ 	{ "", 0, NULL, },				/* entries for LKMs */
+ 	{ "", 0, NULL, },
+ 	{ "", 0, NULL, },
+ 	{ "", 0, NULL, },
+ 	{ "", 0, NULL, },
+ #endif
+ };
+ 
+ int nemuls = sizeof(emulsw) / sizeof(*emulsw);
*** old-NetBSD/src/sys/kern/init_main.c
--- NetBSD/src/sys/kern/init_main.c
***************
*** 102,110 ****
  #endif
  
  extern char sigcode[], esigcode[];
- #ifdef SYSCALL_DEBUG
  extern char *syscallnames[];
- #endif
  
  struct emul emul_netbsd = {
  	"netbsd",
--- 102,108 ----
***************
*** 113,123 ****
  	SYS_syscall,
  	SYS_MAXSYSCALL,
  	sysent,
- #ifdef SYSCALL_DEBUG
  	syscallnames,
- #else
- 	NULL,
- #endif
  	0,
  	copyargs,
  	setregs,
--- 111,117 ----
*** old-NetBSD/src/sys/kern/init_sysent.c
--- NetBSD/src/sys/kern/init_sysent.c
***************
*** 950,953 ****
  	    nosys },				/* 231 = unimplemented shmget */
  #endif
  };
- 
--- 950,952 ----
*** old-NetBSD/src/sys/kern/kern_sysctl.c
--- NetBSD/src/sys/kern/kern_sysctl.c
***************
*** 57,63 ****
--- 57,65 ----
  #include <vm/vm.h>
  #include <sys/sysctl.h>
  
+ #include <sys/emul.h>
  #include <sys/mount.h>
+ #include <sys/syscall.h>
  #include <sys/syscallargs.h>
  
  sysctlfn kern_sysctl;
***************
*** 205,212 ****
  	int error, level, inthostid;
  	extern char ostype[], osrelease[], version[];
  
! 	/* all sysctl names at this level are terminal */
! 	if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF))
  		return (ENOTDIR);		/* overloaded */
  
  	switch (name[0]) {
--- 207,218 ----
  	int error, level, inthostid;
  	extern char ostype[], osrelease[], version[];
  
! 	/*
! 	 * all sysctl names at this level are terminal except for "proc",
! 	 * "prof" & "syscall"
! 	 */
! 	if (namelen != 1 && !(name[0] == KERN_PROC || name[0] == KERN_PROF ||
!             name[0] == KERN_EMUL))
  		return (ENOTDIR);		/* overloaded */
  
  	switch (name[0]) {
***************
*** 284,289 ****
--- 290,300 ----
  		return (sysctl_rdint(oldp, oldlenp, newp, MAXPARTITIONS));
  	case KERN_RAWPARTITION:
  		return (sysctl_rdint(oldp, oldlenp, newp, RAW_PART));
+ 	case KERN_NEMULS:
+ 		return (sysctl_rdint(oldp, oldlenp, newp, nemuls));
+ 	case KERN_EMUL:
+ 		return (sysctl_doemul(name + 1, namelen - 1, oldp, oldlenp,
+ 		    newp));
  	default:
  		return (EOPNOTSUPP);
  	}
***************
*** 590,596 ****
  	int error = 0;
  
  	if (namelen != 2 && !(namelen == 1 && name[0] == KERN_PROC_ALL))
! 		return (EINVAL);
  	p = allproc.lh_first;
  	doingzomb = 0;
  again:
--- 601,607 ----
  	int error = 0;
  
  	if (namelen != 2 && !(namelen == 1 && name[0] == KERN_PROC_ALL))
! 		return (ENOTDIR);
  	p = allproc.lh_first;
  	doingzomb = 0;
  again:
***************
*** 719,721 ****
--- 730,775 ----
  	ep->e_xccount = ep->e_xswrss = 0;
  }
  
+ /*
+  * Get emulation info
+  */
+ sysctl_doemul(name, namelen, where, sizep, newp)
+ 	int *name;
+ 	u_int namelen;
+ 	char *where;
+ 	size_t *sizep;
+         void *newp;
+ {
+ 	char **names;
+ 
+ 	/*
+ 	 * This level holds emulation/var pairs only except for the syscall
+ 	 * table which holds an index as well.
+ 	 */
+ 	if ((namelen != 2 || name[1] == KERN_EMUL_SYSCALL) &&
+ 	    (namelen != 3 || name[1] != KERN_EMUL_SYSCALL))
+ 		return (ENOTDIR);
+ 	/* Check for valid emulations */
+ 	if (name[0] < 0 || name[0] >= nemuls)
+ 		return (EOPNOTSUPP);
+ 	switch (name[1]) {
+ 	case KERN_EMUL_NAME:
+ 		return (sysctl_rdstring(where, sizep, newp,
+ 		    emulsw[name[0]].em_name));
+ 		break;
+ 	case KERN_EMUL_MAXSYSCALL:
+ 		return (sysctl_rdint(where, sizep, newp,
+ 		    emulsw[name[0]].em_maxsyscall));
+ 		break;
+ 	case KERN_EMUL_SYSCALL:
+ 	        /* Check to see we're inside the syscallnames array */
+ 		if (name[2] < 0 || name[2] >= emulsw[name[0]].em_maxsyscall)
+ 			return (EOPNOTSUPP);
+ 		names = emulsw[name[0]].em_syscallnames;
+ 		return (sysctl_rdstring (where, sizep, newp,
+ 		    names == NULL ? "" : names[name[2]]));
+ 		break;
+ 	default:
+ 		return (EOPNOTSUPP);
+ 	}
+ }
*** /dev/null
--- NetBSD/src/sys/sys/emul.h
***************
*** 0 ****
--- 1,40 ----
+ /*	$NetBSD: emul.h,v 1.1 1995/08/27 23:30:47 niklas Exp $	*/
+ 
+ /*
+  * Copyright (c) 1995 Niklas Hallqvist
+  * All rights reserved.
+  *
+  * Redistribution and use in source and binary forms, with or without
+  * modification, are permitted provided that the following conditions
+  * are met:
+  * 1. Redistributions of source code must retain the above copyright
+  *    notice, this list of conditions and the following disclaimer.
+  * 2. Redistributions in binary form must reproduce the above copyright
+  *    notice, this list of conditions and the following disclaimer in the
+  *    documentation and/or other materials provided with the distribution.
+  * 3. All advertising materials mentioning features or use of this software
+  *    must display the following acknowledgement:
+  *      This product includes software developed by Christopher G. Demetriou.
+  * 4. The name of the author may not be used to endorse or promote products
+  *    derived from this software without specific prior written permission
+  *
+  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  */
+ 
+ struct emulsw {
+ 	char *em_name;
+ 	int  em_maxsyscall;
+ 	char **em_syscallnames;
+ };
+ 
+ extern struct emulsw emulsw[];
+ extern int nemuls;
*** old-NetBSD/src/sys/sys/sysctl.h
--- NetBSD/src/sys/sys/sysctl.h
***************
*** 132,138 ****
  #define	KERN_DOMAINNAME		22	/* string: (YP) domainname */
  #define	KERN_MAXPARTITIONS	23	/* int: number of partitions/disk */
  #define KERN_RAWPARTITION	24	/* int: raw partition number */
! #define	KERN_MAXID		25	/* number of valid kern ids */
  
  #define CTL_KERN_NAMES { \
  	{ 0, 0 }, \
--- 132,140 ----
  #define	KERN_DOMAINNAME		22	/* string: (YP) domainname */
  #define	KERN_MAXPARTITIONS	23	/* int: number of partitions/disk */
  #define KERN_RAWPARTITION	24	/* int: raw partition number */
! #define KERN_NEMULS		25	/* int: emulation table size */
! #define KERN_EMUL		26	/* node: emulation info */
! #define	KERN_MAXID		27	/* number of valid kern ids */
  
  #define CTL_KERN_NAMES { \
  	{ 0, 0 }, \
***************
*** 160,165 ****
--- 162,169 ----
  	{ "domainname", CTLTYPE_STRING }, \
  	{ "maxpartitions", CTLTYPE_INT }, \
  	{ "rawpartition", CTLTYPE_INT }, \
+ 	{ "nemuls", CTLTYPE_INT }, \
+ 	{ "emul", CTLTYPE_NODE }, \
  }
  
  /* 
***************
*** 203,208 ****
--- 207,226 ----
  		long	e_spare[4];
  	} kp_eproc;
  };
+ 
+ /*
+  * KERN_EMUL identifiers
+  */
+ #define KERN_EMUL_NAME		0	/* string: emulation name */
+ #define KERN_EMUL_MAXSYSCALL	1	/* int: maximum syscall# + 1 */
+ #define KERN_EMUL_SYSCALL	2	/* node: syscall table */
+ #define KERN_EMUL_MAXID		3
+ 
+ #define KERN_EMUL_NAMES { \
+ 	{ "name", CTLTYPE_STRING }, \
+ 	{ "maxsyscall", CTLTYPE_INT }, \
+ 	{ "syscall", CTLTYPE_NODE }, \
+ }
  
  /*
   * CTL_HW identifiers
*** old-NetBSD/src/sys/sys/systm.h
--- NetBSD/src/sys/sys/systm.h
***************
*** 98,104 ****
  	short	sy_argsize;	/* total size of arguments */
  	int	(*sy_call)();	/* implementing function */
  } sysent[];
- extern int nsysent;
  #define	SCARG(p,k)	((p)->k.datum)	/* get arg from args pointer */
  
  extern int boothowto;		/* reboot flags, from console subsystem */
--- 98,103 ----
*** /dev/null
--- NetBSD/src/usr.bin/file/magdir/ktrace
***************
*** 0 ****
--- 1,5 ----
+ 
+ #------------------------------------------------------------------------------
+ # archive:  file(1) magic for ktrace files
+ #
+ 0	long		0x3ace0100	ktrace(1) dump version 1.0
*** old-NetBSD/src/usr.bin/kdump/kdump.c
--- NetBSD/src/usr.bin/kdump/kdump.c
***************
*** 51,56 ****
--- 51,58 ----
  #include <sys/ktrace.h>
  #include <sys/ioctl.h>
  #include <sys/ptrace.h>
+ #include <sys/syscall.h>
+ #include <sys/sysctl.h>
  #define _KERNEL
  #include <sys/errno.h>
  #undef _KERNEL
***************
*** 94,105 ****
  #undef KTRACE
  
  struct emulation {
! 	char *name;		/* Emulation name */
  	char **sysnames;	/* Array of system call names */
! 	int  nsysnames;		/* Number of */
  };
  
! static struct emulation emulations[] = {
  	{ "netbsd",	     syscallnames,        SYS_MAXSYSCALL },
  	{ "hpux",	hpux_syscallnames,   HPUX_SYS_MAXSYSCALL },
  	{ "ibcs2",     ibcs2_syscallnames,  IBCS2_SYS_MAXSYSCALL },
--- 96,107 ----
  #undef KTRACE
  
  struct emulation {
! 	char *name;	/* Emulation name */
  	char **sysnames;	/* Array of system call names */
! 	int  nsysnames;	/* Number of system calls */
  };
  
! static struct emulation static_emulations[] = {
  	{ "netbsd",	     syscallnames,        SYS_MAXSYSCALL },
  	{ "hpux",	hpux_syscallnames,   HPUX_SYS_MAXSYSCALL },
  	{ "ibcs2",     ibcs2_syscallnames,  IBCS2_SYS_MAXSYSCALL },
***************
*** 111,118 ****
--- 113,142 ----
  	{ NULL,			     NULL,		    NULL }
  };
  
+ int nemul;
+ static struct emulation *emul = static_emulations;
+ 
+ struct emulation_map {
+ 	struct emulation_map *em_link;
+ 	pid_t		     em_pid;
+ 	struct emulation     *em_emulation;
+ };
+ 
+ /* Forward decls. */
+ struct emulation *emulation_from_name __P((char *name));
+ struct emulation *emulation_from_pid __P((pid_t pid));
+ void bind_emulation_to_pid __P((struct emulation *, pid_t));
+ void get_emulations __P((FILE *, char *));
+ 
+ /* A mapping between pids and emulations currently in charge.  */
+ struct emulation_map *current_emulations;
+ 
+ /* The current emulation (cache during a single trace event).  */
  struct emulation *current;
  
+ /* The default emulation, if nothing else is known.  */
+ struct emulation *default_emulation;
+ 
  
  static char *ptrace_ops[] = {
  	"PT_TRACE_ME",	"PT_READ_I",	"PT_READ_D",	"PT_READ_U",
***************
*** 128,140 ****
  	int ch, ktrlen, size;
  	register void *m;
  	int trpoints = ALL_POINTS;
  
! 	current = &emulations[0];	/* NetBSD */
  
  	while ((ch = getopt(argc, argv, "e:f:dlm:nRTt:")) != -1)
  		switch (ch) {
  		case 'e':
! 			setemul(optarg);
  			break;
  		case 'f':
  			tracefile = optarg;
--- 152,165 ----
  	int ch, ktrlen, size;
  	register void *m;
  	int trpoints = ALL_POINTS;
+ 	char *default_emulation_name;
  
! 	default_emulation_name = "netbsd";
  
  	while ((ch = getopt(argc, argv, "e:f:dlm:nRTt:")) != -1)
  		switch (ch) {
  		case 'e':
! 			default_emulation_name = optarg;
  			break;
  		case 'f':
  			tracefile = optarg;
***************
*** 176,182 ****
--- 201,210 ----
  		errx(1, "%s", strerror(ENOMEM));
  	if (!freopen(tracefile, "r", stdin))
  		err(1, "%s", tracefile);
+ 	get_emulations(stdin, tracefile);
+ 	default_emulation = emulation_from_name(default_emulation_name);
  	while (fread_tail(&ktr_header, sizeof(struct ktr_header), 1)) {
+ 		current = emulation_from_pid(ktr_header.ktr_pid);
  		if (trpoints & (1<<ktr_header.ktr_type))
  			dumpheader(&ktr_header);
  		if ((ktrlen = ktr_header.ktr_len) < 0)
***************
*** 211,217 ****
  			ktrcsw((struct ktr_csw *)m);
  			break;
  		case KTR_EMUL:
! 			ktremul(m, ktrlen);
  			break;
  		}
  		if (tail)
--- 239,245 ----
  			ktrcsw((struct ktr_csw *)m);
  			break;
  		case KTR_EMUL:
! 			ktremul(m, ktrlen, ktr_header.ktr_pid);
  			break;
  		}
  		if (tail)
***************
*** 381,388 ****
  	(void)printf("\"%.*s\"\n", len, cp);
  }
  
! ktremul(cp, len) 
  	char *cp;
  {
  	char name[1024];
  
--- 409,417 ----
  	(void)printf("\"%.*s\"\n", len, cp);
  }
  
! ktremul(cp, len, pid) 
  	char *cp;
+ 	pid_t pid;
  {
  	char name[1024];
  
***************
*** 393,399 ****
  	name[len] = '\0';
  	(void)printf("\"%s\"\n", name);
  
! 	setemul(name);
  }
  
  ktrgenio(ktr, len)
--- 422,428 ----
  	name[len] = '\0';
  	(void)printf("\"%s\"\n", name);
  
! 	bind_emulation_to_pid(emulation_from_name(name), pid);
  }
  
  ktrgenio(ktr, len)
***************
*** 484,497 ****
  	exit(1);
  }
  
! setemul(name)
  	char *name;
  {
  	int i;
! 	for (i = 0; emulations[i].name != NULL; i++)
! 		if (strcmp(emulations[i].name, name) == 0) {
! 			current = &emulations[i];
  			return;
  		}
! 	warnx("Emulation `%s' unknown", name);
  }
--- 513,618 ----
  	exit(1);
  }
  
! struct emulation *
! emulation_from_name(name)
  	char *name;
  {
  	int i;
! 
! 	for (i = 0; i < nemul; i++)
! 		if (eqs(emul[i].name, name))
! 			return emul + i;
! 	warnx("Emulation `%s' unknown, using default `%s'", name,
! 	    default_emulation->name);
! 	return default_emulation;
! }
! 
! struct emulation *
! emulation_from_pid(pid)
! 	pid_t pid;
! {
! 	struct emulation_map *entry;
! 
! 	for (entry = current_emulations; entry; entry = entry->em_link)
! 		if (entry->em_pid == pid)
! 			return entry->em_emulation;
! 	return default_emulation;
! }
! 
! void
! bind_emulation_to_pid(emulation, pid)
! 	struct emulation *emulation;
! 	pid_t            pid;
! {
! 	struct emulation_map *entry;
! 
! 	for (entry = current_emulations; entry; entry = entry->em_link)
! 		if (entry->em_pid == pid) {
! 			entry->em_emulation = emulation;
  			return;
  		}
! 	entry = current_emulations;
! 	current_emulations =
! 	    (struct emulation_map *)malloc(sizeof(struct emulation_map));
! 	if (current_emulations == NULL)
! 		errx(1, "%s", strerror(ENOMEM));
! 	current_emulations->em_link = entry;
! 	current_emulations->em_pid = pid;
! 	current_emulations->em_emulation = emulation;
! }
! 
! int
! get_int(f, tracefile)
! 	FILE *f;
! 	char *tracefile;
! {
! 	int i;
! 
! 	if (fread(&i, sizeof(i), 1, f) != 1)
! 		err(1, "%s", tracefile);
! 	return i;
! }
! 
! void
! get_emulations(f, tracefile)
! 	FILE *f;
! 	char *tracefile;
! {
! 	fpos_t start;
! 	int i;
! 	int j;
! 	int len;
! 
! 	if (fgetpos(f, &start))
! 		err(1, "%s", tracefile);
! 	if (get_int(f, tracefile) != KTRACE_MAGIC) {
! 		fsetpos(f, &start);
! 		return;
! 	      }
! 	nemul = get_int(f, tracefile);
! 	emul = (struct emulation *)malloc(nemul * sizeof(*emul));
! 	if (emul == NULL)
! 		errx(1, "%s", strerror(ENOMEM));
! 	for (i = 0; i < nemul; i++) {
! 		len = get_int(f, tracefile);
! 		emul[i].name = malloc(len + 1); 
! 		if (emul[i].name == NULL)
! 			errx(1, "%s", strerror(ENOMEM));
! 		if (fread(emul[i].name, sizeof(char), len, f) != len)
! 			err(1, "%s", tracefile);
! 		emul[i].nsysnames = get_int(f, tracefile);
! 		emul[i].sysnames = (char **)malloc(emul[i].nsysnames *
! 		    sizeof(*emul[i].sysnames));
! 		if (emul[i].sysnames == NULL)
! 			errx(1, "%s", strerror(ENOMEM));
! 		for (j = 0; j < emul[i].nsysnames; j++) {
! 			len = get_int(f, tracefile);
! 			emul[i].sysnames[j] = malloc(len + 1); 
! 			if (emul[i].sysnames[j] == NULL)
! 				errx(1, "%s", strerror(ENOMEM));
! 			if (fread(emul[i].sysnames[j], sizeof(char), len, f) !=
! 			    len)
! 				err(1, "%s", tracefile);
! 	        }
! 	}
  }
*** old-NetBSD/src/usr.bin/ktrace/ktrace.c
--- NetBSD/src/usr.bin/ktrace/ktrace.c
***************
*** 53,67 ****
--- 53,71 ----
  #include <sys/errno.h>
  #include <sys/uio.h>
  #include <sys/ktrace.h>
+ #include <sys/sysctl.h>
  
  #include <err.h>
  #include <stdio.h>
+ #include <stdlib.h>
  #include <unistd.h>
  
  #include "ktrace.h"
  
  void no_ktrace __P((int));
  void usage __P((void));
+ void dump_int __P((FILE *, char *, int));
+ void dump_sysctls __P((int, char *));
  
  main(argc, argv)
  	int argc;
***************
*** 140,145 ****
--- 144,151 ----
  	if ((fd = open(tracefile, O_CREAT | O_WRONLY | (append ? 0 : O_TRUNC),
  	    DEFFILEMODE)) < 0)
  		err(1, tracefile);
+ 	if (!append)
+ 		dump_sysctls(fd, tracefile);
  	(void)close(fd);
  
  	if (*argv) { 
***************
*** 184,187 ****
--- 190,309 ----
          (void)fprintf(stderr,
  "error:\tktrace() system call not supported in the running kernel\n\tre-compile kernel with 'options KTRACE'\n");
          exit(1);
+ }
+ 
+ void
+ dump_int(f, tracefile, i)
+ 	FILE *f;
+ 	char *tracefile;
+ 	int i;
+ {
+ 	/* Should we store this in arch-independent format?  */
+ 	if (fwrite(&i, sizeof(i), 1, f) != 1) {
+ 		unlink(tracefile);
+ 		err(1, "%s", tracefile);
+ 	}
+ }
+ 
+ void
+ dump_sysctls(fd, tracefile)
+ 	int fd;
+ 	char *tracefile;
+ {
+ 	FILE *f;
+ 	int mib[5];
+ 	int len;
+ 	int i;
+ 	int j;
+ 	int nemuls;
+ 	int size;
+ 	struct emul {
+ 		char *name;
+ 		int nsyscalls;
+ 		char **syscall;
+ 	} *emul;
+ 
+ 	f = fdopen(fd, "w");
+ 	if (f == NULL)
+ 		err(1, "%d", tracefile);
+ 
+ 	/* Number of emulations */
+ 	len = 0;
+ 	mib[len++] = CTL_KERN;
+ 	mib[len++] = KERN_NEMULS;
+ 	size = sizeof(nemuls);
+ 	if (sysctl(mib, len, &nemuls, &size, NULL, 0) < 0)
+ 		return;
+ 
+ 	/* Emulation table */
+ 	emul = (struct emul *)malloc(nemuls * sizeof(*emul));
+ 	if (emul == NULL)
+ 		errx(1, "%s", strerror(ENOMEM));
+ 	for (i = 0; i < nemuls; i++) {
+ 		/* Emulation name */
+ 		len = 0;
+ 		mib[len++] = CTL_KERN;
+ 		mib[len++] = KERN_EMUL;
+ 		mib[len++] = i;
+ 		mib[len++] = KERN_EMUL_NAME;
+ 		if (sysctl(mib, len, NULL, &size, NULL, 0) < 0)
+ 			return;
+ 		emul[i].name = malloc(size);
+ 		if (emul[i].name == NULL)
+ 			errx(1, "%s", strerror(ENOMEM));
+ 		if (sysctl(mib, len, emul[i].name, &size, NULL, 0) < 0)
+ 			return;
+ 
+ 		/* Number of syscalls */
+ 		len = 0;
+ 		mib[len++] = CTL_KERN;
+ 		mib[len++] = KERN_EMUL;
+ 		mib[len++] = i;
+ 		mib[len++] = KERN_EMUL_MAXSYSCALL;
+ 		size = sizeof(emul[i].nsyscalls);
+ 		if (sysctl(mib, len, &emul[i].nsyscalls, &size, NULL, 0) < 0)
+ 			return;
+ 
+ 		/* Syscalls */
+ 		emul[i].syscall = (char **)malloc(emul[i].nsyscalls *
+ 		    sizeof(*emul[i].syscall));
+ 		if (emul[i].syscall == NULL)
+ 			errx(1, "%s", strerror(ENOMEM));
+ 		for (j = 0; j < emul[i].nsyscalls; j++) {
+ 			len = 0;
+ 			mib[len++] = CTL_KERN;
+ 			mib[len++] = KERN_EMUL;
+ 			mib[len++] = i;
+ 			mib[len++] = KERN_EMUL_SYSCALL;
+ 			mib[len++] = j;
+ 			if (sysctl(mib, len, NULL, &size, NULL, 0) < 0)
+ 				return;
+ 			emul[i].syscall[j] = malloc(size);
+ 			if (emul[i].syscall[j] == NULL)
+ 				errx(1, "%s", strerror(ENOMEM));
+ 			if (sysctl(mib, len, emul[i].syscall[j], &size, NULL,
+ 			    0) < 0)
+ 				return;
+ 		}
+ 	}
+ 
+ 	/* Ok all info we need got extracted, now dump it.  */
+ 	dump_int(f, tracefile, KTRACE_MAGIC);
+ 	dump_int(f, tracefile, nemuls);
+ 	for (i = 0; i < nemuls; i++) {
+ 		dump_int(f, tracefile, strlen(emul[i].name));
+ 		if (fputs(emul[i].name, f) == EOF) {
+ 			unlink(tracefile);
+ 			err(1, "%s", tracefile);
+ 		}
+ 		dump_int(f, tracefile, emul[i].nsyscalls);
+ 		for (j = 0; j < emul[i].nsyscalls; j++) {
+ 			dump_int(f, tracefile, strlen(emul[i].syscall[j]));
+ 			if (fputs(emul[i].syscall[j], f) == EOF) {
+ 				unlink(tracefile);
+ 				err(1, "%s", tracefile);
+ 			}
+ 		}
+ 	}
+ 	fclose(f);
  }
*** old-NetBSD/src/usr.bin/ktrace/ktrace.h
--- NetBSD/src/usr.bin/ktrace/ktrace.h
***************
*** 40,42 ****
--- 40,44 ----
  #define ALL_POINTS (DEF_POINTS | KTRFAC_CSW)
  
  #define DEF_TRACEFILE	"ktrace.out"
+ 
+ #define KTRACE_MAGIC	0x3ace0100
*** old-NetBSD/src/usr.sbin/sysctl/sysctl.c
--- NetBSD/src/usr.sbin/sysctl/sysctl.c
***************
*** 269,274 ****
--- 269,277 ----
  		case KERN_BOOTTIME:
  			special |= BOOTTIME;
  			break;
+ 		case KERN_EMUL:
+ 			sysctl_emul(mib, &len, &type, &bufp, string);
+ 			break;
  		}
  		break;
  
***************
*** 573,576 ****
--- 576,613 ----
  	    "sysctl [-n] variable ...", "sysctl [-n] -w variable=value ...",
  	    "sysctl [-n] -a", "sysctl [-n] -A");
  	exit(1);
+ }
+ 
+ struct ctlname emulname[] = KERN_EMUL_NAMES;
+ struct list emullist = { emulname, KERN_EMUL_MAXID };
+ 
+ sysctl_emul(mib, lenp, typep, bufpp, string)
+ 	int *mib;
+ 	int *lenp;
+ 	int *typep;
+ 	char **bufpp;
+ 	char *string;
+ {
+ 	char *emulp;
+ 	char *syscallp;
+ 	int indx;
+ 
+ 	emulp = strsep (bufpp, ".");
+ 	if ((indx = findname(string, "fourth", bufpp, &emullist)) == -1)
+ 		return;
+ 	mib[(*lenp)++] = atoi(emulp);
+ 	mib[(*lenp)++] = indx;
+ 	switch (indx) {
+ 	case KERN_EMUL_NAME:
+ 	case KERN_EMUL_MAXSYSCALL:
+ 		*typep = emulname[indx].ctl_type;
+ 		break;
+ 	case KERN_EMUL_SYSCALL:
+ 		syscallp = strsep (bufpp, ".");
+ 		if (syscallp)
+ 			mib[(*lenp)++] = atoi(syscallp);
+ 		*typep = CTLTYPE_STRING;
+ 		break;
+ 	default:
+ 	}
  }
>Audit-Trail:
>Unformatted: