-# $OpenBSD: Makefile,v 1.3 2003/03/02 12:32:08 deraadt Exp $
+# $OpenBSD: Makefile,v 1.4 2008/08/22 15:18:55 deraadt Exp $
-SUBDIR=crunchgen crunchide ../sparc64/mksuncd
+SUBDIR= ../sparc64/mksuncd
.include <bsd.subdir.mk>
+++ /dev/null
-# $OpenBSD: Makefile.inc,v 1.3 2001/01/29 01:19:21 deraadt Exp $
-
-# modify to taste
-DESTDIR=
-BINDIR?= /usr/bin
+++ /dev/null
-
-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
+++ /dev/null
-# $OpenBSD: Makefile,v 1.2 1996/09/25 06:40:52 etheisen Exp $
-
-PROG= crunchgen
-SRCS= crunchgen.c crunched_skel.c
-CFLAGS+= -g -Wall
-CPPFLAGS+= -DMF_NAMES='"Makefile.bsd-wrapper","Makefile"'
-CLEANFILES+= crunched_skel.c
-
-crunched_skel.c: crunched_main.c
- sh ${.CURDIR}/mkskel.sh ${.CURDIR}/crunched_main.c > crunched_skel.c
-
-.include <bsd.prog.mk>
+++ /dev/null
-/* $OpenBSD: crunched_main.c,v 1.5 2003/01/27 19:41:30 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);
-}
+++ /dev/null
-.\" $OpenBSD: crunchgen.1,v 1.21 2007/05/31 19:19:15 jmc 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: May 31 2007 $
-.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.
+++ /dev/null
-/* $OpenBSD: crunchgen.c,v 1.28 2006/12/26 10:20:11 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[] = {
-#if defined(MF_NAMES)
- MF_NAMES,
-#else
- "Makefile",
-#endif
- 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);
-
-int
-main(int argc, char *argv[])
-{
- char *p;
- int optc;
- extern int optind;
- extern char *optarg;
-
- verbose = 1;
- readcache = 1;
- *outmkname = *outcfname = *execfname = '\0';
-
- if (argc > 0)
- progname = argv[0];
-
- 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;
-}
+++ /dev/null
-#! /bin/sh
-# $OpenBSD: mkskel.sh,v 1.2 2000/03/01 22:10:03 todd 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
+++ /dev/null
-# $OpenBSD: Makefile,v 1.4 2000/03/01 22:10:03 todd Exp $
-
-PROG= crunchide
-SRCS= crunchide.c elf_hide.c ecoff_hide.c
-
-.include <bsd.prog.mk>
+++ /dev/null
-.\" $OpenBSD: crunchide.1,v 1.9 2007/05/31 19:19:16 jmc 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: May 31 2007 $
-.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.
+++ /dev/null
-/* $OpenBSD: crunchide.c,v 1.22 2007/02/18 23:50:46 ray 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
-
-char *pname = "crunchide";
-
-void 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
-
-int
-main(int argc, char *argv[])
-{
- int ch;
-
- if (argc > 0)
- pname = argv[0];
-
- 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:
- usage();
- }
-
- argc -= optind;
- argv += optind;
-
- if (argc == 0)
- usage();
-
- while (argc) {
- hide_syms(*argv);
- argc--;
- argv++;
- }
-
- return 0;
-}
-
-void
-usage(void)
-{
- fprintf(stderr,
- "usage: %s [-f keep-list-file] [-k keep-symbol] object-file ...\n",
- pname);
- 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", pname);
- 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;
-
- 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);
- 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, outf, rc;
- struct stat infstat;
- struct relocation_info *relp;
- struct nlist *symp;
- char *buf;
- u_char zero = 0;
-
- /*
- * 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 */
+++ /dev/null
-/* $OpenBSD: ecoff_hide.c,v 1.3 2003/06/03 21:08:59 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 */
+++ /dev/null
-/* $OpenBSD: elf_hide.c,v 1.12 2007/08/14 20:43:10 miod 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)
-{
- int i;
- Elf_Ehdr *pehdr;
- Elf_Shdr *pshdr;
- Elf_Phdr *pphdr;
- 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 *pshdr;
- Elf_Shdr *psymshdr;
- char *shname;
- 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;
- 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++;
- }
-
-}
-
-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 */
-# $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 \
--- /dev/null
+# $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>
--- /dev/null
+
+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
--- /dev/null
+/* $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);
+}
--- /dev/null
+.\" $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.
--- /dev/null
+/* $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;
+}
--- /dev/null
+.\" $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.
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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 */
--- /dev/null
+/* $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 */
--- /dev/null
+#! /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