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