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