summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>2008-08-22 15:18:56 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>2008-08-22 15:18:56 +0000
commitf58dd4fe87fead2d644fc1341d7731fe34c75b13 (patch)
tree0e1c8bda49466845ec92f92ade36dd92d2239379 /usr.sbin
parentc1a84c1c712d13ee22082743780139fe2a4855f5 (diff)
Merge crunchgen & crunchhide (using name checking), and move to usr.sbin
next step is to not install it as two programs, but be even more clever
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/Makefile4
-rw-r--r--usr.sbin/crunchgen/Makefile15
-rw-r--r--usr.sbin/crunchgen/README89
-rw-r--r--usr.sbin/crunchgen/crunched_main.c104
-rw-r--r--usr.sbin/crunchgen/crunchgen.1291
-rw-r--r--usr.sbin/crunchgen/crunchgen.c1022
-rw-r--r--usr.sbin/crunchgen/crunchide.180
-rw-r--r--usr.sbin/crunchgen/crunchide.c351
-rw-r--r--usr.sbin/crunchgen/ecoff_hide.c62
-rw-r--r--usr.sbin/crunchgen/elf_hide.c474
-rw-r--r--usr.sbin/crunchgen/mkskel.sh17
11 files changed, 2507 insertions, 2 deletions
diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile
index a1113306f4a..af9a155f31b 100644
--- a/usr.sbin/Makefile
+++ b/usr.sbin/Makefile
@@ -1,9 +1,9 @@
-# $OpenBSD: Makefile,v 1.142 2008/06/15 04:44:30 sturm Exp $
+# $OpenBSD: Makefile,v 1.143 2008/08/22 15:18:54 deraadt Exp $
.include <bsd.own.mk>
SUBDIR= ac accton acpidump adduser amd apm apmd arp \
- authpf bgpctl bgpd bind chroot config cron dev_mkdb \
+ authpf bgpctl bgpd bind chroot config cron crunchgen dev_mkdb \
dhcpd dhcrelay dvmrpctl dvmrpd edquota eeprom faithd fdformat \
ftp-proxy gpioctl hostapd hotplugd httpd ifstated inetd iostat \
kgmon kvm_mkdb lpr mailwrapper map-mbone memconfig mopd mrinfo \
diff --git a/usr.sbin/crunchgen/Makefile b/usr.sbin/crunchgen/Makefile
new file mode 100644
index 00000000000..314174f33ba
--- /dev/null
+++ b/usr.sbin/crunchgen/Makefile
@@ -0,0 +1,15 @@
+# $OpenBSD: Makefile,v 1.1 2008/08/22 15:18:55 deraadt Exp $
+
+PROG= crunchgen
+MAN= crunchgen.1 crunchide.1
+SRCS= crunchgen.c crunched_skel.c \
+ crunchide.c elf_hide.c ecoff_hide.c
+CFLAGS+= -g -Wall
+CLEANFILES+= crunched_skel.c
+
+crunched_skel.c: crunched_main.c
+ sh ${.CURDIR}/mkskel.sh ${.CURDIR}/crunched_main.c > crunched_skel.c
+
+LINKS= ${BINDIR}/crunchgen ${BINDIR}/crunchide
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/crunchgen/README b/usr.sbin/crunchgen/README
new file mode 100644
index 00000000000..6b150b57225
--- /dev/null
+++ b/usr.sbin/crunchgen/README
@@ -0,0 +1,89 @@
+
+CRUNCH 0.3 README 7/23/94
+
+Crunch is available via anonymous ftp to ftp.cs.umd.edu in
+ pub/bsd/crunch-0.3.tar.gz
+
+WHAT'S NEW IN 0.3
+
+* The prototype awk script has been replaced by a more capable and
+ hopefully more robust C program.
+* No fragile template makefiles or dependencies on the details of the
+ bsd build environment.
+* You can build crunched binaries even with no sources on-line, you
+ just need the .o files. Crunchgen still will try to figure out as
+ much as possible on its own, but you can override its guessing by
+ specifying the list of .o files explicitly.
+* Crunch itself has been bmake'd and some man pages written, so it
+ should be ready to install.
+* Added patch for FreeBSD from Jordan Hubbard, plus the .conf files used
+ for the FreeBSD install floppies as examples.
+
+
+INTRODUCTION
+
+Crunch is a little package that helps create "crunched" binaries for use
+on boot, install, and fixit floppies. A crunched binary in this case is
+one where many programs have been linked together into one a.out file.
+The different programs are run depending on the value of argv[0], so
+hard links to the crunched binary suffice to simulate a perfectly normal
+system.
+
+As an example, I have created an 980K crunched "fixit" binary containing
+the following programs in their entirety:
+
+ cat chmod cp date dd df echo ed expr hostname kill ln ls mkdir
+ mt mv pwd rcp rm rmdir sh sleep stty sync test [ badsect
+ clri disklabel dump rdump dmesg fdisk fsck halt ifconfig init
+ mknod mount newfs ping reboot restore rrestore swapon umount
+ ftp rsh sed telnet rlogin vi cpio gzip gunzip gzcat
+
+Note carefully: vi, cpio, gzip, ed, sed, dump/restore, some networking
+utilities, and the disk management utilities, all in a binary small
+enough to fit on a 1.2 MB root filesystem floppy (albeit with the kernel
+on its own boot floppy). A more reasonable subset can be made to fit
+easily with a kernel for a decent one-disk fixit filesystem.
+
+The linking together of different programs by hand is an old
+space-saving technique. Crunch automates the process by building the
+necessary stub files and makefile for you (via the crunchgen program),
+and by doctoring the symbol tables of the component .o files to allow
+them to link without "symbol multiply defined" conflicts (via the
+crunchide program).
+
+
+BUILDING CRUNCH
+
+Just type make, then make install.
+
+Crunch was written and tested under NetBSD/i386, but should work under
+other PC BSD systems that use GNU ld.
+
+The crunchgen(1) and crunchide(1) man pages have more details on using
+crunch, and the examples subdirectory contains some working .conf files
+and a sample Makefile.
+
+CREDITS
+
+Thanks to the NetBSD team for a consistently high quality effort in
+bringing together a solid, state of the art development environment.
+
+Thanks to the FreeBSD guys; Rod Grimes, Nate Williams and Jordan
+Hubbard; and to Bruce Evans, for immediate and detailed feedback on
+crunch 0.1, and for pressing me to make the prototype more useable.
+
+Crunch was written for the Maruti Hard Real-Time Operating System
+project at the University of Maryland, to help make for better install
+and recovery procedures for our NetBSD-based development environment. It
+is copyright (c) 1994 by the University of Maryland under a UCB-style
+freely- redistributable notice. See the file COPYRIGHT for details.
+
+Please let me know of any problems or of enhancements you make to this
+package. I'm particularly interested in the details of what you found
+was good to put on your fixit or install disks. Thanks!
+
+Share and Enjoy,
+Jaime
+............................................................................
+: Stand on my shoulders, : jds@cs.umd.edu : James da Silva
+: not on my toes. : uunet!mimsy!jds : http://www.cs.umd.edu/users/jds
diff --git a/usr.sbin/crunchgen/crunched_main.c b/usr.sbin/crunchgen/crunched_main.c
new file mode 100644
index 00000000000..c0a7827f66f
--- /dev/null
+++ b/usr.sbin/crunchgen/crunched_main.c
@@ -0,0 +1,104 @@
+/* $OpenBSD: crunched_main.c,v 1.1 2008/08/22 15:18:55 deraadt Exp $ */
+
+/*
+ * Copyright (c) 1994 University of Maryland
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of U.M. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. U.M. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: James da Silva, Systems Design and Analysis Group
+ * Computer Science Department
+ * University of Maryland at College Park
+ */
+/*
+ * crunched_main.c - main program for crunched binaries, it branches to a
+ * particular subprogram based on the value of argv[0]. Also included
+ * is a little program invoked when the crunched binary is called via
+ * its EXECNAME. This one prints out the list of compiled-in binaries,
+ * or calls one of them based on argv[1]. This allows the testing of
+ * the crunched binary without creating all the links.
+ */
+#include <stdio.h>
+#include <string.h>
+
+struct stub {
+ char *name;
+ int (*f)();
+};
+
+extern struct stub entry_points[];
+
+int
+main(int argc, char *argv[], char **envp)
+{
+ char *slash, *basename;
+ struct stub *ep;
+
+ if (argv[0] == NULL || *argv[0] == '\0')
+ crunched_usage();
+
+ slash = strrchr(argv[0], '/');
+ basename = slash ? slash + 1 : argv[0];
+
+ for (ep = entry_points; ep->name != NULL; ep++)
+ if (!strcmp(basename, ep->name))
+ break;
+
+ if (ep->name)
+ return ep->f(argc, argv, envp);
+ else {
+ fprintf(stderr, "%s: %s not compiled in\n", EXECNAME, basename);
+ crunched_usage();
+ }
+}
+
+int
+crunched_main(int argc, char **argv, char **envp)
+{
+ struct stub *ep;
+ int columns, len;
+
+ if (argc <= 1)
+ crunched_usage();
+
+ return main(--argc, ++argv, envp);
+}
+
+int
+crunched_usage()
+{
+ int columns, len;
+ struct stub *ep;
+
+ fprintf(stderr,
+ "Usage: %s <prog> <args> ..., where <prog> is one of:\n",
+ EXECNAME);
+ columns = 0;
+ for (ep = entry_points; ep->name != NULL; ep++) {
+ len = strlen(ep->name) + 1;
+ if (columns + len < 80)
+ columns += len;
+ else {
+ fprintf(stderr, "\n");
+ columns = len;
+ }
+ fprintf(stderr, " %s", ep->name);
+ }
+ fprintf(stderr, "\n");
+ exit(1);
+}
diff --git a/usr.sbin/crunchgen/crunchgen.1 b/usr.sbin/crunchgen/crunchgen.1
new file mode 100644
index 00000000000..11237841ffc
--- /dev/null
+++ b/usr.sbin/crunchgen/crunchgen.1
@@ -0,0 +1,291 @@
+.\" $OpenBSD: crunchgen.1,v 1.1 2008/08/22 15:18:55 deraadt Exp $
+.\"
+.\"
+.\" Copyright (c) 1994 University of Maryland
+.\" All Rights Reserved.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and its
+.\" documentation for any purpose is hereby granted without fee, provided that
+.\" the above copyright notice appear in all copies and that both that
+.\" copyright notice and this permission notice appear in supporting
+.\" documentation, and that the name of U.M. not be used in advertising or
+.\" publicity pertaining to distribution of the software without specific,
+.\" written prior permission. U.M. makes no representations about the
+.\" suitability of this software for any purpose. It is provided "as is"
+.\" without express or implied warranty.
+.\"
+.\" U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+.\" BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+.\" IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" Author: James da Silva, Systems Design and Analysis Group
+.\" Computer Science Department
+.\" University of Maryland at College Park
+.\"
+.Dd $Mdocdate: August 22 2008 $
+.Dt CRUNCHGEN 1
+.Os
+.Sh NAME
+.Nm crunchgen
+.Nd generates build environment for a crunched binary
+.Sh SYNOPSIS
+.Nm crunchgen
+.Bk -words
+.Op Fl Efq
+.Op Fl c Ar c-file-name
+.Op Fl D Ar src-root
+.Op Fl e Ar exec-file-name
+.Op Fl L Ar lib-dir
+.Op Fl m Ar makefile-name
+.Op Fl O Ar objdir-name
+.Ar conf-file
+.Ek
+.Sh DESCRIPTION
+A crunched binary is a program made up of many other programs linked
+together into a single executable.
+The crunched binary main() function determines which component program
+to run by the contents of argv[0].
+The main reason to crunch programs together is for fitting as many programs
+as possible onto an installation or system recovery floppy.
+.Pp
+.Nm
+reads in the specifications in
+.Ar conf-file
+for a crunched binary, and generates a Makefile and accompanying
+top-level C source file that when built create the crunched executable
+file from the component programs.
+For each component program,
+.Nm
+can optionally attempt to determine the object (.o) files that make up
+the program from its source directory Makefile.
+This information is cached in a file named
+.Pa <conf-name>.cache
+between runs.
+.Nm
+uses the companion program
+.Xr crunchide 1
+to eliminate link-time conflicts between the component programs by
+hiding all unnecessary symbols.
+.Pp
+After
+.Nm
+is run, the crunched binary can be built by running
+.Dq make -f <conf-name>.mk .
+The component programs' object files must already be built.
+An
+.Dq objs
+target, included in the output makefile,
+will run make in each component program's source dir to build the object
+files for the user.
+This is not done automatically since in release engineering circumstances
+it is generally not desirable to be modifying objects in other directories.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl c Ar c-file-name
+Set output C file name to
+.Ar c-file-name .
+The default name is
+.Dq Ao conf-name Ac Ns \&.c .
+.It Fl D Ar src-root
+Assume that relative source directory specifications begin with
+.Ar src-root .
+.It Fl E
+Don't prepend stub names with an underscore.
+Used for architectures that don't have underscore prepended to symbol names.
+Example mips ELF.
+.It Fl e Ar exec-file-name
+Set crunched binary executable file name to
+.Ar exec-file-name .
+The default name is
+.Dq Aq conf-name .
+.It Fl f
+Flush cache.
+Forces the recalculation of cached parameters.
+.It Fl L Ar lib-dir
+Try to obtain libraries from
+.Ar lib-dir .
+.It Fl m Ar makefile-name
+Set output Makefile name to
+.Ar makefile-name .
+The default name is
+.Dq Ao conf-name Ac Ns \&.mk .
+.It Fl O Ar objdir-name
+Specify an object directory to use.
+It defaults to
+.Dq obj ,
+though for cross building purposes it can be used to specify
+obj.${HOST}.${MACHINE}.
+Normally used with the make variable ${MAKEOBJDIR}.
+.It Fl q
+Quiet operation.
+Status messages are suppressed.
+.El
+.Sh CRUNCHGEN CONFIGURATION FILE COMMANDS
+.Nm
+reads specifications from the
+.Ar conf-file
+that describe the components of the crunched binary.
+In its simplest use, the component program names are merely listed
+along with the top-level source directories in which their sources
+can be found.
+.Nm
+then calculates (via the source makefiles) and caches the
+list of object files and their locations.
+For more specialized situations, the user can specify by hand
+all the parameters that
+.Nm
+needs.
+.Pp
+The
+.Ar conf-file
+commands are as follows:
+.Bl -tag -width indent
+.It srcdirs Ar dirname ...
+A list of source trees in which the source directories of the
+component programs can be found.
+These dirs are searched using the BSD
+.Dq <source-dir>/<progname>/
+convention.
+Multiple srcdirs lines can be specified.
+The directories are searched in the order they are given.
+.It libdirs Ar dirname
+A list of source trees in which the source directories for supplementary
+libraries can be found.
+.It progs Ar progname ...
+A list of programs that make up the crunched binary.
+Multiple progs lines can be specified.
+.It libs Ar libspec ...
+A list of library specifications to be included in the crunched binary link.
+Multiple libs lines can be specified.
+.It ln Ar progname linkname
+Causes the crunched binary to invoke
+.Ar progname
+whenever
+.Ar linkname
+appears in argv[0].
+This allows programs that change their behavior when
+run under different names to operate correctly.
+.El
+.Pp
+To handle specialized situations, such as when the source is not
+available or not built via a conventional Makefile, the following
+.Ic special
+commands can be used to set
+.Nm
+parameters for a component program.
+.Bl -tag -width indent
+.It special Ar progname No srcdir Ar pathname
+Set the source directory for
+.Ar progname .
+This is normally calculated by searching the specified srcdirs
+for a directory named
+.Ar progname .
+.It special Ar progname No objdir Ar pathname
+Set the obj directory for
+.Ar progname .
+This is normally calculated by looking for a directory named
+.Dq obj
+under the
+.Ar srcdir ,
+and if that is not found, the
+.Ar srcdir
+itself becomes the objdir.
+.It special Ar progname No objs Ar object-file-name ...
+Set the list of object files for program
+.Ar progname .
+This is normally calculated by constructing a temporary makefile that includes
+.Dq srcdir/Makefile
+and outputs the value of $(OBJS).
+.It special Ar progname No objpaths Ar full-pathname-to-object-file ...
+Sets the pathnames of the object files for program
+.Ar progname .
+This is normally calculated by prepending the objdir
+pathname to each file in the objs list.
+.El
+.Pp
+Only the objpaths parameter is actually needed by
+.Nm crunchgen ,
+but it is calculated from objdir and objs,
+which are in turn calculated from srcdir,
+so it is sometimes convenient to specify the earlier parameters and let
+.Nm
+calculate forward from there if it can.
+.Pp
+The makefile produced by
+.Nm
+contains an optional
+.Ar objs
+target that will build the object files for each component program by
+running make inside that program's source directory.
+For this to work the srcdir and objs parameters must also be valid.
+If they are not valid for a particular program, that program is skipped in the
+.Ar objs
+target.
+.Sh EXAMPLES
+Here is an example
+.Nm
+input conf file, named
+.Pa kcopy.conf :
+.Bd -literal -offset indent
+srcdirs /usr/src/bin /usr/src/sbin
+
+progs test cp echo sh fsck halt init mount umount myinstall
+ln test [ # test can be invoked via [
+ln sh -sh # init invokes the shell with "-sh" in argv[0]
+
+special myprog objpaths /homes/leroy/src/myinstall.o # no sources
+
+libs -lutil -lcrypt
+.Ed
+.Pp
+This conf file specifies a small crunched binary consisting of some
+basic system utilities plus a home-grown install program
+.Dq myinstall ,
+for which no source directory is specified, but its object file is
+specified directly with the
+.Ic special
+line.
+.Pp
+The crunched binary
+.Dq kcopy
+can be built as follows:
+.Bd -literal -offset indent
+% crunchgen -m Makefile kcopy.conf # gen Makefile and kcopy.c
+% make objs # build the component programs' .o files
+% make # build the crunched binary kcopy
+% kcopy sh # test that this invokes a sh shell
+$ # it works!
+.Ed
+.Pp
+At this point the binary
+.Dq kcopy
+can be copied onto an install floppy
+and hard-linked to the names of the component programs.
+.Sh SEE ALSO
+.Xr crunchide 1
+.Sh AUTHORS
+.Nm
+was written by James da Silva
+.Aq jds@cs.umd.edu .
+.Pp
+Copyright (c) 1994 University of Maryland. All Rights Reserved.
+.Sh CAVEATS
+While
+.Nm
+takes care to eliminate link conflicts between the component programs
+of a crunched binary, conflicts are still possible between the
+libraries that are linked in.
+Some shuffling in the order of libraries may be required,
+and in some rare cases two libraries may
+have an unresolvable conflict and thus cannot be crunched together.
+.Pp
+Some versions of the BSD build environment do not by default build the
+intermediate object file for single-source file programs.
+The
+.Dq make objs
+target must then be used to get those object files built,
+or some other arrangements made.
diff --git a/usr.sbin/crunchgen/crunchgen.c b/usr.sbin/crunchgen/crunchgen.c
new file mode 100644
index 00000000000..7a4c6983b21
--- /dev/null
+++ b/usr.sbin/crunchgen/crunchgen.c
@@ -0,0 +1,1022 @@
+/* $OpenBSD: crunchgen.c,v 1.1 2008/08/22 15:18:55 deraadt Exp $ */
+
+/*
+ * Copyright (c) 1994 University of Maryland
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of U.M. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. U.M. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: James da Silva, Systems Design and Analysis Group
+ * Computer Science Department
+ * University of Maryland at College Park
+ */
+/*
+ * ========================================================================
+ * crunchgen.c
+ *
+ * Generates a Makefile and main C file for a crunched executable,
+ * from specs given in a .conf file.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+
+#define CRUNCH_VERSION "0.3"
+
+#define MAXLINELEN 16384
+#define MAXFIELDS 2048
+
+/* XXX - This should be runtime configurable */
+/*
+ * We might have more than one makefile
+ * name on any given platform. Make sure
+ * default name is last though.
+ */
+char *mf_name[] = {
+ "Makefile.bsd-wrapper",
+ "Makefile",
+ NULL
+};
+
+/* internal representation of conf file: */
+
+/* simple lists of strings suffice for most parms */
+
+typedef struct strlst {
+ struct strlst *next;
+ char *str;
+} strlst_t;
+
+/* progs have structure, each field can be set with "special" or calculated */
+
+typedef struct prog {
+ struct prog *next;
+ char *name, *ident, *mf_name;
+ char *srcdir, *objdir;
+ strlst_t *objs, *objpaths;
+ strlst_t *links;
+ int goterror;
+} prog_t;
+
+strlst_t *srcdirs = NULL;
+strlst_t *libs = NULL;
+strlst_t *libdirs = NULL;
+char objdir[MAXPATHLEN] = "obj";
+prog_t *progs = NULL;
+
+char line[MAXLINELEN];
+
+char confname[MAXPATHLEN], infilename[MAXPATHLEN];
+char outmkname[MAXPATHLEN], outcfname[MAXPATHLEN];
+char cachename[MAXPATHLEN], curfilename[MAXPATHLEN];
+char topdir[MAXPATHLEN], execfname[MAXPATHLEN];
+int linenum = -1;
+int goterror = 0;
+
+char *progname = "crunchgen";
+
+int verbose, readcache, elf_names; /* options */
+int reading_cache;
+
+void status(char *str);
+void out_of_memory(void);
+void add_string(strlst_t ** listp, char *str);
+int is_dir(char *pathname);
+int is_nonempty_file(char *pathname);
+void usage(void);
+void parse_conf_file(void);
+void gen_outputs(void);
+
+extern int crunchide_main(int, char *[]);
+
+int
+main(int argc, char *argv[])
+{
+ char *p;
+ int optc;
+ extern int optind;
+ extern char *optarg, *__progname;
+
+ verbose = 1;
+ readcache = 1;
+ *outmkname = *outcfname = *execfname = '\0';
+
+ if (argc > 0)
+ progname = argv[0];
+
+ if (strcmp(__progname, "crunchide") == 0)
+ return (crunchide_main(argc, argv));
+
+ while ((optc = getopt(argc, argv, "m:c:e:fqD:EL:O:")) != -1) {
+ switch (optc) {
+ case 'f':
+ readcache = 0;
+ break;
+ case 'q':
+ verbose = 0;
+ break;
+
+ case 'm':
+ if (strlcpy(outmkname, optarg, sizeof(outmkname)) >=
+ sizeof(outmkname))
+ usage();
+ break;
+ case 'c':
+ if (strlcpy(outcfname, optarg, sizeof(outcfname)) >=
+ sizeof(outcfname))
+ usage();
+ break;
+ case 'e':
+ if (strlcpy(execfname, optarg, sizeof(execfname)) >=
+ sizeof(execfname))
+ usage();
+ break;
+
+ case 'D':
+ if (strlcpy(topdir, optarg, sizeof(topdir)) >= sizeof(topdir))
+ usage();
+ break;
+ case 'E':
+ elf_names = 1;
+ break;
+ case 'L':
+ if (strlen(optarg) >= MAXPATHLEN)
+ usage();
+ add_string(&libdirs, optarg);
+ break;
+ case 'O':
+ if (strlcpy(objdir, optarg, sizeof(objdir)) >=
+ sizeof(objdir))
+ usage();
+ break;
+ default:
+ usage();
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 1)
+ usage();
+
+ if (libdirs == NULL)
+ add_string(&libdirs, "/usr/lib");
+ /*
+ * generate filenames
+ */
+
+ if (strlcpy(infilename, argv[0], sizeof(infilename)) >=
+ sizeof(infilename))
+ usage();
+
+ /* confname = `basename infilename .conf` */
+
+ if ((p = strrchr(infilename, '/')) != NULL)
+ strlcpy(confname, p + 1, sizeof confname);
+ else
+ strlcpy(confname, infilename, sizeof confname);
+ if ((p = strrchr(confname, '.')) != NULL && !strcmp(p, ".conf"))
+ *p = '\0';
+
+ if (!*outmkname)
+ snprintf(outmkname, sizeof(outmkname), "%s.mk", confname);
+ if (!*outcfname)
+ snprintf(outcfname, sizeof(outcfname), "%s.c", confname);
+ if (!*execfname)
+ snprintf(execfname, sizeof(execfname), "%s", confname);
+ snprintf(cachename, sizeof(cachename), "%s.cache", confname);
+
+ parse_conf_file();
+ gen_outputs();
+
+ exit(goterror);
+}
+
+void
+usage(void)
+{
+ fprintf(stderr,
+ "usage: %s [-Efq] [-c c-file-name] [-D src-root] [-e exec-file-name]\n"
+ "\t[-L lib-dir] [-m makefile-name] [-O objdir-name] conf-file\n",
+ progname);
+ exit(1);
+}
+
+void parse_one_file(char *filename);
+void parse_line(char *line, int *fc, char **fv, int nf);
+void add_srcdirs(int argc, char **argv);
+void add_progs(int argc, char **argv);
+void add_link(int argc, char **argv);
+void add_libs(int argc, char **argv);
+void add_libdirs(int argc, char **argv);
+void add_special(int argc, char **argv);
+
+prog_t *find_prog(char *str);
+void add_prog(char *progname);
+
+void
+parse_conf_file(void)
+{
+ if (!is_nonempty_file(infilename)) {
+ fprintf(stderr, "%s: fatal: input file \"%s\" not found.\n",
+ progname, infilename);
+ exit(1);
+ }
+ parse_one_file(infilename);
+ if (readcache && is_nonempty_file(cachename)) {
+ reading_cache = 1;
+ parse_one_file(cachename);
+ }
+}
+
+void
+parse_one_file(char *filename)
+{
+ char *fieldv[MAXFIELDS];
+ int fieldc;
+ void (*f) (int c, char **v);
+ FILE *cf;
+
+ snprintf(line, sizeof(line), "reading %s", filename);
+ status(line);
+ strlcpy(curfilename, filename, sizeof curfilename);
+
+ if ((cf = fopen(curfilename, "r")) == NULL) {
+ perror(curfilename);
+ goterror = 1;
+ return;
+ }
+ linenum = 0;
+ while (fgets(line, MAXLINELEN, cf) != NULL) {
+ linenum++;
+ parse_line(line, &fieldc, fieldv, MAXFIELDS);
+ if (fieldc < 1)
+ continue;
+ if (!strcmp(fieldv[0], "srcdirs"))
+ f = add_srcdirs;
+ else if (!strcmp(fieldv[0], "progs"))
+ f = add_progs;
+ else if (!strcmp(fieldv[0], "ln"))
+ f = add_link;
+ else if (!strcmp(fieldv[0], "libs"))
+ f = add_libs;
+ else if (!strcmp(fieldv[0], "special"))
+ f = add_special;
+ else if (!strcmp(fieldv[0], "libdirs"))
+ f = add_libdirs;
+ else {
+ fprintf(stderr, "%s:%d: skipping unknown command `%s'.\n",
+ curfilename, linenum, fieldv[0]);
+ goterror = 1;
+ continue;
+ }
+ if (fieldc < 2) {
+ fprintf(stderr,
+ "%s:%d: %s command needs at least 1 "
+ "argument, skipping.\n",
+ curfilename, linenum, fieldv[0]);
+ goterror = 1;
+ continue;
+ }
+ f(fieldc, fieldv);
+ }
+
+ if (ferror(cf)) {
+ perror(curfilename);
+ goterror = 1;
+ }
+ fclose(cf);
+}
+
+void
+parse_line(char *line, int *fc, char **fv, int nf)
+{
+ char *p;
+
+ p = line;
+ *fc = 0;
+ while (1) {
+ while (isspace(*p))
+ p++;
+ if (*p == '\0' || *p == '#')
+ break;
+
+ if (*fc < nf)
+ fv[(*fc)++] = p;
+ while (*p && !isspace(*p) && *p != '#')
+ p++;
+ if (*p == '\0' || *p == '#')
+ break;
+ *p++ = '\0';
+ }
+ if (*p)
+ *p = '\0'; /* needed for '#' case */
+}
+
+void
+add_srcdirs(int argc, char **argv)
+{
+ int i;
+ char tmppath[MAXPATHLEN];
+ int overflow;
+
+ for (i = 1; i < argc; i++) {
+ overflow = 0;
+ if (argv[i][0] == '/' || topdir[0] == '\0') {
+ if (strlcpy(tmppath, argv[i], sizeof(tmppath)) >=
+ sizeof(tmppath))
+ overflow = 1;
+ } else {
+ if (strlcpy(tmppath, topdir, sizeof(tmppath)) >=
+ sizeof(tmppath) ||
+ strlcat(tmppath, "/", sizeof(tmppath)) >=
+ sizeof(tmppath) ||
+ strlcat(tmppath, argv[i], sizeof(tmppath)) >=
+ sizeof(tmppath))
+ overflow = 1;
+ }
+ if (overflow) {
+ goterror = 1;
+ fprintf(stderr, "%s:%d: `%.40s...' is too long, skipping it.\n",
+ curfilename, linenum, argv[i]);
+ continue;
+ }
+ if (is_dir(tmppath))
+ add_string(&srcdirs, tmppath);
+ else {
+ fprintf(stderr, "%s:%d: `%s' is not a directory, skipping it.\n",
+ curfilename, linenum, tmppath);
+ goterror = 1;
+ }
+ }
+}
+
+void
+add_libdirs(int argc, char **argv)
+{
+ int i;
+ char tmppath[MAXPATHLEN];
+ char tmppath2[MAXPATHLEN];
+ int overflow;
+
+ for (i = 1; i < argc; i++) {
+ overflow = 0;
+ if (argv[i][0] == '/' || topdir[0] == '\0') {
+ if (strlcpy(tmppath, argv[i], sizeof(tmppath)) >=
+ sizeof(tmppath))
+ overflow = 1;
+ } else {
+ if (strlcpy(tmppath, topdir, sizeof(tmppath)) >=
+ sizeof(tmppath) ||
+ strlcat(tmppath, "/", sizeof(tmppath)) >=
+ sizeof(tmppath) ||
+ strlcat(tmppath, argv[i], sizeof(tmppath)) >=
+ sizeof(tmppath))
+ overflow = 1;
+ }
+ if (overflow) {
+ goterror = 1;
+ fprintf(stderr, "%s:%d: `%.40s...' is too long, skipping it.\n",
+ curfilename, linenum, argv[i]);
+ continue;
+ }
+ if (is_dir(tmppath)) {
+ snprintf(tmppath2, sizeof(tmppath2), "%s/%s", tmppath,
+ objdir);
+ if (is_dir(tmppath2))
+ add_string(&libdirs, tmppath2);
+ else {
+ snprintf(tmppath2, sizeof(tmppath2),
+ "%s/obj.%s", tmppath, MACHINE);
+ if (is_dir(tmppath2))
+ add_string(&libdirs, tmppath2);
+ else
+ add_string(&libdirs, tmppath);
+ }
+ }
+ else {
+ fprintf(stderr, "%s:%d: `%s' is not a directory, skipping it.\n",
+ curfilename, linenum, tmppath);
+ goterror = 1;
+ }
+ }
+}
+
+
+void
+add_progs(int argc, char **argv)
+{
+ int i;
+
+ for (i = 1; i < argc; i++)
+ add_prog(argv[i]);
+}
+
+void
+add_prog(char *progname)
+{
+ prog_t *p1, *p2;
+
+ /* add to end, but be smart about dups */
+
+ for (p1 = NULL, p2 = progs; p2 != NULL; p1 = p2, p2 = p2->next)
+ if (!strcmp(p2->name, progname))
+ return;
+
+ p2 = calloc(1, sizeof(prog_t));
+ if (p2)
+ p2->name = strdup(progname);
+ if (!p2 || !p2->name)
+ out_of_memory();
+
+ p2->next = NULL;
+ if (p1 == NULL)
+ progs = p2;
+ else
+ p1->next = p2;
+
+ p2->ident = p2->srcdir = p2->objdir = NULL;
+ p2->links = p2->objs = NULL;
+ p2->goterror = 0;
+}
+
+void
+add_link(int argc, char **argv)
+{
+ int i;
+ prog_t *p = find_prog(argv[1]);
+
+ if (p == NULL) {
+ fprintf(stderr,
+ "%s:%d: no prog %s previously declared, skipping link.\n",
+ curfilename, linenum, argv[1]);
+ goterror = 1;
+ return;
+ }
+ for (i = 2; i < argc; i++)
+ add_string(&p->links, argv[i]);
+}
+
+void
+add_libs(int argc, char **argv)
+{
+ int i;
+
+ for (i = 1; i < argc; i++)
+ add_string(&libs, argv[i]);
+}
+
+void
+add_special(int argc, char **argv)
+{
+ int i;
+ prog_t *p = find_prog(argv[1]);
+
+ if (p == NULL) {
+ if (reading_cache)
+ return;
+ fprintf(stderr,
+ "%s:%d: no prog %s previously declared, skipping special.\n",
+ curfilename, linenum, argv[1]);
+ goterror = 1;
+ return;
+ }
+ if (!strcmp(argv[2], "ident")) {
+ if (argc != 4)
+ goto argcount;
+ if ((p->ident = strdup(argv[3])) == NULL)
+ out_of_memory();
+ } else if (!strcmp(argv[2], "srcdir")) {
+ if (argc != 4)
+ goto argcount;
+ if ((p->srcdir = strdup(argv[3])) == NULL)
+ out_of_memory();
+ } else if (!strcmp(argv[2], "mf_name")) {
+ if (argc != 4)
+ goto argcount;
+ if ((p->mf_name = strdup(argv[3])) == NULL)
+ out_of_memory();
+ } else if (!strcmp(argv[2], "objdir")) {
+ if (argc != 4)
+ goto argcount;
+ if ((p->objdir = strdup(argv[3])) == NULL)
+ out_of_memory();
+ } else if (!strcmp(argv[2], "objs")) {
+ p->objs = NULL;
+ for (i = 3; i < argc; i++)
+ add_string(&p->objs, argv[i]);
+ } else if (!strcmp(argv[2], "objpaths")) {
+ p->objpaths = NULL;
+ for (i = 3; i < argc; i++)
+ add_string(&p->objpaths, argv[i]);
+ } else {
+ fprintf(stderr, "%s:%d: bad parameter name `%s', skipping line.\n",
+ curfilename, linenum, argv[2]);
+ goterror = 1;
+ }
+ return;
+
+argcount:
+ fprintf(stderr,
+ "%s:%d: too %s arguments, expected \"special %s %s <string>\".\n",
+ curfilename, linenum, argc < 4 ? "few" : "many", argv[1], argv[2]);
+ goterror = 1;
+}
+
+prog_t *
+find_prog(char *str)
+{
+ prog_t *p;
+
+ for (p = progs; p != NULL; p = p->next)
+ if (!strcmp(p->name, str))
+ return p;
+ return NULL;
+}
+
+void remove_error_progs(void);
+void fillin_program(prog_t * p);
+void gen_specials_cache(void);
+void gen_output_makefile(void);
+void gen_output_cfile(void);
+
+void fillin_program_objs(prog_t * p, char *path);
+void top_makefile_rules(FILE * outmk);
+void prog_makefile_rules(FILE * outmk, prog_t * p);
+void output_strlst(FILE * outf, strlst_t * lst);
+char *genident(char *str);
+char *dir_search(char *progname);
+
+void
+gen_outputs(void)
+{
+ prog_t *p;
+
+ for (p = progs; p != NULL; p = p->next)
+ fillin_program(p);
+
+ remove_error_progs();
+ gen_specials_cache();
+ gen_output_cfile();
+ gen_output_makefile();
+ status("");
+ fprintf(stderr,
+ "Run \"make -f %s objs exe\" to build crunched binary.\n",
+ outmkname);
+}
+
+void
+fillin_program(prog_t * p)
+{
+ char path[MAXPATHLEN];
+ char *srcparent;
+ strlst_t *s;
+ int i;
+
+ snprintf(line, sizeof(line), "filling in parms for %s", p->name);
+ status(line);
+
+ if (!p->ident)
+ p->ident = genident(p->name);
+ if (!p->srcdir) {
+ srcparent = dir_search(p->name);
+ if (srcparent)
+ snprintf(path, sizeof(path), "%s/%s", srcparent, p->name);
+ if (is_dir(path))
+ p->srcdir = strdup(path);
+ }
+ if (!p->objdir && p->srcdir) {
+ snprintf(path, sizeof(path), "%s/%s", p->srcdir, objdir);
+ if (is_dir(path))
+ p->objdir = strdup(path);
+ else {
+ snprintf(path, sizeof(path), "%s/obj.%s", p->srcdir, MACHINE);
+ if (is_dir(path))
+ p->objdir = strdup(path);
+ else
+ p->objdir = p->srcdir;
+ }
+ }
+ /* We have a sourcedir and no explicit objs, try */
+ /* to find makefile and get objs from it. */
+ if (p->srcdir && !p->objs) {
+ for (i = 0; mf_name[i] != NULL; i++) {
+ snprintf(path, sizeof(path), "%s/%s", p->srcdir, mf_name[i]);
+ if (is_nonempty_file(path)) {
+ p->mf_name = mf_name[i];
+ fillin_program_objs(p, path);
+ break;
+ }
+ }
+ }
+ if (!p->objpaths && p->objdir && p->objs)
+ for (s = p->objs; s != NULL; s = s->next) {
+ snprintf(line, sizeof(line), "%s/%s", p->objdir, s->str);
+ add_string(&p->objpaths, line);
+ }
+
+ if (!p->srcdir && verbose)
+ fprintf(stderr, "%s: %s: warning: could not find source directory.\n",
+ infilename, p->name);
+ if (!p->objs && verbose)
+ fprintf(stderr, "%s: %s: warning: could not find any .o files.\n",
+ infilename, p->name);
+
+ if (!p->objpaths) {
+ fprintf(stderr,
+ "%s: %s: error: no objpaths specified or calculated.\n",
+ infilename, p->name);
+ p->goterror = goterror = 1;
+ }
+}
+
+void
+fillin_program_objs(prog_t * p, char *path)
+{
+ char *cp, *obj, tempfname[MAXPATHLEN];
+ int fd, rc;
+ FILE *f;
+
+ /* discover the objs from the srcdir Makefile */
+
+ snprintf(tempfname, sizeof(tempfname), ".tmp_%sXXXXXXXXXX", confname);
+ if ((fd = mkstemp(tempfname)) == -1 || (f = fdopen(fd, "w")) == NULL) {
+ if (fd != -1)
+ close(fd);
+ perror(tempfname);
+ goterror = 1;
+ return;
+ }
+ fprintf(f, ".include \"%s\"\n", path);
+ fprintf(f, ".if defined(PROG) && !defined(OBJS)\n");
+ fprintf(f, "OBJS=${PROG}.o\n");
+ fprintf(f, ".endif\n");
+ fprintf(f, "crunchgen_objs:\n\t@echo 'OBJS= '${OBJS}\n");
+ fclose(f);
+
+ snprintf(line, sizeof(line), "make -f %s crunchgen_objs 2>&1", tempfname);
+ if ((f = popen(line, "r")) == NULL) {
+ perror("submake pipe");
+ goterror = 1;
+ return;
+ }
+ while (fgets(line, MAXLINELEN, f)) {
+ if (strncmp(line, "OBJS= ", 6)) {
+ if (strcmp(line,
+ "sh: warning: running as root with dot in PATH\n") == 0)
+ continue;
+ fprintf(stderr, "make error: %s", line);
+ goterror = 1;
+ continue;
+ }
+ cp = line + 6;
+ while (isspace(*cp))
+ cp++;
+ while (*cp) {
+ obj = cp;
+ while (*cp && !isspace(*cp))
+ cp++;
+ if (*cp)
+ *cp++ = '\0';
+ add_string(&p->objs, obj);
+ while (isspace(*cp))
+ cp++;
+ }
+ }
+ if ((rc = pclose(f)) != 0) {
+ fprintf(stderr, "make error: make returned %d\n", rc);
+ goterror = 1;
+ }
+ unlink(tempfname);
+}
+
+void
+remove_error_progs(void)
+{
+ prog_t *p1, *p2;
+
+ p1 = NULL;
+ p2 = progs;
+ while (p2 != NULL) {
+ if (!p2->goterror)
+ p1 = p2, p2 = p2->next;
+ else {
+ /* delete it from linked list */
+ fprintf(stderr, "%s: %s: ignoring program because of errors.\n",
+ infilename, p2->name);
+ if (p1)
+ p1->next = p2->next;
+ else
+ progs = p2->next;
+ p2 = p2->next;
+ }
+ }
+}
+
+void
+gen_specials_cache(void)
+{
+ FILE *cachef;
+ prog_t *p;
+
+ snprintf(line, sizeof(line), "generating %s", cachename);
+ status(line);
+
+ if ((cachef = fopen(cachename, "w")) == NULL) {
+ perror(cachename);
+ goterror = 1;
+ return;
+ }
+ fprintf(cachef, "# %s - parm cache generated from %s by crunchgen %s\n\n",
+ cachename, infilename, CRUNCH_VERSION);
+
+ for (p = progs; p != NULL; p = p->next) {
+ fprintf(cachef, "\n");
+ if (p->srcdir)
+ fprintf(cachef, "special %s srcdir %s\n", p->name, p->srcdir);
+ if (p->mf_name)
+ fprintf(cachef, "special %s mf_name %s\n", p->name, p->mf_name);
+ if (p->objdir)
+ fprintf(cachef, "special %s objdir %s\n", p->name, p->objdir);
+ if (p->objs) {
+ fprintf(cachef, "special %s objs", p->name);
+ output_strlst(cachef, p->objs);
+ }
+ fprintf(cachef, "special %s objpaths", p->name);
+ output_strlst(cachef, p->objpaths);
+ }
+ fclose(cachef);
+}
+
+void
+gen_output_makefile(void)
+{
+ prog_t *p;
+ FILE *outmk;
+
+ snprintf(line, sizeof(line), "generating %s", outmkname);
+ status(line);
+
+ if ((outmk = fopen(outmkname, "w")) == NULL) {
+ perror(outmkname);
+ goterror = 1;
+ return;
+ }
+ fprintf(outmk, "# %s - generated from %s by crunchgen %s\n\n",
+ outmkname, infilename, CRUNCH_VERSION);
+
+ top_makefile_rules(outmk);
+
+ for (p = progs; p != NULL; p = p->next)
+ prog_makefile_rules(outmk, p);
+
+ fprintf(outmk, "\n# ========\n");
+ fclose(outmk);
+}
+
+void
+gen_output_cfile(void)
+{
+ extern char *crunched_skel[];
+ char **cp;
+ FILE *outcf;
+ prog_t *p;
+ strlst_t *s;
+
+ snprintf(line, sizeof(line), "generating %s", outcfname);
+ status(line);
+
+ if ((outcf = fopen(outcfname, "w")) == NULL) {
+ perror(outcfname);
+ goterror = 1;
+ return;
+ }
+ fprintf(outcf, "/* %s - generated from %s by crunchgen %s */\n",
+ outcfname, infilename, CRUNCH_VERSION);
+
+ fprintf(outcf, "#define EXECNAME \"%s\"\n", execfname);
+ for (cp = crunched_skel; *cp != NULL; cp++)
+ fprintf(outcf, "%s\n", *cp);
+
+ for (p = progs; p != NULL; p = p->next)
+ fprintf(outcf, "extern int _crunched_%s_stub();\n", p->ident);
+
+ fprintf(outcf, "\nstruct stub entry_points[] = {\n");
+ for (p = progs; p != NULL; p = p->next) {
+ fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n",
+ p->name, p->ident);
+ for (s = p->links; s != NULL; s = s->next)
+ fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n",
+ s->str, p->ident);
+ }
+
+ fprintf(outcf, "\t{ EXECNAME, crunched_main },\n");
+ fprintf(outcf, "\t{ NULL, NULL }\n};\n");
+ fclose(outcf);
+}
+
+char *
+genident(char *str)
+{
+ char *n, *s, *d;
+
+ /*
+ * generates a Makefile/C identifier from a program name, mapping '-' to
+ * '_' and ignoring all other non-identifier characters. This leads to
+ * programs named "foo.bar" and "foobar" to map to the same identifier.
+ */
+
+ if ((n = strdup(str)) == NULL)
+ return NULL;
+ for (d = s = n; *s != '\0'; s++) {
+ if (*s == '-')
+ *d++ = '_';
+ else if (*s == '_' || isalnum(*s))
+ *d++ = *s;
+ }
+ *d = '\0';
+ return n;
+}
+
+char *
+dir_search(char *progname)
+{
+ char path[MAXPATHLEN];
+ strlst_t *dir;
+
+ for (dir = srcdirs; dir != NULL; dir = dir->next) {
+ snprintf(path, sizeof(path), "%s/%s", dir->str, progname);
+ if (is_dir(path))
+ return dir->str;
+ }
+ return NULL;
+}
+
+void
+top_makefile_rules(FILE * outmk)
+{
+ prog_t *p;
+ strlst_t *l;
+
+
+ fprintf(outmk, "STRIP?=strip\n");
+ fprintf(outmk, "LINK=$(LD) -dc -r\n");
+ fprintf(outmk, "LIBS=");
+ for (l = libdirs; l != NULL; l = l->next)
+ fprintf(outmk, " -L%s", l->str);
+ output_strlst(outmk, libs);
+
+ fprintf(outmk, "CRUNCHED_OBJS=");
+ for (p = progs; p != NULL; p = p->next)
+ fprintf(outmk, " %s.lo", p->name);
+ fprintf(outmk, "\n");
+
+ fprintf(outmk, "SUBMAKE_TARGETS=");
+ for (p = progs; p != NULL; p = p->next)
+ fprintf(outmk, " %s_make", p->ident);
+ fprintf(outmk, "\n\n");
+
+ fprintf(outmk, "%s: %s.o $(CRUNCHED_OBJS)\n",
+ execfname, execfname);
+ fprintf(outmk, "\t$(CC) -static -o $@ %s.o $(CRUNCHED_OBJS) $(LIBS)\n",
+ execfname);
+ fprintf(outmk, "\t$(STRIP) %s\n", execfname);
+ fprintf(outmk, "all: objs exe\nobjs: $(SUBMAKE_TARGETS)\n");
+ fprintf(outmk, "exe: %s\n", execfname);
+ fprintf(outmk, "clean:\n\trm -f %s *.lo *.o *_stub.c\n",
+ execfname);
+ fprintf(outmk, ".PHONY: all objs exe clean $(SUBMAKE_TARGETS)\n\n");
+}
+
+void
+prog_makefile_rules(FILE * outmk, prog_t * p)
+{
+ fprintf(outmk, "\n# -------- %s\n\n", p->name);
+
+ if (p->srcdir && p->objs) {
+ fprintf(outmk, "%s_SRCDIR=%s\n", p->ident, p->srcdir);
+ fprintf(outmk, "%s_OBJS=", p->ident);
+ output_strlst(outmk, p->objs);
+ fprintf(outmk, "%s_make:\n", p->ident);
+ fprintf(outmk, "\tcd $(%s_SRCDIR) && exec $(MAKE) -f %s $(%s_OBJS)\n\n",
+ p->ident, p->mf_name, p->ident);
+ } else
+ fprintf(outmk, "%s_make:\n\t@echo \"** cannot make objs for %s\"\n\n",
+ p->ident, p->name);
+
+ fprintf(outmk, "%s_OBJPATHS=", p->ident);
+ output_strlst(outmk, p->objpaths);
+
+ fprintf(outmk, "%s_stub.c:\n", p->name);
+ fprintf(outmk, "\techo \""
+ "int _crunched_%s_stub(int argc, char **argv, char **envp)"
+ "{return main(argc,argv,envp);}\" >$@\n",
+ p->ident);
+ fprintf(outmk, "%s.lo: %s_stub.o $(%s_OBJPATHS)\n",
+ p->name, p->name, p->ident);
+ fprintf(outmk, "\t$(LINK) -o $@ %s_stub.o $(%s_OBJPATHS)\n",
+ p->name, p->ident);
+ fprintf(outmk, "\tcrunchide -k %s_crunched_%s_stub $@\n",
+ elf_names ? "" : "_", p->ident);
+}
+
+void
+output_strlst(FILE * outf, strlst_t * lst)
+{
+ for (; lst != NULL; lst = lst->next)
+ fprintf(outf, " %s", lst->str);
+ fprintf(outf, "\n");
+}
+
+void
+status(char *str)
+{
+ static int lastlen = 0;
+ int len, spaces;
+
+ if (!verbose)
+ return;
+
+ len = strlen(str);
+ spaces = lastlen - len;
+ if (spaces < 1)
+ spaces = 1;
+
+ fprintf(stderr, " [%s]%*.*s\r", str, spaces, spaces, " ");
+ fflush(stderr);
+ lastlen = len;
+}
+
+void
+out_of_memory(void)
+{
+ fprintf(stderr, "%s: %d: out of memory, stopping.\n", infilename, linenum);
+ exit(1);
+}
+
+void
+add_string(strlst_t ** listp, char *str)
+{
+ strlst_t *p1, *p2;
+
+ /* add to end, but be smart about dups */
+
+ for (p1 = NULL, p2 = *listp; p2 != NULL; p1 = p2, p2 = p2->next)
+ if (!strcmp(p2->str, str))
+ return;
+
+ p2 = calloc(1, sizeof(strlst_t));
+ if (p2)
+ p2->str = strdup(str);
+ if (!p2 || !p2->str)
+ out_of_memory();
+
+ p2->next = NULL;
+ if (p1 == NULL)
+ *listp = p2;
+ else
+ p1->next = p2;
+}
+
+int
+is_dir(char *pathname)
+{
+ struct stat buf;
+
+ if (stat(pathname, &buf) == -1)
+ return 0;
+ return S_ISDIR(buf.st_mode);
+}
+
+int
+is_nonempty_file(char *pathname)
+{
+ struct stat buf;
+
+ if (stat(pathname, &buf) == -1)
+ return 0;
+
+ return S_ISREG(buf.st_mode) && buf.st_size > 0;
+}
diff --git a/usr.sbin/crunchgen/crunchide.1 b/usr.sbin/crunchgen/crunchide.1
new file mode 100644
index 00000000000..2f9b4082dc7
--- /dev/null
+++ b/usr.sbin/crunchgen/crunchide.1
@@ -0,0 +1,80 @@
+.\" $OpenBSD: crunchide.1,v 1.1 2008/08/22 15:18:55 deraadt Exp $
+.\"
+.\"
+.\" Copyright (c) 1994 University of Maryland
+.\" All Rights Reserved.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and its
+.\" documentation for any purpose is hereby granted without fee, provided that
+.\" the above copyright notice appear in all copies and that both that
+.\" copyright notice and this permission notice appear in supporting
+.\" documentation, and that the name of U.M. not be used in advertising or
+.\" publicity pertaining to distribution of the software without specific,
+.\" written prior permission. U.M. makes no representations about the
+.\" suitability of this software for any purpose. It is provided "as is"
+.\" without express or implied warranty.
+.\"
+.\" U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+.\" BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+.\" IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" Author: James da Silva, Systems Design and Analysis Group
+.\" Computer Science Department
+.\" University of Maryland at College Park
+.\"
+.Dd $Mdocdate: August 22 2008 $
+.Dt CRUNCHIDE 1
+.Os
+.Sh NAME
+.Nm crunchide
+.Nd hides symbol names from ld, for crunching programs together
+.Sh SYNOPSIS
+.Nm crunchide
+.Op Fl f Ar keep-list-file
+.Op Fl k Ar keep-symbol
+.Ar object-file ...
+.Sh DESCRIPTION
+.Nm
+hides the global symbols of
+.Ar object-file
+such that they are ignored by subsequent runs of the linker,
+.Xr ld 1 .
+Some symbols may be left visible via the
+.Fl k Ar keep-symbol
+and
+.Fl f Ar keep-list-file
+options.
+The
+.Ar keep-list-file
+must contain a list of symbols to keep visible, one symbol per line.
+Note that the C compiler prepends an underscore in front of
+symbols, so to keep the C function ``foo'' visible, the option
+.Dq -k _foo
+must be used.
+.Pp
+.Nm
+is designed as a companion program for
+.Xr crunchgen 1 ,
+which automates the process of creating crunched binaries from
+multiple component programs.
+.Sh NOTES
+The ELF version of
+.Nm crunchide
+mangles the symbol table beyond recognition.
+It is therefore not advisable to try to run
+.Xr nm 1
+on a crunched object file.
+This is due to the nature of the ELF symbol table
+and how some arches uses the symbol attributes for their GOT build.
+.Sh SEE ALSO
+.Xr crunchgen 1 ,
+.Xr ld 1
+.Sh AUTHORS
+.Nm
+was written by James da Silva
+.Aq jds@cs.umd.edu .
+.Pp
+Copyright (c) 1994 University of Maryland. All Rights Reserved.
diff --git a/usr.sbin/crunchgen/crunchide.c b/usr.sbin/crunchgen/crunchide.c
new file mode 100644
index 00000000000..3c74a0da7bb
--- /dev/null
+++ b/usr.sbin/crunchgen/crunchide.c
@@ -0,0 +1,351 @@
+/* $OpenBSD: crunchide.c,v 1.1 2008/08/22 15:18:55 deraadt Exp $ */
+
+/*
+ * Copyright (c) 1994 University of Maryland
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of U.M. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. U.M. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: James da Silva, Systems Design and Analysis Group
+ * Computer Science Department
+ * University of Maryland at College Park
+ */
+/*
+ * crunchide.c - tiptoes through an a.out symbol table, hiding all defined
+ * global symbols. Allows the user to supply a "keep list" of symbols
+ * that are not to be hidden. This program relies on the use of the
+ * linker's -dc flag to actually put global bss data into the file's
+ * bss segment (rather than leaving it as undefined "common" data).
+ *
+ * The point of all this is to allow multiple programs to be linked
+ * together without getting multiple-defined errors.
+ *
+ * For example, consider a program "foo.c". It can be linked with a
+ * small stub routine, called "foostub.c", eg:
+ * int foo_main(int argc, char **argv){ return main(argc, argv); }
+ * like so:
+ * cc -c foo.c foostub.c
+ * ld -dc -r foo.o foostub.o -o foo.combined.o
+ * crunchide -k _foo_main foo.combined.o
+ * at this point, foo.combined.o can be linked with another program
+ * and invoked with "foo_main(argc, argv)". foo's main() and any
+ * other globals are hidden and will not conflict with other symbols.
+ *
+ * TODO:
+ * - resolve the theoretical hanging reloc problem (see check_reloc()
+ * below). I have yet to see this problem actually occur in any real
+ * program. In what cases will gcc/gas generate code that needs a
+ * relative reloc from a global symbol, other than PIC? The
+ * solution is to not hide the symbol from the linker in this case,
+ * but to generate some random name for it so that it doesn't link
+ * with anything but holds the place for the reloc.
+ * - arrange that all the BSS segments start at the same address, so
+ * that the final crunched binary BSS size is the max of all the
+ * component programs' BSS sizes, rather than their sum.
+ */
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <a.out.h>
+#include <sys/types.h>
+#ifdef _NLIST_DO_ECOFF
+#include <sys/exec_ecoff.h>
+#endif
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+/*
+ * if __ELF__ is defined, do not bother supporting AOUT.
+ */
+#if defined(_NLIST_DO_AOUT) && !(defined(__ELF__))
+#define DO_AOUT
+#endif
+
+void crunchide_usage(void);
+
+void add_to_keep_list(char *);
+void add_file_to_keep_list(char *);
+
+void hide_syms(char *);
+#ifdef _NLIST_DO_ECOFF
+void ecoff_hide(int, char *);
+#endif
+#ifdef _NLIST_DO_ELF
+void elf_hide(int, char *);
+#endif
+
+extern char *__progname;
+
+int
+crunchide_main(int argc, char *argv[])
+{
+ int ch;
+
+ while ((ch = getopt(argc, argv, "k:f:")) != -1)
+ switch (ch) {
+ case 'k':
+ add_to_keep_list(optarg);
+ break;
+ case 'f':
+ add_file_to_keep_list(optarg);
+ break;
+ default:
+ crunchide_usage();
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0)
+ crunchide_usage();
+
+ while (argc) {
+ hide_syms(*argv);
+ argc--;
+ argv++;
+ }
+
+ return 0;
+}
+
+void
+crunchide_usage(void)
+{
+ fprintf(stderr,
+ "usage: crunchide [-f keep-list-file] [-k keep-symbol] object-file ...\n");
+ exit(1);
+}
+
+struct keep {
+ struct keep *next;
+ char *sym;
+} *keep_list;
+
+void
+add_to_keep_list(char *symbol)
+{
+ struct keep *newp, *prevp, *curp;
+ int cmp;
+
+ for (curp = keep_list, prevp = NULL; curp; prevp = curp, curp = curp->next)
+ if ((cmp = strcmp(symbol, curp->sym)) <= 0)
+ break;
+
+ if (curp && cmp == 0)
+ return; /* already in table */
+
+ newp = (struct keep *) calloc(1, sizeof(struct keep));
+ if (newp)
+ newp->sym = strdup(symbol);
+ if (newp == NULL || newp->sym == NULL) {
+ fprintf(stderr, "%s: out of memory for keep list\n", __progname);
+ exit(1);
+ }
+ newp->next = curp;
+ if (prevp)
+ prevp->next = newp;
+ else
+ keep_list = newp;
+}
+
+int
+in_keep_list(char *symbol)
+{
+ struct keep *curp;
+ int cmp = 0;
+
+ for (curp = keep_list; curp; curp = curp->next)
+ if ((cmp = strcmp(symbol, curp->sym)) <= 0)
+ break;
+
+ return curp && cmp == 0;
+}
+
+void
+add_file_to_keep_list(char *filename)
+{
+ FILE *keepf;
+ char symbol[1024];
+ int len;
+
+ if ((keepf = fopen(filename, "r")) == NULL) {
+ perror(filename);
+ crunchide_usage();
+ }
+ while (fgets(symbol, sizeof(symbol), keepf)) {
+ len = strlen(symbol);
+ if (len && symbol[len - 1] == '\n')
+ symbol[len - 1] = '\0';
+
+ add_to_keep_list(symbol);
+ }
+ fclose(keepf);
+}
+
+int nsyms, ntextrel, ndatarel;
+struct exec *hdrp;
+char *aoutdata, *strbase;
+struct relocation_info *textrel, *datarel;
+struct nlist *symbase;
+
+#define SYMSTR(sp) &strbase[(sp)->n_un.n_strx]
+
+/* is the symbol a global symbol defined in the current file? */
+#define IS_GLOBAL_DEFINED(sp) \
+ (((sp)->n_type & N_EXT) && ((sp)->n_type & N_TYPE) != N_UNDF)
+
+#ifdef DO_AOUT
+#if defined(__sparc__)
+/* is the relocation entry dependent on a symbol? */
+#define IS_SYMBOL_RELOC(rp) \
+ ((rp)->r_extern || \
+ ((rp)->r_type >= RELOC_BASE10 && (rp)->r_type <= RELOC_BASE22) || \
+ (rp)->r_type == RELOC_JMP_TBL)
+#else
+/* is the relocation entry dependent on a symbol? */
+#define IS_SYMBOL_RELOC(rp) \
+ ((rp)->r_extern||(rp)->r_baserel||(rp)->r_jmptable)
+#endif
+#endif
+
+void check_reloc(char *filename, struct relocation_info * relp);
+
+void
+hide_syms(char *filename)
+{
+ int inf;
+ struct stat infstat;
+#ifdef DO_AOUT
+ struct relocation_info *relp;
+ struct nlist *symp;
+ u_char zero = 0;
+#endif
+ char *buf;
+
+ /*
+ * Open the file and do some error checking.
+ */
+
+ if ((inf = open(filename, O_RDWR)) == -1) {
+ perror(filename);
+ return;
+ }
+ if (fstat(inf, &infstat) == -1) {
+ perror(filename);
+ close(inf);
+ return;
+ }
+ if (infstat.st_size < sizeof(struct exec)) {
+ fprintf(stderr, "%s: short file\n", filename);
+ close(inf);
+ return;
+ }
+ if ((buf = mmap(NULL, infstat.st_size, PROT_READ | PROT_WRITE,
+ MAP_FILE | MAP_SHARED, inf, 0)) == MAP_FAILED) {
+ fprintf(stderr, "%s: cannot map\n", filename);
+ close(inf);
+ return;
+ }
+
+#ifdef _NLIST_DO_ELF
+ if (buf[0] == 0x7f && (buf[1] == 'E' || buf[1] == 'O') &&
+ buf[2] == 'L' && buf[3] == 'F') {
+ elf_hide(inf, buf);
+ return;
+ }
+#endif /* _NLIST_DO_ELF */
+
+#ifdef _NLIST_DO_ECOFF
+ if (!ECOFF_BADMAG((struct ecoff_exechdr *) buf)) {
+ ecoff_hide(inf, buf);
+ return;
+ }
+#endif /* _NLIST_DO_ECOFF */
+
+#ifdef DO_AOUT
+ aoutdata = buf;
+
+ /*
+ * Check the header and calculate offsets and sizes from it.
+ */
+ hdrp = (struct exec *) aoutdata;
+
+ if (N_BADMAG(*hdrp)) {
+ fprintf(stderr, "%s: bad magic: not an a.out, ecoff or elf file\n",
+ filename);
+ close(inf);
+ return;
+ }
+ textrel = (struct relocation_info *) (aoutdata + N_TRELOFF(*hdrp));
+ datarel = (struct relocation_info *) (aoutdata + N_DRELOFF(*hdrp));
+ symbase = (struct nlist *) (aoutdata + N_SYMOFF(*hdrp));
+ strbase = (char *) (aoutdata + N_STROFF(*hdrp));
+
+ ntextrel = hdrp->a_trsize / sizeof(struct relocation_info);
+ ndatarel = hdrp->a_drsize / sizeof(struct relocation_info);
+ nsyms = hdrp->a_syms / sizeof(struct nlist);
+
+ /*
+ * Zap the type field of all globally-defined symbols. The linker will
+ * subsequently ignore these entries. Don't zap any symbols in the
+ * keep list.
+ */
+ for (symp = symbase; symp < symbase + nsyms; symp++)
+ if (IS_GLOBAL_DEFINED(symp) && !in_keep_list(SYMSTR(symp))) {
+ /*
+ * XXX Our VM system has some problems, so
+ * avoid the VM system....
+ */
+ lseek(inf, (off_t) ((void *) &symp->n_type -
+ (void *) buf), SEEK_SET);
+ write(inf, &zero, sizeof zero);
+ symp->n_type = 0;
+ }
+ /*
+ * Check whether the relocation entries reference any symbols that we
+ * just zapped. I don't know whether ld can handle this case, but I
+ * haven't encountered it yet. These checks are here so that the program
+ * doesn't fail silently should such symbols be encountered.
+ */
+ for (relp = textrel; relp < textrel + ntextrel; relp++)
+ check_reloc(filename, relp);
+ for (relp = datarel; relp < datarel + ndatarel; relp++)
+ check_reloc(filename, relp);
+
+ msync(buf, infstat.st_size, MS_SYNC);
+ munmap(buf, infstat.st_size);
+ close(inf);
+#endif /* DO_AOUT */
+}
+
+#ifdef DO_AOUT
+void
+check_reloc(char *filename, struct relocation_info * relp)
+{
+ /* bail out if we zapped a symbol that is needed */
+ if (IS_SYMBOL_RELOC(relp) && symbase[relp->r_symbolnum].n_type == 0) {
+ fprintf(stderr,
+ "%s: oops, have hanging relocation for %s: bailing out!\n",
+ filename, SYMSTR(&symbase[relp->r_symbolnum]));
+ exit(1);
+ }
+}
+#endif /* DO_AOUT */
diff --git a/usr.sbin/crunchgen/ecoff_hide.c b/usr.sbin/crunchgen/ecoff_hide.c
new file mode 100644
index 00000000000..e21383cf9e8
--- /dev/null
+++ b/usr.sbin/crunchgen/ecoff_hide.c
@@ -0,0 +1,62 @@
+/* $OpenBSD: ecoff_hide.c,v 1.1 2008/08/22 15:18:55 deraadt Exp $ */
+
+/*-
+ * Copyright (c) 1997 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.
+ *
+ * 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/types.h>
+#include <sys/exec.h>
+#ifdef _NLIST_DO_ECOFF
+#include <sys/exec_ecoff.h>
+#include <string.h>
+
+/* Do we have these symbols in any include file? */
+#define scText 1
+#define scData 2
+#define scBss 3
+#define scSData 13
+#define scSBss 14
+#define scRData 15
+
+#define stNil 0
+
+extern int in_keep_list(char *);
+
+void
+ecoff_hide(int fd, char *p)
+{
+ struct ecoff_exechdr *ehdr = (struct ecoff_exechdr *) p;
+ struct ecoff_symhdr *shdr = (struct ecoff_symhdr *) (p + ehdr->f.f_symptr);
+ u_int ecnt = shdr->esymMax;
+ struct ecoff_extsym *esym = (struct ecoff_extsym *) (p + shdr->cbExtOffset);
+ char *estr = p + shdr->cbSsExtOffset;
+ int i;
+
+ for (i = 0; i < ecnt; i++, esym++)
+ if ((esym->es_class == scText || esym->es_class == scData ||
+ esym->es_class == scBss || esym->es_class == scSData ||
+ esym->es_class == scSBss || esym->es_class == scRData) &&
+ !in_keep_list(estr + esym->es_strindex))
+ esym->es_type = stNil;
+}
+#endif /* _NLIST_DO_ECOFF */
diff --git a/usr.sbin/crunchgen/elf_hide.c b/usr.sbin/crunchgen/elf_hide.c
new file mode 100644
index 00000000000..b52a7757b07
--- /dev/null
+++ b/usr.sbin/crunchgen/elf_hide.c
@@ -0,0 +1,474 @@
+/* $OpenBSD: elf_hide.c,v 1.1 2008/08/22 15:18:55 deraadt Exp $ */
+
+/*
+ * Copyright (c) 1997 Dale Rahn.
+ * 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.
+ *
+ * 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/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/exec.h>
+#ifdef _NLIST_DO_ELF
+#include <sys/exec_elf.h>
+
+void load_strtab(Elf_Ehdr * pehdr, char *pexe);
+void dump_strtab();
+char *get_str(int indx);
+
+void load_symtab(Elf_Ehdr * pehdr, char *pexe);
+void dump_symtab();
+
+void load_shstr_tab(Elf_Ehdr * pehdr, char *pexe);
+char *get_shstr(int indx);
+void fprint_shstr(FILE * channel, int indx);
+
+void hide_sym();
+void reorder_syms(Elf_Ehdr * ehdr, Elf_Shdr * symsect,
+ Elf_Sym * symtab, int symtabsize, int symtabsecnum);
+typedef long Symmap;
+void renum_reloc_syms(Elf_Ehdr * ehdr, Symmap * symmap,
+ int symtabsecnum);
+
+
+char *pexe;
+
+void
+elf_hide(int pfile, char *p)
+{
+ Elf_Ehdr *pehdr;
+#ifdef DEBUG
+ Elf_Shdr *pshdr;
+ Elf_Phdr *pphdr;
+ int i;
+#endif
+ struct stat sb;
+
+ pexe = p;
+ pehdr = (Elf_Ehdr *) pexe;
+
+#ifdef DEBUG
+ printf("elf header\n");
+ printf("e_type %x\n", pehdr->e_type);
+ printf("e_machine %x\n", pehdr->e_machine);
+ printf("e_version %x\n", pehdr->e_version);
+ printf("e_entry %x\n", pehdr->e_entry);
+ printf("e_phoff %x\n", pehdr->e_phoff);
+ printf("e_shoff %x\n", pehdr->e_shoff);
+ printf("e_flags %x\n", pehdr->e_flags);
+ printf("e_ehsize %x\n", pehdr->e_ehsize);
+ printf("e_phentsize %x\n", pehdr->e_phentsize);
+ printf("e_phnum %x\n", pehdr->e_phnum);
+ printf("e_shentsize %x\n", pehdr->e_shentsize);
+ printf("e_shnum %x\n", pehdr->e_shnum);
+ printf("e_shstrndx %x\n", pehdr->e_shstrndx);
+#endif
+
+ load_shstr_tab(pehdr, pexe);
+#ifdef DEBUG
+ for (i = 0; i < pehdr->e_shnum; i++) {
+ pshdr = (Elf_Phdr *) (pexe + pehdr->e_shoff +
+ (i * pehdr->e_shentsize));
+
+ printf("section header %d\n", i);
+ printf("sh_name %x ", pshdr->sh_name);
+ fprint_shstr(stdout, pshdr->sh_name);
+ printf("\n");
+ printf("sh_type %x\n", pshdr->sh_type);
+ printf("sh_flags %x\n", pshdr->sh_flags);
+ printf("sh_addr %x\n", pshdr->sh_addr);
+ printf("sh_offset %x\n", pshdr->sh_offset);
+ printf("sh_size %x\n", pshdr->sh_size);
+ printf("sh_link %x\n", pshdr->sh_link);
+ printf("sh_info %x\n", pshdr->sh_info);
+ printf("sh_addralign %x\n", pshdr->sh_addralign);
+ printf("sh_entsize %x\n", pshdr->sh_entsize);
+ }
+#endif /* DEBUG */
+
+#ifdef DEBUG
+ for (i = 0; i < pehdr->e_phnum; i++) {
+ pshdr = (Elf_Phdr *) (pexe + pehdr->e_phoff +
+ (i * pehdr->e_phentsize));
+
+ printf("program header %d\n", i);
+ printf("p_type %x\n", pphdr->p_type);
+ printf("p_offset %x\n", pphdr->p_offset);
+ printf("p_vaddr %x\n", pphdr->p_vaddr);
+ printf("p_paddr %x\n", pphdr->p_paddr);
+ printf("p_filesz %x\n", pphdr->p_filesz);
+ printf("p_memsz %x\n", pphdr->p_memsz);
+ printf("p_flags %x\n", pphdr->p_flags);
+ printf("p_align %x\n", pphdr->p_align);
+ }
+#endif /* DEBUG */
+#if 0
+ for (i = 0; i < pehdr->e_shnum; i++) {
+ pshdr = (Elf_Phdr *) (pexe + pehdr->e_shoff +
+ (i * pehdr->e_shentsize));
+ if (strcmp(".strtab", get_shstr(pshdr->sh_name)) == 0)
+ break;
+ }
+ fprint_shstr(stdout, pshdr->sh_name);
+ printf("\n");
+#endif
+
+ load_strtab(pehdr, pexe);
+ load_symtab(pehdr, pexe);
+
+ munmap(pexe, sb.st_size);
+ close(pfile);
+}
+char *shstrtab;
+
+void
+load_shstr_tab(Elf_Ehdr * pehdr, char *pexe)
+{
+ Elf_Shdr *pshdr;
+ shstrtab = NULL;
+ if (pehdr->e_shstrndx == 0)
+ return;
+ pshdr = (Elf_Shdr *) (pexe + pehdr->e_shoff +
+ (pehdr->e_shstrndx * pehdr->e_shentsize));
+
+ shstrtab = (char *) (pexe + pshdr->sh_offset);
+}
+
+void
+fprint_shstr(FILE * channel, int indx)
+{
+ if (shstrtab != NULL)
+ fprintf(channel, "\"%s\"", &(shstrtab[indx]));
+}
+
+char *
+get_shstr(int indx)
+{
+ return &(shstrtab[indx]);
+}
+
+void
+load_symtab(Elf_Ehdr * pehdr, char *pexe)
+{
+ Elf_Sym *symtab;
+ Elf_Shdr *symsect;
+ int symtabsize;
+ Elf_Shdr *psymshdr;
+ Elf_Shdr *pshdr;
+#ifdef DEBUG
+ char *shname;
+#endif
+ int i;
+
+ symtab = NULL;
+ for (i = 0; i < pehdr->e_shnum; i++) {
+ pshdr = (Elf_Shdr *) (pexe + pehdr->e_shoff +
+ (i * pehdr->e_shentsize));
+ if (SHT_REL != pshdr->sh_type && SHT_RELA != pshdr->sh_type)
+ continue;
+ psymshdr = (Elf_Shdr *) (pexe + pehdr->e_shoff +
+ (pshdr->sh_link * pehdr->e_shentsize));
+#ifdef DEBUG
+ fprint_shstr(stdout, pshdr->sh_name);
+ printf("\n");
+#endif
+ symtab = (Elf_Sym *) (pexe + psymshdr->sh_offset);
+ symsect = psymshdr;
+ symtabsize = psymshdr->sh_size;
+
+#ifdef DEBUG
+ dump_symtab(symsect, symtab, symtabsize);
+#endif
+ hide_sym(pehdr, symsect, symtab, symtabsize, pshdr->sh_link);
+ }
+
+}
+
+void
+dump_symtab(Elf_Shdr * symsect, Elf_Sym * symtab, int symtabsize)
+{
+ int i;
+ Elf_Sym *psymtab;
+
+ for (i = 0; i < (symtabsize / sizeof(Elf_Sym)); i++) {
+ psymtab = &(symtab[i]);
+ if ((psymtab->st_info & 0xf0) == 0x10 &&
+ (psymtab->st_shndx != SHN_UNDEF)) {
+ printf("symbol %d:\n", i);
+ printf("st_name %x \"%s\"\n", psymtab->st_name,
+ get_str(psymtab->st_name));
+ printf("st_value %x\n", psymtab->st_value);
+ printf("st_size %x\n", psymtab->st_size);
+ printf("st_info %x\n", psymtab->st_info);
+ printf("st_other %x\n", psymtab->st_other);
+ printf("st_shndx %x\n", psymtab->st_shndx);
+ }
+ }
+}
+
+char *strtab;
+int strtabsize;
+void
+load_strtab(Elf_Ehdr * pehdr, char *pexe)
+{
+ Elf_Shdr *pshdr = NULL;
+ char *shname;
+ int i;
+ strtab = NULL;
+ for (i = 0; i < pehdr->e_shnum; i++) {
+ pshdr = (Elf_Shdr *) (pexe + pehdr->e_shoff +
+ (i * pehdr->e_shentsize));
+
+ shname = get_shstr(pshdr->sh_name);
+ if (strcmp(".strtab", shname) == 0)
+ break;
+ }
+#ifdef DEBUG
+ fprint_shstr(stdout, pshdr->sh_name);
+ printf("\n");
+#endif
+
+ strtab = (char *) (pexe + pshdr->sh_offset);
+
+ strtabsize = pshdr->sh_size;
+
+#ifdef DEBUG
+ dump_strtab();
+#endif
+}
+
+void
+dump_strtab()
+{
+ int index;
+ char *pstr;
+ char *pnstr;
+ int i = 0;
+ index = 0;
+ pstr = strtab;
+ while (index < strtabsize) {
+ printf("string %x: \"%s\"\n", i, pstr);
+ pnstr = pstr + strlen(pstr) + 1;
+ index = pnstr - strtab;
+ pstr = pnstr;
+ i++;
+ }
+
+}
+
+void
+fprint_str(FILE * channel, int indx)
+{
+ if (strtab != NULL)
+ fprintf(channel, "\"%s\"", &(strtab[indx]));
+}
+
+char *
+get_str(int indx)
+{
+ return &(strtab[indx]);
+}
+
+int in_keep_list(char *symbol);
+
+void
+hide_sym(Elf_Ehdr * ehdr, Elf_Shdr * symsect,
+ Elf_Sym * symtab, int symtabsize, int symtabsecnum)
+{
+ int i;
+ unsigned char info;
+ Elf_Sym *psymtab;
+
+#ifdef __mips__
+ u_int32_t f = arc4random();
+#endif
+
+ for (i = 0; i < (symtabsize / sizeof(Elf_Sym)); i++) {
+ psymtab = &(symtab[i]);
+ if ((psymtab->st_info & 0xf0) == 0x10 &&
+ (psymtab->st_shndx != SHN_UNDEF)) {
+ if (in_keep_list(get_str(psymtab->st_name)))
+ continue;
+#ifdef DEBUG
+ printf("symbol %d:\n", i);
+ printf("st_name %x \"%s\"\n", psymtab->st_name,
+ get_str(psymtab->st_name));
+ printf("st_info %x\n", psymtab->st_info);
+#endif
+#ifndef __mips__
+ info = psymtab->st_info;
+ info = info & 0xf;
+ psymtab->st_info = info;
+#else
+ /*
+ * XXX This is a small ugly hack to be able to use
+ * XXX chrunchide with MIPS.
+ * XXX Because MIPS needs global symbols to stay
+ * XXX global (has to do with GOT), we mess around
+ * XXX with the symbol names instead. For most uses
+ * XXX this will be no problem, symbols are stripped
+ * XXX anyway. However, if many one character
+ * XXX symbols exist, names may clash.
+ */
+ {
+ char *p;
+ u_int32_t n, z;
+
+ z = f++;
+ p = get_str(psymtab->st_name);
+ n = strlen(p);
+ if (n > 4)
+ n = 4;
+ while (n--) {
+ p[n] = z;
+ z >>= 8;
+ while (p[n] == 0)
+ p[n] += arc4random();
+ }
+ }
+
+#endif
+#ifdef DEBUG
+ printf("st_info %x\n", psymtab->st_info);
+#endif
+ }
+ }
+ reorder_syms(ehdr, symsect, symtab, symtabsize, symtabsecnum);
+}
+
+void
+reorder_syms(Elf_Ehdr * ehdr, Elf_Shdr * symsect,
+ Elf_Sym * symtab, int symtabsize, int symtabsecnum)
+{
+ int i;
+ int nsyms;
+ int cursym;
+ Elf_Sym *tmpsymtab;
+ Symmap *symmap;
+
+
+ nsyms = symtabsize / sizeof(Elf_Sym);
+
+ tmpsymtab = (Elf_Sym *) calloc(1, symtabsize);
+ symmap = (Symmap *) calloc(nsyms, sizeof(Symmap));
+ if (!tmpsymtab || !symmap)
+ errx(5, "calloc: %s", strerror(ENOMEM));
+
+ bcopy(symtab, tmpsymtab, symtabsize);
+
+ cursym = 1;
+ for (i = 1; i < nsyms; i++) {
+ if ((tmpsymtab[i].st_info & 0xf0) == 0x00) {
+#ifdef DEBUG
+ printf("copying l o%d n%d <%s>\n", i, cursym,
+ get_str(tmpsymtab[i].st_name));
+#endif
+ bcopy(&(tmpsymtab[i]), &(symtab[cursym]),
+ sizeof(Elf_Sym));
+ symmap[i] = cursym;
+ cursym++;
+ }
+ }
+ symsect->sh_info = cursym;
+ for (i = 1; i < nsyms; i++) {
+ if ((tmpsymtab[i].st_info & 0xf0) != 0x00) {
+#ifdef DEBUG
+ printf("copying nl o%d n%d <%s>\n", i, cursym,
+ get_str(tmpsymtab[i].st_name));
+#endif
+ bcopy(&(tmpsymtab[i]), &(symtab[cursym]),
+ sizeof(Elf_Sym));
+ symmap[i] = cursym;
+ cursym++;
+ }
+ }
+ if (cursym != nsyms) {
+ printf("miscounted symbols somewhere c %d n %d \n",
+ cursym, nsyms);
+ exit(5);
+ }
+ renum_reloc_syms(ehdr, symmap, symtabsecnum);
+ free(tmpsymtab);
+ free(symmap);
+}
+
+void
+renum_reloc_syms(Elf_Ehdr * ehdr, Symmap * symmap, int symtabsecnum)
+{
+ Elf_Shdr *pshdr;
+ int i, j;
+ int num_reloc;
+ Elf_Rel *prel;
+ Elf_RelA *prela;
+ int symnum;
+
+ for (i = 0; i < ehdr->e_shnum; i++) {
+ pshdr = (Elf_Shdr *) (pexe + ehdr->e_shoff +
+ (i * ehdr->e_shentsize));
+ if ((pshdr->sh_type == SHT_RELA) &&
+ pshdr->sh_link == symtabsecnum) {
+
+#ifdef DEBUG
+ printf("section %d has rela relocations in symtab\n", i);
+#endif
+ prela = (Elf_RelA *) (pexe + pshdr->sh_offset);
+ num_reloc = pshdr->sh_size / sizeof(Elf_RelA);
+ for (j = 0; j < num_reloc; j++) {
+ symnum = ELF_R_SYM(prela[j].r_info);
+#ifdef DEBUG
+ printf("sym num o %d n %d\n", symnum,
+ symmap[symnum]);
+#endif
+ prela[j].r_info = ELF_R_INFO(symmap[symnum],
+ ELF_R_TYPE(prela[j].r_info));
+ }
+ }
+ if ((pshdr->sh_type == SHT_REL) &&
+ pshdr->sh_link == symtabsecnum) {
+#ifdef DEBUG
+ printf("section %d has rel relocations in symtab\n", i);
+#endif
+ prel = (Elf_Rel *) (pexe + pshdr->sh_offset);
+ num_reloc = pshdr->sh_size / sizeof(Elf_Rel);
+ for (j = 0; j < num_reloc; j++) {
+ symnum = ELF_R_SYM(prel[j].r_info);
+#ifdef DEBUG
+ printf("sym num o %d n %d\n", symnum,
+ symmap[symnum]);
+#endif
+ prel[j].r_info = ELF_R_INFO(symmap[symnum],
+ ELF_R_TYPE(prel[j].r_info));
+ }
+ }
+ }
+
+}
+#endif /* _NLIST_DO_ELF */
diff --git a/usr.sbin/crunchgen/mkskel.sh b/usr.sbin/crunchgen/mkskel.sh
new file mode 100644
index 00000000000..9faa6e9acc9
--- /dev/null
+++ b/usr.sbin/crunchgen/mkskel.sh
@@ -0,0 +1,17 @@
+#! /bin/sh
+# $OpenBSD: mkskel.sh,v 1.1 2008/08/22 15:18:55 deraadt Exp $
+
+# idea and sed lines taken straight from flex
+
+cat <<!EOF
+/* File created via mkskel.sh */
+
+char *crunched_skel[] = {
+!EOF
+
+sed 's/\\/&&/g' $* | sed 's/"/\\"/g' | sed 's/.*/ "&",/'
+
+cat <<!EOF
+ 0
+};
+!EOF