summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mdk-stage1/Makefile20
-rw-r--r--mdk-stage1/Makefile.common2
-rw-r--r--mdk-stage1/insmod-busybox/insmod.c1
-rw-r--r--mdk-stage1/insmod-modutils/Makefile61
-rw-r--r--mdk-stage1/insmod-modutils/include/config.h105
-rw-r--r--mdk-stage1/insmod-modutils/include/elf_alpha.h10
-rw-r--r--mdk-stage1/insmod-modutils/include/elf_arm.h10
-rw-r--r--mdk-stage1/insmod-modutils/include/elf_hppa.h9
-rw-r--r--mdk-stage1/insmod-modutils/include/elf_hppa64.h9
-rw-r--r--mdk-stage1/insmod-modutils/include/elf_i386.h10
-rw-r--r--mdk-stage1/insmod-modutils/include/elf_ia64.h9
-rw-r--r--mdk-stage1/insmod-modutils/include/elf_m68k.h10
-rw-r--r--mdk-stage1/insmod-modutils/include/elf_mips.h24
-rw-r--r--mdk-stage1/insmod-modutils/include/elf_ppc.h10
-rw-r--r--mdk-stage1/insmod-modutils/include/elf_s390.h10
-rw-r--r--mdk-stage1/insmod-modutils/include/elf_sparc.h10
-rw-r--r--mdk-stage1/insmod-modutils/include/elf_sparc64.h27
-rw-r--r--mdk-stage1/insmod-modutils/include/kallsyms.h131
-rw-r--r--mdk-stage1/insmod-modutils/include/kerneld.h46
-rw-r--r--mdk-stage1/insmod-modutils/include/modstat.h55
-rw-r--r--mdk-stage1/insmod-modutils/include/module.h210
-rw-r--r--mdk-stage1/insmod-modutils/include/obj.h275
-rw-r--r--mdk-stage1/insmod-modutils/include/util.h101
-rw-r--r--mdk-stage1/insmod-modutils/include/version.h1
-rw-r--r--mdk-stage1/insmod-modutils/insmod-frontend.c24
-rw-r--r--mdk-stage1/insmod-modutils/insmod.c1964
-rw-r--r--mdk-stage1/insmod-modutils/obj/Makefile31
-rw-r--r--mdk-stage1/insmod-modutils/obj/obj_alpha.c305
-rw-r--r--mdk-stage1/insmod-modutils/obj/obj_arm.c318
-rw-r--r--mdk-stage1/insmod-modutils/obj/obj_common.c399
-rw-r--r--mdk-stage1/insmod-modutils/obj/obj_hppa.c668
-rw-r--r--mdk-stage1/insmod-modutils/obj/obj_hppa64.c686
-rw-r--r--mdk-stage1/insmod-modutils/obj/obj_i386.c245
-rw-r--r--mdk-stage1/insmod-modutils/obj/obj_ia64.c1065
-rw-r--r--mdk-stage1/insmod-modutils/obj/obj_kallsyms.c292
-rw-r--r--mdk-stage1/insmod-modutils/obj/obj_load.c354
-rw-r--r--mdk-stage1/insmod-modutils/obj/obj_m68k.c147
-rw-r--r--mdk-stage1/insmod-modutils/obj/obj_mips.c238
-rw-r--r--mdk-stage1/insmod-modutils/obj/obj_ppc.c255
-rw-r--r--mdk-stage1/insmod-modutils/obj/obj_reloc.c435
-rw-r--r--mdk-stage1/insmod-modutils/obj/obj_s390.c245
-rw-r--r--mdk-stage1/insmod-modutils/obj/obj_sparc.c226
-rw-r--r--mdk-stage1/insmod-modutils/obj/obj_sparc64.c352
-rw-r--r--mdk-stage1/insmod-modutils/util/Makefile39
-rw-r--r--mdk-stage1/insmod-modutils/util/alias.h244
-rw-r--r--mdk-stage1/insmod-modutils/util/arch64.c35
-rw-r--r--mdk-stage1/insmod-modutils/util/config.c1591
-rw-r--r--mdk-stage1/insmod-modutils/util/gzfiles.c74
-rw-r--r--mdk-stage1/insmod-modutils/util/logger.c163
-rw-r--r--mdk-stage1/insmod-modutils/util/meta_expand.c339
-rw-r--r--mdk-stage1/insmod-modutils/util/modstat.c419
-rw-r--r--mdk-stage1/insmod-modutils/util/snap_shot.c154
-rw-r--r--mdk-stage1/insmod-modutils/util/sys_cm.c88
-rw-r--r--mdk-stage1/insmod-modutils/util/sys_dm.c37
-rw-r--r--mdk-stage1/insmod-modutils/util/sys_gks.c37
-rw-r--r--mdk-stage1/insmod-modutils/util/sys_nim.c53
-rw-r--r--mdk-stage1/insmod-modutils/util/sys_oim.c40
-rw-r--r--mdk-stage1/insmod-modutils/util/sys_qm.c56
-rw-r--r--mdk-stage1/insmod-modutils/util/xftw.c422
-rw-r--r--mdk-stage1/insmod-modutils/util/xmalloc.c39
-rw-r--r--mdk-stage1/insmod-modutils/util/xrealloc.c39
-rw-r--r--mdk-stage1/insmod-modutils/util/xstrcat.c40
-rw-r--r--mdk-stage1/insmod-modutils/util/xstrdup.c41
-rw-r--r--mdk-stage1/insmod-modutils/util/xsystem.c51
-rw-r--r--mdk-stage1/insmod.h20
-rw-r--r--mdk-stage1/modules.c2
-rw-r--r--mdk-stage1/stage1.c2
67 files changed, 13421 insertions, 9 deletions
diff --git a/mdk-stage1/Makefile b/mdk-stage1/Makefile
index c230d4b39..530c8b9b2 100644
--- a/mdk-stage1/Makefile
+++ b/mdk-stage1/Makefile
@@ -26,9 +26,6 @@ top_dir = .
include $(top_dir)/Makefile.common
-ARCH := $(patsubst i%86,i386,$(shell uname -m))
-ARCH := $(patsubst sparc%,sparc,$(ARCH))
-
CFLAGS = -Os -pipe -Wall -Werror -fomit-frame-pointer
DEFS = -DVERSION=\"$(VERSION)\"
@@ -73,9 +70,14 @@ MEDIAS_FRONTEND_LINK = $(FRONTEND_LINK)
endif
endif
+ifeq (i386, $(ARCH))
+INSMOD = insmod-busybox
+else
+INSMOD = insmod-modutils
+endif
-GLIBC_STAGE1_OWN_LIBS = insmod-busybox/libinsmod.a mar/libmar.a bzlib/libbzlib.a
-DIETLIBC_STAGE1_OWN_LIBS = insmod-busybox/libinsmod-DIET.a mar/libmar-DIET.a bzlib/libbzlib-DIET.a
+GLIBC_STAGE1_OWN_LIBS = $(INSMOD)/libinsmod.a mar/libmar.a bzlib/libbzlib.a
+DIETLIBC_STAGE1_OWN_LIBS = $(INSMOD)/libinsmod-DIET.a mar/libmar-DIET.a bzlib/libbzlib-DIET.a
STAGE1_OWN_LIBS = $($(L)_STAGE1_OWN_LIBS)
@@ -116,10 +118,14 @@ INIT_LIBC = $(DIETLIBC_LIBC)
endif
-BINS = init stage1-cdrom stage1-disk stage1-network stage1-full
+BINS = init stage1-full
+
+ifeq (i386, $(ARCH))
+BINS += stage1-cdrom stage1-disk stage1-network
+endif
-DIRS = dietlibc mar insmod-busybox pci-resource bzlib
+DIRS = dietlibc mar pci-resource bzlib $(INSMOD)
ifeq (i386,$(ARCH))
DIRS += pcmcia
endif
diff --git a/mdk-stage1/Makefile.common b/mdk-stage1/Makefile.common
index 9d2d3f9f3..ec8441978 100644
--- a/mdk-stage1/Makefile.common
+++ b/mdk-stage1/Makefile.common
@@ -14,6 +14,8 @@
#
#*****************************************************************************
+ARCH := $(patsubst i%86,i386,$(shell uname -m))
+ARCH := $(patsubst sparc%,sparc,$(ARCH))
#- default lib is dietlibc (honoured by main Makefile whenever possible)
L = DIETLIBC
diff --git a/mdk-stage1/insmod-busybox/insmod.c b/mdk-stage1/insmod-busybox/insmod.c
index 95dee8855..d1027004c 100644
--- a/mdk-stage1/insmod-busybox/insmod.c
+++ b/mdk-stage1/insmod-busybox/insmod.c
@@ -36,6 +36,7 @@
*
*/
+#include "../insmod.h"
#include "busybox.h"
#include <stdlib.h>
#include <stdio.h>
diff --git a/mdk-stage1/insmod-modutils/Makefile b/mdk-stage1/insmod-modutils/Makefile
new file mode 100644
index 000000000..74ebdeafb
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/Makefile
@@ -0,0 +1,61 @@
+ #******************************************************************************
+ #
+ # insmod from modutils (generic)
+ #
+ # $Id$
+ #
+ # Copyright 1996, 1997 Linux International.
+ #
+ #*****************************************************************************
+
+top_dir = ..
+
+include $(top_dir)/Makefile.common
+
+
+FLAGS = -c -Wall -Os -fomit-frame-pointer -I./include -D_GNU_SOURCE -DELF_MACHINE_H='"elf_$(ARCH).h"' -DARCH_$(ARCH)
+
+
+DIRS = util obj
+
+all: dirs insmod libinsmod.a #libinsmod-DIET.a
+
+dirs:
+ @for n in . $(DIRS); do \
+ [ "$$n" = "." ] || make -C $$n ;\
+ done
+
+clean:
+ @for n in $(DIRS); do \
+ (cd $$n; make clean) \
+ done
+ rm -rf t *.o insmod libinsmod.a libinsmod-DIET.a
+
+
+insmod: insmod-frontend.o insmod.o ./util/libutil-STANDALONE.a ./obj/libobj.a
+ gcc -o $@ $^
+ $(STRIPCMD) $@
+
+t/.create_stuff: util/libutil.a obj/libobj.a
+ rm -rf t
+ mkdir t
+ cd t && for e in $^; do ar -x ../$$e; done
+ touch t/.create_stuff
+
+libinsmod.a: insmod.o t/.create_stuff
+ ar cru $@ insmod.o t/*
+ ranlib $@
+
+libinsmod-DIET.a: insmod-DIET.o ./util/libutil-DIET.a ./obj/libobj-DIET.a
+ ar cru $@ $^
+ ranlib $@
+
+insmod-frontend.o: insmod-frontend.c insmod.c
+ gcc $(FLAGS) $(GLIBC_INCLUDES) insmod-frontend.c
+
+insmod.o: insmod.c
+ gcc $(FLAGS) $(GLIBC_INCLUDES) insmod.c
+
+insmod-DIET.o: insmod.c
+ gcc $(FLAGS) $(DIETLIBC_INCLUDES) -o $@ insmod.c
+
diff --git a/mdk-stage1/insmod-modutils/include/config.h b/mdk-stage1/insmod-modutils/include/config.h
new file mode 100644
index 000000000..11da6a523
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/include/config.h
@@ -0,0 +1,105 @@
+/*
+ * Configuration file management
+ *
+ * Copyright 1994, 1995, 1996, 1997:
+ * Jacques Gelinas <jack@solucorp.qc.ca>
+ * Björn Ekwall <bj0rn@blox.se> February, March 1999
+ *
+ * This file is part of the Linux modutils.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _CONFIG_H
+#define _CONFIG_H
+
+#include <stdio.h>
+#include <sys/utsname.h>
+
+#define ETC_MODULES_CONF "/etc/modules.conf"
+
+#define EXEC_PRE_INSTALL 0
+#define EXEC_POST_INSTALL 1
+#define EXEC_PRE_REMOVE 2
+#define EXEC_POST_REMOVE 3
+#define EXEC_INSTALL 4
+#define EXEC_REMOVE 5
+
+struct PATH_TYPE {
+ char *type;
+ char *path;
+};
+
+struct EXEC_TYPE {
+ int when;
+ char *module;
+ char *cmd;
+};
+
+typedef struct {
+ char *name;
+ GLOB_LIST *opts;
+ int autoclean;
+} OPT_LIST;
+
+/* config.c */
+extern int flag_autoclean;
+extern struct utsname uts_info;
+extern char *aliaslist[];
+extern struct PATH_TYPE *modpath;
+extern int nmodpath;
+extern struct EXEC_TYPE *execs;
+extern int nexecs;
+extern char *insmod_opt;
+extern char *config_file;
+extern char *optlist[];
+extern char *prune[];
+extern OPT_LIST *opt_list;
+extern OPT_LIST *abovelist;
+extern OPT_LIST *belowlist;
+extern OPT_LIST *prunelist;
+extern OPT_LIST *probe_list;
+extern OPT_LIST *probeall_list;
+extern OPT_LIST *aliases;
+extern time_t config_mtime;
+extern int root_check_off; /* Check modules are owned by root? */
+
+/* Information about generated files */
+struct gen_files {
+ char *base; /* xxx in /lib/modules/`uname -r`/modules.xxx */
+ char *name; /* name actually used */
+ time_t mtime;
+};
+
+extern struct gen_files gen_file[];
+extern const int gen_file_count;
+/* The enum order must match the gen_file initialization order in config.c */
+enum gen_file_enum {
+ GEN_GENERIC_STRINGFILE,
+ GEN_PCIMAPFILE,
+ GEN_ISAPNPMAPFILE,
+ GEN_USBMAPFILE,
+ GEN_PARPORTMAPFILE,
+ GEN_DEPFILE,
+};
+
+extern char *persistdir;
+
+char *fgets_strip(char *buf, int sizebuf, FILE * fin, int *lineno);
+int config_read(int all, char *force_ver, char *base_dir, char *conf_file);
+GLOB_LIST *config_lstmod(const char *match, const char *type, int first_only);
+char *search_module_path(const char *base);
+
+#endif /* _CONFIG_H */
diff --git a/mdk-stage1/insmod-modutils/include/elf_alpha.h b/mdk-stage1/insmod-modutils/include/elf_alpha.h
new file mode 100644
index 000000000..f1ec66f1c
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/include/elf_alpha.h
@@ -0,0 +1,10 @@
+/* Machine-specific elf macros for the Alpha. */
+#ident "$Id$"
+
+#define ELFCLASSM ELFCLASS64
+#define ELFDATAM ELFDATA2LSB
+
+#define MATCH_MACHINE(x) (x == EM_ALPHA)
+
+#define SHT_RELM SHT_RELA
+#define Elf64_RelM Elf64_Rela
diff --git a/mdk-stage1/insmod-modutils/include/elf_arm.h b/mdk-stage1/insmod-modutils/include/elf_arm.h
new file mode 100644
index 000000000..f6b531e88
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/include/elf_arm.h
@@ -0,0 +1,10 @@
+/* Machine-specific elf macros for ARM. */
+#ident "$Id$"
+
+#define ELFCLASSM ELFCLASS32
+#define ELFDATAM ELFDATA2LSB
+
+#define MATCH_MACHINE(x) (x == EM_ARM)
+
+#define SHT_RELM SHT_REL
+#define Elf32_RelM Elf32_Rel
diff --git a/mdk-stage1/insmod-modutils/include/elf_hppa.h b/mdk-stage1/insmod-modutils/include/elf_hppa.h
new file mode 100644
index 000000000..9a1bd34ce
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/include/elf_hppa.h
@@ -0,0 +1,9 @@
+/* Machine-specific elf macros for HP-PA. */
+
+#define ELFCLASSM ELFCLASS32
+#define ELFDATAM ELFDATA2MSB
+
+#define MATCH_MACHINE(x) (x == EM_PARISC)
+
+#define SHT_RELM SHT_RELA
+#define Elf32_RelM Elf32_Rela
diff --git a/mdk-stage1/insmod-modutils/include/elf_hppa64.h b/mdk-stage1/insmod-modutils/include/elf_hppa64.h
new file mode 100644
index 000000000..05b201aef
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/include/elf_hppa64.h
@@ -0,0 +1,9 @@
+/* Machine-specific elf macros for HP-PA64. */
+
+#define ELFCLASSM ELFCLASS64
+#define ELFDATAM ELFDATA2MSB
+
+#define MATCH_MACHINE(x) (x == EM_PARISC)
+
+#define SHT_RELM SHT_RELA
+#define Elf64_RelM Elf64_Rela
diff --git a/mdk-stage1/insmod-modutils/include/elf_i386.h b/mdk-stage1/insmod-modutils/include/elf_i386.h
new file mode 100644
index 000000000..c6c2d326e
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/include/elf_i386.h
@@ -0,0 +1,10 @@
+/* Machine-specific elf macros for i386 et al. */
+#ident "$Id$"
+
+#define ELFCLASSM ELFCLASS32
+#define ELFDATAM ELFDATA2LSB
+
+#define MATCH_MACHINE(x) (x == EM_386)
+
+#define SHT_RELM SHT_REL
+#define Elf32_RelM Elf32_Rel
diff --git a/mdk-stage1/insmod-modutils/include/elf_ia64.h b/mdk-stage1/insmod-modutils/include/elf_ia64.h
new file mode 100644
index 000000000..b4d902956
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/include/elf_ia64.h
@@ -0,0 +1,9 @@
+/* Machine-specific elf macros for ia64. */
+
+#define ELFCLASSM ELFCLASS64
+#define ELFDATAM ELFDATA2LSB
+
+#define MATCH_MACHINE(x) (x == EM_IA_64)
+
+#define SHT_RELM SHT_RELA
+#define Elf64_RelM Elf64_Rela
diff --git a/mdk-stage1/insmod-modutils/include/elf_m68k.h b/mdk-stage1/insmod-modutils/include/elf_m68k.h
new file mode 100644
index 000000000..817fc8f2c
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/include/elf_m68k.h
@@ -0,0 +1,10 @@
+/* Machine-specific elf macros for m68k. */
+#ident "$Id$"
+
+#define ELFCLASSM ELFCLASS32
+#define ELFDATAM ELFDATA2MSB
+
+#define MATCH_MACHINE(x) (x == EM_68K)
+
+#define SHT_RELM SHT_RELA
+#define Elf32_RelM Elf32_Rela
diff --git a/mdk-stage1/insmod-modutils/include/elf_mips.h b/mdk-stage1/insmod-modutils/include/elf_mips.h
new file mode 100644
index 000000000..8a0430216
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/include/elf_mips.h
@@ -0,0 +1,24 @@
+/* Machine-specific elf macros for MIPS. */
+#ident "$Id$"
+
+#define ELFCLASSM ELFCLASS32
+#ifdef __MIPSEB__
+#define ELFDATAM ELFDATA2MSB
+#endif
+#ifdef __MIPSEL__
+#define ELFDATAM ELFDATA2LSB
+#endif
+
+/* Account for ELF spec changes. */
+#ifndef EM_MIPS_RS3_LE
+#ifdef EM_MIPS_RS4_BE
+#define EM_MIPS_RS3_LE EM_MIPS_RS4_BE
+#else
+#define EM_MIPS_RS3_LE 10
+#endif
+#endif /* !EM_MIPS_RS3_LE */
+
+#define MATCH_MACHINE(x) (x == EM_MIPS || x == EM_MIPS_RS3_LE)
+
+#define SHT_RELM SHT_REL
+#define Elf32_RelM Elf32_Rel
diff --git a/mdk-stage1/insmod-modutils/include/elf_ppc.h b/mdk-stage1/insmod-modutils/include/elf_ppc.h
new file mode 100644
index 000000000..71596de8c
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/include/elf_ppc.h
@@ -0,0 +1,10 @@
+/* Machine-specific elf macros for the PowerPC. */
+#ident "$Id$"
+
+#define ELFCLASSM ELFCLASS32
+#define ELFDATAM ELFDATA2MSB
+
+#define MATCH_MACHINE(x) (x == EM_PPC)
+
+#define SHT_RELM SHT_RELA
+#define Elf32_RelM Elf32_Rela
diff --git a/mdk-stage1/insmod-modutils/include/elf_s390.h b/mdk-stage1/insmod-modutils/include/elf_s390.h
new file mode 100644
index 000000000..547d66b83
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/include/elf_s390.h
@@ -0,0 +1,10 @@
+/* Machine-specific elf macros for i386 et al. */
+#ident "$Id$"
+
+#define ELFCLASSM ELFCLASS32
+#define ELFDATAM ELFDATA2MSB
+
+#define MATCH_MACHINE(x) (x == EM_S390)
+
+#define SHT_RELM SHT_RELA
+#define Elf32_RelM Elf32_Rela
diff --git a/mdk-stage1/insmod-modutils/include/elf_sparc.h b/mdk-stage1/insmod-modutils/include/elf_sparc.h
new file mode 100644
index 000000000..9b5c348d9
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/include/elf_sparc.h
@@ -0,0 +1,10 @@
+/* Machine-specific elf macros for the Sparc. */
+#ident "$Id$"
+
+#define ELFCLASSM ELFCLASS32
+#define ELFDATAM ELFDATA2MSB
+
+#define MATCH_MACHINE(x) (x == EM_SPARC)
+
+#define SHT_RELM SHT_RELA
+#define Elf32_RelM Elf32_Rela
diff --git a/mdk-stage1/insmod-modutils/include/elf_sparc64.h b/mdk-stage1/insmod-modutils/include/elf_sparc64.h
new file mode 100644
index 000000000..158edd7e1
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/include/elf_sparc64.h
@@ -0,0 +1,27 @@
+/* Machine-specific elf macros for the Sparc. */
+#ident "$Id$"
+
+#define ELFCLASSM ELFCLASS64
+#define ELFDATAM ELFDATA2MSB
+
+#ifndef EM_SPARCV9
+#define EM_SPARCV9 43
+#endif
+#ifndef EM_SPARC64
+#define EM_SPARC64 11
+#endif
+#define MATCH_MACHINE(x) ((x) == EM_SPARCV9 || (x) == EM_SPARC64)
+
+#define SHT_RELM SHT_RELA
+#define Elf64_RelM Elf64_Rela
+
+#ifndef ELF64_R_SYM
+#define ELF64_R_SYM(x) ((x) >> 32)
+#define ELF64_R_TYPE(x) ((unsigned)(x))
+#endif
+
+#ifndef ELF64_ST_BIND
+#define ELF64_ST_BIND(x) ((x) >> 4)
+#define ELF64_ST_TYPE(x) ((x) & 0xf)
+#endif
+
diff --git a/mdk-stage1/insmod-modutils/include/kallsyms.h b/mdk-stage1/insmod-modutils/include/kallsyms.h
new file mode 100644
index 000000000..9748873cf
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/include/kallsyms.h
@@ -0,0 +1,131 @@
+/* kallsyms headers
+ Copyright 2000 Keith Owens <kaos@ocs.com.au>
+
+ This file is part of the Linux modutils. It is exported to kernel
+ space so debuggers can access the kallsyms data.
+
+ The kallsyms data contains all the non-stack symbols from a kernel
+ or a module. The kernel symbols are held between __start___kallsyms
+ and __stop___kallsyms. The symbols for a module are accessed via
+ the struct module chain which is based at module_list.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ident "$Id$"
+
+#ifndef MODUTILS_KALLSYMS_H
+#define MODUTILS_KALLSYMS_H 1
+
+/* Have to (re)define these ElfW entries here because external kallsyms
+ * code does not have access to modutils/include/obj.h. This code is
+ * included from user spaces tools (modutils) and kernel, they need
+ * different includes.
+ */
+
+#ifndef ELFCLASS32
+#ifdef __KERNEL__
+#include <linux/elf.h>
+#else /* __KERNEL__ */
+#include <elf.h>
+#endif /* __KERNEL__ */
+#endif /* ELFCLASS32 */
+
+#ifndef ELFCLASSM
+#define ELFCLASSM ELF_CLASS
+#endif
+
+#ifndef ElfW
+# if ELFCLASSM == ELFCLASS32
+# define ElfW(x) Elf32_ ## x
+# define ELFW(x) ELF32_ ## x
+# else
+# define ElfW(x) Elf64_ ## x
+# define ELFW(x) ELF64_ ## x
+# endif
+#endif
+
+/* Format of data in the kallsyms section.
+ * Most of the fields are small numbers but the total size and all
+ * offsets can be large so use the 32/64 bit types for these fields.
+ *
+ * Do not use sizeof() on these structures, modutils may be using extra
+ * fields. Instead use the size fields in the header to access the
+ * other bits of data.
+ */
+
+struct kallsyms_header {
+ int size; /* Size of this header */
+ ElfW(Word) total_size; /* Total size of kallsyms data */
+ int sections; /* Number of section entries */
+ ElfW(Off) section_off; /* Offset to first section entry */
+ int section_size; /* Size of one section entry */
+ int symbols; /* Number of symbol entries */
+ ElfW(Off) symbol_off; /* Offset to first symbol entry */
+ int symbol_size; /* Size of one symbol entry */
+ ElfW(Off) string_off; /* Offset to first string */
+ ElfW(Addr) start; /* Start address of first section */
+ ElfW(Addr) end; /* End address of last section */
+};
+
+struct kallsyms_section {
+ ElfW(Addr) start; /* Start address of section */
+ ElfW(Word) size; /* Size of this section */
+ ElfW(Off) name_off; /* Offset to section name */
+ ElfW(Word) flags; /* Flags from section */
+};
+
+struct kallsyms_symbol {
+ ElfW(Off) section_off; /* Offset to section that owns this symbol */
+ ElfW(Addr) symbol_addr; /* Address of symbol */
+ ElfW(Off) name_off; /* Offset to symbol name */
+};
+
+#define KALLSYMS_SEC_NAME "__kallsyms"
+#define KALLSYMS_IDX 2 /* obj_kallsyms creates kallsyms as section 2 */
+
+#define kallsyms_next_sec(h,s) \
+ ((s) = (struct kallsyms_section *)((char *)(s) + (h)->section_size))
+#define kallsyms_next_sym(h,s) \
+ ((s) = (struct kallsyms_symbol *)((char *)(s) + (h)->symbol_size))
+
+int kallsyms_symbol_to_address(
+ const char *name, /* Name to lookup */
+ unsigned long *token, /* Which module to start with */
+ const char **mod_name, /* Set to module name or "kernel" */
+ unsigned long *mod_start, /* Set to start address of module */
+ unsigned long *mod_end, /* Set to end address of module */
+ const char **sec_name, /* Set to section name */
+ unsigned long *sec_start, /* Set to start address of section */
+ unsigned long *sec_end, /* Set to end address of section */
+ const char **sym_name, /* Set to full symbol name */
+ unsigned long *sym_start, /* Set to start address of symbol */
+ unsigned long *sym_end /* Set to end address of symbol */
+ );
+
+int kallsyms_address_to_symbol(
+ unsigned long address, /* Address to lookup */
+ const char **mod_name, /* Set to module name */
+ unsigned long *mod_start, /* Set to start address of module */
+ unsigned long *mod_end, /* Set to end address of module */
+ const char **sec_name, /* Set to section name */
+ unsigned long *sec_start, /* Set to start address of section */
+ unsigned long *sec_end, /* Set to end address of section */
+ const char **sym_name, /* Set to full symbol name */
+ unsigned long *sym_start, /* Set to start address of symbol */
+ unsigned long *sym_end /* Set to end address of symbol */
+ );
+
+#endif /* kallsyms.h */
diff --git a/mdk-stage1/insmod-modutils/include/kerneld.h b/mdk-stage1/insmod-modutils/include/kerneld.h
new file mode 100644
index 000000000..3bc2c9d42
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/include/kerneld.h
@@ -0,0 +1,46 @@
+/* Definitions for the Linux kerneld SYSV IPC interface.
+ This file was part of the Linux kernel, and so is covered by the GPL. */
+
+#ifndef MODUTILS_KERNELD_H
+#define MODUTILS_KERNELD_H
+
+#ident "$Id$"
+
+#define KERNELD_SYSTEM 1
+#define KERNELD_REQUEST_MODULE 2 /* "insmod" */
+#define KERNELD_RELEASE_MODULE 3 /* "rmmod" */
+#define KERNELD_DELAYED_RELEASE_MODULE 4 /* "rmmod" */
+#define KERNELD_CANCEL_RELEASE_MODULE 5 /* "rmmod" */
+#define KERNELD_REQUEST_ROUTE 6 /* net/ipv4/route.c */
+#define KERNELD_BLANKER 7 /* drivers/char/console.c */
+#define KERNELD_PNP 8 /* drivers/pnp/kerneld.c */
+#define KERNELD_ARP 256 /* net/ipv4/arp.c */
+
+#ifdef NEW_KERNELD_PROTOCOL
+# define OLDIPC_KERNELD 00040000 /* old kerneld message channel */
+# define IPC_KERNELD 00140000 /* new kerneld message channel */
+# define KDHDR (sizeof(long) + sizeof(short) + sizeof(short))
+# define NULL_KDHDR 0, 2, 0
+#else /* NEW_KERNELD_PROTOCOL */
+# define IPC_KERNELD 00040000
+# define KDHDR (sizeof(long))
+# define NULL_KDHDR 0
+#endif /* NEW_KERNELD_PROTOCOL */
+
+#define KERNELD_MAXCMD 0x7ffeffff
+#define KERNELD_MINSEQ 0x7fff0000 /* "commands" legal up to 0x7ffeffff */
+#define KERNELD_WAIT 0x80000000
+#define KERNELD_NOWAIT 0
+
+struct kerneld_msg
+ {
+ long mtype;
+ long id;
+#ifdef NEW_KERNELD_PROTOCOL
+ short version;
+ short pid;
+#endif /* NEW_KERNELD_PROTOCOL */
+ char text[1];
+ };
+
+#endif /* kerneld.h */
diff --git a/mdk-stage1/insmod-modutils/include/modstat.h b/mdk-stage1/insmod-modutils/include/modstat.h
new file mode 100644
index 000000000..b8a58eeae
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/include/modstat.h
@@ -0,0 +1,55 @@
+/*
+ * For kernel module status and information
+ *
+ * Add module_name_list and l_module_name_list.
+ * Keith Owens <kaos@ocs.com.au> November 1999.
+ * Björn Ekwall <bj0rn@blox.se> February 1999.
+ *
+ * This file is part of the Linux modutils.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#ifndef _KERNEL_H
+#define _KERNEL_H
+
+#define K_SYMBOLS 1 /* Want info about symbols */
+#define K_INFO 2 /* Want extended module info */
+#define K_REFS 4 /* Want info about references */
+
+struct module_stat {
+ char *name;
+ unsigned long addr;
+ unsigned long modstruct; /* COMPAT_2_0! *//* depends on architecture? */
+ unsigned long size;
+ unsigned long flags;
+ long usecount;
+ size_t nsyms;
+ struct module_symbol *syms;
+ size_t nrefs;
+ struct module_stat **refs;
+ unsigned long status;
+};
+
+extern struct module_stat *module_stat;
+extern size_t n_module_stat;
+extern char *module_name_list;
+extern size_t l_module_name_list;
+extern struct module_symbol *ksyms;
+extern size_t nksyms;
+extern int k_new_syscalls;
+
+int get_kernel_info(int type);
+
+#endif /* _KERNEL_H */
diff --git a/mdk-stage1/insmod-modutils/include/module.h b/mdk-stage1/insmod-modutils/include/module.h
new file mode 100644
index 000000000..db49ab2b2
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/include/module.h
@@ -0,0 +1,210 @@
+/* Definitions for the Linux module syscall interface.
+ Copyright 1996, 1997 Linux International.
+
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+
+#ifndef MODUTILS_MODULE_H
+#define MODUTILS_MODULE_H 1
+
+#ident "$Id$"
+
+/* This file contains the structures used by the 2.0 and 2.1 kernels.
+ We do not use the kernel headers directly because we do not wish
+ to be dependant on a particular kernel version to compile insmod. */
+
+
+/*======================================================================*/
+/* The structures used by Linux 2.0. */
+
+/* The symbol format used by get_kernel_syms(2). */
+struct old_kernel_sym
+{
+ unsigned long value;
+ char name[60];
+};
+
+struct old_module_ref
+{
+ unsigned long module; /* kernel addresses */
+ unsigned long next;
+};
+
+struct old_module_symbol
+{
+ unsigned long addr;
+ unsigned long name;
+};
+
+struct old_symbol_table
+{
+ int size; /* total, including string table!!! */
+ int n_symbols;
+ int n_refs;
+ struct old_module_symbol symbol[0]; /* actual size defined by n_symbols */
+ struct old_module_ref ref[0]; /* actual size defined by n_refs */
+};
+
+struct old_mod_routines
+{
+ unsigned long init;
+ unsigned long cleanup;
+};
+
+struct old_module
+{
+ unsigned long next;
+ unsigned long ref; /* the list of modules that refer to me */
+ unsigned long symtab;
+ unsigned long name;
+ int size; /* size of module in pages */
+ unsigned long addr; /* address of module */
+ int state;
+ unsigned long cleanup; /* cleanup routine */
+};
+
+/* Sent to init_module(2) or'ed into the code size parameter. */
+#define OLD_MOD_AUTOCLEAN 0x40000000 /* big enough, but no sign problems... */
+
+int get_kernel_syms(struct old_kernel_sym *);
+int old_sys_init_module(const char *name, char *code, unsigned codesize,
+ struct old_mod_routines *, struct old_symbol_table *);
+
+/*======================================================================*/
+/* For sizeof() which are related to the module platform and not to the
+ environment isnmod is running in, use sizeof_xx instead of sizeof(xx). */
+
+#define tgt_sizeof_char sizeof(char)
+#define tgt_sizeof_short sizeof(short)
+#define tgt_sizeof_int sizeof(int)
+#define tgt_sizeof_long sizeof(long)
+#define tgt_sizeof_char_p sizeof(char *)
+#define tgt_sizeof_void_p sizeof(void *)
+#define tgt_long long
+#define tgt_long_fmt "l"
+
+/* This assumes that long long on a 32 bit system is equivalent to long on the
+ * equivalent 64 bit system. Also that void and char pointers are 8 bytes on
+ * all 64 bit systems. Add per system tweaks if it ever becomes necessary.
+ */
+#if defined(COMMON_3264) && defined(ONLY_64)
+#undef tgt_long
+#undef tgt_long_fmt
+#undef tgt_sizeof_long
+#undef tgt_sizeof_char_p
+#undef tgt_sizeof_void_p
+#define tgt_long long long
+#define tgt_long_fmt "ll"
+#define tgt_sizeof_long 8
+#define tgt_sizeof_char_p 8
+#define tgt_sizeof_void_p 8
+#endif
+
+/*======================================================================*/
+/* The structures used in Linux 2.1 onwards. */
+
+/* Note: module_symbol does not use tgt_long intentionally */
+struct module_symbol
+{
+ unsigned long value;
+ unsigned long name;
+};
+
+struct module_ref
+{
+ unsigned tgt_long dep; /* kernel addresses */
+ unsigned tgt_long ref;
+ unsigned tgt_long next_ref;
+};
+
+struct module
+{
+ unsigned tgt_long size_of_struct; /* == sizeof(module) */
+ unsigned tgt_long next;
+ unsigned tgt_long name;
+ unsigned tgt_long size;
+
+ tgt_long usecount;
+ unsigned tgt_long flags; /* AUTOCLEAN et al */
+
+ unsigned nsyms;
+ unsigned ndeps;
+
+ unsigned tgt_long syms;
+ unsigned tgt_long deps;
+ unsigned tgt_long refs;
+ unsigned tgt_long init;
+ unsigned tgt_long cleanup;
+ unsigned tgt_long ex_table_start;
+ unsigned tgt_long ex_table_end;
+#ifdef __alpha__
+ unsigned tgt_long gp;
+#endif
+ /* Everything after here is extension. */
+ unsigned tgt_long read_start; /* Read data from existing module */
+ unsigned tgt_long read_end;
+ unsigned tgt_long can_unload;
+ unsigned tgt_long runsize;
+ unsigned tgt_long kallsyms_start;
+ unsigned tgt_long kallsyms_end;
+ unsigned tgt_long archdata_start;
+ unsigned tgt_long archdata_end;
+ unsigned tgt_long kernel_data;
+};
+
+struct module_info
+{
+ unsigned long addr;
+ unsigned long size;
+ unsigned long flags;
+ long usecount;
+};
+
+/* Bits of module.flags. */
+#define NEW_MOD_RUNNING 1
+#define NEW_MOD_DELETED 2
+#define NEW_MOD_AUTOCLEAN 4
+#define NEW_MOD_VISITED 8
+#define NEW_MOD_USED_ONCE 16
+#define NEW_MOD_INITIALIZING 64
+
+int sys_init_module(const char *name, const struct module *);
+int query_module(const char *name, int which, void *buf, size_t bufsize,
+ size_t *ret);
+
+/* Values for query_module's which. */
+
+#define QM_MODULES 1
+#define QM_DEPS 2
+#define QM_REFS 3
+#define QM_SYMBOLS 4
+#define QM_INFO 5
+
+/*======================================================================*/
+/* The system calls unchanged between 2.0 and 2.1. */
+
+unsigned long create_module(const char *, size_t);
+int delete_module(const char *);
+
+/* In safe mode the last parameter is forced to be a module name and meta
+ * expansion is not allowed on that name.
+ */
+extern unsigned int safemode;
+
+#endif /* module.h */
diff --git a/mdk-stage1/insmod-modutils/include/obj.h b/mdk-stage1/insmod-modutils/include/obj.h
new file mode 100644
index 000000000..b140c65c3
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/include/obj.h
@@ -0,0 +1,275 @@
+/* Elf object file loading and relocation routines.
+ Copyright 1996, 1997 Linux International.
+
+ Contributed by Richard Henderson <rth@tamu.edu>
+ obj_free() added by Björn Ekwall <bj0rn@blox.se> March 1999
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+
+#ifndef MODUTILS_OBJ_H
+#define MODUTILS_OBJ_H 1
+
+#ident "$Id$"
+
+/* The relocatable object is manipulated using elfin types. */
+
+#include <stdio.h>
+#include <elf.h>
+#include ELF_MACHINE_H
+
+#ifndef ElfW
+# if ELFCLASSM == ELFCLASS32
+# define ElfW(x) Elf32_ ## x
+# define ELFW(x) ELF32_ ## x
+# else
+# define ElfW(x) Elf64_ ## x
+# define ELFW(x) ELF64_ ## x
+# endif
+#endif
+
+#if defined(COMMON_3264) && defined(ONLY_32)
+# define ObjW(x) obj32_ ## x
+#else
+# if defined(COMMON_3264) && defined(ONLY_64)
+# define ObjW(x) obj64_ ## x
+# else
+# define ObjW(x) obj_ ## x
+# endif
+#endif
+
+/* For some reason this is missing from lib5. */
+#ifndef ELF32_ST_INFO
+# define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf))
+#endif
+
+#ifndef ELF64_ST_INFO
+# define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf))
+#endif
+
+struct obj_string_patch_struct;
+struct obj_symbol_patch_struct;
+
+struct obj_section
+{
+ ElfW(Shdr) header;
+ const char *name;
+ char *contents;
+ struct obj_section *load_next;
+ int idx;
+};
+
+struct obj_symbol
+{
+ struct obj_symbol *next; /* hash table link */
+ const char *name;
+ unsigned long value;
+ unsigned long size;
+ int secidx; /* the defining section index/module */
+ int info;
+ int ksymidx; /* for export to the kernel symtab */
+ int r_type; /* relocation type */
+};
+
+/* Hardcode the hash table size. We shouldn't be needing so many
+ symbols that we begin to degrade performance, and we get a big win
+ by giving the compiler a constant divisor. */
+
+#define HASH_BUCKETS 521
+
+struct obj_file
+{
+ ElfW(Ehdr) header;
+ ElfW(Addr) baseaddr;
+ struct obj_section **sections;
+ struct obj_section *load_order;
+ struct obj_section **load_order_search_start;
+ struct obj_string_patch_struct *string_patches;
+ struct obj_symbol_patch_struct *symbol_patches;
+ int (*symbol_cmp)(const char *, const char *);
+ unsigned long (*symbol_hash)(const char *);
+ unsigned long local_symtab_size;
+ struct obj_symbol **local_symtab;
+ struct obj_symbol *symtab[HASH_BUCKETS];
+ const char *filename;
+ char *persist;
+};
+
+enum obj_reloc
+{
+ obj_reloc_ok,
+ obj_reloc_overflow,
+ obj_reloc_dangerous,
+ obj_reloc_unhandled,
+ obj_reloc_constant_gp
+};
+
+struct obj_string_patch_struct
+{
+ struct obj_string_patch_struct *next;
+ int reloc_secidx;
+ ElfW(Addr) reloc_offset;
+ ElfW(Addr) string_offset;
+};
+
+struct obj_symbol_patch_struct
+{
+ struct obj_symbol_patch_struct *next;
+ int reloc_secidx;
+ ElfW(Addr) reloc_offset;
+ struct obj_symbol *sym;
+};
+
+
+/* Generic object manipulation routines. */
+
+#define obj_elf_hash ObjW(elf_hash)
+#define obj_elf_hash_n ObjW(elf_hash_n)
+#define obj_add_symbol ObjW(add_symbol)
+#define obj_find_symbol ObjW(find_symbol)
+#define obj_symbol_final_value ObjW(symbol_final_value)
+#define obj_set_symbol_compare ObjW(set_symbol_compare)
+#define obj_find_section ObjW(find_section)
+#define obj_insert_section_load_order ObjW(insert_section_load_order)
+#define obj_create_alloced_section ObjW(create_alloced_section)
+#define obj_create_alloced_section_first \
+ ObjW(create_alloced_section_first)
+#define obj_extend_section ObjW(extend_section)
+#define obj_string_patch ObjW(string_patch)
+#define obj_symbol_patch ObjW(symbol_patch)
+#define obj_check_undefineds ObjW(check_undefineds)
+#define obj_clear_undefineds ObjW(clear_undefineds)
+#define obj_allocate_commons ObjW(allocate_commons)
+#define obj_load_size ObjW(load_size)
+#define obj_relocate ObjW(relocate)
+#define obj_load ObjW(load)
+#define obj_free ObjW(free)
+#define obj_create_image ObjW(create_image)
+#define obj_addr_to_native_ptr ObjW(addr_to_native_ptr)
+#define obj_native_ptr_to_addr ObjW(native_ptr_to_addr)
+#define arch_new_file ObjW(arch_new_file)
+#define arch_new_section ObjW(arch_new_section)
+#define arch_new_symbol ObjW(arch_new_symbol)
+#define arch_apply_relocation ObjW(arch_apply_relocation)
+#define arch_create_got ObjW(arch_create_got)
+#define arch_init_module ObjW(arch_init_module)
+#define arch_load_proc_section ObjW(arch_load_proc_section)
+#define arch_finalize_section_address ObjW(arch_finalize_section_address)
+#define arch_archdata ObjW(arch_archdata)
+
+unsigned long obj_elf_hash (const char *);
+
+unsigned long obj_elf_hash_n (const char *, unsigned long len);
+
+struct obj_symbol *obj_add_symbol (struct obj_file *f, const char *name,
+ unsigned long symidx, int info, int secidx,
+ ElfW(Addr) value, unsigned long size);
+
+struct obj_symbol *obj_find_symbol (struct obj_file *f,
+ const char *name);
+
+ElfW(Addr) obj_symbol_final_value (struct obj_file *f,
+ struct obj_symbol *sym);
+
+void obj_set_symbol_compare (struct obj_file *f,
+ int (*cmp)(const char *, const char *),
+ unsigned long (*hash)(const char *));
+
+struct obj_section *obj_find_section (struct obj_file *f,
+ const char *name);
+
+void obj_insert_section_load_order (struct obj_file *f,
+ struct obj_section *sec);
+
+struct obj_section *obj_create_alloced_section (struct obj_file *f,
+ const char *name,
+ unsigned long align,
+ unsigned long size);
+
+struct obj_section *obj_create_alloced_section_first (struct obj_file *f,
+ const char *name,
+ unsigned long align,
+ unsigned long size);
+
+void *obj_extend_section (struct obj_section *sec, unsigned long more);
+
+int obj_string_patch (struct obj_file *f, int secidx, ElfW(Addr) offset,
+ const char *string);
+
+int obj_symbol_patch (struct obj_file *f, int secidx, ElfW(Addr) offset,
+ struct obj_symbol *sym);
+
+int obj_check_undefineds (struct obj_file *f, int quiet);
+
+void obj_clear_undefineds (struct obj_file *f);
+
+void obj_allocate_commons (struct obj_file *f);
+
+unsigned long obj_load_size (struct obj_file *f);
+
+int obj_relocate (struct obj_file *f, ElfW(Addr) base);
+
+struct obj_file *obj_load (int f, Elf32_Half e_type, const char *filename);
+
+void obj_free (struct obj_file *f);
+
+int obj_create_image (struct obj_file *f, char *image);
+
+int obj_kallsyms (struct obj_file *fin, struct obj_file **fout);
+
+/* Architecture specific manipulation routines. */
+
+struct obj_file *arch_new_file (void);
+
+struct obj_section *arch_new_section (void);
+
+struct obj_symbol *arch_new_symbol (void);
+
+enum obj_reloc arch_apply_relocation (struct obj_file *f,
+ struct obj_section *targsec,
+ struct obj_section *symsec,
+ struct obj_symbol *sym,
+ ElfW(RelM) *rel, ElfW(Addr) value);
+
+int arch_create_got (struct obj_file *f);
+
+struct module;
+int arch_init_module (struct obj_file *f, struct module *);
+
+int arch_load_proc_section (struct obj_section *sec, int fp);
+
+int arch_finalize_section_address (struct obj_file *f, ElfW(Addr) base);
+
+int arch_archdata (struct obj_file *fin, struct obj_section *sec);
+
+#define ARCHDATA_SEC_NAME "__archdata"
+
+/* Pointers in objects can be 32 or 64 bit */
+union obj_ptr_4 {
+ Elf32_Word addr;
+ void *ptr;
+};
+union obj_ptr_8 {
+ Elf64_Xword addr;
+ void *ptr;
+};
+
+void *obj_addr_to_native_ptr(ElfW(Addr));
+
+ElfW(Addr) obj_native_ptr_to_addr(void *);
+
+#endif /* obj.h */
diff --git a/mdk-stage1/insmod-modutils/include/util.h b/mdk-stage1/insmod-modutils/include/util.h
new file mode 100644
index 000000000..b2e4a67c3
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/include/util.h
@@ -0,0 +1,101 @@
+/* Miscelaneous utility functions.
+ Copyright 1996, 1997 Linux International.
+
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+
+#ifndef MODUTILS_UTIL_H
+#define MODUTILS_UTIL_H 1
+
+#ident "$Id$"
+
+#include <stdio.h>
+#include <sys/stat.h>
+
+#define SHELL_META "&();|<>$`\"'\\!{}[]~=+:?*" /* Sum of bj0rn and Debian */
+
+void *xmalloc(size_t);
+void *xrealloc(void *, size_t);
+char *xstrdup(const char *);
+char *xstrcat(char *, const char *, size_t);
+int xsystem(const char *, char *const[]);
+int arch64(void);
+
+typedef int (*xftw_func_t)(const char *, const struct stat *);
+extern int xftw(const char *directory, xftw_func_t);
+
+/* Error logging */
+extern int log;
+extern int errors;
+extern const char *error_file;
+
+extern int flag_verbose;
+extern void verbose(const char *ctl,...);
+
+void error(const char *fmt, ...)
+#ifdef __GNUC__
+ __attribute__((format(printf, 1, 2)))
+#endif
+ ;
+
+void lprintf(const char *fmt, ...)
+#ifdef __GNUC__
+ __attribute__((format(printf, 1, 2)))
+#endif
+ ;
+
+void setsyslog(const char *program);
+
+/*
+ * Generic globlist <bj0rn@blox.se>
+ */
+typedef struct {
+ int pathc; /* Count of paths matched so far */
+ char **pathv; /* List of matched pathnames. */
+} GLOB_LIST;
+int meta_expand(char *pt, GLOB_LIST *g, char *base_dir, char *version, int type);
+#define ME_BUILTIN_COMMAND 1
+#define ME_SHELL_COMMAND 2
+#define ME_GLOB 4
+#define ME_ALL (ME_GLOB|ME_SHELL_COMMAND|ME_BUILTIN_COMMAND)
+
+extern void snap_shot(const char *module_name, int number);
+extern void snap_shot_log(const char *fmt,...);
+
+#ifdef CONFIG_USE_ZLIB
+int gzf_open(const char *name, int mode);
+int gzf_read(int fd, void *buf, size_t count);
+off_t gzf_lseek(int fd, off_t offset, int whence);
+void gzf_close(int fd);
+
+#else /* ! CONFIG_USE_ZLIB */
+
+#include <unistd.h>
+
+#define gzf_open open
+#define gzf_read read
+#define gzf_lseek lseek
+#define gzf_close close
+
+#endif /* CONFIG_USE_ZLIB */
+
+#define SYMPREFIX "__insmod_";
+extern const char symprefix[10]; /* Must be sizeof(SYMPREFIX), including nul */
+
+#endif /* util.h */
diff --git a/mdk-stage1/insmod-modutils/include/version.h b/mdk-stage1/insmod-modutils/include/version.h
new file mode 100644
index 000000000..51ca0eb29
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/include/version.h
@@ -0,0 +1 @@
+#define MODUTILS_VERSION "2.4.2"
diff --git a/mdk-stage1/insmod-modutils/insmod-frontend.c b/mdk-stage1/insmod-modutils/insmod-frontend.c
new file mode 100644
index 000000000..2b3aa1acb
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/insmod-frontend.c
@@ -0,0 +1,24 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 MandrakeSoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdio.h>
+
+
+int insmod_main( int argc, char **argv);
+
+int main( int argc, char **argv)
+{
+ printf("Using insmod provided by modutils.\n");
+ return insmod_main(argc, argv);
+}
diff --git a/mdk-stage1/insmod-modutils/insmod.c b/mdk-stage1/insmod-modutils/insmod.c
new file mode 100644
index 000000000..359b28837
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/insmod.c
@@ -0,0 +1,1964 @@
+/* Insert a module into a running kernel.
+ Copyright 1996, 1997 Linux International.
+
+ New implementation contributed by Richard Henderson <rth@tamu.edu>
+ Based on original work by Bjorn Ekwall <bj0rn@blox.se>
+ Restructured (and partly rewritten) by:
+ Björn Ekwall <bj0rn@blox.se> February 1999
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+ /*
+ Fixes:
+
+ Adjust module size for mod_use_count in old_init_module:
+ B. James Phillippe <bryan@terran.org>
+
+ Merged modprobe + many fixes: Björn Ekwall <bj0rn@blox.se> February 1999
+ SMP "friendliness" (and -P): Bill Zumach <zumach+@transarc.com>
+
+ Ksymoops support: Keith Owens <kaos@ocs.com.au> August 1999.
+
+ Add -r flag: Keith Owens <kaos@ocs.com.au> October 1999.
+
+ More flexible recognition of the way the utility was called.
+ Suggested by Stepan Kasal, implemented in a different way by Keith
+ Owens <kaos@ocs.com.au> December 1999.
+
+ Rationalize common code for 32/64 bit architectures.
+ Keith Owens <kaos@ocs.com.au> December 1999.
+ Add arch64().
+ Keith Owens <kaos@ocs.com.au> December 1999.
+ kallsyms support
+ Keith Owens <kaos@ocs.com.au> April 2000.
+ archdata support
+ Keith Owens <kaos@ocs.com.au> August 2000.
+ Add insmod -O, move print map before sys_init_module.
+ Keith Owens <kaos@ocs.com.au> October 2000.
+ Add insmod -S.
+ Keith Owens <kaos@ocs.com.au> November 2000.
+ Add persistent data support.
+ Keith Owens <kaos@ocs.com.au> November 2000.
+ */
+
+#ident "$Id$"
+
+#include "../insmod.h"
+#include <sys/types.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+//#include <alloca.h> provided by stdlib
+#include <limits.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stddef.h>
+#include <getopt.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+
+#include "module.h"
+#include "obj.h"
+#include "kallsyms.h"
+#include "util.h"
+#include "version.h"
+
+#include "modstat.h"
+#include "config.h"
+
+#define STRVERSIONLEN 32
+
+/*======================================================================*/
+
+static int flag_force_load = 0;
+static int flag_silent_probe = 0;
+static int flag_export = 1;
+static int flag_load_map = 0;
+static int flag_ksymoops = 1;
+
+static int n_ext_modules_used;
+static int m_has_modinfo;
+
+extern int insmod_main(int argc, char **argv);
+extern int insmod_main_32(int argc, char **argv);
+extern int insmod_main_64(int argc, char **argv);
+extern int modprobe_main(int argc, char **argv);
+extern int rmmod_main(int argc, char **argv);
+extern int ksyms_main(int argc, char **argv);
+extern int lsmod_main(int argc, char **argv);
+extern int kallsyms_main(int argc, char **argv);
+
+/*======================================================================*/
+
+/* Get the kernel version in the canonical integer form. */
+
+static int get_kernel_version(char str[STRVERSIONLEN])
+{
+ char *p, *q;
+ int a, b, c;
+
+ strncpy(str, uts_info.release, STRVERSIONLEN);
+ p = uts_info.release;
+
+ a = strtoul(p, &p, 10);
+ if (*p != '.')
+ return -1;
+ b = strtoul(p + 1, &p, 10);
+ if (*p != '.')
+ return -1;
+ c = strtoul(p + 1, &q, 10);
+ if (p + 1 == q)
+ return -1;
+
+ return a << 16 | b << 8 | c;
+}
+
+/* String comparison for non-co-versioned kernel and module.
+ * prefix should be the same as used by genksyms for this kernel.
+ */
+static char *ncv_prefix = NULL; /* Overridden by --prefix option */
+static int ncv_plen = 0;
+
+/* Only set prefix once. If set by the user, use it. If not set by the
+ * user, look for a well known kernel symbol and derive the prefix from
+ * there. Otherwise set the prefix depending on whether uts_info
+ * includes SMP or not for backwards compatibility.
+ */
+static void set_ncv_prefix(char *prefix)
+{
+ static char derived_prefix[256];
+ static const char *well_known_symbol[] = { "get_module_symbol_R",
+ "inter_module_get_R",
+ };
+ struct module_symbol *s;
+ int i, j, l, m, pl;
+ const char *name;
+ char *p;
+
+ if (ncv_prefix)
+ return;
+
+ if (prefix)
+ ncv_prefix = prefix;
+ else {
+ /* Extract the prefix (if any) from well known symbols */
+ for (i = 0, s = ksyms; i < nksyms; ++i, ++s) {
+ name = (char *) s->name;
+ l = strlen(name);
+ for (j = 0; j < sizeof(well_known_symbol)/sizeof(well_known_symbol[0]); ++j) {
+ m = strlen(well_known_symbol[j]);
+ if (m + 8 > l ||
+ strncmp(name, well_known_symbol[j], m))
+ continue;
+ pl = l - m - 8;
+ if (pl > sizeof(derived_prefix)-1)
+ continue; /* Prefix is wrong length */
+ /* Must end with 8 hex digits */
+ (void) strtoul(name+l-8, &p, 16);
+ if (*p == 0) {
+ strncpy(derived_prefix, name+m, pl);
+ *(derived_prefix+pl) = '\0';
+ ncv_prefix = derived_prefix;
+ break;
+ }
+ }
+ }
+ }
+ if (!ncv_prefix) {
+ p = strchr(uts_info.version, ' ');
+ if (p && *(++p) && !strncmp(p, "SMP ", 4))
+ ncv_prefix = "smp_";
+ else
+ ncv_prefix = "";
+ }
+ ncv_plen = strlen(ncv_prefix);
+ if (flag_verbose)
+ lprintf("Symbol version prefix '%s'", ncv_prefix);
+}
+
+static int ncv_strcmp(const char *a, const char *b)
+{
+ size_t alen = strlen(a), blen = strlen(b);
+
+ if (blen == alen + 10 + ncv_plen &&
+ b[alen] == '_' &&
+ b[alen + 1] == 'R' &&
+ !(ncv_plen && strncmp(b + alen + 2, ncv_prefix, ncv_plen))) {
+ return strncmp(a, b, alen);
+ } else if (alen == blen + 10 + ncv_plen &&
+ a[blen] == '_' && a[blen + 1] == 'R' &&
+ !(ncv_plen && strncmp(a + blen + 2, ncv_prefix, ncv_plen))) {
+ return strncmp(a, b, blen);
+ } else
+ return strcmp(a, b);
+}
+
+/*
+ * String hashing for non-co-versioned kernel and module.
+ * Here we are simply forced to drop the crc from the hash.
+ */
+static unsigned long ncv_symbol_hash(const char *str)
+{
+ size_t len = strlen(str);
+
+ if (len > 10 + ncv_plen &&
+ str[len - 10 - ncv_plen] == '_' &&
+ str[len - 9 - ncv_plen] == 'R' &&
+ !(
+ ncv_plen &&
+ strncmp(str + len - (8 + ncv_plen), ncv_prefix, ncv_plen)
+ ))
+ len -= 10 + ncv_plen;
+ return obj_elf_hash_n(str, len);
+}
+
+/*
+ * Conditionally add the symbols from the given symbol set
+ * to the new module.
+ */
+static int add_symbols_from(struct obj_file *f, int idx,
+ struct module_symbol *syms, size_t nsyms)
+{
+ struct module_symbol *s;
+ size_t i;
+ int used = 0;
+
+ for (i = 0, s = syms; i < nsyms; ++i, ++s) {
+ /*
+ * Only add symbols that are already marked external.
+ * If we override locals we may cause problems for
+ * argument initialization.
+ * We will also create a false dependency on the module.
+ */
+ struct obj_symbol *sym;
+
+ sym = obj_find_symbol(f, (char *) s->name);
+ if (sym && !ELFW(ST_BIND) (sym->info) == STB_LOCAL) {
+ sym = obj_add_symbol(f, (char *) s->name, -1,
+ ELFW(ST_INFO) (STB_GLOBAL, STT_NOTYPE),
+ idx, s->value, 0);
+ /*
+ * Did our symbol just get installed?
+ * If so, mark the module as "used".
+ */
+ if (sym->secidx == idx)
+ used = 1;
+ }
+ }
+
+ return used;
+}
+
+static void add_kernel_symbols(struct obj_file *f)
+{
+ struct module_stat *m;
+ size_t i, nused = 0;
+
+ /* Add module symbols first. */
+ for (i = 0, m = module_stat; i < n_module_stat; ++i, ++m)
+ if (m->nsyms &&
+ add_symbols_from(f, SHN_HIRESERVE + 2 + i, m->syms, m->nsyms))
+ m->status = 1 /* used */, ++nused;
+ n_ext_modules_used = nused;
+
+ /* And finally the symbols from the kernel proper. */
+ if (nksyms)
+ add_symbols_from(f, SHN_HIRESERVE + 1, ksyms, nksyms);
+}
+
+static void hide_special_symbols(struct obj_file *f)
+{
+ struct obj_symbol *sym;
+ const char *const *p;
+ static const char *const specials[] =
+ {
+ "cleanup_module",
+ "init_module",
+ "kernel_version",
+ NULL
+ };
+
+ for (p = specials; *p; ++p)
+ if ((sym = obj_find_symbol(f, *p)) != NULL)
+ sym->info = ELFW(ST_INFO) (STB_LOCAL, ELFW(ST_TYPE) (sym->info));
+}
+
+static void print_load_map(struct obj_file *f)
+{
+ struct obj_symbol *sym;
+ struct obj_symbol **all, **p;
+ struct obj_section *sec;
+ int load_map_cmp(const void *a, const void *b) {
+ struct obj_symbol **as = (struct obj_symbol **) a;
+ struct obj_symbol **bs = (struct obj_symbol **) b;
+ unsigned long aa = obj_symbol_final_value(f, *as);
+ unsigned long ba = obj_symbol_final_value(f, *bs);
+ return aa < ba ? -1 : aa > ba ? 1 : 0;
+ }
+ int i, nsyms, *loaded;
+
+ /* Report on the section layout. */
+
+ lprintf("Sections: Size %-*s Align",
+ (int) (2 * sizeof(void *)), "Address");
+
+ for (sec = f->load_order; sec; sec = sec->load_next) {
+ int a;
+ unsigned long tmp;
+
+ for (a = -1, tmp = sec->header.sh_addralign; tmp; ++a)
+ tmp >>= 1;
+ if (a == -1)
+ a = 0;
+
+ lprintf("%-16s%08lx %0*lx 2**%d",
+ sec->name,
+ (long)sec->header.sh_size,
+ (int) (2 * sizeof(void *)),
+ (long)sec->header.sh_addr,
+ a);
+ }
+
+ /* Quick reference which section indicies are loaded. */
+
+ loaded = alloca(sizeof(int) * (i = f->header.e_shnum));
+ while (--i >= 0)
+ loaded[i] = (f->sections[i]->header.sh_flags & SHF_ALLOC) != 0;
+
+ /* Collect the symbols we'll be listing. */
+
+ for (nsyms = i = 0; i < HASH_BUCKETS; ++i)
+ for (sym = f->symtab[i]; sym; sym = sym->next)
+ if (sym->secidx <= SHN_HIRESERVE
+ && (sym->secidx >= SHN_LORESERVE || loaded[sym->secidx]))
+ ++nsyms;
+
+ all = alloca(nsyms * sizeof(struct obj_symbol *));
+
+ for (i = 0, p = all; i < HASH_BUCKETS; ++i)
+ for (sym = f->symtab[i]; sym; sym = sym->next)
+ if (sym->secidx <= SHN_HIRESERVE
+ && (sym->secidx >= SHN_LORESERVE || loaded[sym->secidx]))
+ *p++ = sym;
+
+ /* Sort them by final value. */
+ qsort(all, nsyms, sizeof(struct obj_file *), load_map_cmp);
+
+ /* And list them. */
+ lprintf("\nSymbols:");
+ for (p = all; p < all + nsyms; ++p) {
+ char type = '?';
+ unsigned long value;
+
+ sym = *p;
+ if (sym->secidx == SHN_ABS) {
+ type = 'A';
+ value = sym->value;
+ } else if (sym->secidx == SHN_UNDEF) {
+ type = 'U';
+ value = 0;
+ } else {
+ struct obj_section *sec = f->sections[sym->secidx];
+
+ if (sec->header.sh_type == SHT_NOBITS)
+ type = 'B';
+ else if (sec->header.sh_flags & SHF_ALLOC) {
+ if (sec->header.sh_flags & SHF_EXECINSTR)
+ type = 'T';
+ else if (sec->header.sh_flags & SHF_WRITE)
+ type = 'D';
+ else
+ type = 'R';
+ }
+ value = sym->value + sec->header.sh_addr;
+ }
+
+ if (ELFW(ST_BIND) (sym->info) == STB_LOCAL)
+ type = tolower(type);
+
+ lprintf("%0*lx %c %s", (int) (2 * sizeof(void *)), value,
+ type, sym->name);
+ }
+}
+
+/************************************************************************/
+/* begin compat */
+
+static char * get_modinfo_value(struct obj_file *f, const char *key)
+{
+ struct obj_section *sec;
+ char *p, *v, *n, *ep;
+ size_t klen = strlen(key);
+
+ sec = obj_find_section(f, ".modinfo");
+ if (sec == NULL)
+ return NULL;
+
+ p = sec->contents;
+ ep = p + sec->header.sh_size;
+ while (p < ep) {
+ v = strchr(p, '=');
+ n = strchr(p, '\0');
+ if (v) {
+ if (v - p == klen && strncmp(p, key, klen) == 0)
+ return v + 1;
+ } else {
+ if (n - p == klen && strcmp(p, key) == 0)
+ return n;
+ }
+ p = n + 1;
+ }
+
+ return NULL;
+}
+
+static int create_this_module(struct obj_file *f, const char *m_name)
+{
+ struct obj_section *sec;
+
+ sec = obj_create_alloced_section_first(f, ".this", tgt_sizeof_long,
+ sizeof(struct module));
+ memset(sec->contents, 0, sizeof(struct module));
+
+ obj_add_symbol(f, "__this_module", -1, ELFW(ST_INFO) (STB_LOCAL, STT_OBJECT),
+ sec->idx, 0, sizeof(struct module));
+
+ obj_string_patch(f, sec->idx, offsetof(struct module, name), m_name);
+
+ return 1;
+}
+
+#ifdef COMPAT_2_0
+static int old_create_mod_use_count(struct obj_file *f)
+{
+ struct obj_section *sec;
+ struct obj_symbol *got;
+
+ sec = obj_create_alloced_section_first(f, ".moduse",
+ sizeof(long), sizeof(long));
+
+ obj_add_symbol(f, "mod_use_count_",
+ -1, ELFW(ST_INFO)(STB_LOCAL, STT_OBJECT),
+ sec->idx, 0, sizeof(long));
+
+ /*
+ * patb: if there is a _GLOBAL_OFFSET_TABLE_,
+ * add .got section for PIC type modules;
+ * we have to do this here, because obj_* calls are not made until
+ * after obj_check_undefined
+ * is there a better place for this exception?
+ */
+ got = obj_find_symbol(f, "_GLOBAL_OFFSET_TABLE_");
+ if (got)
+{
+ sec = obj_create_alloced_section(f, ".got",
+ sizeof(long), sizeof(long));
+ got->secidx = sec->idx; /* mark the symbol as defined */
+ }
+ return 1;
+}
+#endif
+
+/* add an entry to the __ksymtab section, creating it if necessary */
+static void add_ksymtab(struct obj_file *f, struct obj_symbol *sym)
+{
+ struct obj_section *sec;
+ ElfW(Addr) ofs;
+
+ /* ensure __ksymtab is allocated, EXPORT_NOSYMBOLS creates a non-alloc section.
+ * If __ksymtab is defined but not marked alloc, x out the first character
+ * (no obj_delete routine) and create a new __ksymtab with the correct
+ * characteristics.
+ */
+ sec = obj_find_section(f, "__ksymtab");
+ if (sec && !(sec->header.sh_flags & SHF_ALLOC)) {
+ *((char *)(sec->name)) = 'x'; /* override const */
+ sec = NULL;
+ }
+ if (!sec)
+ sec = obj_create_alloced_section(f, "__ksymtab", tgt_sizeof_void_p, 0);
+ if (!sec)
+ return;
+ sec->header.sh_flags |= SHF_ALLOC;
+
+ ofs = sec->header.sh_size;
+ obj_symbol_patch(f, sec->idx, ofs, sym);
+ obj_string_patch(f, sec->idx, ofs + tgt_sizeof_void_p, sym->name);
+ obj_extend_section(sec, 2 * tgt_sizeof_char_p);
+}
+
+static int create_module_ksymtab(struct obj_file *f)
+{
+ struct obj_section *sec;
+ int i;
+
+ /* We must always add the module references. */
+
+ if (n_ext_modules_used) {
+ struct module_ref *dep;
+ struct obj_symbol *tm;
+
+ sec = obj_create_alloced_section(f, ".kmodtab", tgt_sizeof_void_p,
+ (sizeof(struct module_ref)
+ * n_ext_modules_used));
+ if (!sec)
+ return 0;
+
+ tm = obj_find_symbol(f, "__this_module");
+ dep = (struct module_ref *) sec->contents;
+ for (i = 0; i < n_module_stat; ++i)
+ if (module_stat[i].status /* used */) {
+ dep->dep = module_stat[i].addr;
+ obj_symbol_patch(f, sec->idx, (char *) &dep->ref - sec->contents, tm);
+ dep->next_ref = 0;
+ ++dep;
+ }
+ }
+ if (flag_export && !obj_find_section(f, "__ksymtab")) {
+ int *loaded;
+
+ /* We don't want to export symbols residing in sections that
+ aren't loaded. There are a number of these created so that
+ we make sure certain module options don't appear twice. */
+
+ loaded = alloca(sizeof(int) * (i = f->header.e_shnum));
+ while (--i >= 0)
+ loaded[i] = (f->sections[i]->header.sh_flags & SHF_ALLOC) != 0;
+
+ for (i = 0; i < HASH_BUCKETS; ++i) {
+ struct obj_symbol *sym;
+ for (sym = f->symtab[i]; sym; sym = sym->next) {
+ if (ELFW(ST_BIND) (sym->info) != STB_LOCAL
+ && sym->secidx <= SHN_HIRESERVE
+ && (sym->secidx >= SHN_LORESERVE
+ || loaded[sym->secidx])) {
+ add_ksymtab(f, sym);
+ }
+ }
+ }
+ }
+ return 1;
+}
+
+/* Get the module's kernel version in the canonical integer form. */
+static int get_module_version(struct obj_file *f, char str[STRVERSIONLEN])
+{
+ int a, b, c;
+ char *p, *q;
+
+ if ((p = get_modinfo_value(f, "kernel_version")) == NULL) {
+ struct obj_symbol *sym;
+
+ m_has_modinfo = 0;
+ if ((sym = obj_find_symbol(f, "kernel_version")) == NULL)
+ sym = obj_find_symbol(f, "__module_kernel_version");
+ if (sym == NULL)
+ return -1;
+ p = f->sections[sym->secidx]->contents + sym->value;
+ } else
+ m_has_modinfo = 1;
+
+ strncpy(str, p, STRVERSIONLEN);
+
+ a = strtoul(p, &p, 10);
+ if (*p != '.')
+ return -1;
+ b = strtoul(p + 1, &p, 10);
+ if (*p != '.')
+ return -1;
+ c = strtoul(p + 1, &q, 10);
+ if (p + 1 == q)
+ return -1;
+
+ return a << 16 | b << 8 | c;
+}
+
+/* Return the kernel symbol checksum version, or zero if not used. */
+static int is_kernel_checksummed(void)
+{
+ struct module_symbol *s;
+ size_t i;
+
+ /*
+ * Using_Versions might not be the first symbol,
+ * but it should be in there.
+ */
+ for (i = 0, s = ksyms; i < nksyms; ++i, ++s)
+ if (strcmp((char *) s->name, "Using_Versions") == 0)
+ return s->value;
+
+ return 0;
+}
+
+static int is_module_checksummed(struct obj_file *f)
+{
+ if (m_has_modinfo) {
+ const char *p = get_modinfo_value(f, "using_checksums");
+ if (p)
+ return atoi(p);
+ else
+ return 0;
+ } else
+ return obj_find_symbol(f, "Using_Versions") != NULL;
+}
+
+/* add module source, timestamp, kernel version and a symbol for the
+ * start of some sections. this info is used by ksymoops to do better
+ * debugging.
+ */
+static void add_ksymoops_symbols(struct obj_file *f, const char *filename,
+ const char *m_name)
+{
+ struct obj_section *sec;
+ struct obj_symbol *sym;
+ char *name, *absolute_filename;
+ char str[STRVERSIONLEN], real[PATH_MAX];
+ int i, l, lm_name, lfilename, use_ksymtab, version;
+ struct stat statbuf;
+
+ static const char *section_names[] = {
+ ".text",
+ ".rodata",
+ ".data",
+ ".bss"
+ };
+
+ if (realpath(filename, real)) {
+ absolute_filename = xstrdup(real);
+ }
+ else {
+ int save_errno = errno;
+ error("cannot get realpath for %s", filename);
+ errno = save_errno;
+ absolute_filename = xstrdup(filename);
+ }
+
+ lm_name = strlen(m_name);
+ lfilename = strlen(absolute_filename);
+
+ /* add to ksymtab if it already exists or there is no ksymtab and other symbols
+ * are not to be exported. otherwise leave ksymtab alone for now, the
+ * "export all symbols" compatibility code will export these symbols later.
+ */
+
+ use_ksymtab = obj_find_section(f, "__ksymtab") || !flag_export;
+
+ if ((sec = obj_find_section(f, ".this"))) {
+ /* tag the module header with the object name, last modified
+ * timestamp and module version. worst case for module version
+ * is 0xffffff, decimal 16777215. putting all three fields in
+ * one symbol is less readable but saves kernel space.
+ */
+ l = sizeof(symprefix)+ /* "__insmod_" */
+ lm_name+ /* module name */
+ 2+ /* "_O" */
+ lfilename+ /* object filename */
+ 2+ /* "_M" */
+ 2*sizeof(statbuf.st_mtime)+ /* mtime in hex */
+ 2+ /* "_V" */
+ 8+ /* version in dec */
+ 1; /* nul */
+ name = xmalloc(l);
+ if (stat(absolute_filename, &statbuf) != 0)
+ statbuf.st_mtime = 0;
+ version = get_module_version(f, str); /* -1 if not found */
+ snprintf(name, l, "%s%s_O%s_M%0*lX_V%d",
+ symprefix, m_name, absolute_filename,
+ 2*sizeof(statbuf.st_mtime), statbuf.st_mtime,
+ version);
+ sym = obj_add_symbol(f, name, -1,
+ ELFW(ST_INFO) (STB_GLOBAL, STT_NOTYPE),
+ sec->idx, sec->header.sh_addr, 0);
+ if (use_ksymtab)
+ add_ksymtab(f, sym);
+ }
+ free(absolute_filename);
+
+ /* record where the persistent data is going, same address as previous symbol */
+
+ if (f->persist) {
+ l = sizeof(symprefix)+ /* "__insmod_" */
+ lm_name+ /* module name */
+ 2+ /* "_P" */
+ strlen(f->persist)+ /* data store */
+ 1; /* nul */
+ name = xmalloc(l);
+ snprintf(name, l, "%s%s_P%s",
+ symprefix, m_name, f->persist);
+ sym = obj_add_symbol(f, name, -1, ELFW(ST_INFO) (STB_GLOBAL, STT_NOTYPE),
+ sec->idx, sec->header.sh_addr, 0);
+ if (use_ksymtab)
+ add_ksymtab(f, sym);
+ }
+
+ /* tag the desired sections if size is non-zero */
+
+ for (i = 0; i < sizeof(section_names)/sizeof(section_names[0]); ++i) {
+ if ((sec = obj_find_section(f, section_names[i])) &&
+ sec->header.sh_size) {
+ l = sizeof(symprefix)+ /* "__insmod_" */
+ lm_name+ /* module name */
+ 2+ /* "_S" */
+ strlen(sec->name)+ /* section name */
+ 2+ /* "_L" */
+ 8+ /* length in dec */
+ 1; /* nul */
+ name = xmalloc(l);
+ snprintf(name, l, "%s%s_S%s_L%ld",
+ symprefix, m_name, sec->name,
+ (long)sec->header.sh_size);
+ sym = obj_add_symbol(f, name, -1, ELFW(ST_INFO) (STB_GLOBAL, STT_NOTYPE),
+ sec->idx, sec->header.sh_addr, 0);
+ if (use_ksymtab)
+ add_ksymtab(f, sym);
+ }
+ }
+}
+
+static int process_module_arguments(struct obj_file *f, int argc, char **argv, int required)
+{
+ for (; argc > 0; ++argv, --argc) {
+ struct obj_symbol *sym;
+ int c;
+ int min, max;
+ int n;
+ char *contents;
+ char *input;
+ char *fmt;
+ char *key;
+ char *loc;
+
+ if ((input = strchr(*argv, '=')) == NULL)
+ continue;
+
+ n = input - *argv;
+ input += 1; /* skip '=' */
+
+ key = alloca(n + 6);
+
+ if (m_has_modinfo) {
+ memcpy(key, "parm_", 5);
+ memcpy(key + 5, *argv, n);
+ key[n + 5] = '\0';
+ if ((fmt = get_modinfo_value(f, key)) == NULL) {
+ if (required) {
+ error("invalid parameter %s", key);
+ return 0;
+ }
+ else {
+ if (flag_verbose)
+ lprintf("ignoring %s", *argv);
+ continue; /* silently ignore optional parameters */
+ }
+ }
+ key += 5;
+
+ if (isdigit(*fmt)) {
+ min = strtoul(fmt, &fmt, 10);
+ if (*fmt == '-')
+ max = strtoul(fmt + 1, &fmt, 10);
+ else
+ max = min;
+ } else
+ min = max = 1;
+ } else { /* not m_has_modinfo */
+ memcpy(key, *argv, n);
+ key[n] = '\0';
+
+ if (isdigit(*input))
+ fmt = "i";
+ else
+ fmt = "s";
+ min = max = 0;
+ }
+
+ sym = obj_find_symbol(f, key);
+
+ /*
+ * Also check that the parameter was not
+ * resolved from the kernel.
+ */
+ if (sym == NULL || sym->secidx > SHN_HIRESERVE) {
+ error("symbol for parameter %s not found", key);
+ return 0;
+ }
+
+ contents = f->sections[sym->secidx]->contents;
+ loc = contents + sym->value;
+ n = 1;
+
+ while (*input) {
+ char *str;
+
+ switch (*fmt) {
+ case 's':
+ case 'c':
+ /*
+ * Do C quoting if we begin with a ",
+ * else slurp the lot.
+ */
+ if (*input == '"') {
+ char *r;
+
+ str = alloca(strlen(input));
+ for (r = str, input++; *input != '"'; ++input, ++r) {
+ if (*input == '\0') {
+ error("improperly terminated string argument for %s", key);
+ return 0;
+ }
+ /* else */
+ if (*input != '\\') {
+ *r = *input;
+ continue;
+ }
+ /* else handle \ */
+ switch (*++input) {
+ case 'a': *r = '\a'; break;
+ case 'b': *r = '\b'; break;
+ case 'e': *r = '\033'; break;
+ case 'f': *r = '\f'; break;
+ case 'n': *r = '\n'; break;
+ case 'r': *r = '\r'; break;
+ case 't': *r = '\t'; break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ c = *input - '0';
+ if ('0' <= input[1] && input[1] <= '7') {
+ c = (c * 8) + *++input - '0';
+ if ('0' <= input[1] && input[1] <= '7')
+ c = (c * 8) + *++input - '0';
+ }
+ *r = c;
+ break;
+
+ default: *r = *input; break;
+ }
+ }
+ *r = '\0';
+ ++input;
+ } else {
+ /*
+ * The string is not quoted.
+ * We will break it using the comma
+ * (like for ints).
+ * If the user wants to include commas
+ * in a string, he just has to quote it
+ */
+ char *r;
+
+ /* Search the next comma */
+ if ((r = strchr(input, ',')) != NULL) {
+ /*
+ * Found a comma
+ * Recopy the current field
+ */
+ str = alloca(r - input + 1);
+ memcpy(str, input, r - input);
+ str[r - input] = '\0';
+ /* Keep next fields */
+ input = r;
+ } else {
+ /* last string */
+ str = input;
+ input = "";
+ }
+ }
+
+ if (*fmt == 's') {
+ /* Normal string */
+ obj_string_patch(f, sym->secidx, loc - contents, str);
+ loc += tgt_sizeof_char_p;
+ } else {
+ /* Array of chars (in fact, matrix !) */
+ long charssize; /* size of each member */
+
+ /* Get the size of each member */
+ /* Probably we should do that outside the loop ? */
+ if (!isdigit(*(fmt + 1))) {
+ error("parameter type 'c' for %s must be followed by"
+ " the maximum size", key);
+ return 0;
+ }
+ charssize = strtoul(fmt + 1, (char **) NULL, 10);
+
+ /* Check length */
+ if (strlen(str) >= charssize-1) {
+ error("string too long for %s (max %ld)",
+ key, charssize - 1);
+ return 0;
+ }
+ /* Copy to location */
+ strcpy((char *) loc, str); /* safe, see check above */
+ loc += charssize;
+ }
+ /*
+ * End of 's' and 'c'
+ */
+ break;
+
+ case 'b':
+ *loc++ = strtoul(input, &input, 0);
+ break;
+
+ case 'h':
+ *(short *) loc = strtoul(input, &input, 0);
+ loc += tgt_sizeof_short;
+ break;
+
+ case 'i':
+ *(int *) loc = strtoul(input, &input, 0);
+ loc += tgt_sizeof_int;
+ break;
+
+ case 'l':
+ *(long *) loc = strtoul(input, &input, 0);
+ loc += tgt_sizeof_long;
+ break;
+
+ default:
+ error("unknown parameter type '%c' for %s",
+ *fmt, key);
+ return 0;
+ }
+ /*
+ * end of switch (*fmt)
+ */
+
+ while (*input && isspace(*input))
+ ++input;
+ if (*input == '\0')
+ break; /* while (*input) */
+ /* else */
+
+ if (*input == ',') {
+ if (max && (++n > max)) {
+ error("too many values for %s (max %d)", key, max);
+ return 0;
+ }
+ ++input;
+ /* continue with while (*input) */
+ } else {
+ error("invalid argument syntax for %s: '%c'",
+ key, *input);
+ return 0;
+ }
+ } /* end of while (*input) */
+
+ if (min && (n < min)) {
+ error("too few values for %s (min %d)", key, min);
+ return 0;
+ }
+ } /* end of for (;argc > 0;) */
+
+ return 1;
+}
+
+
+/* Add a kallsyms section if the kernel supports all symbols. */
+static int add_kallsyms(struct obj_file *f,
+ struct obj_section **module_kallsyms, int force_kallsyms)
+{
+ struct module_symbol *s;
+ struct obj_file *f_kallsyms;
+ struct obj_section *sec_kallsyms;
+ size_t i;
+ int l;
+ const char *p, *pt_R;
+ unsigned long start = 0, stop = 0;
+
+ for (i = 0, s = ksyms; i < nksyms; ++i, ++s) {
+ p = (char *)s->name;
+ pt_R = strstr(p, "_R");
+ if (pt_R)
+ l = pt_R - p;
+ else
+ l = strlen(p);
+ if (strncmp(p, "__start_" KALLSYMS_SEC_NAME, l) == 0)
+ start = s->value;
+ else if (strncmp(p, "__stop_" KALLSYMS_SEC_NAME, l) == 0)
+ stop = s->value;
+ }
+
+ if (start >= stop && !force_kallsyms)
+ return(0);
+
+ /* The kernel contains all symbols, do the same for this module. */
+
+ /* Add an empty kallsyms section to the module if necessary */
+ for (i = 0; i < f->header.e_shnum; ++i) {
+ if (strcmp(f->sections[i]->name, KALLSYMS_SEC_NAME) == 0) {
+ *module_kallsyms = f->sections[i];
+ break;
+ }
+ }
+ if (!*module_kallsyms)
+ *module_kallsyms = obj_create_alloced_section(f, KALLSYMS_SEC_NAME, 0, 0);
+
+ /* Size and populate kallsyms */
+ if (obj_kallsyms(f, &f_kallsyms))
+ return(1);
+ sec_kallsyms = f_kallsyms->sections[KALLSYMS_IDX];
+ (*module_kallsyms)->header.sh_addralign = sec_kallsyms->header.sh_addralign;
+ (*module_kallsyms)->header.sh_size = sec_kallsyms->header.sh_size;
+ free((*module_kallsyms)->contents);
+ (*module_kallsyms)->contents = sec_kallsyms->contents;
+ sec_kallsyms->contents = NULL;
+ obj_free(f_kallsyms);
+
+ return 0;
+}
+
+
+/* Add an arch data section if the arch wants it. */
+static int add_archdata(struct obj_file *f,
+ struct obj_section **sec)
+{
+ size_t i;
+
+ *sec = NULL;
+ /* Add an empty archdata section to the module if necessary */
+ for (i = 0; i < f->header.e_shnum; ++i) {
+ if (strcmp(f->sections[i]->name, ARCHDATA_SEC_NAME) == 0) {
+ *sec = f->sections[i];
+ break;
+ }
+ }
+ if (!*sec)
+ *sec = obj_create_alloced_section(f, ARCHDATA_SEC_NAME, 16, 0);
+
+ /* Size and populate archdata */
+ if (arch_archdata(f, *sec))
+ return(1);
+ return 0;
+}
+
+
+static int init_module(const char *m_name, struct obj_file *f,
+ unsigned long m_size, const char *blob_name,
+ unsigned int noload, unsigned int flag_load_map)
+{
+ struct module *module;
+ struct obj_section *sec;
+ void *image;
+ int ret = 0;
+ tgt_long m_addr;
+
+ sec = obj_find_section(f, ".this");
+ module = (struct module *) sec->contents;
+ m_addr = sec->header.sh_addr;
+
+ module->size_of_struct = sizeof(*module);
+ module->size = m_size;
+ module->flags = flag_autoclean ? NEW_MOD_AUTOCLEAN : 0;
+
+ sec = obj_find_section(f, "__ksymtab");
+ if (sec && sec->header.sh_size) {
+ module->syms = sec->header.sh_addr;
+ module->nsyms = sec->header.sh_size / (2 * tgt_sizeof_char_p);
+ }
+ if (n_ext_modules_used) {
+ sec = obj_find_section(f, ".kmodtab");
+ module->deps = sec->header.sh_addr;
+ module->ndeps = n_ext_modules_used;
+ }
+ module->init = obj_symbol_final_value(f, obj_find_symbol(f, "init_module"));
+ module->cleanup = obj_symbol_final_value(f,
+ obj_find_symbol(f, "cleanup_module"));
+
+ sec = obj_find_section(f, "__ex_table");
+ if (sec) {
+ module->ex_table_start = sec->header.sh_addr;
+ module->ex_table_end = sec->header.sh_addr + sec->header.sh_size;
+ }
+ sec = obj_find_section(f, ".text.init");
+ if (sec) {
+ module->runsize = sec->header.sh_addr - m_addr;
+ }
+ sec = obj_find_section(f, ".data.init");
+ if (sec) {
+ if (!module->runsize ||
+ module->runsize > sec->header.sh_addr - m_addr)
+ module->runsize = sec->header.sh_addr - m_addr;
+ }
+ sec = obj_find_section(f, ARCHDATA_SEC_NAME);
+ if (sec && sec->header.sh_size) {
+ module->archdata_start = sec->header.sh_addr;
+ module->archdata_end = module->archdata_start + sec->header.sh_size;
+ }
+ sec = obj_find_section(f, KALLSYMS_SEC_NAME);
+ if (sec && sec->header.sh_size) {
+ module->kallsyms_start = sec->header.sh_addr;
+ module->kallsyms_end = module->kallsyms_start + sec->header.sh_size;
+ }
+ if (!arch_init_module(f, module))
+ return 0;
+
+ /*
+ * Whew! All of the initialization is complete.
+ * Collect the final module image and give it to the kernel.
+ */
+ image = xmalloc(m_size);
+ obj_create_image(f, image);
+
+ if (flag_load_map)
+ print_load_map(f);
+
+ if (blob_name) {
+ int fd, l;
+ fd = open(blob_name, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+ if (fd < 0) {
+ error("open %s failed %m", blob_name);
+ ret = -1;
+ }
+ else {
+ if ((l = write(fd, image, m_size)) != m_size) {
+ error("write %s failed %m", blob_name);
+ ret = -1;
+ }
+ close(fd);
+ }
+ }
+
+ if (ret == 0 && !noload) {
+ fflush(stdout); /* Flush any debugging output */
+ ret = sys_init_module(m_name, (struct module *) image);
+ if (ret) {
+ error("init_module: %m");
+ lprintf("Hint: insmod errors can be caused by incorrect module parameters, "
+ "including invalid IO or IRQ parameters");
+ }
+ }
+
+ free(image);
+
+ return ret == 0;
+}
+
+#ifdef COMPAT_2_0
+static int old_init_module(const char *m_name, struct obj_file *f,
+ unsigned long m_size)
+{
+ char *image;
+ struct old_mod_routines routines;
+ struct old_symbol_table *symtab;
+ int ret;
+ int nsyms = 0, strsize = 0, total;
+
+ /* Create the symbol table */
+ /* Size things first... */
+ if (flag_export) {
+ int i;
+ for (i = 0; i < HASH_BUCKETS; ++i) {
+ struct obj_symbol *sym;
+
+ for (sym = f->symtab[i]; sym; sym = sym->next)
+ if (ELFW(ST_BIND) (sym->info) != STB_LOCAL &&
+ sym->secidx <= SHN_HIRESERVE) {
+ sym->ksymidx = nsyms++;
+ strsize += strlen(sym->name) + 1;
+ }
+ }
+ }
+ total = (sizeof(struct old_symbol_table) +
+ nsyms * sizeof(struct old_module_symbol) +
+ n_ext_modules_used * sizeof(struct old_module_ref) +
+ strsize);
+ symtab = xmalloc(total);
+ symtab->size = total;
+ symtab->n_symbols = nsyms;
+ symtab->n_refs = n_ext_modules_used;
+
+ if (flag_export && nsyms) {
+ struct old_module_symbol *ksym;
+ char *str;
+ int i;
+
+ ksym = symtab->symbol;
+ str = ((char *) ksym +
+ nsyms * sizeof(struct old_module_symbol) +
+ n_ext_modules_used * sizeof(struct old_module_ref));
+
+ for (i = 0; i < HASH_BUCKETS; ++i) {
+ struct obj_symbol *sym;
+ for (sym = f->symtab[i]; sym; sym = sym->next)
+ if (sym->ksymidx >= 0) {
+ ksym->addr = obj_symbol_final_value(f, sym);
+ ksym->name = (unsigned long) str - (unsigned long) symtab;
+
+ str = stpcpy(str, sym->name) + 1;
+ ksym++;
+ }
+ }
+ }
+
+ if (n_ext_modules_used) {
+ struct old_module_ref *ref;
+ int i;
+
+ ref = (struct old_module_ref *)
+ ((char *) symtab->symbol + nsyms * sizeof(struct old_module_symbol));
+
+ for (i = 0; i < n_module_stat; ++i) {
+ if (module_stat[i].status /* used */) {
+ ref++->module = module_stat[i].modstruct;
+ }
+ }
+ }
+
+ /* Fill in routines. */
+
+ routines.init = obj_symbol_final_value(f, obj_find_symbol(f, "init_module"));
+ routines.cleanup = obj_symbol_final_value(f,
+ obj_find_symbol(f, "cleanup_module"));
+
+ /*
+ * Whew! All of the initialization is complete.
+ * Collect the final module image and give it to the kernel.
+ */
+ image = xmalloc(m_size);
+ obj_create_image(f, image);
+
+ /*
+ * image holds the complete relocated module,
+ * accounting correctly for mod_use_count.
+ * However the old module kernel support assume that it
+ * is receiving something which does not contain mod_use_count.
+ */
+ ret = old_sys_init_module(m_name, image + sizeof(long),
+ (m_size - sizeof(long)) |
+ (flag_autoclean ? OLD_MOD_AUTOCLEAN : 0),
+ &routines,
+ symtab);
+ if (ret)
+ error("init_module: %m");
+
+ free(image);
+ free(symtab);
+
+ return ret == 0;
+}
+#endif
+/* end compat */
+/************************************************************************/
+
+/* Check that a module parameter has a reasonable definition */
+static int check_module_parameter(struct obj_file *f, char *key, char *value, int *persist_flag)
+{
+ struct obj_symbol *sym;
+ int min, max;
+ char *p = value;
+
+ sym = obj_find_symbol(f, key);
+ if (sym == NULL) {
+ /* FIXME: For 2.2 kernel compatibility, only issue warnings for
+ * most error conditions. Make these all errors in 2.5.
+ */
+ lprintf("Warning: %s symbol for parameter %s not found", error_file, key);
+ return(1);
+ }
+
+ if (isdigit(*p)) {
+ min = strtoul(p, &p, 10);
+ if (*p == '-')
+ max = strtoul(p + 1, &p, 10);
+ else
+ max = min;
+ } else
+ min = max = 1;
+
+ if (max < min) {
+ lprintf("Warning: %s parameter %s has max < min!", error_file, key);
+ return(1);
+ }
+
+ switch (*p) {
+ case 'c':
+ if (!isdigit(p[1])) {
+ lprintf("%s parameter %s has no size after 'c'!", error_file, key);
+ return(1);
+ }
+ while (isdigit(p[1]))
+ ++p; /* swallow c array size */
+ break;
+ case 'b': /* drop through */
+ case 'h': /* drop through */
+ case 'i': /* drop through */
+ case 'l': /* drop through */
+ case 's':
+ break;
+ case '\0':
+ lprintf("%s parameter %s has no format character!", error_file, key);
+ return(1);
+ default:
+ lprintf("%s parameter %s has unknown format character '%c'", error_file, key, *p);
+ return(1);
+ }
+ switch (*++p) {
+ case 'p':
+ if (*(p-1) == 's') {
+ error("parameter %s is invalid persistent string", key);
+ return(1);
+ }
+ *persist_flag = 1;
+ break;
+ case '\0':
+ break;
+ default:
+ lprintf("%s parameter %s has unknown format modifier '%c'", error_file, key, *p);
+ return(1);
+ }
+ return(0);
+}
+
+/* Check that all module parameters have reasonable definitions */
+static void check_module_parameters(struct obj_file *f, int *persist_flag)
+{
+ struct obj_section *sec;
+ char *ptr, *value, *n, *endptr;
+ int namelen, err = 0;
+
+ sec = obj_find_section(f, ".modinfo");
+ if (sec == NULL) {
+ /* module does not support typed parameters */
+ return;
+ }
+
+ ptr = sec->contents;
+ endptr = ptr + sec->header.sh_size;
+ while (ptr < endptr && !err) {
+ value = strchr(ptr, '=');
+ n = strchr(ptr, '\0');
+ if (value) {
+ namelen = value - ptr;
+ if (namelen >= 5 && strncmp(ptr, "parm_", 5) == 0
+ && !(namelen > 10 && strncmp(ptr, "parm_desc_", 10) == 0)) {
+ char *pname = xmalloc(namelen + 1);
+ strncpy(pname, ptr + 5, namelen - 5);
+ pname[namelen - 5] = '\0';
+ err = check_module_parameter(f, pname, value+1, persist_flag);
+ free(pname);
+ }
+ } else {
+ if (n - ptr >= 5 && strncmp(ptr, "parm_", 5) == 0) {
+ error("parameter %s found with no value", ptr);
+ err = 1;
+ }
+ }
+ ptr = n + 1;
+ }
+
+ if (err)
+ *persist_flag = 0;
+ return;
+}
+
+
+/* For common 3264 code, only compile the usage message once, in the 64 bit version */
+#if defined(COMMON_3264) && defined(ONLY_32)
+extern void insmod_usage(void); /* Use the copy in the 64 bit version */
+#else /* Common 64 bit version or any non common code - compile usage routine */
+void insmod_usage(void)
+{
+ fputs("Usage:\n"
+ "insmod [-fhkLmnpqrsSvVxXyY] [-e persist_name] [-o module_name] [-O blob_name] [-P prefix] module [ symbol=value ... ]\n"
+ "\n"
+ " module Name of a loadable kernel module ('.o' can be omitted)\n"
+ " -f, --force Force loading under wrong kernel version\n"
+ " -h, --help Print this message\n"
+ " -k, --autoclean Make module autoclean-able\n"
+ " -L, --lock Prevent simultaneous loads of the same module\n"
+ " -m, --map Generate load map (so crashes can be traced)\n"
+ " -n, --noload Don't load, just show\n"
+ " -p, --probe Probe mode; check if the module matches the kernel\n"
+ " -q, --quiet Don't print unresolved symbols\n"
+ " -r, --root Allow root to load modules not owned by root\n"
+ " -s, --syslog Report errors via syslog\n"
+ " -S, --kallsyms Force kallsyms on module\n"
+ " -v, --verbose Verbose output\n"
+ " -V, --version Show version\n"
+ " -x, --noexport Do not export externs\n"
+ " -X, --export Do export externs (default)\n"
+ " -y, --noksymoops Do not add ksymoops symbols\n"
+ " -Y, --ksymoops Do add ksymoops symbols (default)\n"
+ " -e persist_name\n"
+ " --persist=persist_name Filename to hold any persistent data from the module\n"
+ " -o NAME, --name=NAME Set internal module name to NAME\n"
+ " -O NAME, --blob=NAME Save the object as a binary blob in NAME\n"
+ " -P PREFIX\n"
+ " --prefix=PREFIX Prefix for kernel or module symbols\n"
+ ,stderr);
+ exit(1);
+}
+#endif /* defined(COMMON_3264) && defined(ONLY_32) */
+
+#if defined(COMMON_3264) && defined(ONLY_32)
+#define INSMOD_MAIN insmod_main_32 /* 32 bit version */
+#elif defined(COMMON_3264) && defined(ONLY_64)
+#define INSMOD_MAIN insmod_main_64 /* 64 bit version */
+#else
+#define INSMOD_MAIN insmod_main /* Not common code */
+#endif
+
+int INSMOD_MAIN(int argc, char **argv)
+{
+ int k_version;
+ int k_crcs;
+ char k_strversion[STRVERSIONLEN];
+ struct option long_opts[] = {
+ {"force", 0, 0, 'f'},
+ {"help", 0, 0, 'h'},
+ {"autoclean", 0, 0, 'k'},
+ {"lock", 0, 0, 'L'},
+ {"map", 0, 0, 'm'},
+ {"noload", 0, 0, 'n'},
+ {"probe", 0, 0, 'p'},
+ {"poll", 0, 0, 'p'}, /* poll is deprecated, remove in 2.5 */
+ {"quiet", 0, 0, 'q'},
+ {"root", 0, 0, 'r'},
+ {"syslog", 0, 0, 's'},
+ {"kallsyms", 0, 0, 'S'},
+ {"verbose", 0, 0, 'v'},
+ {"version", 0, 0, 'V'},
+ {"noexport", 0, 0, 'x'},
+ {"export", 0, 0, 'X'},
+ {"noksymoops", 0, 0, 'y'},
+ {"ksymoops", 0, 0, 'Y'},
+
+ {"persist", 1, 0, 'e'},
+ {"name", 1, 0, 'o'},
+ {"blob", 1, 0, 'O'},
+ {"prefix", 1, 0, 'P'},
+ {0, 0, 0, 0}
+ };
+ char *m_name = NULL;
+ char *blob_name = NULL; /* Save object as binary blob */
+ int m_version;
+ ElfW(Addr) m_addr;
+ unsigned long m_size;
+ int m_crcs;
+ char m_strversion[STRVERSIONLEN];
+ char *filename;
+ char *persist_name = NULL; /* filename to hold any persistent data */
+ int fp;
+ struct obj_file *f;
+ struct obj_section *kallsyms = NULL, *archdata = NULL;
+ int o;
+ int noload = 0;
+ int dolock = 1; /*Note: was: 0; */
+ int quiet = 0;
+ int exit_status = 1;
+ int force_kallsyms = 0;
+ int persist_parms = 0; /* does module have persistent parms? */
+ int i;
+
+ error_file = "insmod";
+
+ /* To handle repeated calls from combined modprobe */
+ errors = optind = 0;
+
+ /* Process the command line. */
+ while ((o = getopt_long(argc, argv, "fhkLmnpqrsSvVxXyYe:o:O:P:R:",
+ &long_opts[0], NULL)) != EOF)
+ switch (o) {
+ case 'f': /* force loading */
+ flag_force_load = 1;
+ break;
+ case 'h': /* Print the usage message. */
+ insmod_usage();
+ break;
+ case 'k': /* module loaded by kerneld, auto-cleanable */
+ flag_autoclean = 1;
+ break;
+ case 'L': /* protect against recursion. */
+ dolock = 1;
+ break;
+ case 'm': /* generate load map */
+ flag_load_map = 1;
+ break;
+ case 'n': /* don't load, just check */
+ noload = 1;
+ break;
+ case 'p': /* silent probe mode */
+ flag_silent_probe = 1;
+ break;
+ case 'q': /* Don't print unresolved symbols */
+ quiet = 1;
+ break;
+ case 'r': /* allow root to load non-root modules */
+ root_check_off = !root_check_off;
+ break;
+ case 's': /* start syslog */
+ setsyslog("insmod");
+ break;
+ case 'S': /* Force kallsyms */
+ force_kallsyms = 1;
+ break;
+ case 'v': /* verbose output */
+ flag_verbose = 1;
+ break;
+ case 'V':
+ fputs("insmod version " MODUTILS_VERSION "\n", stderr);
+ break;
+ case 'x': /* do not export externs */
+ flag_export = 0;
+ break;
+ case 'X': /* do export externs */
+ flag_export = 1;
+ break;
+ case 'y': /* do not define ksymoops symbols */
+ flag_ksymoops = 0;
+ break;
+ case 'Y': /* do define ksymoops symbols */
+ flag_ksymoops = 1;
+ break;
+
+ case 'e': /* persistent data filename */
+ free(persist_name);
+ persist_name = xstrdup(optarg);
+ break;
+ case 'o': /* name the output module */
+ m_name = optarg;
+ break;
+ case 'O': /* save the output module object */
+ blob_name = optarg;
+ break;
+ case 'P': /* use prefix on crc */
+ set_ncv_prefix(optarg);
+ break;
+
+ default:
+ insmod_usage();
+ break;
+ }
+
+ if (optind >= argc) {
+ insmod_usage();
+ }
+ filename = argv[optind++];
+
+ if (config_read(0, NULL, "", NULL) < 0) {
+ error("Failed handle configuration");
+ }
+
+ if (persist_name && !*persist_name &&
+ (!persistdir || !*persistdir)) {
+ free(persist_name);
+ persist_name = NULL;
+ if (flag_verbose)
+ lprintf("insmod: -e \"\" ignored, no persistdir");
+ }
+
+ if (m_name == NULL) {
+ size_t len;
+ char *p;
+
+ if ((p = strrchr(filename, '/')) != NULL)
+ p++;
+ else
+ p = filename;
+ len = strlen(p);
+ if (len > 2 && p[len - 2] == '.' && p[len - 1] == 'o')
+ len -= 2;
+ else if (len > 4 && p[len - 4] == '.' && p[len - 3] == 'm'
+ && p[len - 2] == 'o' && p[len - 1] == 'd')
+ len -= 4;
+#ifdef CONFIG_USE_ZLIB
+ else if (len > 5 && !strcmp(p + len - 5, ".o.gz"))
+ len -= 5;
+#endif
+
+ m_name = xmalloc(len + 1);
+ memcpy(m_name, p, len);
+ m_name[len] = '\0';
+ }
+
+ /* Locate the file to be loaded. */
+ if (!strchr(filename, '/') && !strchr(filename, '.')) {
+ char *tmp = search_module_path(filename);
+ if (tmp == NULL) {
+ error("%s: no module by that name found", filename);
+ return 1;
+ }
+ filename = tmp;
+ lprintf("Using %s", filename);
+ } else if (flag_verbose)
+ lprintf("Using %s", filename);
+
+ /* And open it. */
+ if ((fp = gzf_open(filename, O_RDONLY)) == -1) {
+ error("%s: %m", filename);
+ return 1;
+ }
+ /* Try to prevent multiple simultaneous loads. */
+ if (dolock)
+ flock(fp, LOCK_EX);
+
+ if (!get_kernel_info(K_SYMBOLS))
+ goto out;
+
+ /*
+ * Set the genksyms prefix if this is a versioned kernel
+ * and it's not already set.
+ */
+ set_ncv_prefix(NULL);
+
+ for (i = 0; i < n_module_stat; ++i) {
+ if (strcmp(module_stat[i].name, m_name) == 0) {
+ error("a module named %s already exists", m_name);
+ goto out;
+ }
+ }
+
+ error_file = filename;
+ if ((f = obj_load(fp, ET_REL, filename)) == NULL)
+ goto out;
+
+ /* Version correspondence? */
+ k_version = get_kernel_version(k_strversion);
+ m_version = get_module_version(f, m_strversion);
+ if (m_version == -1) {
+ error("couldn't find the kernel version the module was compiled for");
+ goto out;
+ }
+
+ k_crcs = is_kernel_checksummed();
+ m_crcs = is_module_checksummed(f);
+ if ((m_crcs == 0 || k_crcs == 0) &&
+ strncmp(k_strversion, m_strversion, STRVERSIONLEN) != 0) {
+ if (flag_force_load) {
+ lprintf("Warning: kernel-module version mismatch\n"
+ "\t%s was compiled for kernel version %s\n"
+ "\twhile this kernel is version %s",
+ filename, m_strversion, k_strversion);
+ } else {
+ if (!quiet)
+ error("kernel-module version mismatch\n"
+ "\t%s was compiled for kernel version %s\n"
+ "\twhile this kernel is version %s.",
+ filename, m_strversion, k_strversion);
+ goto out;
+ }
+ }
+ if (m_crcs != k_crcs)
+ obj_set_symbol_compare(f, ncv_strcmp, ncv_symbol_hash);
+
+ /* Let the module know about the kernel symbols. */
+ add_kernel_symbols(f);
+
+ /* Allocate common symbols, symbol tables, and string tables.
+ *
+ * The calls marked DEPMOD indicate the bits of code that depmod
+ * uses to do a pseudo relocation, ignoring undefined symbols.
+ * Any changes made to the relocation sequence here should be
+ * checked against depmod.
+ */
+#ifdef COMPAT_2_0
+ if (k_new_syscalls
+ ? !create_this_module(f, m_name)
+ : !old_create_mod_use_count(f))
+ goto out;
+#else
+ if (!create_this_module(f, m_name))
+ goto out;
+#endif
+
+ if (!obj_check_undefineds(f, quiet)) /* DEPMOD, obj_clear_undefineds */
+ goto out;
+ obj_allocate_commons(f); /* DEPMOD */
+
+ check_module_parameters(f, &persist_parms);
+
+ if (optind < argc) {
+ if (!process_module_arguments(f, argc - optind, argv + optind, 1))
+ goto out;
+ }
+ arch_create_got(f); /* DEPMOD */
+ hide_special_symbols(f);
+
+ if (persist_parms && persist_name && *persist_name) {
+ f->persist = persist_name;
+ persist_name = NULL;
+ }
+
+ if (persist_parms &&
+ persist_name && !*persist_name) {
+ /* -e "". This is ugly. Take the filename, compare it against
+ * each of the module paths until we find a match on the start
+ * of the filename, assume the rest is the relative path. Have
+ * to do it this way because modprobe uses absolute filenames
+ * for module names in modules.dep and the format of modules.dep
+ * does not allow for any backwards compatible changes, so there
+ * is nowhere to store the relative filename. The only way this
+ * should fail to calculate a relative path is "insmod ./xxx", for
+ * that case the user has to specify -e filename.
+ */
+ int j, l = strlen(filename);
+ char *relative = NULL;
+ char *p;
+ for (i = 0; i < nmodpath; ++i) {
+ p = modpath[i].path;
+ j = strlen(p);
+ while (j && p[j] == '/')
+ --j;
+ if (j < l && strncmp(filename, p, j) == 0 && filename[j] == '/') {
+ while (filename[j] == '/')
+ ++j;
+ relative = xstrdup(filename+j);
+ break;
+ }
+ }
+ if (relative) {
+ i = strlen(relative);
+ if (i > 3 && strcmp(relative+i-3, ".gz") == 0)
+ relative[i -= 3] = '\0';
+ if (i > 2 && strcmp(relative+i-2, ".o") == 0)
+ relative[i -= 2] = '\0';
+ else if (i > 4 && strcmp(relative+i-4, ".mod") == 0)
+ relative[i -= 4] = '\0';
+ f->persist = xmalloc(strlen(persistdir) + 1 + i + 1);
+ strcpy(f->persist, persistdir); /* safe, xmalloc */
+ strcat(f->persist, "/"); /* safe, xmalloc */
+ strcat(f->persist, relative); /* safe, xmalloc */
+ free(relative);
+ }
+ else
+ error("Cannot calculate persistent filename");
+ }
+
+ if (f->persist && *(f->persist) != '/') {
+ error("Persistent filenames must be absolute, ignoring '%s'",
+ f->persist);
+ free(f->persist);
+ f->persist = NULL;
+ }
+
+ if (f->persist && !flag_ksymoops) {
+ error("has persistent data but ksymoops symbols are not available");
+ free(f->persist);
+ f->persist = NULL;
+ }
+
+ if (f->persist && !k_new_syscalls) {
+ error("has persistent data but the kernel is too old to support it");
+ free(f->persist);
+ f->persist = NULL;
+ }
+
+ if (persist_parms && flag_verbose) {
+ if (f->persist)
+ lprintf("Persist filename '%s'", f->persist);
+ else
+ lprintf("No persistent filename available");
+ }
+
+ if (f->persist) {
+ FILE *fp = fopen(f->persist, "r");
+ if (!fp) {
+ if (flag_verbose)
+ lprintf("Cannot open persist file '%s' %m", f->persist);
+ }
+ else {
+ int pargc = 0;
+ char *pargv[1000]; /* hard coded but big enough */
+ char line[3000]; /* hard coded but big enough */
+ char *p;
+ while (fgets(line, sizeof(line), fp)) {
+ p = strchr(line, '\n');
+ if (!p) {
+ error("Persistent data line is too long\n%s", line);
+ break;
+ }
+ *p = '\0';
+ p = line;
+ while (isspace(*p))
+ ++p;
+ if (!*p || *p == '#')
+ continue;
+ if (pargc == sizeof(pargv)/sizeof(pargv[0])) {
+ error("More than %d persistent parameters", pargc);
+ break;
+ }
+ pargv[pargc++] = xstrdup(p);
+ }
+ fclose(fp);
+ if (!process_module_arguments(f, pargc, pargv, 0))
+ goto out;
+ while (pargc--)
+ free(pargv[pargc]);
+ }
+ }
+
+ if (flag_ksymoops)
+ add_ksymoops_symbols(f, filename, m_name);
+
+ if (k_new_syscalls)
+ create_module_ksymtab(f);
+
+ /* archdata based on relocatable addresses */
+ if (add_archdata(f, &archdata))
+ goto out;
+
+ /* kallsyms based on relocatable addresses */
+ if (add_kallsyms(f, &kallsyms, force_kallsyms))
+ goto out;
+ /**** No symbols or sections to be changed after kallsyms above ***/
+
+ if (errors)
+ goto out;
+
+ /* If we were just checking, we made it. */
+ if (flag_silent_probe) {
+ exit_status = 0;
+ goto out;
+ }
+ /* Module has now finished growing; find its size and install it. */
+ m_size = obj_load_size(f); /* DEPMOD */
+
+ if (noload) {
+ /* Don't bother actually touching the kernel. */
+ m_addr = 0x12340000;
+ } else {
+ errno = 0;
+ m_addr = create_module(m_name, m_size);
+ switch (errno) {
+ case 0:
+ break;
+ case EEXIST:
+ if (dolock) {
+ /*
+ * Assume that we were just invoked
+ * simultaneous with another insmod
+ * and return success.
+ */
+ exit_status = 0;
+ goto out;
+ }
+ error("a module named %s already exists", m_name);
+ goto out;
+ case ENOMEM:
+ error("can't allocate kernel memory for module; needed %lu bytes",
+ m_size);
+ goto out;
+ default:
+ error("create_module: %m");
+ goto out;
+ }
+ }
+
+ /* module is already built, complete with ksymoops symbols for the
+ * persistent filename. If the kernel does not support persistent data
+ * then give an error but continue. It is too difficult to clean up at
+ * this stage and this error will only occur on backported modules.
+ * rmmod will also get an error so warn the user now.
+ */
+ if (f->persist && !noload) {
+ struct {
+ struct module m;
+ int data;
+ } test_read;
+ memset(&test_read, 0, sizeof(test_read));
+ test_read.m.size_of_struct = -sizeof(test_read.m); /* -ve size => read, not write */
+ test_read.m.read_start = m_addr + sizeof(struct module);
+ test_read.m.read_end = test_read.m.read_start + sizeof(test_read.data);
+ if (sys_init_module(m_name, (struct module *) &test_read)) {
+ int old_errors = errors;
+ error("has persistent data but the kernel is too old to support it."
+ " Expect errors during rmmod as well");
+ errors = old_errors;
+ }
+ }
+
+ if (!obj_relocate(f, m_addr)) { /* DEPMOD */
+ if (!noload)
+ delete_module(m_name);
+ goto out;
+ }
+
+ /* Do archdata again, this time we have the final addresses */
+ if (add_archdata(f, &archdata))
+ goto out;
+
+ /* Do kallsyms again, this time we have the final addresses */
+ if (add_kallsyms(f, &kallsyms, force_kallsyms))
+ goto out;
+
+#ifdef COMPAT_2_0
+ if (k_new_syscalls)
+ init_module(m_name, f, m_size, blob_name, noload, flag_load_map);
+ else if (!noload)
+ old_init_module(m_name, f, m_size);
+#else
+ init_module(m_name, f, m_size, blob_name, noload, flag_load_map);
+#endif
+ if (errors) {
+ if (!noload)
+ delete_module(m_name);
+ goto out;
+ }
+ exit_status = 0;
+
+ out:
+ if (dolock)
+ flock(fp, LOCK_UN);
+ close(fp);
+ if (!noload)
+ snap_shot(NULL, 0);
+
+ return exit_status;
+}
+
+/* For common 3264 code, add an overall insmod_main, in the 64 bit version. */
+#if defined(COMMON_3264) && defined(ONLY_64)
+int insmod_main(int argc, char **argv)
+{
+ if (arch64())
+ return insmod_main_64(argc, argv);
+ else
+ return insmod_main_32(argc, argv);
+}
+#endif /* defined(COMMON_3264) && defined(ONLY_64) */
+
+
+
+int insmod_call(char * full_filename, char * params)
+{
+ int argc = 2;
+ char *argv[50];
+ char * ptr = params;
+ argv[0] = "stage1";
+ argv[1] = full_filename;
+
+ while (ptr != NULL) {
+ argv[argc] = ptr;
+ argc++;
+ ptr = strchr(ptr, ' ');
+ if (ptr) {
+ ptr[0] = '\0';
+ ptr++;
+ }
+ }
+
+ return insmod_main(argc, argv);
+}
diff --git a/mdk-stage1/insmod-modutils/obj/Makefile b/mdk-stage1/insmod-modutils/obj/Makefile
new file mode 100644
index 000000000..9bcf8bac8
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/obj/Makefile
@@ -0,0 +1,31 @@
+ #******************************************************************************
+ #
+ # insmod from modutils (generic)
+ #
+ # $Id$
+ #
+ # Copyright 1996, 1997 Linux International.
+ #
+ #*****************************************************************************
+
+top_dir = ../..
+
+include $(top_dir)/Makefile.common
+
+
+all: libobj.a
+
+clean:
+ rm -f *.o *.a
+
+
+FLAGS = -c -Wall -Os -fomit-frame-pointer -I./../include -D_GNU_SOURCE -DELF_MACHINE_H='"elf_$(ARCH).h"' -DARCH_$(ARCH) -DCONFIG_ROOT_CHECK_OFF=0
+
+OBJS = obj_kallsyms.o obj_common.o obj_load.o obj_reloc.o obj_$(ARCH).o
+
+libobj.a: $(OBJS)
+ ar cru $@ $^
+ ranlib $@
+
+.c.o:
+ gcc $(FLAGS) $(GLIBC_INCLUDES) -c $<
diff --git a/mdk-stage1/insmod-modutils/obj/obj_alpha.c b/mdk-stage1/insmod-modutils/obj/obj_alpha.c
new file mode 100644
index 000000000..4006b3442
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/obj/obj_alpha.c
@@ -0,0 +1,305 @@
+/* Alpha specific support for Elf loading and relocation.
+ Copyright 1996, 1997 Linux International.
+
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <string.h>
+#include <assert.h>
+
+#include <module.h>
+#include <obj.h>
+#include <util.h>
+
+/*======================================================================*/
+
+struct alpha_got_entry
+{
+ struct alpha_got_entry *next;
+ ElfW(Addr) addend;
+ int offset;
+ int reloc_done;
+};
+
+struct alpha_file
+{
+ struct obj_file root;
+ struct obj_section *got;
+};
+
+struct alpha_symbol
+{
+ struct obj_symbol root;
+ struct alpha_got_entry *got_entries;
+};
+
+
+/*======================================================================*/
+
+struct obj_file *
+arch_new_file (void)
+{
+ struct alpha_file *f;
+ f = xmalloc(sizeof(*f));
+ f->got = NULL;
+ return &f->root;
+}
+
+struct obj_section *
+arch_new_section (void)
+{
+ return xmalloc(sizeof(struct obj_section));
+}
+
+struct obj_symbol *
+arch_new_symbol (void)
+{
+ struct alpha_symbol *sym;
+ sym = xmalloc(sizeof(*sym));
+ sym->got_entries = NULL;
+ return &sym->root;
+}
+
+int
+arch_load_proc_section(struct obj_section *sec, int fp)
+{
+ /* Assume it's just a debugging section that we can safely
+ ignore ... */
+ sec->contents = NULL;
+
+ return 0;
+}
+
+enum obj_reloc
+arch_apply_relocation (struct obj_file *f,
+ struct obj_section *targsec,
+ struct obj_section *symsec,
+ struct obj_symbol *sym,
+ Elf64_Rela *rel,
+ Elf64_Addr v)
+{
+ struct alpha_file *af = (struct alpha_file *)f;
+ struct alpha_symbol *asym = (struct alpha_symbol *)sym;
+
+ unsigned long *lloc = (unsigned long *)(targsec->contents + rel->r_offset);
+ unsigned int *iloc = (unsigned int *)lloc;
+ Elf64_Addr dot = targsec->header.sh_addr + rel->r_offset;
+ Elf64_Addr gp = af->got->header.sh_addr + 0x8000;
+
+ enum obj_reloc ret = obj_reloc_ok;
+
+ switch (ELF64_R_TYPE(rel->r_info))
+ {
+ case R_ALPHA_NONE:
+ case R_ALPHA_LITUSE:
+ break;
+
+ case R_ALPHA_REFQUAD:
+ *lloc += v;
+ break;
+
+ case R_ALPHA_GPREL32:
+ v -= gp;
+ if ((Elf64_Sxword)v > 0x7fffffff
+ || (Elf64_Sxword)v < -(Elf64_Sxword)0x80000000)
+ ret = obj_reloc_overflow;
+ *iloc = v;
+ break;
+
+ case R_ALPHA_LITERAL:
+ {
+ struct alpha_got_entry *gotent;
+
+ assert(asym != NULL);
+ gotent = asym->got_entries;
+ while (gotent->addend != rel->r_addend)
+ gotent = gotent->next;
+
+ if (!gotent->reloc_done)
+ {
+ *(unsigned long *)(af->got->contents + gotent->offset) = v;
+ gotent->reloc_done = 1;
+ }
+
+ *iloc = (*iloc & ~0xffff) | ((gotent->offset - 0x8000) & 0xffff);
+ }
+ break;
+
+ case R_ALPHA_GPDISP:
+ {
+ unsigned int *p_ldah, *p_lda;
+ unsigned int i_ldah, i_lda, hi, lo;
+
+ p_ldah = iloc;
+ p_lda = (unsigned int *)((char *)iloc + rel->r_addend);
+ i_ldah = *p_ldah;
+ i_lda = *p_lda;
+
+ /* Make sure the instructions are righteous. */
+ if ((i_ldah >> 26) != 9 || (i_lda >> 26) != 8)
+ ret = obj_reloc_dangerous;
+
+ /* Extract the existing addend. */
+ v = (i_ldah & 0xffff) << 16 | (i_lda & 0xffff);
+ v = (v ^ 0x80008000) - 0x80008000;
+
+ v += gp - dot;
+
+ if ((Elf64_Sxword)v >= 0x7fff8000
+ || (Elf64_Sxword)v < -(Elf64_Sxword)0x80000000)
+ ret = obj_reloc_overflow;
+
+ /* Modify the instructions and finish up. */
+ lo = v & 0xffff;
+ hi = ((v >> 16) + ((v >> 15) & 1)) & 0xffff;
+
+ *p_ldah = (i_ldah & 0xffff0000) | hi;
+ *p_lda = (i_lda & 0xffff0000) | lo;
+ }
+ break;
+
+ case R_ALPHA_BRADDR:
+ v -= dot + 4;
+ if (v % 4)
+ ret = obj_reloc_dangerous;
+ else if ((Elf64_Sxword)v > 0x3fffff
+ || (Elf64_Sxword)v < -(Elf64_Sxword)0x400000)
+ ret = obj_reloc_overflow;
+ v /= 4;
+
+ *iloc = (*iloc & ~0x1fffff) | (v & 0x1fffff);
+ break;
+
+ case R_ALPHA_HINT:
+ v -= dot + 4;
+ if (v % 4)
+ ret = obj_reloc_dangerous;
+ v /= 4;
+
+ *iloc = (*iloc & ~0x3fff) | (v & 0x3fff);
+ break;
+
+ default:
+ ret = obj_reloc_unhandled;
+ break;
+ }
+
+ return ret;
+}
+
+int
+arch_create_got (struct obj_file *f)
+{
+ struct alpha_file *af = (struct alpha_file *)f;
+ int i, n, offset = 0;
+
+ n = af->root.header.e_shnum;
+ for (i = 0; i < n; ++i)
+ {
+ struct obj_section *relsec, *symsec, *strsec;
+ Elf64_Rela *rel, *relend;
+ Elf64_Sym *symtab;
+ const char *strtab;
+
+ relsec = af->root.sections[i];
+ if (relsec->header.sh_type != SHT_RELA)
+ continue;
+
+ symsec = af->root.sections[relsec->header.sh_link];
+ strsec = af->root.sections[symsec->header.sh_link];
+
+ rel = (Elf64_Rela *)relsec->contents;
+ relend = rel + (relsec->header.sh_size / sizeof(Elf64_Rela));
+ symtab = (Elf64_Sym *)symsec->contents;
+ strtab = (const char *)strsec->contents;
+
+ for (; rel < relend; ++rel)
+ {
+ struct alpha_got_entry *ent;
+ Elf64_Sym *extsym;
+ struct alpha_symbol *intsym;
+ const char *name;
+
+ if (ELF64_R_TYPE(rel->r_info) != R_ALPHA_LITERAL)
+ continue;
+
+ extsym = &symtab[ELF64_R_SYM(rel->r_info)];
+ if (extsym->st_name)
+ name = strtab + extsym->st_name;
+ else
+ name = f->sections[extsym->st_shndx]->name;
+ intsym = (struct alpha_symbol *)obj_find_symbol(&af->root, name);
+
+ for (ent = intsym->got_entries; ent ; ent = ent->next)
+ if (ent->addend == rel->r_addend)
+ goto found;
+
+ ent = xmalloc(sizeof(*ent));
+ ent->addend = rel->r_addend;
+ ent->offset = offset;
+ ent->reloc_done = 0;
+ ent->next = intsym->got_entries;
+ intsym->got_entries = ent;
+ offset += 8;
+
+ found:;
+ }
+ }
+
+ if (offset > 0x10000)
+ {
+ error(".got section overflow: %#x > 0x10000", offset);
+ return 0;
+ }
+
+ /* We always want a .got section so that we always have a GP for
+ use with GPDISP and GPREL32 relocs. Besides, if the section
+ is empty we don't use up space anyway. */
+ af->got = obj_create_alloced_section(&af->root, ".got", 8, offset);
+
+ return 1;
+}
+
+int
+arch_init_module (struct obj_file *f, struct module *mod)
+{
+ struct alpha_file *af = (struct alpha_file *)f;
+
+ mod->gp = af->got->header.sh_addr + 0x8000;
+
+ return 1;
+}
+
+int
+arch_finalize_section_address(struct obj_file *f, Elf64_Addr base)
+{
+ int i, n = f->header.e_shnum;
+
+ f->baseaddr = base;
+ for (i = 0; i < n; ++i)
+ f->sections[i]->header.sh_addr += base;
+ return 1;
+}
+
+int
+arch_archdata (struct obj_file *fin, struct obj_section *sec)
+{
+ return 0;
+}
diff --git a/mdk-stage1/insmod-modutils/obj/obj_arm.c b/mdk-stage1/insmod-modutils/obj/obj_arm.c
new file mode 100644
index 000000000..7a843f947
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/obj/obj_arm.c
@@ -0,0 +1,318 @@
+/* ARM specific support for Elf loading and relocation.
+ Copyright 1996, 1997, 1998 Linux International.
+
+ Contributed by Phil Blundell <philb@gnu.org>
+ and wms <woody@corelcomputer.com>
+ based on the i386 code by Richard Henderson <rth@tamu.edu>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <string.h>
+#include <assert.h>
+
+#include <module.h>
+#include <obj.h>
+#include <util.h>
+
+
+/*======================================================================*/
+
+struct arm_plt_entry
+{
+ int offset;
+ int allocated:1;
+ int inited:1; // has been set up
+};
+
+struct arm_got_entry
+{
+ int offset;
+ int allocated : 1;
+ unsigned reloc_done : 1;
+};
+
+struct arm_file
+{
+ struct obj_file root;
+ struct obj_section *plt;
+ struct obj_section *got;
+};
+
+struct arm_symbol
+{
+ struct obj_symbol root;
+ struct arm_plt_entry pltent;
+ struct arm_got_entry gotent;
+};
+
+
+/*======================================================================*/
+
+struct obj_file *
+arch_new_file (void)
+{
+ struct arm_file *f;
+ f = xmalloc(sizeof(*f));
+ f->got = NULL;
+ return &f->root;
+}
+
+struct obj_section *
+arch_new_section (void)
+{
+ return xmalloc(sizeof(struct obj_section));
+}
+
+struct obj_symbol *
+arch_new_symbol (void)
+{
+ struct arm_symbol *sym;
+ sym = xmalloc(sizeof(*sym));
+ memset(&sym->gotent, 0, sizeof(sym->gotent));
+ memset(&sym->pltent, 0, sizeof(sym->pltent));
+ return &sym->root;
+}
+
+int
+arch_load_proc_section(struct obj_section *sec, int fp)
+{
+ /* Assume it's just a debugging section that we can safely
+ ignore ... */
+ sec->contents = NULL;
+
+ return 0;
+}
+
+enum obj_reloc
+arch_apply_relocation (struct obj_file *f,
+ struct obj_section *targsec,
+ struct obj_section *symsec,
+ struct obj_symbol *sym,
+ Elf32_Rel *rel,
+ Elf32_Addr v)
+{
+ struct arm_file *afile = (struct arm_file *)f;
+ struct arm_symbol *asym = (struct arm_symbol *)sym;
+
+ Elf32_Addr *loc = (Elf32_Addr *)(targsec->contents + rel->r_offset);
+ Elf32_Addr dot = targsec->header.sh_addr + rel->r_offset;
+ Elf32_Addr got = afile->got ? afile->got->header.sh_addr : 0;
+ Elf32_Addr plt = afile->plt ? afile->plt->header.sh_addr : 0;
+
+ struct arm_plt_entry *pe;
+ unsigned long *ip;
+
+ enum obj_reloc ret = obj_reloc_ok;
+
+ switch (ELF32_R_TYPE(rel->r_info))
+ {
+ case R_ARM_NONE:
+ break;
+
+ case R_ARM_ABS32:
+ *loc += v;
+ break;
+
+ case R_ARM_GOT32:
+ /* needs an entry in the .got: set it, once */
+ if (! asym->gotent.reloc_done)
+ {
+ asym->gotent.reloc_done = 1;
+ *(Elf32_Addr *)(afile->got->contents + asym->gotent.offset) = v;
+ }
+ /* make the reloc with_respect_to_.got */
+ *loc += asym->gotent.offset;
+ break;
+
+ /* relative reloc, always to _GLOBAL_OFFSET_TABLE_ (which is .got)
+ similar to branch, but is full 32 bits relative */
+ case R_ARM_GOTPC:
+ assert(got);
+ *loc += got - dot;
+ break;
+
+ case R_ARM_PC24:
+ case R_ARM_PLT32:
+ /* find the plt entry and initialize it if necessary */
+ assert(asym != NULL);
+ pe = (struct arm_plt_entry*) &asym->pltent;
+ if (! pe->inited)
+ {
+ ip = (unsigned long *) (afile->plt->contents + pe->offset);
+ ip[0] = 0xe51ff004; /* ldr pc,[pc,#-4] */
+ ip[1] = v; /* sym@ */
+ pe->inited = 1;
+ }
+
+ /* relative distance to target */
+ v -= dot;
+ /* if the target is too far away.... */
+ if ((int)v < -0x02000000 || (int)v >= 0x02000000)
+ {
+ /* go via the plt */
+ v = plt + pe->offset - dot;
+ }
+ if (v & 3)
+ ret = obj_reloc_dangerous;
+
+ /* Convert to words. */
+ v >>= 2;
+
+ /* merge the offset into the instruction. */
+ *loc = (*loc & ~0x00ffffff) | ((v + *loc) & 0x00ffffff);
+ break;
+
+ /* address relative to the got */
+ case R_ARM_GOTOFF:
+ assert(got);
+ *loc += v - got;
+ break;
+
+ default:
+ printf("Warning: unhandled reloc %d\n",ELF32_R_TYPE(rel->r_info));
+ ret = obj_reloc_unhandled;
+ break;
+ }
+
+ return ret;
+}
+
+int
+arch_create_got (struct obj_file *f)
+{
+ struct arm_file *afile = (struct arm_file *) f;
+ int i;
+ struct obj_section *sec, *syms, *strs;
+ ElfW(Rel) *rel, *relend;
+ ElfW(Sym) *symtab, *extsym;
+ const char *strtab, *name;
+ struct arm_symbol *intsym;
+ struct arm_plt_entry *pe;
+ struct arm_got_entry *ge;
+ int got_offset = 0, plt_offset = 0;
+
+ for (i = 0; i < f->header.e_shnum; ++i)
+ {
+ sec = f->sections[i];
+ if (sec->header.sh_type != SHT_RELM)
+ continue;
+ syms = f->sections[sec->header.sh_link];
+ strs = f->sections[syms->header.sh_link];
+
+ rel = (ElfW(RelM) *) sec->contents;
+ relend = rel + (sec->header.sh_size / sizeof(ElfW(RelM)));
+ symtab = (ElfW(Sym) *) syms->contents;
+ strtab = (const char *) strs->contents;
+
+ for (; rel < relend; ++rel)
+ {
+ extsym = &symtab[ELF32_R_SYM(rel->r_info)];
+
+ switch(ELF32_R_TYPE(rel->r_info)) {
+ case R_ARM_PC24:
+ case R_ARM_PLT32:
+ if (extsym->st_name)
+ name = strtab + extsym->st_name;
+ else
+ name = f->sections[extsym->st_shndx]->name;
+ intsym = (struct arm_symbol *) obj_find_symbol(f, name);
+
+ pe = &intsym->pltent;
+
+ if (! pe->allocated)
+ {
+ pe->allocated = 1;
+ pe->offset = plt_offset;
+ plt_offset += 8;
+ pe->inited = 0;
+ }
+ break;
+
+ /* these two don_t need got entries, but they need
+ the .got to exist */
+ case R_ARM_GOTOFF:
+ case R_ARM_GOTPC:
+ if (got_offset==0) got_offset = 4;
+ break;
+
+ case R_ARM_GOT32:
+ if (extsym->st_name)
+ name = strtab + extsym->st_name;
+ else
+ name = f->sections[extsym->st_shndx]->name;
+ intsym = (struct arm_symbol *) obj_find_symbol(f, name);
+
+ ge = (struct arm_got_entry *) &intsym->gotent;
+ if (! ge->allocated)
+ {
+ ge->allocated = 1;
+ ge->offset = got_offset;
+ got_offset += sizeof(void*);
+ }
+ break;
+
+ default:
+ continue;
+ }
+ }
+ }
+
+ /* if there was a _GLOBAL_OFFSET_TABLE_, then the .got section
+ exists already; find it and use it */
+ if (got_offset)
+ {
+ struct obj_section* sec = obj_find_section(f, ".got");
+ if (sec)
+ obj_extend_section(sec, got_offset);
+ else
+ {
+ sec = obj_create_alloced_section(f, ".got", 8, got_offset);
+ assert(sec);
+ }
+ afile->got = sec;
+ }
+
+ if (plt_offset)
+ afile->plt = obj_create_alloced_section(f, ".plt", 8, plt_offset);
+
+ return 1;
+}
+
+int
+arch_init_module (struct obj_file *f, struct module *mod)
+{
+ return 1;
+}
+
+int
+arch_finalize_section_address(struct obj_file *f, Elf32_Addr base)
+{
+ int i, n = f->header.e_shnum;
+
+ f->baseaddr = base;
+ for (i = 0; i < n; ++i)
+ f->sections[i]->header.sh_addr += base;
+ return 1;
+}
+
+int
+arch_archdata (struct obj_file *fin, struct obj_section *sec)
+{
+ return 0;
+}
diff --git a/mdk-stage1/insmod-modutils/obj/obj_common.c b/mdk-stage1/insmod-modutils/obj/obj_common.c
new file mode 100644
index 000000000..2a6606c94
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/obj/obj_common.c
@@ -0,0 +1,399 @@
+/* Elf file, section, and symbol manipulation routines.
+ Copyright 1996, 1997 Linux International.
+
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include <obj.h>
+#include <util.h>
+#include <module.h>
+
+/*======================================================================*/
+
+/* Standard ELF hash function. */
+inline unsigned long
+obj_elf_hash_n(const char *name, unsigned long n)
+{
+ unsigned long h = 0;
+ unsigned long g;
+ unsigned char ch;
+
+ while (n > 0)
+ {
+ ch = *name++;
+ h = (h << 4) + ch;
+ if ((g = (h & 0xf0000000)) != 0)
+ {
+ h ^= g >> 24;
+ h &= ~g;
+ }
+ n--;
+ }
+ return h;
+}
+
+unsigned long
+obj_elf_hash (const char *name)
+{
+ return obj_elf_hash_n(name, strlen(name));
+}
+
+void
+obj_set_symbol_compare (struct obj_file *f,
+ int (*cmp)(const char *, const char *),
+ unsigned long (*hash)(const char *))
+{
+ if (cmp)
+ f->symbol_cmp = cmp;
+ if (hash)
+ {
+ struct obj_symbol *tmptab[HASH_BUCKETS], *sym, *next;
+ int i;
+
+ f->symbol_hash = hash;
+
+ memcpy(tmptab, f->symtab, sizeof(tmptab));
+ memset(f->symtab, 0, sizeof(f->symtab));
+
+ for (i = 0; i < HASH_BUCKETS; ++i)
+ for (sym = tmptab[i]; sym ; sym = next)
+ {
+ unsigned long h = hash(sym->name) % HASH_BUCKETS;
+ next = sym->next;
+ sym->next = f->symtab[h];
+ f->symtab[h] = sym;
+ }
+ }
+}
+
+struct obj_symbol *
+obj_add_symbol (struct obj_file *f, const char *name, unsigned long symidx,
+ int info, int secidx, ElfW(Addr) value, unsigned long size)
+{
+ struct obj_symbol *sym;
+ unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS;
+ int n_type = ELFW(ST_TYPE)(info);
+ int n_binding = ELFW(ST_BIND)(info);
+
+ for (sym = f->symtab[hash]; sym; sym = sym->next)
+ if (f->symbol_cmp(sym->name, name) == 0)
+ {
+ int o_secidx = sym->secidx;
+ int o_info = sym->info;
+ int o_type = ELFW(ST_TYPE)(o_info);
+ int o_binding = ELFW(ST_BIND)(o_info);
+
+ /* A redefinition! Is it legal? */
+
+ if (secidx == SHN_UNDEF)
+ return sym;
+ else if (o_secidx == SHN_UNDEF)
+ goto found;
+ else if (n_binding == STB_GLOBAL && o_binding == STB_LOCAL)
+ {
+ /* Cope with local and global symbols of the same name
+ in the same object file, as might have been created
+ by ld -r. The only reason locals are now seen at this
+ level at all is so that we can do semi-sensible things
+ with parameters. */
+
+ struct obj_symbol *nsym, **p;
+
+ nsym = arch_new_symbol();
+ nsym->next = sym->next;
+ nsym->ksymidx = -1;
+
+ /* Excise the old (local) symbol from the hash chain. */
+ for (p = &f->symtab[hash]; *p != sym; p = &(*p)->next)
+ continue;
+ *p = sym = nsym;
+ goto found;
+ }
+ else if (n_binding == STB_LOCAL)
+ {
+ /* Another symbol of the same name has already been defined.
+ Just add this to the local table. */
+ sym = arch_new_symbol();
+ sym->next = NULL;
+ sym->ksymidx = -1;
+ f->local_symtab[symidx] = sym;
+ goto found;
+ }
+ else if (n_binding == STB_WEAK)
+ return sym;
+ else if (o_binding == STB_WEAK)
+ goto found;
+ /* Don't unify COMMON symbols with object types the programmer
+ doesn't expect. */
+ else if (secidx == SHN_COMMON
+ && (o_type == STT_NOTYPE || o_type == STT_OBJECT))
+ return sym;
+ else if (o_secidx == SHN_COMMON
+ && (n_type == STT_NOTYPE || n_type == STT_OBJECT))
+ goto found;
+ else
+ {
+ /* Don't report an error if the symbol is coming from
+ the kernel or some external module. */
+ if (secidx <= SHN_HIRESERVE)
+ error("%s multiply defined", name);
+ return sym;
+ }
+ }
+
+ /* Completely new symbol. */
+ sym = arch_new_symbol();
+ sym->next = f->symtab[hash];
+ f->symtab[hash] = sym;
+ sym->ksymidx = -1;
+
+ if (ELFW(ST_BIND)(info) == STB_LOCAL && symidx != -1) {
+ if (symidx >= f->local_symtab_size)
+ error("local symbol %s with index %ld exceeds local_symtab_size %ld",
+ name, (long) symidx, (long) f->local_symtab_size);
+ else
+ f->local_symtab[symidx] = sym;
+ }
+
+found:
+ sym->name = name;
+ sym->value = value;
+ sym->size = size;
+ sym->secidx = secidx;
+ sym->info = info;
+ sym->r_type = 0; /* should be R_arch_NONE for all arch */
+
+ return sym;
+}
+
+struct obj_symbol *
+obj_find_symbol (struct obj_file *f, const char *name)
+{
+ struct obj_symbol *sym;
+ unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS;
+
+ for (sym = f->symtab[hash]; sym; sym = sym->next)
+ if (f->symbol_cmp(sym->name, name) == 0)
+ return sym;
+
+ return NULL;
+}
+
+ElfW(Addr)
+obj_symbol_final_value (struct obj_file *f, struct obj_symbol *sym)
+{
+ if (sym)
+ {
+ if (sym->secidx >= SHN_LORESERVE)
+ return sym->value;
+
+ return sym->value + f->sections[sym->secidx]->header.sh_addr;
+ }
+ else
+ {
+ /* As a special case, a NULL sym has value zero. */
+ return 0;
+ }
+}
+
+struct obj_section *
+obj_find_section (struct obj_file *f, const char *name)
+{
+ int i, n = f->header.e_shnum;
+
+ for (i = 0; i < n; ++i)
+ if (strcmp(f->sections[i]->name, name) == 0)
+ return f->sections[i];
+
+ return NULL;
+}
+
+static int
+obj_load_order_prio(struct obj_section *a)
+{
+ unsigned long af, ac;
+
+ af = a->header.sh_flags;
+
+ ac = 0;
+ if (a->name[0] != '.' || strlen(a->name) != 10 ||
+ strcmp(a->name + 5, ".init")) ac |= 32;
+ if (af & SHF_ALLOC) ac |= 16;
+ if (!(af & SHF_WRITE)) ac |= 8;
+ if (af & SHF_EXECINSTR) ac |= 4;
+ if (a->header.sh_type != SHT_NOBITS) ac |= 2;
+#if defined(ARCH_ia64)
+ if (af & SHF_IA_64_SHORT) ac -= 1;
+#endif
+
+ return ac;
+}
+
+void
+obj_insert_section_load_order (struct obj_file *f, struct obj_section *sec)
+{
+ struct obj_section **p;
+ int prio = obj_load_order_prio(sec);
+ for (p = f->load_order_search_start; *p ; p = &(*p)->load_next)
+ if (obj_load_order_prio(*p) < prio)
+ break;
+ sec->load_next = *p;
+ *p = sec;
+}
+
+struct obj_section *
+obj_create_alloced_section (struct obj_file *f, const char *name,
+ unsigned long align, unsigned long size)
+{
+ int newidx = f->header.e_shnum++;
+ struct obj_section *sec;
+
+ f->sections = xrealloc(f->sections, (newidx+1) * sizeof(sec));
+ f->sections[newidx] = sec = arch_new_section();
+
+ memset(sec, 0, sizeof(*sec));
+ sec->header.sh_type = SHT_PROGBITS;
+ sec->header.sh_flags = SHF_WRITE|SHF_ALLOC;
+ sec->header.sh_size = size;
+ sec->header.sh_addralign = align;
+ sec->name = name;
+ sec->idx = newidx;
+ if (size)
+ sec->contents = xmalloc(size);
+
+ obj_insert_section_load_order(f, sec);
+
+ return sec;
+}
+
+struct obj_section *
+obj_create_alloced_section_first (struct obj_file *f, const char *name,
+ unsigned long align, unsigned long size)
+{
+ int newidx = f->header.e_shnum++;
+ struct obj_section *sec;
+
+ f->sections = xrealloc(f->sections, (newidx+1) * sizeof(sec));
+ f->sections[newidx] = sec = arch_new_section();
+
+ memset(sec, 0, sizeof(*sec));
+ sec->header.sh_type = SHT_PROGBITS;
+ sec->header.sh_flags = SHF_WRITE|SHF_ALLOC;
+ sec->header.sh_size = size;
+ sec->header.sh_addralign = align;
+ sec->name = name;
+ sec->idx = newidx;
+ if (size)
+ sec->contents = xmalloc(size);
+
+ sec->load_next = f->load_order;
+ f->load_order = sec;
+ if (f->load_order_search_start == &f->load_order)
+ f->load_order_search_start = &sec->load_next;
+
+ return sec;
+}
+
+void *
+obj_extend_section (struct obj_section *sec, unsigned long more)
+{
+ unsigned long oldsize = sec->header.sh_size;
+ sec->contents = xrealloc(sec->contents, sec->header.sh_size += more);
+ return sec->contents + oldsize;
+}
+
+/* Convert an object pointer (address) to a native pointer and vice versa.
+ * It gets interesting when the object has 64 bit pointers but modutils
+ * is running 32 bit. This is nasty code but it stops the compiler giving
+ * spurious warning messages. "I know what I am doing" ...
+ */
+
+void *
+obj_addr_to_native_ptr (ElfW(Addr) addr)
+{
+ unsigned int convert = (sizeof(void *) << 8) + sizeof(addr); /* to, from */
+ union obj_ptr_4 p4;
+ union obj_ptr_8 p8;
+ switch (convert) {
+ case 0x0404:
+ p4.addr = addr;
+ return(p4.ptr);
+ break;
+ case 0x0408:
+ p4.addr = addr;
+ if (p4.addr != addr) {
+ error("obj_addr_to_native_ptr truncation %" tgt_long_fmt "x",
+ (tgt_long) addr);
+ exit(1);
+ }
+ return(p4.ptr);
+ break;
+ case 0x0804:
+ p8.addr = addr;
+ return(p8.ptr);
+ break;
+ case 0x0808:
+ p8.addr = addr;
+ return(p8.ptr);
+ break;
+ default:
+ error("obj_addr_to_native_ptr unknown conversion 0x%04x", convert);
+ exit(1);
+ }
+}
+
+ElfW(Addr)
+obj_native_ptr_to_addr (void *ptr)
+{
+ unsigned int convert = (sizeof(ElfW(Addr)) << 8) + sizeof(ptr); /* to, from */
+ union obj_ptr_4 p4;
+ union obj_ptr_8 p8;
+ switch (convert) {
+ case 0x0404:
+ p4.ptr = ptr;
+ return(p4.addr);
+ break;
+ case 0x0408:
+ p8.ptr = ptr;
+ p4.addr = p8.addr;
+ if (p4.addr != p8.addr) {
+ error("obj_native_ptr_to_addr truncation %" tgt_long_fmt "x",
+ (tgt_long) p8.addr);
+ exit(1);
+ }
+ return(p4.addr);
+ break;
+ case 0x0804:
+ p4.ptr = ptr;
+ return(p4.addr); /* compiler expands to 8 */
+ break;
+ case 0x0808:
+ p8.ptr = ptr;
+ return(p8.addr);
+ break;
+ default:
+ error("obj_native_ptr_to_addr unknown conversion 0x%04x", convert);
+ exit(1);
+ }
+}
diff --git a/mdk-stage1/insmod-modutils/obj/obj_hppa.c b/mdk-stage1/insmod-modutils/obj/obj_hppa.c
new file mode 100644
index 000000000..4207e692e
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/obj/obj_hppa.c
@@ -0,0 +1,668 @@
+/*
+ * PA-RISC specific support for Elf loading and relocation.
+ * Copyright 2000 David Huggins-Daines <dhd@linuxcare.com>, Linuxcare Inc.
+ * Copyright 2000 Richard Hirst <rhirst@linuxcare.com>, Linuxcare Inc.
+ *
+ * Based on the IA-64 support, which is:
+ * Copyright 2000 Mike Stephens <mike.stephens@intel.com>
+ *
+ * This file is part of the Linux modutils.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include <module.h>
+#include <obj.h>
+#include <util.h>
+#include <modstat.h> /* For ksyms */
+
+
+typedef struct _hppa_stub_t
+{
+ struct _hppa_stub_t *next;
+ int offset;
+ int reloc_done;
+} hppa_stub_t;
+
+typedef struct _hppa_symbol_t
+{
+ struct obj_symbol root;
+ hppa_stub_t *stub;
+} hppa_symbol_t;
+
+typedef struct _hppa_file_t
+{
+ struct obj_file root;
+ struct obj_section *stub;
+ Elf32_Addr dp;
+} hppa_file_t;
+
+/* The ABI defines various more esoteric types, but these are the only
+ ones we actually need. */
+enum hppa_fsel
+{
+ e_fsel,
+ e_lsel,
+ e_rsel,
+ e_lrsel,
+ e_rrsel
+};
+
+/* This could be a call to obj_create_alloced_section() followed
+ * by an overwrite of sec->header.sh_flags.
+ */
+
+struct obj_section *
+obj_hppa_create_alloced_section (struct obj_file *f, const char *name,
+ unsigned long align, unsigned long size,
+ unsigned long sh_flags)
+{
+ int newidx = f->header.e_shnum++;
+ struct obj_section *sec;
+
+ f->sections = xrealloc(f->sections, (newidx+1) * sizeof(sec));
+ f->sections[newidx] = sec = arch_new_section();
+
+ memset(sec, 0, sizeof(*sec));
+ sec->header.sh_type = SHT_PROGBITS;
+ sec->header.sh_flags = sh_flags;
+ sec->header.sh_size = size;
+ sec->header.sh_addralign = align;
+ sec->name = name;
+ sec->idx = newidx;
+ if (size)
+ sec->contents = xmalloc(size);
+
+ obj_insert_section_load_order(f, sec);
+
+ return sec;
+}
+
+struct obj_file *
+arch_new_file (void)
+{
+ hppa_file_t *f;
+ f = xmalloc(sizeof(*f));
+ f->stub = NULL;
+ return &f->root;
+}
+
+struct obj_section *
+arch_new_section (void)
+{
+ return xmalloc(sizeof(struct obj_section));
+}
+
+struct obj_symbol *
+arch_new_symbol (void)
+{
+ hppa_symbol_t *sym;
+ sym = xmalloc(sizeof(*sym));
+ sym->stub = NULL;
+ return &sym->root;
+}
+
+/* This is called for architecture specific sections we might need to
+ do special things to. */
+int
+arch_load_proc_section(struct obj_section *sec, int fp)
+{
+ /* Assume it's just a debugging section that we can safely
+ ignore ... */
+ sec->contents = NULL;
+
+ return 0;
+}
+
+/* =================================================================
+
+ These functions are from libhppa.h in the GNU BFD library.
+ (c) 1990, 91, 92, 93, 94, 95, 96, 98, 99, 2000
+ Free Software Foundation, Inc.
+
+ ================================================================= */
+
+/* The *sign_extend functions are used to assemble various bitfields
+ taken from an instruction and return the resulting immediate
+ value. */
+
+static inline int
+sign_extend (x, len)
+ int x, len;
+{
+ int signbit = (1 << (len - 1));
+ int mask = (signbit << 1) - 1;
+ return ((x & mask) ^ signbit) - signbit;
+}
+
+static inline int
+low_sign_extend (x, len)
+ int x, len;
+{
+ return (x >> 1) - ((x & 1) << (len - 1));
+}
+
+
+/* The re_assemble_* functions prepare an immediate value for
+ insertion into an opcode. pa-risc uses all sorts of weird bitfields
+ in the instruction to hold the value. */
+
+static inline int
+sign_unext (x, len)
+ int x, len;
+{
+ int len_ones;
+
+ len_ones = (1 << len) - 1;
+
+ return x & len_ones;
+}
+
+static inline int
+low_sign_unext (x, len)
+ int x, len;
+{
+ int temp;
+ int sign;
+
+ sign = (x >> (len-1)) & 1;
+
+ temp = sign_unext (x, len-1);
+
+ return (temp << 1) | sign;
+}
+
+static inline int
+re_assemble_3 (as3)
+ int as3;
+{
+ return (( (as3 & 4) << (13-2))
+ | ((as3 & 3) << (13+1)));
+}
+
+static inline int
+re_assemble_12 (as12)
+ int as12;
+{
+ return (( (as12 & 0x800) >> 11)
+ | ((as12 & 0x400) >> (10 - 2))
+ | ((as12 & 0x3ff) << (1 + 2)));
+}
+
+static inline int
+re_assemble_14 (as14)
+ int as14;
+{
+ return (( (as14 & 0x1fff) << 1)
+ | ((as14 & 0x2000) >> 13));
+}
+
+static inline int
+re_assemble_16 (as16)
+ int as16;
+{
+ int s, t;
+
+ /* Unusual 16-bit encoding, for wide mode only. */
+ t = (as16 << 1) & 0xffff;
+ s = (as16 & 0x8000);
+ return (t ^ s ^ (s >> 1)) | (s >> 15);
+}
+
+static inline int
+re_assemble_17 (as17)
+ int as17;
+{
+ return (( (as17 & 0x10000) >> 16)
+ | ((as17 & 0x0f800) << (16 - 11))
+ | ((as17 & 0x00400) >> (10 - 2))
+ | ((as17 & 0x003ff) << (1 + 2)));
+}
+
+static inline int
+re_assemble_21 (as21)
+ int as21;
+{
+ return (( (as21 & 0x100000) >> 20)
+ | ((as21 & 0x0ffe00) >> 8)
+ | ((as21 & 0x000180) << 7)
+ | ((as21 & 0x00007c) << 14)
+ | ((as21 & 0x000003) << 12));
+}
+
+static inline int
+re_assemble_22 (as22)
+ int as22;
+{
+ return (( (as22 & 0x200000) >> 21)
+ | ((as22 & 0x1f0000) << (21 - 16))
+ | ((as22 & 0x00f800) << (16 - 11))
+ | ((as22 & 0x000400) >> (10 - 2))
+ | ((as22 & 0x0003ff) << (1 + 2)));
+}
+
+
+/* Handle field selectors for PA instructions.
+ The L and R (and LS, RS etc.) selectors are used in pairs to form a
+ full 32 bit address. eg.
+
+ LDIL L'start,%r1 ; put left part into r1
+ LDW R'start(%r1),%r2 ; add r1 and right part to form address
+
+ This function returns sign extended values in all cases.
+*/
+
+static inline unsigned int
+hppa_field_adjust (value, addend, r_field)
+ unsigned int value;
+ int addend;
+ enum hppa_fsel r_field;
+{
+ unsigned int sym_val;
+
+ sym_val = value - addend;
+ switch (r_field)
+ {
+ case e_fsel:
+ /* F: No change. */
+ break;
+
+ case e_lsel:
+ /* L: Select top 21 bits. */
+ value = value >> 11;
+ break;
+
+ case e_rsel:
+ /* R: Select bottom 11 bits. */
+ value = value & 0x7ff;
+ break;
+
+ case e_lrsel:
+ /* LR: L with rounding of the addend to nearest 8k. */
+ value = sym_val + ((addend + 0x1000) & -0x2000);
+ value = value >> 11;
+ break;
+
+ case e_rrsel:
+ /* RR: R with rounding of the addend to nearest 8k.
+ We need to return a value such that 2048 * LR'x + RR'x == x
+ ie. RR'x = s+a - (s + (((a + 0x1000) & -0x2000) & -0x800))
+ . = s+a - ((s & -0x800) + ((a + 0x1000) & -0x2000))
+ . = (s & 0x7ff) + a - ((a + 0x1000) & -0x2000) */
+ value = (sym_val & 0x7ff) + (((addend & 0x1fff) ^ 0x1000) - 0x1000);
+ break;
+
+ default:
+ abort();
+ }
+ return value;
+}
+
+/* Insert VALUE into INSN using R_FORMAT to determine exactly what
+ bits to change. */
+
+static inline int
+hppa_rebuild_insn (insn, value, r_format)
+ int insn;
+ int value;
+ int r_format;
+{
+ switch (r_format)
+ {
+ case 11:
+ return (insn & ~ 0x7ff) | low_sign_unext (value, 11);
+
+ case 12:
+ return (insn & ~ 0x1ffd) | re_assemble_12 (value);
+
+
+ case 10:
+ return (insn & ~ 0x3ff1) | re_assemble_14 (value & -8);
+
+ case -11:
+ return (insn & ~ 0x3ff9) | re_assemble_14 (value & -4);
+
+ case 14:
+ return (insn & ~ 0x3fff) | re_assemble_14 (value);
+
+
+ case -10:
+ return (insn & ~ 0xfff1) | re_assemble_16 (value & -8);
+
+ case -16:
+ return (insn & ~ 0xfff9) | re_assemble_16 (value & -4);
+
+ case 16:
+ return (insn & ~ 0xffff) | re_assemble_16 (value);
+
+
+ case 17:
+ return (insn & ~ 0x1f1ffd) | re_assemble_17 (value);
+
+ case 21:
+ return (insn & ~ 0x1fffff) | re_assemble_21 (value);
+
+ case 22:
+ return (insn & ~ 0x3ff1ffd) | re_assemble_22 (value);
+
+ case 32:
+ return value;
+
+ default:
+ abort ();
+ }
+ return insn;
+}
+
+/* ====================================================================
+
+ End of functions from GNU BFD.
+
+ ==================================================================== */
+
+/* This is where we get the opportunity to create any extra dynamic
+ sections we might need. In our case we do not need a GOT because
+ our code is not PIC, but we do need to create a stub section.
+
+ This is significantly less complex than what we do for shared
+ libraries because, obviously, modules are not shared. Also we have
+ no issues related to symbol visibility, lazy linking, etc.
+ The kernels dp is fixed (at symbol data_start), and we can fix up any
+ DPREL refs in the module to use that same dp value.
+ All PCREL17F refs result in a stub with the following format:
+
+ ldil L'func_addr,%r1
+ be,n R'func_addr(%sr4,%r1)
+
+ Note, all PCREL17F get a stub, regardless of whether they are
+ local or external. With local ones, and external ones to other
+ modules, there is a good chance we could manage without the stub.
+ I'll leave that for a future optimisation.
+ */
+
+#define LDIL_R1 0x20200000 /* ldil L'XXX,%r1 */
+#define BE_N_SR4_R1 0xe0202002 /* be,n R'XXX(%sr4,%r1) */
+
+#define STUB_SIZE 8
+
+int
+arch_create_got(struct obj_file *f)
+{
+ hppa_file_t *hfile = (hppa_file_t *)f;
+ int i, n;
+ int stub_offset = 0;
+
+ /* Create stub section.
+ * XXX set flags, see obj_ia64.c
+ */
+ hfile->stub = obj_create_alloced_section(f, ".stub", STUB_SIZE, 0);
+
+ /* Actually this is a lot like check_relocs() in a BFD backend. We
+ walk all sections and all their relocations and look for ones
+ that need special treatment. */
+ n = hfile->root.header.e_shnum;
+ for (i = 0; i < n; ++i)
+ {
+ struct obj_section *relsec, *symsec, *strsec;
+ Elf32_Rela *rel, *relend;
+ Elf32_Sym *symtab;
+ char const *strtab;
+
+ relsec = hfile->root.sections[i];
+ if (relsec->header.sh_type != SHT_RELA)
+ continue;
+
+ symsec = hfile->root.sections[relsec->header.sh_link];
+ strsec = hfile->root.sections[symsec->header.sh_link];
+
+ rel = (Elf32_Rela *)relsec->contents;
+ relend = rel + (relsec->header.sh_size / sizeof(Elf32_Rela));
+ symtab = (Elf32_Sym *)symsec->contents;
+ strtab = (char const *)strsec->contents;
+
+ for (; rel < relend; rel++)
+ {
+ int need_stub = 0;
+
+ switch (ELF32_R_TYPE(rel->r_info))
+ {
+ default:
+ continue;
+
+ case R_PARISC_PCREL17F:
+ need_stub = 1;
+ break;
+ }
+
+ if (need_stub)
+ {
+ Elf32_Sym *extsym;
+ hppa_symbol_t *hsym;
+ char const *name;
+ int local;
+ unsigned long symndx;
+
+ symndx = ELF32_R_SYM(rel->r_info);
+ extsym = symtab + symndx;
+ if (ELF32_ST_BIND(extsym->st_info) == STB_LOCAL)
+ hsym = (hppa_symbol_t *) f->local_symtab[symndx];
+ else
+ {
+ if (extsym->st_name)
+ name = strtab + extsym->st_name;
+ else
+ name = f->sections[extsym->st_shndx]->name;
+ hsym = (hppa_symbol_t *)obj_find_symbol(f, name);
+ }
+ local = hsym->root.secidx <= SHN_HIRESERVE;
+
+ if (need_stub)
+ {
+ hppa_stub_t *stub;
+
+ if (hsym->stub == NULL)
+ {
+ stub = (hppa_stub_t *) xmalloc(sizeof(hppa_stub_t));
+ stub->offset = stub_offset;
+ stub->reloc_done = 0;
+ hsym->stub = stub;
+ stub_offset += STUB_SIZE;
+ need_stub = 0;
+ }
+ }
+ }
+ }
+ }
+ if (stub_offset)
+ {
+ hfile->stub->contents = xmalloc(stub_offset);
+ hfile->stub->header.sh_size = stub_offset;
+ }
+ return 1;
+}
+
+
+enum obj_reloc
+arch_apply_relocation(struct obj_file *f,
+ struct obj_section *targsec,
+ struct obj_section *symsec,
+ struct obj_symbol *sym,
+ Elf32_Rela *rel,
+ Elf32_Addr v)
+{
+ hppa_file_t *hfile = (hppa_file_t *) f;
+ hppa_symbol_t *hsym = (hppa_symbol_t *) sym;
+
+ Elf32_Addr *loc = (Elf32_Addr *)(targsec->contents + rel->r_offset);
+ Elf32_Addr dot = (targsec->header.sh_addr + rel->r_offset) & ~0x03;
+ Elf32_Addr dp = hfile->dp;
+ Elf32_Word r_info = ELF32_R_TYPE(rel->r_info);
+
+ enum obj_reloc ret = obj_reloc_ok;
+ enum hppa_fsel fsel = e_fsel; /* Avoid compiler warning */
+ unsigned int r_format;
+
+ /* Fix up the value, and determine whether we can handle this
+ relocation. */
+ switch (r_info)
+ {
+ case R_PARISC_PLABEL32:
+ case R_PARISC_DIR32:
+ case R_PARISC_DIR21L:
+ case R_PARISC_DIR14R:
+ /* Easy. */
+ break;
+
+ case R_PARISC_DPREL21L:
+ case R_PARISC_DPREL14R:
+ v -= dp;
+ break;
+
+ case R_PARISC_PCREL17F:
+ /* Find an import stub. */
+ assert(hsym->stub != NULL);
+ assert(hfile->stub != NULL);
+ /* XXX Optimise. We may not need a stub for short branches */
+ if (!hsym->stub->reloc_done) {
+ /* Need to create the .stub entry */
+ Elf32_Addr *pstub, stubv;
+
+ pstub = (Elf32_Addr *)(hfile->stub->contents + hsym->stub->offset);
+ pstub[0] = LDIL_R1;
+ pstub[1] = BE_N_SR4_R1;
+ stubv = hppa_field_adjust(v, rel->r_addend, e_lrsel);
+ pstub[0] = hppa_rebuild_insn(pstub[0], stubv, 21);
+ stubv = hppa_field_adjust(v, rel->r_addend, e_rrsel);
+ stubv >>= 2; /* Branch; divide by 4 */
+ pstub[1] = hppa_rebuild_insn(pstub[1], stubv, 17);
+ hsym->stub->reloc_done = 1;
+ }
+ v = hsym->stub->offset + hfile->stub->header.sh_addr;
+ break;
+
+ default:
+ return obj_reloc_unhandled;
+ }
+
+ /* Find the field selector. */
+ switch (r_info)
+ {
+ case R_PARISC_DIR32:
+ case R_PARISC_PLABEL32:
+ case R_PARISC_PCREL17F:
+ fsel = e_fsel;
+ break;
+
+ case R_PARISC_DPREL21L:
+ case R_PARISC_DIR21L:
+ fsel = e_lrsel;
+ break;
+
+ case R_PARISC_DPREL14R:
+ case R_PARISC_DIR14R:
+ fsel = e_rrsel;
+ break;
+ }
+
+ v = hppa_field_adjust(v, rel->r_addend, fsel);
+
+ switch (r_info)
+ {
+ case R_PARISC_PCREL17F:
+ case R_PARISC_PCREL17R:
+ case R_PARISC_PCREL22F:
+ v = v - dot - 8;
+ case R_PARISC_DIR17F:
+ case R_PARISC_DIR17R:
+ /* This is a branch. Divide the offset by four. */
+ v >>= 2;
+ break;
+ default:
+ break;
+ }
+
+ /* Find the format. */
+ switch (r_info)
+ {
+ case R_PARISC_DIR32:
+ case R_PARISC_PLABEL32:
+ r_format = 32;
+ break;
+
+ case R_PARISC_DPREL21L:
+ case R_PARISC_DIR21L:
+ r_format = 21;
+ break;
+
+ case R_PARISC_PCREL17F:
+ r_format = 17;
+ break;
+
+ case R_PARISC_DPREL14R:
+ case R_PARISC_DIR14R:
+ r_format = 14;
+ break;
+
+ default:
+ abort();
+ }
+
+ *loc = hppa_rebuild_insn(*loc, v, r_format);
+
+ return ret;
+}
+
+int
+arch_init_module (struct obj_file *f, struct module *mod)
+{
+ return 1;
+}
+
+int
+arch_finalize_section_address(struct obj_file *f, Elf32_Addr base)
+{
+ int i, n = f->header.e_shnum;
+
+ f->baseaddr = base;
+ for (i = 0; i < n; ++i)
+ f->sections[i]->header.sh_addr += base;
+ return 1;
+}
+
+int
+arch_archdata (struct obj_file *f, struct obj_section *sec)
+{
+ struct module_symbol *s;
+ int i;
+ hppa_file_t *hfile = (hppa_file_t *)f;
+
+ /* Initialise dp to the kernels dp (symbol data_start)
+ */
+ for (i = 0, s = ksyms; i < nksyms; i++, s++)
+ if (!strcmp((char *)s->name, "data_start"))
+ break;
+ if (i >= nksyms) {
+ error("Cannot initialise dp, 'data_start' not found\n");
+ return 1;
+ }
+ hfile->dp = s->value;
+
+ return 0;
+}
+
diff --git a/mdk-stage1/insmod-modutils/obj/obj_hppa64.c b/mdk-stage1/insmod-modutils/obj/obj_hppa64.c
new file mode 100644
index 000000000..fe32911ff
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/obj/obj_hppa64.c
@@ -0,0 +1,686 @@
+/*
+ * hppa parisc64 specific support for Elf loading and relocation.
+ * Copyright 2000 Richard Hirst <rhirst@linuxcare.com>, Linuxcare Inc.
+ *
+ * Based on ia64 specific support which was
+ * Copyright 2000 Mike Stephens <mike.stephens@intel.com>
+ *
+ * This file is part of the Linux modutils.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ident "$Id$"
+
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include <module.h>
+#include <obj.h>
+#include <util.h>
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE ~FALSE
+#endif
+
+/*======================================================================*/
+
+typedef struct _hppa64_opd_t
+{
+ int offset;
+ int reloc_done;
+} hppa64_opd_t;
+
+typedef struct _hppa64_stub_t
+{
+ struct _hppa64_stub_t *next;
+ Elf64_Addr addend;
+ int offset;
+ int reloc_done;
+} hppa64_stub_t;
+
+typedef struct _hppa64_got_t
+{
+ struct _hppa64_got_t *next;
+ Elf64_Addr addend;
+ int offset;
+ int reloc_done;
+} hppa64_got_t;
+
+typedef struct _hppa64_symbol_t
+{
+ struct obj_symbol root;
+ hppa64_got_t *gotent;
+ hppa64_opd_t *opdent;
+ hppa64_stub_t *stubent;
+} hppa64_symbol_t;
+
+typedef struct _hppa64_file_t
+{
+ struct obj_file root;
+ struct obj_section *got;
+ struct obj_section *opd;
+ struct obj_section *stub;
+ Elf64_Addr gp;
+ Elf64_Addr text;
+ Elf64_Addr data;
+ Elf64_Addr bss;
+} hppa64_file_t;
+
+/*
+ * XXX This stub assumes it can reach the .got entry with a +/- 8K offset
+ * from dp. Perhaps we should use a .plt for these entries to give a
+ * greater chance of that being true.
+ *
+ * 53 7b 00 00 ldd 0(dp),dp
+ * R_PARISC_LTOFF14R <.got entry offset from dp>
+ * 53 61 00 20 ldd 10(dp),r1
+ * e8 20 d0 00 bve (r1)
+ * 53 7b 00 30 ldd 18(dp),dp
+ *
+ * We need a different stub for millicode calls, which doesn't screw
+ * dp:
+ *
+ * 53 61 00 00 ldd 0(dp),r1
+ * R_PARISC_LTOFF14R <.got entry offset from dp>
+ * 50 21 00 20 ldd 10(r1),r1
+ * e8 20 d0 00 bve (r1)
+ * 08 00 02 40 nop
+ *
+ */
+
+/* NOTE: to keep the code cleaner we make all stubs the same size.
+ */
+
+#define SIZEOF_STUB 16
+
+unsigned char hppa64_stub_extern[] =
+{
+ 0x53, 0x7b, 0x00, 0x00,
+ 0x53, 0x61, 0x00, 0x20,
+ 0xe8, 0x20, 0xd0, 0x00,
+ 0x53, 0x7b, 0x00, 0x30,
+};
+
+unsigned char hppa64_stub_millicode[] =
+{
+ 0x53, 0x61, 0x00, 0x00,
+ 0x50, 0x21, 0x00, 0x20,
+ 0xe8, 0x20, 0xd0, 0x00,
+ 0x08, 0x00, 0x02, 0x40,
+};
+
+/*======================================================================*/
+
+enum obj_reloc
+patch_14r(Elf64_Xword v64, Elf64_Word *p)
+{
+ Elf64_Word i = *p;
+ Elf64_Word v = (Elf64_Word)v64;
+
+ if (v & 0x80000000)
+ v |= ~0x7ff;
+ else
+ v &= 0x7ff;
+ i &= ~ 0x3fff;
+ i |= (v & 0x1fff) << 1 |
+ (v & 0x2000) >> 13;
+ *p = i;
+
+ return obj_reloc_ok;
+}
+
+enum obj_reloc
+patch_21l(Elf64_Xword v64, Elf64_Word *p)
+{
+ Elf64_Word i = *p;
+ Elf64_Word v = (Elf64_Word)v64;
+
+ v &= 0xfffff800;
+ if (v & 0x80000000)
+ v += 0x800;
+ i &= ~ 0x1fffff;
+ i |= (v & 0x80000000) >> 31 |
+ (v & 0x7ff00000) >> 19 |
+ (v & 0x000c0000) >> 4 |
+ (v & 0x0003e000) << 3 |
+ (v & 0x00001800) << 1;
+ *p = i;
+
+ return obj_reloc_ok;
+}
+
+
+/* All 14 bits this time... This is used to patch the .got offset in
+ * a stub for PCREL22F.
+ */
+
+enum obj_reloc
+patch_14r2(Elf64_Xword v64, Elf64_Word *p)
+{
+ Elf64_Word i = *p;
+ Elf64_Word v = (Elf64_Word)v64;
+
+ if ((Elf64_Sxword)v64 > 0x1fffL ||
+ (Elf64_Sxword)v64 < -0x2000L)
+ return obj_reloc_overflow;
+ i &= ~ 0x3fff;
+ i |= (v & 0x2000) >> 13 |
+ (v & 0x1fff) << 1;
+ *p = i;
+
+ return obj_reloc_ok;
+}
+
+
+enum obj_reloc
+patch_22f(Elf64_Xword v64, Elf64_Word *p)
+{
+ Elf64_Word i = *p;
+ Elf64_Word v = (Elf64_Word)v64;
+
+ if ((Elf64_Sxword)v64 > 0x800000-1 ||
+ (Elf64_Sxword)v64 < -0x800000)
+ return obj_reloc_overflow;
+
+ i &= ~ 0x03ff1ffd;
+ i |= (v & 0x00800000) >> 23 |
+ (v & 0x007c0000) << 3 |
+ (v & 0x0003e000) << 3 |
+ (v & 0x00001000) >> 10 |
+ (v & 0x00000ffc) << 1;
+ *p = i;
+
+ return obj_reloc_ok;
+}
+
+
+struct obj_section *
+obj_hppa64_create_alloced_section (struct obj_file *f, const char *name,
+ unsigned long align, unsigned long size, unsigned long sh_flags)
+{
+ int newidx = f->header.e_shnum++;
+ struct obj_section *sec;
+
+ f->sections = xrealloc(f->sections, (newidx+1) * sizeof(sec));
+ f->sections[newidx] = sec = arch_new_section();
+
+ memset(sec, 0, sizeof(*sec));
+ sec->header.sh_type = SHT_PROGBITS;
+ sec->header.sh_flags = sh_flags;
+ sec->header.sh_size = size;
+ sec->header.sh_addralign = align;
+ sec->name = name;
+ sec->idx = newidx;
+ if (size)
+ sec->contents = xmalloc(size);
+
+ obj_insert_section_load_order(f, sec);
+
+ return sec;
+}
+
+/*======================================================================*/
+
+struct obj_file *
+arch_new_file (void)
+{
+ hppa64_file_t *f;
+ f = xmalloc(sizeof(*f));
+ f->got = NULL;
+ f->opd = NULL;
+ f->stub = NULL;
+ return &f->root;
+}
+
+struct obj_section *
+arch_new_section (void)
+{
+ return xmalloc(sizeof(struct obj_section));
+}
+
+struct obj_symbol *
+arch_new_symbol (void)
+{
+ hppa64_symbol_t *sym;
+ sym = xmalloc(sizeof(*sym));
+ sym->gotent = NULL;
+ sym->opdent = NULL;
+ sym->stubent = NULL;
+ return &sym->root;
+}
+
+/* This may not be needed, but does no harm (copied from ia64).
+ */
+
+int
+arch_load_proc_section(struct obj_section *sec, int fp)
+{
+ switch (sec->header.sh_type)
+ {
+ case SHT_PARISC_EXT :
+ sec->contents = NULL;
+ break;
+
+ case SHT_PARISC_UNWIND :
+ if (sec->header.sh_size > 0)
+ {
+ sec->contents = xmalloc(sec->header.sh_size);
+ gzf_lseek(fp, sec->header.sh_offset, SEEK_SET);
+ if (gzf_read(fp, sec->contents, sec->header.sh_size) != sec->header.sh_size)
+ {
+ error("error reading ELF section data: %m");
+ return -1;
+ }
+ }
+ else
+ sec->contents = NULL;
+ break;
+ default:
+ error("Unknown section header type: %08x", sec->header.sh_type);
+ return -1;
+ }
+ return 0;
+}
+
+int
+arch_create_got(struct obj_file *f)
+{
+ hppa64_file_t *hfile = (hppa64_file_t *)f;
+ int i;
+ int n;
+ int got_offset = 0;
+ int opd_offset = 64;
+ int stub_offset = 0;
+
+ n = hfile->root.header.e_shnum;
+ for (i = 0; i < n; ++i)
+ {
+ struct obj_section *relsec, *symsec, *strsec;
+ Elf64_Rela *rel, *relend;
+ Elf64_Sym *symtab;
+ const char *strtab;
+
+ relsec = hfile->root.sections[i];
+ if (relsec->header.sh_type != SHT_RELA)
+ continue;
+
+ symsec = hfile->root.sections[relsec->header.sh_link];
+ strsec = hfile->root.sections[symsec->header.sh_link];
+
+ rel = (Elf64_Rela *)relsec->contents;
+ relend = rel + (relsec->header.sh_size / sizeof(Elf64_Rela));
+ symtab = (Elf64_Sym *)symsec->contents;
+ strtab = (const char *)strsec->contents;
+
+ for (; rel < relend; ++rel)
+ {
+ int need_got = FALSE;
+ int need_opd = FALSE;
+ int need_stub = FALSE;
+
+ switch (ELF64_R_TYPE(rel->r_info))
+ {
+ default:
+ {
+ unsigned r_info = ELF64_R_TYPE(rel->r_info);
+ printf("r_info 0x%x not handled\n", r_info);
+ }
+ continue;
+ case R_PARISC_LTOFF14R:
+ case R_PARISC_LTOFF21L:
+ /* These are simple indirect references to symbols through the
+ * DLT. We need to create a DLT entry for any symbols which
+ * appears in a DLTIND relocation.
+ */
+ need_got = TRUE;
+ break;
+ case R_PARISC_PCREL22F:
+ /* These are function calls. Depending on their precise
+ * target we may need to make a stub for them. The stub
+ * uses the dlt, so we need to create dlt entries for
+ * these symbols too.
+ */
+ need_got = TRUE;
+ need_stub = TRUE;
+ break;
+ case R_PARISC_DIR64:
+ break;
+ case R_PARISC_FPTR64:
+ /* This is a simple OPD entry (only created for local symbols,
+ * see below).
+ */
+ need_opd = TRUE;
+ break;
+ }
+
+ if (need_got || need_opd || need_stub)
+ {
+ Elf64_Sym *extsym;
+ hppa64_symbol_t *isym;
+ const char *name;
+ int local;
+ unsigned long symndx;
+
+ symndx = ELF64_R_SYM(rel->r_info);
+ extsym = &symtab[symndx];
+ if (ELF64_ST_BIND(extsym->st_info) == STB_LOCAL)
+ {
+ isym = (hppa64_symbol_t *) f->local_symtab[symndx];
+ }
+ else
+ {
+ if (extsym->st_name)
+ name = strtab + extsym->st_name;
+ else
+ name = f->sections[extsym->st_shndx]->name;
+ isym = (hppa64_symbol_t *)obj_find_symbol(f, name);
+ }
+ local = isym->root.secidx <= SHN_HIRESERVE;
+
+ if (need_stub)
+ {
+ hppa64_stub_t *stub;
+
+ for (stub = isym->stubent; stub != NULL; stub = stub->next)
+ if (stub->addend == rel->r_addend)
+ break;
+ if (stub == NULL)
+ {
+ stub = (hppa64_stub_t *) xmalloc(sizeof(hppa64_stub_t));
+ stub->next = isym->stubent;
+ stub->addend = rel->r_addend;
+ stub->offset = stub_offset;
+ stub->reloc_done = FALSE;
+ isym->stubent = stub;
+ {
+ stub_offset += SIZEOF_STUB;
+ }
+ need_stub = FALSE;
+ }
+ }
+ if (need_got)
+ {
+ hppa64_got_t *got;
+
+ for (got = isym->gotent; got != NULL; got = got->next)
+ if (got->addend == rel->r_addend)
+ break;
+ if (got == NULL)
+ {
+ got = (hppa64_got_t *) xmalloc(sizeof(hppa64_got_t));
+ got->next = isym->gotent;
+ got->addend = rel->r_addend;
+ got->offset = got_offset;
+ got->reloc_done = FALSE;
+ isym->gotent = got;
+ got_offset += 8;
+ need_got = FALSE;
+ }
+ }
+ if (need_opd && local)
+ {
+ hppa64_opd_t *opd;
+
+ if (isym->opdent == NULL)
+ {
+ opd = (hppa64_opd_t *) xmalloc(sizeof(hppa64_opd_t));
+ opd->offset = opd_offset;
+ opd->reloc_done = FALSE;
+ isym->opdent = opd;
+ opd_offset += 32;
+ need_opd = FALSE;
+ }
+ }
+ }
+ }
+ }
+
+ hfile->got = obj_hppa64_create_alloced_section(f, ".got", 8, got_offset,
+ (SHF_ALLOC | SHF_WRITE | SHF_PARISC_SHORT));
+ assert(hfile->got != NULL);
+
+ hfile->opd = obj_hppa64_create_alloced_section(f, ".opd", 16, opd_offset,
+ (SHF_ALLOC | SHF_WRITE | SHF_PARISC_SHORT));
+ assert(hfile->opd != NULL);
+
+ if (stub_offset > 0)
+ {
+ hfile->stub = obj_hppa64_create_alloced_section(f, ".stub", 16,
+ stub_offset, (SHF_ALLOC | SHF_EXECINSTR | SHF_PARISC_SHORT));
+ assert(hfile->stub != NULL);
+ }
+
+ return 1;
+}
+
+
+/* This is a small simple version which seems to work fine. ia64 has
+ * a much more complex algorithm. We point dp at the end of the .got,
+ * which is the start of the .opd.
+ */
+
+int
+arch_finalize_section_address(struct obj_file *f, Elf64_Addr base)
+{
+ hppa64_file_t *hfile = (hppa64_file_t *)f;
+ int n = f->header.e_shnum;
+ int i;
+
+ f->baseaddr = base;
+ for (i = 0; i < n; ++i)
+ f->sections[i]->header.sh_addr += base;
+
+ /* Pick a sensible value for gp */
+ hfile->gp = hfile->got->header.sh_addr + hfile->got->header.sh_size;
+
+ return 1;
+}
+
+
+enum obj_reloc
+arch_apply_relocation(struct obj_file *f,
+ struct obj_section *targsec,
+ struct obj_section *symsec,
+ struct obj_symbol *sym,
+ Elf64_Rela *rel,
+ Elf64_Addr v)
+{
+ hppa64_file_t *hfile = (hppa64_file_t *) f;
+ hppa64_symbol_t *isym = (hppa64_symbol_t *) sym;
+
+ Elf64_Word *loc = (Elf64_Word *)(targsec->contents + rel->r_offset);
+ Elf64_Addr dot = (targsec->header.sh_addr + rel->r_offset) & ~0x03;
+
+ Elf64_Addr got = hfile->got->header.sh_addr;
+ Elf64_Addr gp = hfile->gp;
+
+ Elf64_Xword r_info = ELF64_R_TYPE(rel->r_info);
+
+ enum obj_reloc ret = obj_reloc_ok;
+
+ switch (r_info)
+ {
+ default:
+ ret = obj_reloc_unhandled;
+ break;
+ case R_PARISC_LTOFF14R:
+ case R_PARISC_LTOFF21L:
+ {
+ hppa64_got_t *ge;
+
+ assert(isym != NULL);
+ for (ge = isym->gotent; ge != NULL && ge->addend != rel->r_addend; )
+ ge = ge->next;
+ assert(ge != NULL);
+ if (!ge->reloc_done)
+ {
+ ge->reloc_done = TRUE;
+ *(Elf64_Addr *)(hfile->got->contents + ge->offset) = v;
+ }
+ v = got + ge->offset - gp;
+ if (r_info == R_PARISC_LTOFF14R)
+ ret = patch_14r(v, loc);
+ else
+ ret = patch_21l(v, loc);
+ }
+ break;
+ case R_PARISC_PCREL22F:
+ {
+ hppa64_got_t *ge;
+
+ assert(isym != NULL);
+ for (ge = isym->gotent; ge != NULL && ge->addend != rel->r_addend; )
+ ge = ge->next;
+ assert(ge != NULL);
+ if (!ge->reloc_done)
+ {
+ ge->reloc_done = TRUE;
+ *(Elf64_Addr *)(hfile->got->contents + ge->offset) = v;
+ }
+ if ((isym->root.secidx > SHN_HIRESERVE) ||
+ ((Elf64_Sxword) (v - dot - 8) > 0x800000-1) ||
+ ((Elf64_Sxword) (v - dot - 8) < -0x800000))
+ {
+ hppa64_stub_t *se;
+
+ for (se = isym->stubent; se != NULL && se->addend != rel->r_addend; )
+ se = se->next;
+ assert(se != NULL);
+ if (!se->reloc_done)
+ {
+ /* This requires that we can get from dp to the entry in +/- 8K,
+ * or +/- 1000 entries. patch_14r2() will check that.
+ * Only need these dlt entries for calls to external/far
+ * functions, so should probably put them in a seperate section
+ * before dlt and point dp at the section. Change to that
+ * scheme if we hit problems with big modules.
+ */
+ unsigned char *stub;
+
+ if (!strncmp(isym->root.name, "$$", 2))
+ stub = hppa64_stub_millicode;
+ else
+ stub = hppa64_stub_extern;
+ se->reloc_done = TRUE;
+ memcpy((Elf64_Addr *)(hfile->stub->contents + se->offset),
+ stub, SIZEOF_STUB);
+ v = (Elf64_Addr)(hfile->got->header.sh_addr + ge->offset) - gp;
+ ret = patch_14r2(v, (Elf64_Word *)(hfile->stub->contents + se->offset));
+ }
+ v = hfile->stub->header.sh_addr + se->offset;
+ }
+ v = v - dot - 8;
+ if (ret == obj_reloc_ok)
+ ret = patch_22f(v, loc);
+ }
+ break;
+ case R_PARISC_DIR64:
+ {
+ loc[0] = v >> 32;
+ loc[1] = v;
+ }
+ break;
+ case R_PARISC_FPTR64:
+ {
+ assert(isym != NULL);
+ if (isym->root.secidx <= SHN_HIRESERVE) /* local */
+ {
+ assert(isym->opdent != NULL);
+ if (!isym->opdent->reloc_done)
+ {
+ isym->opdent->reloc_done = TRUE;
+ *(Elf64_Addr *)(hfile->opd->contents + isym->opdent->offset + 16) = v;
+ *(Elf64_Addr *)(hfile->opd->contents + isym->opdent->offset + 24) = gp;
+ }
+ v = hfile->opd->header.sh_addr + isym->opdent->offset;
+ }
+ loc[0] = v >> 32;
+ loc[1] = v;
+ }
+ break;
+ }
+ return ret;
+}
+
+int
+arch_init_module (struct obj_file *f, struct module *mod)
+{
+ hppa64_file_t *hfile = (hppa64_file_t *)f;
+ Elf64_Addr *opd = (Elf64_Addr *)(hfile->opd->contents);
+
+ opd[0] = 0;
+ opd[1] = 0;
+ if ((opd[2] = mod->init) != 0)
+ {
+ opd[3] = hfile->gp;
+ mod->init = hfile->opd->header.sh_addr;
+ }
+
+ opd[4] = 0;
+ opd[5] = 0;
+ if ((opd[6] = mod->cleanup) != 0)
+ {
+ opd[7] = hfile->gp;
+ mod->cleanup = hfile->opd->header.sh_addr + 32;
+ }
+
+ return 1;
+}
+
+/* XXX Is this relevant to parisc? */
+
+int
+arch_archdata (struct obj_file *f, struct obj_section *archdata_sec)
+{
+ hppa64_file_t *hfile = (hppa64_file_t *)f;
+ struct archdata {
+ unsigned tgt_long unw_table;
+ unsigned tgt_long segment_base;
+ unsigned tgt_long unw_start;
+ unsigned tgt_long unw_end;
+ unsigned tgt_long gp;
+ } *ad;
+ int i;
+ struct obj_section *sec;
+
+ free(archdata_sec->contents);
+ archdata_sec->contents = xmalloc(sizeof(struct archdata));
+ memset(archdata_sec->contents, 0, sizeof(struct archdata));
+ archdata_sec->header.sh_size = sizeof(struct archdata);
+
+ ad = (struct archdata *)(archdata_sec->contents);
+ ad->gp = hfile->gp;
+ ad->unw_start = 0;
+ ad->unw_end = 0;
+ ad->unw_table = 0;
+ ad->segment_base = f->sections[1]->header.sh_addr;
+ for (i = 0; i < f->header.e_shnum; ++i)
+ {
+ sec = f->sections[i];
+ if (sec->header.sh_type == SHT_PARISC_UNWIND)
+ {
+ ad->unw_start = sec->header.sh_addr;
+ ad->unw_end = sec->header.sh_addr + sec->header.sh_size;
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/mdk-stage1/insmod-modutils/obj/obj_i386.c b/mdk-stage1/insmod-modutils/obj/obj_i386.c
new file mode 100644
index 000000000..28df3448c
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/obj/obj_i386.c
@@ -0,0 +1,245 @@
+/* i386 specific support for Elf loading and relocation.
+ Copyright 1996, 1997 Linux International.
+
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <string.h>
+#include <assert.h>
+
+#include <module.h>
+#include <obj.h>
+#include <util.h>
+
+
+/*======================================================================*/
+
+struct i386_got_entry
+{
+ int offset;
+ unsigned offset_done : 1;
+ unsigned reloc_done : 1;
+};
+
+struct i386_file
+{
+ struct obj_file root;
+ struct obj_section *got;
+};
+
+struct i386_symbol
+{
+ struct obj_symbol root;
+ struct i386_got_entry gotent;
+};
+
+
+/*======================================================================*/
+
+struct obj_file *
+arch_new_file (void)
+{
+ struct i386_file *f;
+ f = xmalloc(sizeof(*f));
+ f->got = NULL;
+ return &f->root;
+}
+
+struct obj_section *
+arch_new_section (void)
+{
+ return xmalloc(sizeof(struct obj_section));
+}
+
+struct obj_symbol *
+arch_new_symbol (void)
+{
+ struct i386_symbol *sym;
+ sym = xmalloc(sizeof(*sym));
+ memset(&sym->gotent, 0, sizeof(sym->gotent));
+ return &sym->root;
+}
+
+int
+arch_load_proc_section(struct obj_section *sec, int fp)
+{
+ /* Assume it's just a debugging section that we can safely
+ ignore ... */
+ sec->contents = NULL;
+
+ return 0;
+}
+
+enum obj_reloc
+arch_apply_relocation (struct obj_file *f,
+ struct obj_section *targsec,
+ struct obj_section *symsec,
+ struct obj_symbol *sym,
+ Elf32_Rel *rel,
+ Elf32_Addr v)
+{
+ struct i386_file *ifile = (struct i386_file *)f;
+ struct i386_symbol *isym = (struct i386_symbol *)sym;
+
+ Elf32_Addr *loc = (Elf32_Addr *)(targsec->contents + rel->r_offset);
+ Elf32_Addr dot = targsec->header.sh_addr + rel->r_offset;
+ Elf32_Addr got = ifile->got ? ifile->got->header.sh_addr : 0;
+
+ enum obj_reloc ret = obj_reloc_ok;
+
+ switch (ELF32_R_TYPE(rel->r_info))
+ {
+ case R_386_NONE:
+ break;
+
+ case R_386_32:
+ *loc += v;
+ break;
+
+ case R_386_PLT32:
+ case R_386_PC32:
+ *loc += v - dot;
+ break;
+
+ case R_386_GLOB_DAT:
+ case R_386_JMP_SLOT:
+ *loc = v;
+ break;
+
+ case R_386_RELATIVE:
+ *loc += f->baseaddr;
+ break;
+
+ case R_386_GOTPC:
+ assert(got != 0);
+ *loc += got - dot;
+ break;
+
+ case R_386_GOT32:
+ assert(isym != NULL);
+ if (!isym->gotent.reloc_done)
+ {
+ isym->gotent.reloc_done = 1;
+ *(Elf32_Addr *)(ifile->got->contents + isym->gotent.offset) = v;
+ }
+ *loc += isym->gotent.offset;
+ break;
+
+ case R_386_GOTOFF:
+ assert(got != 0);
+ *loc += v - got;
+ break;
+
+ default:
+ ret = obj_reloc_unhandled;
+ break;
+ }
+
+ return ret;
+}
+
+int
+arch_create_got (struct obj_file *f)
+{
+ struct i386_file *ifile = (struct i386_file *)f;
+ int i, n, offset = 0, gotneeded = 0;
+
+ n = ifile->root.header.e_shnum;
+ for (i = 0; i < n; ++i)
+ {
+ struct obj_section *relsec, *symsec, *strsec;
+ Elf32_Rel *rel, *relend;
+ Elf32_Sym *symtab;
+ const char *strtab;
+
+ relsec = ifile->root.sections[i];
+ if (relsec->header.sh_type != SHT_REL)
+ continue;
+
+ symsec = ifile->root.sections[relsec->header.sh_link];
+ strsec = ifile->root.sections[symsec->header.sh_link];
+
+ rel = (Elf32_Rel *)relsec->contents;
+ relend = rel + (relsec->header.sh_size / sizeof(Elf32_Rel));
+ symtab = (Elf32_Sym *)symsec->contents;
+ strtab = (const char *)strsec->contents;
+
+ for (; rel < relend; ++rel)
+ {
+ Elf32_Sym *extsym;
+ struct i386_symbol *intsym;
+ const char *name;
+
+ switch (ELF32_R_TYPE(rel->r_info))
+ {
+ case R_386_GOTPC:
+ case R_386_GOTOFF:
+ gotneeded = 1;
+ default:
+ continue;
+
+ case R_386_GOT32:
+ break;
+ }
+
+ extsym = &symtab[ELF32_R_SYM(rel->r_info)];
+ if (extsym->st_name)
+ name = strtab + extsym->st_name;
+ else
+ name = f->sections[extsym->st_shndx]->name;
+ intsym = (struct i386_symbol *)obj_find_symbol(&ifile->root, name);
+
+ if (!intsym->gotent.offset_done)
+ {
+ intsym->gotent.offset_done = 1;
+ intsym->gotent.offset = offset;
+ offset += 4;
+ }
+ }
+ }
+
+ if (offset > 0 || gotneeded)
+ ifile->got = obj_create_alloced_section(&ifile->root, ".got", 4, offset);
+
+ return 1;
+}
+
+int
+arch_init_module (struct obj_file *f, struct module *mod)
+{
+ return 1;
+}
+
+int
+arch_finalize_section_address(struct obj_file *f, Elf32_Addr base)
+{
+ int i, n = f->header.e_shnum;
+
+ f->baseaddr = base;
+ for (i = 0; i < n; ++i)
+ f->sections[i]->header.sh_addr += base;
+ return 1;
+}
+
+int
+arch_archdata (struct obj_file *fin, struct obj_section *sec)
+{
+ return 0;
+}
diff --git a/mdk-stage1/insmod-modutils/obj/obj_ia64.c b/mdk-stage1/insmod-modutils/obj/obj_ia64.c
new file mode 100644
index 000000000..4f92c5d27
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/obj/obj_ia64.c
@@ -0,0 +1,1065 @@
+/*
+ * ia64 specific support for Elf loading and relocation.
+ * Copyright 2000 Mike Stephens <mike.stephens@intel.com>
+ *
+ * This file is part of the Linux modutils.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ident "$Id$"
+
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include <module.h>
+#include <obj.h>
+#include <util.h>
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE ~FALSE
+#endif
+
+/*======================================================================*/
+
+typedef struct _ia64_opd_t
+{
+ int offset;
+ int reloc_done;
+} ia64_opd_t;
+
+typedef struct _ia64_plt_t
+{
+ struct _ia64_plt_t *next;
+ Elf64_Addr addend;
+ int text_offset;
+ int data_offset;
+ int reloc_done;
+} ia64_plt_t;
+
+typedef struct _ia64_got_t
+{
+ struct _ia64_got_t *next;
+ Elf64_Addr addend;
+ int offset;
+ int reloc_done;
+} ia64_got_t;
+
+typedef struct _ia64_symbol_t
+{
+ struct obj_symbol root;
+ ia64_got_t *gotent;
+ ia64_opd_t *opdent;
+ ia64_plt_t *pltent;
+} ia64_symbol_t;
+
+typedef struct _ia64_file_t
+{
+ struct obj_file root;
+ struct obj_section *got;
+ struct obj_section *opd;
+ struct obj_section *pltt;
+ struct obj_section *pltd;
+ Elf64_Addr gp;
+ Elf64_Addr text;
+ Elf64_Addr data;
+ Elf64_Addr bss;
+} ia64_file_t;
+
+/*
+ * aa=gp rel address of the function descriptor in the .IA_64.pltoff section
+ */
+unsigned char ia64_plt_local[] =
+{
+ 0x0b, 0x78, 0x00, 0x02, 0x00, 0x24, /* [MMI] addl r15=aa,gp;; */
+ 0x00, 0x41, 0x3c, 0x30, 0x28, 0xc0, /* ld8 r16=[r15],8 */
+ 0x01, 0x08, 0x00, 0x84, /* mov r14=gp;; */
+ 0x11, 0x08, 0x00, 0x1e, 0x18, 0x10, /* [MIB] ld8 gp=[r15] */
+ 0x60, 0x80, 0x04, 0x80, 0x03, 0x00, /* mov b6=r16 */
+ 0x60, 0x00, 0x80, 0x00 /* br.few b6;; */
+};
+
+unsigned char ia64_plt_extern[] =
+{
+ 0x0b, 0x80, 0x00, 0x02, 0x00, 0x24, /* [MMI] addl r16=aa,gp;; */
+ 0xf0, 0x00, 0x40, 0x30, 0x20, 0x00, /* ld8 r15=[r16] */
+ 0x00, 0x00, 0x04, 0x00, /* nop.i 0x0;; */
+ 0x0b, 0x80, 0x20, 0x1e, 0x18, 0x14, /* [MMI] ld8 r16=[r15],8;; */
+ 0x10, 0x00, 0x3c, 0x30, 0x20, 0xc0, /* ld8 gp=[r15] */
+ 0x00, 0x09, 0x00, 0x07, /* mov b6=r16;; */
+ 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, /* [MIB] nop.m 0x0 */
+ 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, /* nop.i 0x0 */
+ 0x60, 0x00, 0x80, 0x00 /* br.few b6;; */
+};
+
+/*======================================================================*/
+
+/*
+ * return the instruction at slot in bundle
+ */
+Elf64_Xword
+obj_ia64_ins_extract_from_bundle(Elf64_Addr *bundle, Elf64_Xword slot)
+{
+ switch (slot)
+ {
+ case 0 :
+ return (*bundle >> 5) & 0x1ffffffffff;
+
+ case 1 :
+ return (((*bundle >> 46) & 0x3ffff) |
+ (*(bundle + 1) << 18)) & 0x1ffffffffff;
+
+ case 2 :
+ return (*(bundle + 1) >> 23) & 0x1ffffffffff;
+
+ default:
+ }
+ return (-1);
+}
+
+/*
+ * insert a instruction at slot in bundle
+ */
+void
+obj_ia64_ins_insert_in_bundle(Elf64_Addr *bundle, Elf64_Xword slot, Elf64_Xword ins)
+{
+ Elf64_Xword i;
+ Elf64_Xword in = ins & 0x1ffffffffff;
+
+ switch (slot)
+ {
+ case 0 :
+ i = *bundle & 0xffffc0000000001f;
+ *bundle = i | (in << 5);
+ break;
+
+ case 1 :
+ i = *bundle & 0x00003fffffffffff;
+ *bundle = i | (in << 46);
+
+ ++bundle;
+ i = *bundle & 0xffffffffff800000;
+ *bundle = i | (in >> 18);
+ break;
+
+ case 2 :
+ ++bundle;
+ i = *bundle & 0x00000000007fffff;
+ *bundle = i | (in << 23);
+ break;
+ }
+}
+
+/*
+ * add a immediate 14 value to the instruction at slot in bundle
+ */
+enum obj_reloc
+obj_ia64_ins_imm14(Elf64_Xword v, Elf64_Addr *bundle, Elf64_Xword slot)
+{
+ Elf64_Xword ins;
+
+ ins = obj_ia64_ins_extract_from_bundle(bundle, slot);
+ ins &= 0xffffffee07f01fff;
+ ins |= ((v & 0x2000) << 23) | ((v & 0x1f80) << 20) | ((v & 0x007f) << 13);
+ obj_ia64_ins_insert_in_bundle(bundle, slot, ins);
+ if (((Elf64_Sxword) v > 8191) || ((Elf64_Sxword) v < -8192))
+ return obj_reloc_overflow;
+ return obj_reloc_ok;
+}
+
+/*
+ * add a immediate 22 value to the instruction at slot in bundle
+ */
+enum obj_reloc
+obj_ia64_ins_imm22(Elf64_Xword v, Elf64_Addr *bundle, Elf64_Xword slot)
+{
+ Elf64_Xword ins;
+
+ ins = obj_ia64_ins_extract_from_bundle(bundle, slot);
+ ins &= 0xffffffe000301fff;
+ ins |= ((v & 0x200000) << 15) | ((v & 0x1f0000) << 6) |
+ ((v & 0x00ff80) << 20) | ((v & 0x00007f) << 13);
+ obj_ia64_ins_insert_in_bundle(bundle, slot, ins);
+ if (((Elf64_Sxword) v > 2097151) || ((Elf64_Sxword) v < -2097152))
+ return obj_reloc_overflow;
+ return obj_reloc_ok;
+}
+
+/*
+ * add a immediate 21 value (form 1) to the instruction at slot in bundle
+ */
+enum obj_reloc
+obj_ia64_ins_pcrel21b(Elf64_Xword v, Elf64_Addr *bundle, Elf64_Xword slot)
+{
+ Elf64_Xword ins;
+
+ ins = obj_ia64_ins_extract_from_bundle(bundle, slot);
+ ins &= 0xffffffee00001fff;
+ ins |= ((v & 0x1000000) << 12) | ((v & 0x0fffff0) << 9);
+ obj_ia64_ins_insert_in_bundle(bundle, slot, ins);
+ return obj_reloc_ok;
+}
+
+/*
+ * add a immediate 21 value (form 2) to the instruction at slot in bundle
+ */
+enum obj_reloc
+obj_ia64_ins_pcrel21m(Elf64_Xword v, Elf64_Addr *bundle, Elf64_Xword slot)
+{
+ Elf64_Xword ins;
+
+ ins = obj_ia64_ins_extract_from_bundle(bundle, slot);
+ ins &= 0xffffffee000fe03f;
+ ins |= ((v & 0x1000000) << 12) | ((v & 0x0fff800) << 9) |
+ ((v & 0x00007f0) << 2);
+ obj_ia64_ins_insert_in_bundle(bundle, slot, ins);
+ return obj_reloc_ok;
+}
+
+/*
+ * add a immediate 21 value (form 3) to the instruction at slot in bundle
+ */
+enum obj_reloc
+obj_ia64_ins_pcrel21f(Elf64_Xword v, Elf64_Addr *bundle, Elf64_Xword slot)
+{
+ Elf64_Xword ins;
+
+ ins = obj_ia64_ins_extract_from_bundle(bundle, slot);
+ ins &= 0xffffffeffc00003f;
+ ins |= ((v & 0x1000000) << 12) | ((v & 0x0fffff0) << 2);
+ obj_ia64_ins_insert_in_bundle(bundle, slot, ins);
+ return obj_reloc_ok;
+}
+
+/*
+ * add a immediate 64 value to the instruction at slot in bundle
+ */
+enum obj_reloc
+obj_ia64_ins_imm64(Elf64_Xword v, Elf64_Addr *bundle, Elf64_Xword slot)
+{
+ Elf64_Xword ins;
+
+ assert(slot == 1);
+ ins = obj_ia64_ins_extract_from_bundle(bundle, slot);
+ ins &= 0xffffffee000101ff;
+ ins |= ((v & 0x8000000000000000) >> 28) | ((v & 0x0000000000200000)) |
+ ((v & 0x00000000001f0000) << 6) | ((v & 0x000000000000ff80) << 20) |
+ ((v & 0x000000000000007f) << 13);
+ obj_ia64_ins_insert_in_bundle(bundle, slot, ins);
+ obj_ia64_ins_insert_in_bundle(bundle, ++slot, ((v & 0x7fffffffffc00000) >> 22));
+ return obj_reloc_ok;
+}
+
+/*
+ * create a plt entry
+ */
+enum obj_reloc
+obj_ia64_generate_plt(Elf64_Addr v,
+ Elf64_Addr gp,
+ ia64_file_t *ifile,
+ ia64_symbol_t *isym,
+ ia64_plt_t *pltent)
+{
+ *(Elf64_Addr *)(ifile->pltd->contents + pltent->data_offset) = v;
+ if (isym->root.secidx <= SHN_HIRESERVE)
+ {
+ /* local entry */
+ *(Elf64_Addr *)(ifile->pltd->contents + pltent->data_offset + 8) = gp;
+ memcpy((Elf64_Addr *)(ifile->pltt->contents + pltent->text_offset),
+ ia64_plt_local, sizeof(ia64_plt_local));
+ }
+ else
+ {
+ /* external entry */
+ memcpy((Elf64_Addr *)(ifile->pltt->contents + pltent->text_offset),
+ ia64_plt_extern, sizeof(ia64_plt_extern));
+ }
+ return obj_ia64_ins_imm22(
+ (ifile->pltd->header.sh_addr + pltent->data_offset - gp),
+ (Elf64_Addr *)(ifile->pltt->contents + pltent->text_offset), 0);
+}
+
+struct obj_section *
+obj_ia64_create_alloced_section (struct obj_file *f, const char *name,
+ unsigned long align, unsigned long size, unsigned long sh_flags)
+{
+ int newidx = f->header.e_shnum++;
+ struct obj_section *sec;
+
+ f->sections = xrealloc(f->sections, (newidx+1) * sizeof(sec));
+ f->sections[newidx] = sec = arch_new_section();
+
+ memset(sec, 0, sizeof(*sec));
+ sec->header.sh_type = SHT_PROGBITS;
+ sec->header.sh_flags = sh_flags;
+ sec->header.sh_size = size;
+ sec->header.sh_addralign = align;
+ sec->name = name;
+ sec->idx = newidx;
+ if (size)
+ sec->contents = xmalloc(size);
+
+ obj_insert_section_load_order(f, sec);
+
+ return sec;
+}
+
+/*======================================================================*/
+
+struct obj_file *
+arch_new_file (void)
+{
+ ia64_file_t *f;
+ f = xmalloc(sizeof(*f));
+ f->got = NULL;
+ f->opd = NULL;
+ f->pltt = NULL;
+ f->pltd = NULL;
+ return &f->root;
+}
+
+struct obj_section *
+arch_new_section (void)
+{
+ return xmalloc(sizeof(struct obj_section));
+}
+
+struct obj_symbol *
+arch_new_symbol (void)
+{
+ ia64_symbol_t *sym;
+ sym = xmalloc(sizeof(*sym));
+ sym->gotent = NULL;
+ sym->opdent = NULL;
+ sym->pltent = NULL;
+ return &sym->root;
+}
+
+int
+arch_load_proc_section(struct obj_section *sec, int fp)
+{
+ switch (sec->header.sh_type)
+ {
+ case SHT_IA_64_EXT :
+ sec->contents = NULL;
+ break;
+
+ case SHT_IA_64_UNWIND :
+ if (sec->header.sh_size > 0)
+ {
+ sec->contents = xmalloc(sec->header.sh_size);
+ gzf_lseek(fp, sec->header.sh_offset, SEEK_SET);
+ if (gzf_read(fp, sec->contents, sec->header.sh_size) != sec->header.sh_size)
+ {
+ error("error reading ELF section data: %m");
+ return -1;
+ }
+ }
+ else
+ sec->contents = NULL;
+ break;
+
+ default:
+ error("Unknown section header type: %08x", sec->header.sh_type);
+ return -1;
+ }
+ return 0;
+}
+
+int
+arch_create_got(struct obj_file *f)
+{
+ ia64_file_t *ifile = (ia64_file_t *)f;
+ int i;
+ int n;
+ int got_offset = 0;
+ int opd_offset = 32;
+ int plt_text_offset = 0;
+ int plt_data_offset = 0;
+
+ n = ifile->root.header.e_shnum;
+ for (i = 0; i < n; ++i)
+ {
+ struct obj_section *relsec, *symsec, *strsec;
+ Elf64_Rela *rel, *relend;
+ Elf64_Sym *symtab;
+ const char *strtab;
+
+ relsec = ifile->root.sections[i];
+ if (relsec->header.sh_type != SHT_RELA)
+ continue;
+
+ symsec = ifile->root.sections[relsec->header.sh_link];
+ strsec = ifile->root.sections[symsec->header.sh_link];
+
+ rel = (Elf64_Rela *)relsec->contents;
+ relend = rel + (relsec->header.sh_size / sizeof(Elf64_Rela));
+ symtab = (Elf64_Sym *)symsec->contents;
+ strtab = (const char *)strsec->contents;
+
+ for (; rel < relend; ++rel)
+ {
+ int need_got = FALSE;
+ int need_opd = FALSE;
+ int need_plt = FALSE;
+
+ switch (ELF64_R_TYPE(rel->r_info))
+ {
+ default:
+ continue;
+
+ case R_IA64_FPTR64I : /* @fptr(sym + add), mov imm64 */
+ case R_IA64_FPTR32LSB : /* @fptr(sym + add), data4 LSB */
+ case R_IA64_FPTR64LSB : /* @fptr(sym + add), data8 LSB */
+ need_opd = TRUE;
+ break;
+
+ case R_IA64_LTOFF22 : /* @ltoff(sym + add), add imm22 */
+ case R_IA64_LTOFF22X :
+ case R_IA64_LTOFF64I : /* @ltoff(sym + add), mov imm64 */
+ need_got = TRUE;
+ break;
+
+ case R_IA64_LTOFF_FPTR22 : /* @ltoff(@fptr(s+a)), imm22 */
+ case R_IA64_LTOFF_FPTR64I : /* @ltoff(@fptr(s+a)), imm64 */
+ case R_IA64_LTOFF_FPTR32LSB :
+ case R_IA64_LTOFF_FPTR64LSB :
+ need_got = TRUE;
+ need_opd = TRUE;
+ break;
+
+ case R_IA64_PLTOFF22 : /* @pltoff(sym + add), add imm22 */
+ case R_IA64_PLTOFF64I : /* @pltoff(sym + add), mov imm64 */
+ case R_IA64_PLTOFF64LSB : /* @pltoff(sym + add), data8 LSB */
+
+ case R_IA64_PCREL21B : /* @pcrel(sym + add), ptb, call */
+ case R_IA64_PCREL21M : /* @pcrel(sym + add), chk.s */
+ case R_IA64_PCREL21F : /* @pcrel(sym + add), fchkf */
+ need_plt = TRUE;
+ break;
+ }
+
+ if (need_got || need_opd || need_plt)
+ {
+ Elf64_Sym *extsym;
+ ia64_symbol_t *isym;
+ const char *name;
+ int local;
+ unsigned long symndx;
+
+ symndx = ELF64_R_SYM(rel->r_info);
+ extsym = &symtab[symndx];
+ if (ELF64_ST_BIND(extsym->st_info) == STB_LOCAL)
+ {
+ isym = (ia64_symbol_t *) f->local_symtab[symndx];
+ }
+ else
+ {
+ if (extsym->st_name)
+ name = strtab + extsym->st_name;
+ else
+ name = f->sections[extsym->st_shndx]->name;
+ isym = (ia64_symbol_t *)obj_find_symbol(f, name);
+ }
+ local = isym->root.secidx <= SHN_HIRESERVE;
+
+ if (need_plt)
+ {
+ ia64_plt_t *plt;
+
+ for (plt = isym->pltent; plt != NULL; plt = plt->next)
+ if (plt->addend == rel->r_addend)
+ break;
+ if (plt == NULL)
+ {
+ plt = (ia64_plt_t *) xmalloc(sizeof(ia64_plt_t));
+ plt->next = isym->pltent;
+ plt->addend = rel->r_addend;
+ plt->text_offset = plt_text_offset;
+ plt->data_offset = plt_data_offset;
+ plt->reloc_done = FALSE;
+ isym->pltent = plt;
+ if (local)
+ {
+ plt_text_offset += sizeof(ia64_plt_local);
+ plt_data_offset += 16;
+ }
+ else
+ {
+ plt_text_offset += sizeof(ia64_plt_extern);
+ plt_data_offset += 8;
+ }
+ need_plt = FALSE;
+ }
+ }
+ if (need_got)
+ {
+ ia64_got_t *got;
+
+ for (got = isym->gotent; got != NULL; got = got->next)
+ if (got->addend == rel->r_addend)
+ break;
+ if (got == NULL)
+ {
+ got = (ia64_got_t *) xmalloc(sizeof(ia64_got_t));
+ got->next = isym->gotent;
+ got->addend = rel->r_addend;
+ got->offset = got_offset;
+ got->reloc_done = FALSE;
+ isym->gotent = got;
+ got_offset += 8;
+ need_got = FALSE;
+ }
+ }
+ if (need_opd && local)
+ {
+ ia64_opd_t *opd;
+
+ if (isym->opdent == NULL)
+ {
+ opd = (ia64_opd_t *) xmalloc(sizeof(ia64_opd_t));
+ opd->offset = opd_offset;
+ opd->reloc_done = FALSE;
+ isym->opdent = opd;
+ opd_offset += 16;
+ need_opd = FALSE;
+ }
+ }
+ }
+ }
+ }
+
+ ifile->got = obj_ia64_create_alloced_section(f, ".got", 8, got_offset,
+ (SHF_ALLOC | SHF_WRITE | SHF_IA_64_SHORT));
+ assert(ifile->got != NULL);
+
+ ifile->opd = obj_ia64_create_alloced_section(f, ".opd", 16, opd_offset,
+ (SHF_ALLOC | SHF_WRITE | SHF_IA_64_SHORT));
+ assert(ifile->opd != NULL);
+
+ if (plt_text_offset > 0)
+ {
+ ifile->pltt = obj_ia64_create_alloced_section(f, ".plt", 16,
+ plt_text_offset, (SHF_ALLOC | SHF_EXECINSTR | SHF_IA_64_SHORT));
+ ifile->pltd = obj_ia64_create_alloced_section(f, ".IA_64.pltoff",
+ 16, plt_data_offset, (SHF_ALLOC | SHF_WRITE | SHF_IA_64_SHORT));
+ assert(ifile->pltt != NULL);
+ assert(ifile->pltd != NULL);
+ }
+
+ return 1;
+}
+
+int
+arch_finalize_section_address(struct obj_file *f, Elf64_Addr base)
+{
+ ia64_file_t *ifile = (ia64_file_t *)f;
+ Elf64_Addr min_addr = (Elf64_Addr) -1;
+ Elf64_Addr max_addr = 0;
+ Elf64_Addr min_short_addr = (Elf64_Addr) -1;
+ Elf64_Addr max_short_addr = 0;
+ Elf64_Addr gp;
+ Elf64_Addr text = (Elf64_Addr) -1;
+ Elf64_Addr data = (Elf64_Addr) -1;
+ Elf64_Addr bss = (Elf64_Addr) -1;
+ int n = f->header.e_shnum;
+ int i;
+
+ /*
+ * Finalize the addresses of the sections, find the min and max
+ * address of all sections marked short, and collect min and max
+ * address of any type, for use in selecting a nice gp.
+ *
+ * The algorithm used for selecting set the GP value was taken from
+ * the ld/bfd code contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+ */
+ f->baseaddr = base;
+ for (i = 0; i < n; ++i)
+ {
+ Elf64_Shdr *header = &f->sections[i]->header;
+ Elf64_Addr lo;
+ Elf64_Addr hi;
+
+ header->sh_addr += base;
+ if (header->sh_flags & SHF_ALLOC)
+ {
+ lo = header->sh_addr;
+ hi = header->sh_addr + header->sh_size;
+ if (hi < lo)
+ hi = (Elf64_Addr) -1;
+
+ if (min_addr > lo)
+ min_addr = lo;
+ if (max_addr < hi)
+ max_addr = hi;
+ if (header->sh_flags & SHF_IA_64_SHORT)
+ {
+ if (min_short_addr > lo)
+ min_short_addr = lo;
+ if (max_short_addr < hi)
+ max_short_addr = hi;
+ }
+ if ((header->sh_type & SHT_NOBITS) && (lo < bss))
+ bss = lo;
+ else if ((header->sh_flags & SHF_EXECINSTR) && (lo < text))
+ text = lo;
+ else if (lo < data)
+ data = lo;
+ }
+ }
+ /* Pick a sensible value for gp */
+
+ /* Start with just the address of the .got */
+ gp = ifile->got->header.sh_addr;
+
+ /*
+ * If it is possible to address the entire image, but we
+ * don't with the choice above, adjust.
+ */
+ if ((max_addr - min_addr < 0x400000) && (max_addr - gp <= 0x200000) &&
+ (gp - min_addr > 0x200000))
+ {
+ gp = min_addr + 0x200000;
+ }
+ else if (max_short_addr != 0)
+ {
+ /* If we don't cover all the short data, adjust */
+ if (max_short_addr - gp >= 0x200000)
+ gp = min_short_addr + 0x200000;
+
+ /* If we're addressing stuff past the end, adjust back */
+ if (gp > max_addr)
+ gp = max_addr - 0x200000 + 8;
+ }
+
+ /*
+ * Validate whether all SHF_IA_64_SHORT sections are within
+ * range of the chosen GP.
+ */
+ if (max_short_addr != 0)
+ {
+ if (max_short_addr - min_short_addr >= 0x400000)
+ {
+ error("short data segment overflowed (0x%lx >= 0x400000)",
+ (unsigned long)(max_short_addr - min_short_addr));
+ return 0;
+ }
+ else if (((gp > min_short_addr) && (gp - min_short_addr > 0x200000)) ||
+ ((gp < max_short_addr) && (max_short_addr - gp >= 0x200000)))
+ {
+ error("GP does not cover short data segment");
+ return 0;
+ }
+ }
+ ifile->gp = gp;
+ ifile->text = text;
+ ifile->data = data;
+ ifile->bss = bss;
+ return 1;
+}
+
+/* Targets can be unaligned, use memcpy instead of assignment */
+#define COPY_64LSB(loc, v) \
+ do { \
+ Elf64_Xword reloc = (v); \
+ memcpy((void *)(loc), &reloc, 8); \
+ } while(0)
+#define COPY_32LSB(loc, v) \
+ do { \
+ Elf32_Xword reloc = (v); \
+ memcpy((void *)(loc), &reloc, 4); \
+ if ((v) != reloc) \
+ ret = obj_reloc_overflow; \
+ } while(0)
+
+enum obj_reloc
+arch_apply_relocation(struct obj_file *f,
+ struct obj_section *targsec,
+ struct obj_section *symsec,
+ struct obj_symbol *sym,
+ Elf64_Rela *rel,
+ Elf64_Addr v)
+{
+ ia64_file_t *ifile = (ia64_file_t *) f;
+ ia64_symbol_t *isym = (ia64_symbol_t *) sym;
+
+ Elf64_Addr loc = (Elf64_Addr)(targsec->contents + rel->r_offset);
+ Elf64_Addr dot = (targsec->header.sh_addr + rel->r_offset) & ~0x03;
+
+ Elf64_Addr got = ifile->got->header.sh_addr;
+ Elf64_Addr gp = ifile->gp;
+
+ Elf64_Addr *bundle = (Elf64_Addr *)(loc & ~0x03);
+ Elf64_Xword slot = loc & 0x03;
+
+ Elf64_Xword r_info = ELF64_R_TYPE(rel->r_info);
+
+ enum obj_reloc ret = obj_reloc_ok;
+
+ /* We cannot load modules compiled with -mconstant-gp */
+#ifndef EF_IA_64_CONS_GP
+#define EF_IA_64_CONS_GP 0x00000040
+#endif
+#ifndef EF_IA_64_NOFUNCDESC_CONS_GP
+#define EF_IA_64_NOFUNCDESC_CONS_GP 0x00000080
+#endif
+ if (f->header.e_flags & (EF_IA_64_CONS_GP | EF_IA_64_NOFUNCDESC_CONS_GP))
+ return obj_reloc_constant_gp;
+
+ switch (r_info)
+ {
+ case R_IA64_NONE : /* none */
+ case R_IA64_LDXMOV : /* Use of LTOFF22X. */
+ break;
+
+ case R_IA64_IMM14 : /* symbol + addend, add imm14 */
+ ret = obj_ia64_ins_imm14(v, bundle, slot);
+ break;
+
+ case R_IA64_IMM22 : /* symbol + addend, add imm22 */
+ ret = obj_ia64_ins_imm22(v, bundle, slot);
+ break;
+
+ case R_IA64_IMM64 : /* symbol + addend, movl imm64 */
+ ret = obj_ia64_ins_imm64(v, bundle, slot);
+ break;
+
+ case R_IA64_DIR32LSB : /* symbol + addend, data4 LSB */
+ COPY_32LSB(loc, v);
+ break;
+
+ case R_IA64_DIR64LSB : /* symbol + addend, data8 LSB */
+ COPY_64LSB(loc, v);
+ break;
+
+ case R_IA64_GPREL22 : /* @gprel(sym + add), add imm22 */
+ v -= gp;
+ ret = obj_ia64_ins_imm22(v, bundle, slot);
+ break;
+
+ case R_IA64_GPREL64I : /* @gprel(sym + add), mov imm64 */
+ v -= gp;
+ ret = obj_ia64_ins_imm64(v, bundle, slot);
+ break;
+
+ case R_IA64_GPREL32LSB : /* @gprel(sym + add), data4 LSB */
+ COPY_32LSB(loc, v-gp);
+ break;
+
+ case R_IA64_GPREL64LSB : /* @gprel(sym + add), data8 LSB */
+ COPY_64LSB(loc, v-gp);
+ break;
+
+ case R_IA64_LTOFF22 : /* @ltoff(sym + add), add imm22 */
+ case R_IA64_LTOFF22X : /* LTOFF22, relaxable. */
+ case R_IA64_LTOFF64I : /* @ltoff(sym + add), mov imm64 */
+ {
+ ia64_got_t *ge;
+
+ assert(isym != NULL);
+ for (ge = isym->gotent; ge != NULL && ge->addend != rel->r_addend; )
+ ge = ge->next;
+ assert(ge != NULL);
+ if (!ge->reloc_done)
+ {
+ ge->reloc_done = TRUE;
+ *(Elf64_Addr *)(ifile->got->contents + ge->offset) = v;
+ }
+ v = got + ge->offset - gp;
+ if (r_info == R_IA64_LTOFF64I)
+ ret = obj_ia64_ins_imm64(v, bundle, slot);
+ else
+ ret = obj_ia64_ins_imm22(v, bundle, slot);
+ }
+ break;
+
+ case R_IA64_PLTOFF22 : /* @pltoff(sym + add), add imm22 */
+ case R_IA64_PLTOFF64I : /* @pltoff(sym + add), mov imm64 */
+ case R_IA64_PLTOFF64LSB : /* @pltoff(sym + add), data8 LSB */
+ {
+ ia64_plt_t *pe;
+
+ assert(isym != NULL);
+ for (pe = isym->pltent; pe != NULL && pe->addend != rel->r_addend; )
+ pe = pe->next;
+ assert(pe != NULL);
+ if (!pe->reloc_done)
+ {
+ pe->reloc_done = TRUE;
+ ret = obj_ia64_generate_plt(v, gp, ifile, isym, pe);
+ }
+ v = ifile->pltt->header.sh_addr + pe->text_offset - gp;
+ switch (r_info)
+ {
+ case R_IA64_PLTOFF22 :
+ ret = obj_ia64_ins_imm22(v, bundle, slot);
+ break;
+
+ case R_IA64_PLTOFF64I :
+ ret = obj_ia64_ins_imm64(v, bundle, slot);
+ break;
+
+ case R_IA64_PLTOFF64LSB :
+ COPY_64LSB(loc, v);
+ break;
+ }
+ }
+ break;
+
+ case R_IA64_FPTR64I : /* @fptr(sym + add), mov imm64 */
+ case R_IA64_FPTR32LSB : /* @fptr(sym + add), data4 LSB */
+ case R_IA64_FPTR64LSB : /* @fptr(sym + add), data8 LSB */
+ assert(isym != NULL);
+ if (isym->root.secidx <= SHN_HIRESERVE)
+ {
+ assert(isym->opdent != NULL);
+ if (!isym->opdent->reloc_done)
+ {
+ isym->opdent->reloc_done = TRUE;
+ *(Elf64_Addr *)(ifile->opd->contents + isym->opdent->offset) = v;
+ *(Elf64_Addr *)(ifile->opd->contents + isym->opdent->offset + 8) = gp;
+ }
+ v = ifile->opd->header.sh_addr + isym->opdent->offset;
+ }
+ switch (r_info)
+ {
+ case R_IA64_FPTR64I :
+ ret = obj_ia64_ins_imm64(v, bundle, slot);
+ break;
+
+ case R_IA64_FPTR32LSB :
+ COPY_32LSB(loc, v);
+ break;
+
+ case R_IA64_FPTR64LSB : /* @fptr(sym + add), data8 LSB */
+ /* Target can be unaligned */
+ COPY_64LSB(loc, v);
+ break;
+ }
+ break;
+
+ case R_IA64_PCREL21B : /* @pcrel(sym + add), ptb, call */
+ case R_IA64_PCREL21M : /* @pcrel(sym + add), chk.s */
+ case R_IA64_PCREL21F : /* @pcrel(sym + add), fchkf */
+ assert(isym != NULL);
+ if ((isym->root.secidx > SHN_HIRESERVE) ||
+ ((Elf64_Sxword) (v - dot) > 16777215) ||
+ ((Elf64_Sxword) (v - dot) < -16777216))
+ {
+ ia64_plt_t *pe;
+
+ for (pe = isym->pltent; pe != NULL && pe->addend != rel->r_addend; )
+ pe = pe->next;
+ assert(pe != NULL);
+ if (!pe->reloc_done)
+ {
+ pe->reloc_done = TRUE;
+ ret = obj_ia64_generate_plt(v, gp, ifile, isym, pe);
+ }
+ v = ifile->pltt->header.sh_addr + pe->text_offset;
+ }
+ v -= dot;
+ switch (r_info)
+ {
+ case R_IA64_PCREL21B :
+ ret = obj_ia64_ins_pcrel21b(v, bundle, slot);
+ break;
+
+ case R_IA64_PCREL21M :
+ ret = obj_ia64_ins_pcrel21m(v, bundle, slot);
+ break;
+
+ case R_IA64_PCREL21F :
+ ret = obj_ia64_ins_pcrel21f(v, bundle, slot);
+ break;
+ }
+ break;
+
+ case R_IA64_PCREL32LSB : /* @pcrel(sym + add), data4 LSB */
+ COPY_32LSB(loc, v-dot);
+ break;
+
+ case R_IA64_PCREL64LSB : /* @pcrel(sym + add), data8 LSB */
+ COPY_64LSB(loc, v-dot);
+ break;
+
+ case R_IA64_LTOFF_FPTR22 : /* @ltoff(@fptr(s+a)), imm22 */
+ case R_IA64_LTOFF_FPTR64I : /* @ltoff(@fptr(s+a)), imm64 */
+ case R_IA64_LTOFF_FPTR32LSB : /* @ltoff(@fptr(s+a)), data4 */
+ case R_IA64_LTOFF_FPTR64LSB : /* @ltoff(@fptr(s+a)), data8 */
+ {
+ ia64_got_t *ge;
+
+ assert(isym != NULL);
+ if (isym->root.secidx <= SHN_HIRESERVE)
+ {
+ assert(isym->opdent != NULL);
+ if (!isym->opdent->reloc_done)
+ {
+ isym->opdent->reloc_done = TRUE;
+ *(Elf64_Addr *)(ifile->opd->contents + isym->opdent->offset) = v;
+ *(Elf64_Addr *)(ifile->opd->contents + isym->opdent->offset + 8) = gp;
+ }
+ v = ifile->opd->header.sh_addr + isym->opdent->offset;
+ }
+ for (ge = isym->gotent; ge != NULL && ge->addend != rel->r_addend; )
+ ge = ge->next;
+ assert(ge != NULL);
+ if (!ge->reloc_done)
+ {
+ ge->reloc_done = TRUE;
+ *(Elf64_Addr *)(ifile->got->contents + ge->offset) = v;
+ }
+ v = got + ge->offset - gp;
+ switch (r_info)
+ {
+ case R_IA64_LTOFF_FPTR22 :
+ ret = obj_ia64_ins_imm22(v, bundle, slot);
+ break;
+
+ case R_IA64_LTOFF_FPTR64I :
+ ret = obj_ia64_ins_imm64(v, bundle, slot);
+ break;
+
+ case R_IA64_LTOFF_FPTR32LSB :
+ COPY_32LSB(loc, v);
+ break;
+
+ case R_IA64_LTOFF_FPTR64LSB :
+ COPY_64LSB(loc, v);
+ break;
+ }
+ }
+ break;
+
+ case R_IA64_SEGREL32LSB : /* @segrel(sym + add), data4 LSB */
+ case R_IA64_SEGREL64LSB : /* @segrel(sym + add), data8 LSB */
+ if (targsec->header.sh_type & SHT_NOBITS)
+ v = ifile->bss - v;
+ else if (targsec->header.sh_flags & SHF_EXECINSTR)
+ v = ifile->text - v;
+ else
+ v = ifile->data - v;
+ if (r_info == R_IA64_SEGREL32LSB)
+ COPY_32LSB(loc, v);
+ else
+ COPY_64LSB(loc, v);
+ break;
+
+ case R_IA64_SECREL32LSB : /* @secrel(sym + add), data4 LSB */
+ COPY_32LSB(loc, targsec->header.sh_addr - v);
+ break;
+
+ case R_IA64_SECREL64LSB : /* @secrel(sym + add), data8 LSB */
+ COPY_64LSB(loc, targsec->header.sh_addr - v);
+ break;
+
+ /*
+ * We don't handle the big-endian relocates
+ *
+ * R_IA64_DIR32MSB symbol + addend, data4 MSB
+ * R_IA64_DIR64MSB symbol + addend, data8 MSB
+ * R_IA64_GPREL32MSB @gprel(sym + add), data4 MSB
+ * R_IA64_GPREL64MSB @gprel(sym + add), data8 MSB
+ * R_IA64_PLTOFF64MSB @pltoff(sym + add), data8 MSB
+ * R_IA64_FPTR32MSB @fptr(sym + add), data4 MSB
+ * R_IA64_FPTR64MSB @fptr(sym + add), data8 MSB
+ * R_IA64_PCREL32MSB @pcrel(sym + add), data4 MSB
+ * R_IA64_PCREL64MSB @pcrel(sym + add), data8 MSB
+ * R_IA64_SEGREL32MSB @segrel(sym + add), data4 MSB
+ * R_IA64_SEGREL64MSB @segrel(sym + add), data8 MSB
+ * R_IA64_SECREL32MSB @secrel(sym + add), data4 MSB
+ * R_IA64_SECREL64MSB @secrel(sym + add), data8 MSB
+ * R_IA64_REL32MSB data 4 + REL
+ * R_IA64_REL64MSB data 8 + REL
+ * R_IA64_LTV32MSB symbol + addend, data4 MSB
+ * R_IA64_LTV64MSB symbol + addend, data8 MSB
+ * R_IA64_IPLTMSB dynamic reloc, imported PLT, MSB
+ */
+ default:
+ case R_IA64_REL32LSB : /* data 4 + REL */
+ case R_IA64_REL64LSB : /* data 8 + REL */
+ case R_IA64_LTV32LSB : /* symbol + addend, data4 LSB */
+ case R_IA64_LTV64LSB : /* symbol + addend, data8 LSB */
+ case R_IA64_IPLTLSB : /* dynamic reloc, imported PLT, LSB */
+ ret = obj_reloc_unhandled;
+ break;
+ }
+ return ret;
+}
+
+int
+arch_init_module (struct obj_file *f, struct module *mod)
+{
+ ia64_file_t *ifile = (ia64_file_t *)f;
+ Elf64_Addr *opd = (Elf64_Addr *)(ifile->opd->contents);
+
+ if ((opd[0] = mod->init) != 0)
+ {
+ opd[1] = ifile->gp;
+ mod->init = ifile->opd->header.sh_addr;
+ }
+
+ if ((opd[2] = mod->cleanup) != 0)
+ {
+ opd[3] = ifile->gp;
+ mod->cleanup = ifile->opd->header.sh_addr + 16;
+ }
+
+ return 1;
+}
+
+int
+arch_archdata (struct obj_file *f, struct obj_section *archdata_sec)
+{
+ ia64_file_t *ifile = (ia64_file_t *)f;
+ struct archdata {
+ unsigned tgt_long unw_table;
+ unsigned tgt_long segment_base;
+ unsigned tgt_long unw_start;
+ unsigned tgt_long unw_end;
+ unsigned tgt_long gp;
+ } *ad;
+ int i;
+ struct obj_section *sec;
+
+ free(archdata_sec->contents);
+ archdata_sec->contents = xmalloc(sizeof(struct archdata));
+ memset(archdata_sec->contents, 0, sizeof(struct archdata));
+ archdata_sec->header.sh_size = sizeof(struct archdata);
+
+ ad = (struct archdata *)(archdata_sec->contents);
+ ad->gp = ifile->gp;
+ ad->unw_start = 0;
+ ad->unw_end = 0;
+ ad->unw_table = 0;
+ ad->segment_base = f->sections[1]->header.sh_addr;
+ for (i = 0; i < f->header.e_shnum; ++i)
+ {
+ sec = f->sections[i];
+ if (sec->header.sh_type == SHT_IA_64_UNWIND)
+ {
+ ad->unw_start = sec->header.sh_addr;
+ ad->unw_end = sec->header.sh_addr + sec->header.sh_size;
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/mdk-stage1/insmod-modutils/obj/obj_kallsyms.c b/mdk-stage1/insmod-modutils/obj/obj_kallsyms.c
new file mode 100644
index 000000000..8385fb892
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/obj/obj_kallsyms.c
@@ -0,0 +1,292 @@
+/* Build a section containing all non-stack symbols.
+ Copyright 2000 Keith Owens <kaos@ocs.com.au>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <stdlib.h>
+#include <string.h>
+#include <malloc.h>
+
+#include "obj.h"
+#include "kallsyms.h"
+#include "util.h"
+
+/*======================================================================*/
+
+#define EXPAND_BY 4096 /* Arbitrary */
+
+/* Append a string to the big list of strings */
+
+static void
+append_string (const char *s, char **strings,
+ ElfW(Word) *strings_size, ElfW(Word) *strings_left)
+{
+ int l = strlen(s) + 1;
+ while (l > *strings_left) {
+ *strings = xrealloc(*strings, *strings_size += EXPAND_BY);
+ *strings_left += EXPAND_BY;
+ }
+ memcpy((char *)*strings+*strings_size-*strings_left, s, l);
+ *strings_left -= l;
+}
+
+
+/* Append a symbol to the big list of symbols */
+
+static void
+append_symbol (const struct kallsyms_symbol *s,
+ struct kallsyms_symbol **symbols,
+ ElfW(Word) *symbols_size, ElfW(Word) *symbols_left)
+{
+ int l = sizeof(*s);
+ while (l > *symbols_left) {
+ *symbols = xrealloc(*symbols, *symbols_size += EXPAND_BY);
+ *symbols_left += EXPAND_BY;
+ }
+ memcpy((char *)*symbols+*symbols_size-*symbols_left, s, l);
+ *symbols_left -= l;
+}
+
+/* qsort compare routine to sort symbols */
+
+static const char *sym_strings;
+
+static int
+symbol_compare (const void *a, const void *b)
+{
+ struct kallsyms_symbol *c = (struct kallsyms_symbol *) a;
+ struct kallsyms_symbol *d = (struct kallsyms_symbol *) b;
+
+ if (c->symbol_addr > d->symbol_addr)
+ return(1);
+ if (c->symbol_addr < d->symbol_addr)
+ return(-1);
+ return(strcmp(sym_strings+c->name_off, sym_strings+d->name_off));
+}
+
+
+/* Extract all symbols from the input obj_file, ignore ones that are
+ * no use for debugging, build an output obj_file containing only the
+ * kallsyms section.
+ *
+ * The kallsyms section is a bit unusual. It deliberately has no
+ * relocatable data, all "pointers" are represented as byte offsets
+ * into the the section. This means it can be stored anywhere without
+ * relocation problems. In particular it can be stored within a kernel
+ * image, it can be stored separately from the kernel image, it can be
+ * appended to a module just before loading, it can be stored in a
+ * separate area etc.
+ *
+ * Format of the kallsyms section.
+ *
+ * Header:
+ * Size of header.
+ * Total size of kallsyms data, including strings.
+ * Number of loaded sections.
+ * Offset to first section entry from start of header.
+ * Size of each section entry, excluding the name string.
+ * Number of symbols.
+ * Offset to first symbol entry from start of header.
+ * Size of each symbol entry, excluding the name string.
+ *
+ * Section entry - one per loaded section.
+ * Start of section[1].
+ * Size of section.
+ * Offset to name of section, from start of strings.
+ * Section flags.
+ *
+ * Symbol entry - one per symbol in the input file[2].
+ * Offset of section that owns this symbol, from start of section data.
+ * Address of symbol within the real section[1].
+ * Offset to name of symbol, from start of strings.
+ *
+ * Notes: [1] This is an exception to the "represent pointers as
+ * offsets" rule, it is a value, not an offset. The start
+ * address of a section or a symbol is extracted from the
+ * obj_file data which may contain absolute or relocatable
+ * addresses. If the addresses are relocatable then the
+ * caller must adjust the section and/or symbol entries in
+ * kallsyms after relocation.
+ * [2] Only symbols that fall within loaded sections are stored.
+ */
+
+int
+obj_kallsyms (struct obj_file *fin, struct obj_file **fout_result)
+{
+ struct obj_file *fout;
+ int i, loaded = 0, *fin_to_allsym_map;
+ struct obj_section *isec, *osec;
+ struct kallsyms_header *a_hdr;
+ struct kallsyms_section *a_sec;
+ ElfW(Off) sec_off;
+ struct kallsyms_symbol *symbols = NULL, a_sym;
+ ElfW(Word) symbols_size = 0, symbols_left = 0;
+ char *strings = NULL, *p;
+ ElfW(Word) strings_size = 0, strings_left = 0;
+ ElfW(Off) file_offset;
+ static char strtab[] = "\000" KALLSYMS_SEC_NAME;
+
+ /* Create the kallsyms section. */
+ fout = arch_new_file();
+ memset(fout, 0, sizeof(*fout));
+ fout->symbol_cmp = strcmp;
+ fout->symbol_hash = obj_elf_hash;
+ fout->load_order_search_start = &fout->load_order;
+
+ /* Copy file characteristics from input file and modify to suit */
+ memcpy(&fout->header, &fin->header, sizeof(fout->header));
+ fout->header.e_type = ET_REL; /* Output is relocatable */
+ fout->header.e_entry = 0; /* No entry point */
+ fout->header.e_phoff = 0; /* No program header */
+ file_offset = sizeof(fout->header); /* Step over Elf header */
+ fout->header.e_shoff = file_offset; /* Section headers next */
+ fout->header.e_phentsize = 0; /* No program header */
+ fout->header.e_phnum = 0; /* No program header */
+ fout->header.e_shnum = KALLSYMS_IDX+1; /* Initial, strtab, kallsyms */
+ fout->header.e_shstrndx = KALLSYMS_IDX-1; /* strtab */
+ file_offset += fout->header.e_shentsize * fout->header.e_shnum;
+
+ /* Populate the section data for kallsyms itself */
+ fout->sections = xmalloc(sizeof(*(fout->sections))*fout->header.e_shnum);
+ memset(fout->sections, 0, sizeof(*(fout->sections))*fout->header.e_shnum);
+
+ fout->sections[0] = osec = arch_new_section();
+ memset(osec, 0, sizeof(*osec));
+ osec->header.sh_type = SHT_NULL;
+ osec->header.sh_link = SHN_UNDEF;
+
+ fout->sections[KALLSYMS_IDX-1] = osec = arch_new_section();
+ memset(osec, 0, sizeof(*osec));
+ osec->name = ".strtab";
+ osec->header.sh_type = SHT_STRTAB;
+ osec->header.sh_link = SHN_UNDEF;
+ osec->header.sh_offset = file_offset;
+ osec->header.sh_size = sizeof(strtab);
+ osec->contents = xmalloc(sizeof(strtab));
+ memcpy(osec->contents, strtab, sizeof(strtab));
+ file_offset += osec->header.sh_size;
+
+ fout->sections[KALLSYMS_IDX] = osec = arch_new_section();
+ memset(osec, 0, sizeof(*osec));
+ osec->name = KALLSYMS_SEC_NAME;
+ osec->header.sh_name = 1; /* Offset in strtab */
+ osec->header.sh_type = SHT_PROGBITS; /* Load it */
+ osec->header.sh_flags = SHF_ALLOC; /* Read only data */
+ osec->header.sh_link = SHN_UNDEF;
+ osec->header.sh_addralign = sizeof(ElfW(Word));
+ file_offset = (file_offset + osec->header.sh_addralign - 1)
+ & -(osec->header.sh_addralign);
+ osec->header.sh_offset = file_offset;
+
+ /* How many loaded sections are there? */
+ for (i = 0; i < fin->header.e_shnum; ++i) {
+ if (fin->sections[i]->header.sh_flags & SHF_ALLOC)
+ ++loaded;
+ }
+
+ /* Initial contents, header + one entry per input section. No strings. */
+ osec->header.sh_size = sizeof(*a_hdr) + loaded*sizeof(*a_sec);
+ a_hdr = (struct kallsyms_header *) osec->contents =
+ xmalloc(osec->header.sh_size);
+ memset(osec->contents, 0, osec->header.sh_size);
+ a_hdr->size = sizeof(*a_hdr);
+ a_hdr->sections = loaded;
+ a_hdr->section_off = a_hdr->size;
+ a_hdr->section_size = sizeof(*a_sec);
+ a_hdr->symbol_off = osec->header.sh_size;
+ a_hdr->symbol_size = sizeof(a_sym);
+ a_hdr->start = (ElfW(Addr))(~0);
+
+ /* Map input section numbers to kallsyms section offsets. */
+ sec_off = 0; /* Offset to first kallsyms section entry */
+ fin_to_allsym_map = xmalloc(sizeof(*fin_to_allsym_map)*fin->header.e_shnum);
+ for (i = 0; i < fin->header.e_shnum; ++i) {
+ isec = fin->sections[i];
+ if (isec->header.sh_flags & SHF_ALLOC) {
+ fin_to_allsym_map[isec->idx] = sec_off;
+ sec_off += a_hdr->section_size;
+ }
+ else
+ fin_to_allsym_map[isec->idx] = -1; /* Ignore this section */
+ }
+
+ /* Copy the loaded section data. */
+ a_sec = (struct kallsyms_section *) ((char *) a_hdr + a_hdr->section_off);
+ for (i = 0; i < fin->header.e_shnum; ++i) {
+ isec = fin->sections[i];
+ if (!(isec->header.sh_flags & SHF_ALLOC))
+ continue;
+ a_sec->start = isec->header.sh_addr;
+ a_sec->size = isec->header.sh_size;
+ a_sec->flags = isec->header.sh_flags;
+ a_sec->name_off = strings_size - strings_left;
+ append_string(isec->name, &strings, &strings_size, &strings_left);
+ if (a_sec->start < a_hdr->start)
+ a_hdr->start = a_sec->start;
+ if (a_sec->start+a_sec->size > a_hdr->end)
+ a_hdr->end = a_sec->start+a_sec->size;
+ ++a_sec;
+ }
+
+ /* Build the kallsyms symbol table from the symbol hashes. */
+ for (i = 0; i < HASH_BUCKETS; ++i) {
+ struct obj_symbol *sym = fin->symtab[i];
+ for (sym = fin->symtab[i]; sym ; sym = sym->next) {
+ if (!sym || sym->secidx >= fin->header.e_shnum)
+ continue;
+ if ((a_sym.section_off = fin_to_allsym_map[sym->secidx]) == -1)
+ continue;
+ if (strcmp(sym->name, "gcc2_compiled.") == 0 ||
+ strncmp(sym->name, "__insmod_", 9) == 0)
+ continue;
+ a_sym.symbol_addr = sym->value;
+ if (fin->header.e_type == ET_REL)
+ a_sym.symbol_addr += fin->sections[sym->secidx]->header.sh_addr;
+ a_sym.name_off = strings_size - strings_left;
+ append_symbol(&a_sym, &symbols, &symbols_size, &symbols_left);
+ append_string(sym->name, &strings, &strings_size, &strings_left);
+ ++a_hdr->symbols;
+ }
+ }
+ free(fin_to_allsym_map);
+
+ /* Sort the symbols into ascending order by address and name */
+ sym_strings = strings; /* For symbol_compare */
+ qsort((char *) symbols, (unsigned) a_hdr->symbols,
+ sizeof(* symbols), symbol_compare);
+ sym_strings = NULL;
+
+ /* Put the lot together */
+ osec->header.sh_size = a_hdr->total_size =
+ a_hdr->symbol_off +
+ a_hdr->symbols*a_hdr->symbol_size +
+ strings_size - strings_left;
+ a_hdr = (struct kallsyms_header *) osec->contents =
+ xrealloc(a_hdr, a_hdr->total_size);
+ p = (char *)a_hdr + a_hdr->symbol_off;
+ memcpy(p, symbols, a_hdr->symbols*a_hdr->symbol_size);
+ free(symbols);
+ p += a_hdr->symbols*a_hdr->symbol_size;
+ a_hdr->string_off = p - (char *)a_hdr;
+ memcpy(p, strings, strings_size - strings_left);
+ free(strings);
+
+ *fout_result = fout;
+ return 0;
+}
diff --git a/mdk-stage1/insmod-modutils/obj/obj_load.c b/mdk-stage1/insmod-modutils/obj/obj_load.c
new file mode 100644
index 000000000..4db20a998
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/obj/obj_load.c
@@ -0,0 +1,354 @@
+/* Elf file reader.
+ Copyright 1996, 1997 Linux International.
+
+ Contributed by Richard Henderson <rth@tamu.edu>
+ obj_free() added by Björn Ekwall <bj0rn@blox.se> March 1999
+ Support for kallsyms Keith Owens <kaos@ocs.com.au> April 2000
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <alloca.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "obj.h"
+#include "util.h"
+
+/*======================================================================*/
+
+struct obj_file *
+obj_load (int fp, Elf32_Half e_type, const char *filename)
+{
+ struct obj_file *f;
+ ElfW(Shdr) *section_headers;
+ int shnum, i;
+ char *shstrtab;
+
+ /* Read the file header. */
+
+ f = arch_new_file();
+ memset(f, 0, sizeof(*f));
+ f->symbol_cmp = strcmp;
+ f->symbol_hash = obj_elf_hash;
+ f->load_order_search_start = &f->load_order;
+
+ gzf_lseek(fp, 0, SEEK_SET);
+ if (gzf_read(fp, &f->header, sizeof(f->header)) != sizeof(f->header))
+ {
+ error("error reading ELF header %s: %m", filename);
+ return NULL;
+ }
+
+ if (f->header.e_ident[EI_MAG0] != ELFMAG0
+ || f->header.e_ident[EI_MAG1] != ELFMAG1
+ || f->header.e_ident[EI_MAG2] != ELFMAG2
+ || f->header.e_ident[EI_MAG3] != ELFMAG3)
+ {
+ error("%s is not an ELF file", filename);
+ return NULL;
+ }
+ if (f->header.e_ident[EI_CLASS] != ELFCLASSM
+ || f->header.e_ident[EI_DATA] != ELFDATAM
+ || f->header.e_ident[EI_VERSION] != EV_CURRENT
+ || !MATCH_MACHINE(f->header.e_machine))
+ {
+ error("ELF file %s not for this architecture", filename);
+ return NULL;
+ }
+ if (f->header.e_type != e_type && e_type != ET_NONE)
+ {
+ switch (e_type) {
+ case ET_REL:
+ error("ELF file %s not a relocatable object", filename);
+ break;
+ case ET_EXEC:
+ error("ELF file %s not an executable object", filename);
+ break;
+ default:
+ error("ELF file %s has wrong type, expecting %d got %d",
+ filename, e_type, f->header.e_type);
+ break;
+ }
+ return NULL;
+ }
+
+ /* Read the section headers. */
+
+ if (f->header.e_shentsize != sizeof(ElfW(Shdr)))
+ {
+ error("section header size mismatch %s: %lu != %lu",
+ filename,
+ (unsigned long)f->header.e_shentsize,
+ (unsigned long)sizeof(ElfW(Shdr)));
+ return NULL;
+ }
+
+ shnum = f->header.e_shnum;
+ f->sections = xmalloc(sizeof(struct obj_section *) * shnum);
+ memset(f->sections, 0, sizeof(struct obj_section *) * shnum);
+
+ section_headers = alloca(sizeof(ElfW(Shdr)) * shnum);
+ gzf_lseek(fp, f->header.e_shoff, SEEK_SET);
+ if (gzf_read(fp, section_headers, sizeof(ElfW(Shdr))*shnum) != sizeof(ElfW(Shdr))*shnum)
+ {
+ error("error reading ELF section headers %s: %m", filename);
+ return NULL;
+ }
+
+ /* Read the section data. */
+
+ for (i = 0; i < shnum; ++i)
+ {
+ struct obj_section *sec;
+
+ f->sections[i] = sec = arch_new_section();
+ memset(sec, 0, sizeof(*sec));
+
+ sec->header = section_headers[i];
+ sec->idx = i;
+
+ switch (sec->header.sh_type)
+ {
+ case SHT_NULL:
+ case SHT_NOTE:
+ case SHT_NOBITS:
+ /* ignore */
+ break;
+
+ case SHT_PROGBITS:
+ case SHT_SYMTAB:
+ case SHT_STRTAB:
+ case SHT_RELM:
+ if (sec->header.sh_size > 0)
+ {
+ sec->contents = xmalloc(sec->header.sh_size);
+ gzf_lseek(fp, sec->header.sh_offset, SEEK_SET);
+ if (gzf_read(fp, sec->contents, sec->header.sh_size) != sec->header.sh_size)
+ {
+ error("error reading ELF section data %s: %m", filename);
+ return NULL;
+ }
+ }
+ else
+ sec->contents = NULL;
+ break;
+
+#if SHT_RELM == SHT_REL
+ case SHT_RELA:
+ if (sec->header.sh_size) {
+ error("RELA relocations not supported on this architecture %s", filename);
+ return NULL;
+ }
+ break;
+#else
+ case SHT_REL:
+ if (sec->header.sh_size) {
+ error("REL relocations not supported on this architecture %s", filename);
+ return NULL;
+ }
+ break;
+#endif
+
+ default:
+ if (sec->header.sh_type >= SHT_LOPROC)
+ {
+ if (arch_load_proc_section(sec, fp) < 0)
+ return NULL;
+ break;
+ }
+
+ error("can't handle sections of type %ld %s",
+ (long)sec->header.sh_type, filename);
+ return NULL;
+ }
+ }
+
+ /* Do what sort of interpretation as needed by each section. */
+
+ shstrtab = f->sections[f->header.e_shstrndx]->contents;
+
+ for (i = 0; i < shnum; ++i)
+ {
+ struct obj_section *sec = f->sections[i];
+ sec->name = shstrtab + sec->header.sh_name;
+ }
+
+ for (i = 0; i < shnum; ++i)
+ {
+ struct obj_section *sec = f->sections[i];
+
+ /* .modinfo and .modstring should be contents only but gcc has no
+ * attribute for that. The kernel may have marked these sections as
+ * ALLOC, ignore the allocate bit.
+ */
+ if (strcmp(sec->name, ".modinfo") == 0 ||
+ strcmp(sec->name, ".modstring") == 0)
+ sec->header.sh_flags &= ~SHF_ALLOC;
+
+ if (sec->header.sh_flags & SHF_ALLOC)
+ obj_insert_section_load_order(f, sec);
+
+ switch (sec->header.sh_type)
+ {
+ case SHT_SYMTAB:
+ {
+ unsigned long nsym, j;
+ char *strtab;
+ ElfW(Sym) *sym;
+
+ if (sec->header.sh_entsize != sizeof(ElfW(Sym)))
+ {
+ error("symbol size mismatch %s: %lu != %lu",
+ filename,
+ (unsigned long)sec->header.sh_entsize,
+ (unsigned long)sizeof(ElfW(Sym)));
+ return NULL;
+ }
+
+ nsym = sec->header.sh_size / sizeof(ElfW(Sym));
+ strtab = f->sections[sec->header.sh_link]->contents;
+ sym = (ElfW(Sym) *) sec->contents;
+
+ /* Allocate space for a table of local symbols. */
+ j = f->local_symtab_size = sec->header.sh_info;
+ f->local_symtab = xmalloc(j *= sizeof(struct obj_symbol *));
+ memset(f->local_symtab, 0, j);
+
+ /* Insert all symbols into the hash table. */
+ for (j = 1, ++sym; j < nsym; ++j, ++sym)
+ {
+ const char *name;
+ if (sym->st_name)
+ name = strtab+sym->st_name;
+ else
+ name = f->sections[sym->st_shndx]->name;
+
+ obj_add_symbol(f, name, j, sym->st_info, sym->st_shndx,
+ sym->st_value, sym->st_size);
+
+ }
+ }
+ break;
+ }
+ }
+
+ /* second pass to add relocation data to symbols */
+ for (i = 0; i < shnum; ++i)
+ {
+ struct obj_section *sec = f->sections[i];
+ switch (sec->header.sh_type)
+ {
+ case SHT_RELM:
+ {
+ unsigned long nrel, j;
+ ElfW(RelM) *rel;
+ struct obj_section *symtab;
+ char *strtab;
+ if (sec->header.sh_entsize != sizeof(ElfW(RelM)))
+ {
+ error("relocation entry size mismatch %s: %lu != %lu",
+ filename,
+ (unsigned long)sec->header.sh_entsize,
+ (unsigned long)sizeof(ElfW(RelM)));
+ return NULL;
+ }
+
+ nrel = sec->header.sh_size / sizeof(ElfW(RelM));
+ rel = (ElfW(RelM) *) sec->contents;
+ symtab = f->sections[sec->header.sh_link];
+ strtab = f->sections[symtab->header.sh_link]->contents;
+
+ /* Save the relocate type in each symbol entry. */
+ for (j = 0; j < nrel; ++j, ++rel)
+ {
+ ElfW(Sym) *extsym;
+ struct obj_symbol *intsym;
+ unsigned long symndx;
+ symndx = ELFW(R_SYM)(rel->r_info);
+ if (symndx)
+ {
+ extsym = ((ElfW(Sym) *) symtab->contents) + symndx;
+ if (ELFW(ST_BIND)(extsym->st_info) == STB_LOCAL)
+ {
+ /* Local symbols we look up in the local table to be sure
+ we get the one that is really intended. */
+ intsym = f->local_symtab[symndx];
+ }
+ else
+ {
+ /* Others we look up in the hash table. */
+ const char *name;
+ if (extsym->st_name)
+ name = strtab + extsym->st_name;
+ else
+ name = f->sections[extsym->st_shndx]->name;
+ intsym = obj_find_symbol(f, name);
+ }
+ intsym->r_type = ELFW(R_TYPE)(rel->r_info);
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ f->filename = xstrdup(filename);
+
+ return f;
+}
+
+void obj_free(struct obj_file *f)
+{
+ struct obj_section *sec;
+ struct obj_symbol *sym;
+ struct obj_symbol *next;
+ int i;
+ int n;
+
+ if (f->sections) {
+ n = f->header.e_shnum;
+ for (i = 0; i < n; ++i) {
+ if ((sec = f->sections[i]) != NULL) {
+ if (sec->contents)
+ free(sec->contents);
+ free(sec);
+ }
+ }
+ free(f->sections);
+ }
+
+ for (i = 0; i < HASH_BUCKETS; ++i) {
+ for (sym = f->symtab[i]; sym; sym = next) {
+ next = sym->next;
+ free(sym);
+ }
+ }
+
+ if (f->local_symtab)
+ free(f->local_symtab);
+
+ if (f->filename)
+ free((char *)(f->filename));
+
+ if (f->persist)
+ free((char *)(f->persist));
+
+ free(f);
+}
diff --git a/mdk-stage1/insmod-modutils/obj/obj_m68k.c b/mdk-stage1/insmod-modutils/obj/obj_m68k.c
new file mode 100644
index 000000000..cb485aed7
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/obj/obj_m68k.c
@@ -0,0 +1,147 @@
+/* m68k specific support for Elf loading and relocation.
+ Copyright 1996, 1997 Linux International.
+
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <stddef.h>
+#include <module.h>
+#include <obj.h>
+#include <util.h>
+
+
+/*======================================================================*/
+
+struct obj_file *
+arch_new_file (void)
+{
+ return xmalloc(sizeof(struct obj_file));
+}
+
+struct obj_section *
+arch_new_section (void)
+{
+ return xmalloc(sizeof(struct obj_section));
+}
+
+struct obj_symbol *
+arch_new_symbol (void)
+{
+ return xmalloc(sizeof(struct obj_symbol));
+}
+
+int
+arch_load_proc_section(struct obj_section *sec, int fp)
+{
+ /* Assume it's just a debugging section that we can safely
+ ignore ... */
+ sec->contents = NULL;
+
+ return 0;
+}
+
+enum obj_reloc
+arch_apply_relocation (struct obj_file *ef,
+ struct obj_section *targsec,
+ struct obj_section *symsec,
+ struct obj_symbol *sym,
+ Elf32_Rela *rel,
+ Elf32_Addr v)
+{
+ char *loc = targsec->contents + rel->r_offset;
+ Elf32_Addr dot = targsec->header.sh_addr + rel->r_offset;
+
+ enum obj_reloc ret = obj_reloc_ok;
+
+ switch (ELF32_R_TYPE(rel->r_info))
+ {
+ case R_68K_NONE:
+ break;
+
+ case R_68K_8:
+ if (v > 0xff)
+ ret = obj_reloc_overflow;
+ *(char *)loc = v;
+ break;
+ case R_68K_16:
+ if (v > 0xffff)
+ ret = obj_reloc_overflow;
+ *(short *)loc = v;
+ break;
+ case R_68K_32:
+ *(int *)loc = v;
+ break;
+
+ case R_68K_PC8:
+ v -= dot;
+ if ((Elf32_Sword)v > 0x7f || (Elf32_Sword)v < -(Elf32_Sword)0x80)
+ ret = obj_reloc_overflow;
+ *(char *)loc = v;
+ break;
+ case R_68K_PC16:
+ v -= dot;
+ if ((Elf32_Sword)v > 0x7fff || (Elf32_Sword)v < -(Elf32_Sword)0x8000)
+ ret = obj_reloc_overflow;
+ *(short *)loc = v;
+ break;
+ case R_68K_PC32:
+ *(int *)loc = v - dot;
+ break;
+
+ case R_68K_RELATIVE:
+ *(int *)loc += ef->baseaddr;
+ break;
+
+ default:
+ ret = obj_reloc_unhandled;
+ break;
+ }
+
+ return ret;
+}
+
+int
+arch_create_got (struct obj_file *ef)
+{
+ return 1;
+}
+
+int
+arch_init_module (struct obj_file *f, struct module *mod)
+{
+ return 1;
+}
+
+int
+arch_finalize_section_address(struct obj_file *f, Elf32_Addr base)
+{
+ int i, n = f->header.e_shnum;
+
+ f->baseaddr = base;
+ for (i = 0; i < n; ++i)
+ f->sections[i]->header.sh_addr += base;
+ return 1;
+}
+
+int
+arch_archdata (struct obj_file *fin, struct obj_section *sec)
+{
+ return 0;
+}
diff --git a/mdk-stage1/insmod-modutils/obj/obj_mips.c b/mdk-stage1/insmod-modutils/obj/obj_mips.c
new file mode 100644
index 000000000..c2315b659
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/obj/obj_mips.c
@@ -0,0 +1,238 @@
+/* MIPS specific support for Elf loading and relocation.
+ Copyright 1997, 1998 Linux International.
+ Contributed by Ralf Baechle <ralf@gnu.ai.mit.edu>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include <module.h>
+#include <obj.h>
+#include <util.h>
+
+
+/*======================================================================*/
+
+struct mips_hi16
+{
+ struct mips_hi16 *next;
+ Elf32_Addr *addr;
+ Elf32_Addr value;
+};
+
+struct mips_file
+{
+ struct obj_file root;
+ struct mips_hi16 *mips_hi16_list;
+};
+
+/*======================================================================*/
+
+struct obj_file *
+arch_new_file (void)
+{
+ struct mips_file *mf;
+
+ mf = xmalloc(sizeof(*mf));
+ mf->mips_hi16_list = NULL;
+
+ return (struct obj_file *) mf;
+}
+
+struct obj_section *
+arch_new_section (void)
+{
+ return xmalloc(sizeof(struct obj_section));
+}
+
+struct obj_symbol *
+arch_new_symbol (void)
+{
+ return xmalloc(sizeof(struct obj_symbol));
+}
+
+int
+arch_load_proc_section(struct obj_section *sec, int fp)
+{
+ switch (sec->header.sh_type)
+ {
+ case SHT_MIPS_DEBUG:
+ case SHT_MIPS_REGINFO:
+ /* Actually these two sections are as useless as something can be ... */
+ sec->contents = NULL;
+ break;
+
+ case SHT_MIPS_LIBLIST:
+ case SHT_MIPS_CONFLICT:
+ case SHT_MIPS_GPTAB:
+ case SHT_MIPS_UCODE:
+ case SHT_MIPS_OPTIONS:
+ case SHT_MIPS_DWARF:
+ case SHT_MIPS_EVENTS:
+ /* These shouldn't ever be in a module file. */
+ error("Unhandled section header type: %08x", sec->header.sh_type);
+
+ default:
+ /* We don't even know the type. This time it might as well be a
+ supernova. */
+ error("Unknown section header type: %08x", sec->header.sh_type);
+ return -1;
+ }
+
+ return 0;
+}
+
+enum obj_reloc
+arch_apply_relocation (struct obj_file *f,
+ struct obj_section *targsec,
+ struct obj_section *symsec,
+ struct obj_symbol *sym,
+ Elf32_Rel *rel,
+ Elf32_Addr v)
+{
+ struct mips_file *mf = (struct mips_file *)f;
+ Elf32_Addr *loc = (Elf32_Addr *)(targsec->contents + rel->r_offset);
+ Elf32_Addr dot = targsec->header.sh_addr + rel->r_offset;
+ enum obj_reloc ret = obj_reloc_ok;
+
+ /* _gp_disp is a magic symbol for PIC which is not supported for
+ the kernel and loadable modules. */
+ if (strcmp(sym->name, "_gp_disp") == 0)
+ ret = obj_reloc_unhandled;
+
+ switch (ELF32_R_TYPE(rel->r_info))
+ {
+ case R_MIPS_NONE:
+ break;
+
+ case R_MIPS_32:
+ *loc += v;
+ break;
+
+ case R_MIPS_26:
+ if (v % 4)
+ ret = obj_reloc_dangerous;
+ if ((v & 0xf0000000) != ((dot + 4) & 0xf0000000))
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0x03ffffff) | ((*loc + (v >> 2)) & 0x03ffffff);
+ break;
+
+ case R_MIPS_HI16:
+ {
+ struct mips_hi16 *n;
+
+ /* We cannot relocate this one now because we don't know the value
+ of the carry we need to add. Save the information, and let LO16
+ do the actual relocation. */
+ n = (struct mips_hi16 *) xmalloc (sizeof *n);
+ n->addr = loc;
+ n->value = v;
+ n->next = mf->mips_hi16_list;
+ mf->mips_hi16_list = n;
+ break;
+ }
+
+ case R_MIPS_LO16:
+ {
+ unsigned long insnlo = *loc;
+ Elf32_Addr val, vallo;
+
+ /* Sign extend the addend we extract from the lo insn. */
+ vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000;
+
+ if (mf->mips_hi16_list != NULL)
+ {
+ struct mips_hi16 *l;
+
+ l = mf->mips_hi16_list;
+ while (l != NULL)
+ {
+ struct mips_hi16 *next;
+ unsigned long insn;
+
+ /* The value for the HI16 had best be the same. */
+ assert(v == l->value);
+
+ /* Do the HI16 relocation. Note that we actually don't
+ need to know anything about the LO16 itself, except where
+ to find the low 16 bits of the addend needed by the LO16. */
+ insn = *l->addr;
+ val = ((insn & 0xffff) << 16) + vallo;
+ val += v;
+
+ /* Account for the sign extension that will happen in the
+ low bits. */
+ val = ((val >> 16) + ((val & 0x8000) != 0)) & 0xffff;
+
+ insn = (insn &~ 0xffff) | val;
+ *l->addr = insn;
+
+ next = l->next;
+ free(l);
+ l = next;
+ }
+
+ mf->mips_hi16_list = NULL;
+ }
+
+ /* Ok, we're done with the HI16 relocs. Now deal with the LO16. */
+ val = v + vallo;
+ insnlo = (insnlo & ~0xffff) | (val & 0xffff);
+ *loc = insnlo;
+ break;
+ }
+
+ default:
+ ret = obj_reloc_unhandled;
+ break;
+ }
+
+ return ret;
+}
+
+int
+arch_create_got (struct obj_file *f)
+{
+ return 1;
+}
+
+int
+arch_init_module (struct obj_file *f, struct module *mod)
+{
+ return 1;
+}
+
+int
+arch_finalize_section_address(struct obj_file *f, Elf32_Addr base)
+{
+ int i, n = f->header.e_shnum;
+
+ f->baseaddr = base;
+ for (i = 0; i < n; ++i)
+ f->sections[i]->header.sh_addr += base;
+ return 1;
+}
+
+int
+arch_archdata (struct obj_file *fin, struct obj_section *sec)
+{
+ return 0;
+}
diff --git a/mdk-stage1/insmod-modutils/obj/obj_ppc.c b/mdk-stage1/insmod-modutils/obj/obj_ppc.c
new file mode 100644
index 000000000..89bb8e46b
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/obj/obj_ppc.c
@@ -0,0 +1,255 @@
+/* PowerPC specific support for Elf loading and relocation.
+ Copyright 1996, 1997 Linux International.
+
+ Adapted by Paul Mackerras <paulus@cs.anu.edu.au> from the
+ obj-sparc.c and obj-alpha.c files.
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <stddef.h>
+#include <module.h>
+#include <obj.h>
+#include <util.h>
+#include <assert.h>
+
+
+/*======================================================================*/
+
+/*
+ * Unfortunately, the bl (branch-and-link) instruction used for
+ * procedure calls on the PowerPC can only reach +/- 32MB from the
+ * current instruction. If the module is loaded far enough away from
+ * the main kernel text (or other modules) that this limit is
+ * exceeded, we have to redirect procedure calls via a procedure
+ * linkage table (PLT). Each entry in the PLT contains instructions
+ * to put the address of the procedure in a register and jump to it.
+ */
+
+typedef unsigned int instruction; /* a powerpc instruction (4 bytes) */
+
+struct ppc_plt_entry
+{
+ struct ppc_plt_entry *next;
+ ElfW(Addr) addend;
+ int offset;
+ int inited;
+};
+
+struct ppc_file
+{
+ struct obj_file file;
+ struct obj_section *plt;
+};
+
+struct ppc_symbol
+{
+ struct obj_symbol sym;
+ struct ppc_plt_entry *plt_entries;
+};
+
+struct obj_file *
+arch_new_file (void)
+{
+ struct ppc_file *f;
+
+ f = xmalloc(sizeof(struct ppc_file));
+ f->plt = NULL;
+ return &f->file;
+}
+
+struct obj_section *
+arch_new_section (void)
+{
+ return xmalloc(sizeof(struct obj_section));
+}
+
+struct obj_symbol *
+arch_new_symbol (void)
+{
+ struct ppc_symbol *p;
+
+ p = xmalloc(sizeof(struct ppc_symbol));
+ p->plt_entries = NULL;
+ return &p->sym;
+}
+
+int
+arch_load_proc_section(struct obj_section *sec, int fp)
+{
+ /* Assume it's just a debugging section that we can safely
+ ignore ... */
+ sec->contents = NULL;
+
+ return 0;
+}
+
+enum obj_reloc
+arch_apply_relocation (struct obj_file *ef,
+ struct obj_section *targsec,
+ struct obj_section *symsec,
+ struct obj_symbol *sym,
+ Elf32_Rela *rel,
+ Elf32_Addr v)
+{
+ Elf32_Addr *loc = (Elf32_Addr *)(targsec->contents + rel->r_offset);
+ Elf32_Addr dot = targsec->header.sh_addr + rel->r_offset;
+ struct ppc_file *pf = (struct ppc_file *) ef;
+ struct ppc_symbol *psym = (struct ppc_symbol *) sym;
+ struct ppc_plt_entry *pe;
+ instruction *ip;
+
+ enum obj_reloc ret = obj_reloc_ok;
+
+ switch (ELF32_R_TYPE(rel->r_info))
+ {
+ case R_PPC_ADDR16_HA:
+ *(unsigned short *)loc = (v + 0x8000) >> 16;
+ break;
+
+ case R_PPC_ADDR16_HI:
+ *(unsigned short *)loc = v >> 16;
+ break;
+
+ case R_PPC_ADDR16_LO:
+ *(unsigned short *)loc = v;
+ break;
+
+ case R_PPC_REL24:
+ /* find the plt entry and initialize it if necessary */
+ assert(psym != NULL);
+ for (pe = psym->plt_entries; pe != NULL && pe->addend != rel->r_addend; )
+ pe = pe->next;
+ assert(pe != NULL);
+ if (!pe->inited)
+ {
+ ip = (instruction *) (pf->plt->contents + pe->offset);
+ ip[0] = 0x3d600000 + ((v + 0x8000) >> 16); /* lis r11,sym@ha */
+ ip[1] = 0x396b0000 + (v & 0xffff); /* addi r11,r11,sym@l */
+ ip[2] = 0x7d6903a6; /* mtctr r11 */
+ ip[3] = 0x4e800420; /* bctr */
+ pe->inited = 1;
+ }
+
+ v -= dot;
+ if ((int)v < -0x02000000 || (int)v >= 0x02000000)
+ {
+ /* go via the plt */
+ v = pf->plt->header.sh_addr + pe->offset - dot;
+ }
+ if (v & 3)
+ ret = obj_reloc_dangerous;
+ *loc = (*loc & ~0x03fffffc) | (v & 0x03fffffc);
+ break;
+
+ case R_PPC_REL32:
+ *loc = v - dot;
+ break;
+
+ case R_PPC_ADDR32:
+ *loc = v;
+ break;
+
+ default:
+ ret = obj_reloc_unhandled;
+ break;
+ }
+
+ return ret;
+}
+
+int
+arch_create_got (struct obj_file *f)
+{
+ struct ppc_file *pf = (struct ppc_file *) f;
+ int i, offset;
+ struct obj_section *sec, *syms, *strs;
+ ElfW(Rela) *rel, *relend;
+ ElfW(Sym) *symtab, *extsym;
+ const char *strtab, *name;
+ struct ppc_symbol *intsym;
+ struct ppc_plt_entry *pe;
+
+ offset = 0;
+ for (i = 0; i < f->header.e_shnum; ++i)
+ {
+ sec = f->sections[i];
+ if (sec->header.sh_type != SHT_RELM)
+ continue;
+ syms = f->sections[sec->header.sh_link];
+ strs = f->sections[syms->header.sh_link];
+
+ rel = (ElfW(RelM) *) sec->contents;
+ relend = rel + (sec->header.sh_size / sizeof(ElfW(RelM)));
+ symtab = (ElfW(Sym) *) syms->contents;
+ strtab = (const char *) strs->contents;
+
+ for (; rel < relend; ++rel)
+ {
+ if (ELF32_R_TYPE(rel->r_info) != R_PPC_REL24)
+ continue;
+ extsym = &symtab[ELF32_R_SYM(rel->r_info)];
+ if (extsym->st_name)
+ name = strtab + extsym->st_name;
+ else
+ name = f->sections[extsym->st_shndx]->name;
+ intsym = (struct ppc_symbol *) obj_find_symbol(f, name);
+
+ for (pe = intsym->plt_entries; pe != NULL; pe = pe->next)
+ if (pe->addend == rel->r_addend)
+ break;
+ if (pe == NULL)
+ {
+ pe = xmalloc(sizeof(struct ppc_plt_entry));
+ pe->next = intsym->plt_entries;
+ pe->addend = rel->r_addend;
+ pe->offset = offset;
+ pe->inited = 0;
+ intsym->plt_entries = pe;
+ offset += 16;
+ }
+ }
+ }
+
+ pf->plt = obj_create_alloced_section(f, ".plt", 16, offset);
+
+ return 1;
+}
+
+int
+arch_init_module (struct obj_file *f, struct module *mod)
+{
+ return 1;
+}
+
+int
+arch_finalize_section_address(struct obj_file *f, Elf32_Addr base)
+{
+ int i, n = f->header.e_shnum;
+
+ f->baseaddr = base;
+ for (i = 0; i < n; ++i)
+ f->sections[i]->header.sh_addr += base;
+ return 1;
+}
+
+int
+arch_archdata (struct obj_file *fin, struct obj_section *sec)
+{
+ return 0;
+}
diff --git a/mdk-stage1/insmod-modutils/obj/obj_reloc.c b/mdk-stage1/insmod-modutils/obj/obj_reloc.c
new file mode 100644
index 000000000..f5f2de90d
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/obj/obj_reloc.c
@@ -0,0 +1,435 @@
+/* Elf relocation routines.
+ Copyright 1996, 1997 Linux International.
+
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <string.h>
+#include <assert.h>
+#include <alloca.h>
+
+#include <obj.h>
+#include <util.h>
+
+/*======================================================================*/
+
+int
+obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
+ const char *string)
+{
+ struct obj_string_patch_struct *p;
+ struct obj_section *strsec;
+ size_t len = strlen(string)+1;
+ char *loc;
+
+ p = xmalloc(sizeof(*p));
+ p->next = f->string_patches;
+ p->reloc_secidx = secidx;
+ p->reloc_offset = offset;
+ f->string_patches = p;
+
+ strsec = obj_find_section(f, ".kstrtab");
+ if (strsec == NULL)
+ {
+ strsec = obj_create_alloced_section(f, ".kstrtab", 1, len);
+ p->string_offset = 0;
+ loc = strsec->contents;
+ }
+ else
+ {
+ p->string_offset = strsec->header.sh_size;
+ loc = obj_extend_section(strsec, len);
+ }
+ memcpy(loc, string, len);
+
+ return 1;
+}
+
+int
+obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
+ struct obj_symbol *sym)
+{
+ struct obj_symbol_patch_struct *p;
+
+ p = xmalloc(sizeof(*p));
+ p->next = f->symbol_patches;
+ p->reloc_secidx = secidx;
+ p->reloc_offset = offset;
+ p->sym = sym;
+ f->symbol_patches = p;
+
+ return 1;
+}
+
+int
+obj_check_undefineds(struct obj_file *f, int quiet)
+{
+ unsigned long i;
+ int ret = 1;
+
+ for (i = 0; i < HASH_BUCKETS; ++i)
+ {
+ struct obj_symbol *sym;
+ for (sym = f->symtab[i]; sym ; sym = sym->next)
+ if (sym->secidx == SHN_UNDEF)
+ {
+ if (ELFW(ST_BIND)(sym->info) == STB_WEAK)
+ {
+ sym->secidx = SHN_ABS;
+ sym->value = 0;
+ }
+ else if (sym->r_type) /* assumes R_arch_NONE is 0 on all arch */
+ {
+ if (!quiet)
+ error("unresolved symbol %s", sym->name);
+ ret = 0;
+ }
+ }
+ }
+
+ return ret;
+}
+
+void
+obj_clear_undefineds(struct obj_file *f)
+{
+ unsigned long i;
+ struct obj_symbol *sym;
+ for (i = 0; i < HASH_BUCKETS; ++i)
+ {
+ for (sym = f->symtab[i]; sym ; sym = sym->next)
+ if (sym->secidx == SHN_UNDEF)
+ {
+ sym->secidx = SHN_ABS;
+ sym->value = 0;
+ }
+ }
+}
+
+void
+obj_allocate_commons(struct obj_file *f)
+{
+ struct common_entry
+ {
+ struct common_entry *next;
+ struct obj_symbol *sym;
+ } *common_head = NULL;
+
+ unsigned long i;
+
+ for (i = 0; i < HASH_BUCKETS; ++i)
+ {
+ struct obj_symbol *sym;
+ for (sym = f->symtab[i]; sym ; sym = sym->next)
+ if (sym->secidx == SHN_COMMON)
+ {
+ /* Collect all COMMON symbols and sort them by size so as to
+ minimize space wasted by alignment requirements. */
+ {
+ struct common_entry **p, *n;
+ for (p = &common_head; *p ; p = &(*p)->next)
+ if (sym->size <= (*p)->sym->size)
+ break;
+
+ n = alloca(sizeof(*n));
+ n->next = *p;
+ n->sym = sym;
+ *p = n;
+ }
+ }
+ }
+
+ for (i = 1; i < f->local_symtab_size; ++i)
+ {
+ struct obj_symbol *sym = f->local_symtab[i];
+ if (sym && sym->secidx == SHN_COMMON)
+ {
+ struct common_entry **p, *n;
+ for (p = &common_head; *p ; p = &(*p)->next)
+ if (sym == (*p)->sym)
+ break;
+ else if (sym->size < (*p)->sym->size)
+ {
+ n = alloca(sizeof(*n));
+ n->next = *p;
+ n->sym = sym;
+ *p = n;
+ break;
+ }
+ }
+ }
+
+ if (common_head)
+ {
+ /* Find the bss section. */
+ for (i = 0; i < f->header.e_shnum; ++i)
+ if (f->sections[i]->header.sh_type == SHT_NOBITS)
+ break;
+
+ /* If for some reason there hadn't been one, create one. */
+ if (i == f->header.e_shnum)
+ {
+ struct obj_section *sec;
+
+ f->sections = xrealloc(f->sections, (i+1) * sizeof(sec));
+ f->sections[i] = sec = arch_new_section();
+ f->header.e_shnum = i+1;
+
+ memset(sec, 0, sizeof(*sec));
+ sec->header.sh_type = SHT_PROGBITS;
+ sec->header.sh_flags = SHF_WRITE|SHF_ALLOC;
+ sec->name = ".bss";
+ sec->idx = i;
+ }
+
+ /* Allocate the COMMONS. */
+ {
+ ElfW(Addr) bss_size = f->sections[i]->header.sh_size;
+ ElfW(Addr) max_align = f->sections[i]->header.sh_addralign;
+ struct common_entry *c;
+
+ for (c = common_head; c ; c = c->next)
+ {
+ ElfW(Addr) align = c->sym->value;
+
+ if (align > max_align)
+ max_align = align;
+ if (bss_size & (align - 1))
+ bss_size = (bss_size | (align - 1)) + 1;
+
+ c->sym->secidx = i;
+ c->sym->value = bss_size;
+
+ bss_size += c->sym->size;
+ }
+
+ f->sections[i]->header.sh_size = bss_size;
+ f->sections[i]->header.sh_addralign = max_align;
+ }
+ }
+
+ /* For the sake of patch relocation and parameter initialization,
+ allocate zeroed data for NOBITS sections now. Note that after
+ this we cannot assume NOBITS are really empty. */
+ for (i = 0; i < f->header.e_shnum; ++i)
+ {
+ struct obj_section *s = f->sections[i];
+ if (s->header.sh_type == SHT_NOBITS)
+ {
+ if (s->header.sh_size)
+ s->contents = memset(xmalloc(s->header.sh_size),
+ 0, s->header.sh_size);
+ else
+ s->contents = NULL;
+ s->header.sh_type = SHT_PROGBITS;
+ }
+ }
+}
+
+unsigned long
+obj_load_size (struct obj_file *f)
+{
+ unsigned long dot = 0;
+ struct obj_section *sec;
+
+ /* Finalize the positions of the sections relative to one another. */
+
+ for (sec = f->load_order; sec ; sec = sec->load_next)
+ {
+ ElfW(Addr) align;
+
+ align = sec->header.sh_addralign;
+ if (align && (dot & (align - 1)))
+ dot = (dot | (align - 1)) + 1;
+
+ sec->header.sh_addr = dot;
+ dot += sec->header.sh_size;
+ }
+
+ return dot;
+}
+
+int
+obj_relocate (struct obj_file *f, ElfW(Addr) base)
+{
+ int i, n = f->header.e_shnum;
+ int ret = 1;
+
+ /* Finalize the addresses of the sections. */
+
+ arch_finalize_section_address(f, base);
+
+ /* And iterate over all of the relocations. */
+
+ for (i = 0; i < n; ++i)
+ {
+ struct obj_section *relsec, *symsec, *targsec, *strsec;
+ ElfW(RelM) *rel, *relend;
+ ElfW(Sym) *symtab;
+ const char *strtab;
+
+ relsec = f->sections[i];
+ if (relsec->header.sh_type != SHT_RELM)
+ continue;
+
+ symsec = f->sections[relsec->header.sh_link];
+ targsec = f->sections[relsec->header.sh_info];
+ strsec = f->sections[symsec->header.sh_link];
+
+ rel = (ElfW(RelM) *)relsec->contents;
+ relend = rel + (relsec->header.sh_size / sizeof(ElfW(RelM)));
+ symtab = (ElfW(Sym) *)symsec->contents;
+ strtab = (const char *)strsec->contents;
+
+ for (; rel < relend; ++rel)
+ {
+ ElfW(Addr) value = 0;
+ struct obj_symbol *intsym = NULL;
+ unsigned long symndx;
+ ElfW(Sym) *extsym = 0;
+ const char *errmsg;
+
+ /* Attempt to find a value to use for this relocation. */
+
+ symndx = ELFW(R_SYM)(rel->r_info);
+ if (symndx)
+ {
+ /* Note we've already checked for undefined symbols. */
+
+ extsym = &symtab[symndx];
+ if (ELFW(ST_BIND)(extsym->st_info) == STB_LOCAL)
+ {
+ /* Local symbols we look up in the local table to be sure
+ we get the one that is really intended. */
+ intsym = f->local_symtab[symndx];
+ }
+ else
+ {
+ /* Others we look up in the hash table. */
+ const char *name;
+ if (extsym->st_name)
+ name = strtab + extsym->st_name;
+ else
+ name = f->sections[extsym->st_shndx]->name;
+ intsym = obj_find_symbol(f, name);
+ }
+
+ value = obj_symbol_final_value(f, intsym);
+ }
+
+#if SHT_RELM == SHT_RELA
+#if defined(__alpha__) && defined(AXP_BROKEN_GAS)
+ /* Work around a nasty GAS bug, that is fixed as of 2.7.0.9. */
+ if (!extsym || !extsym->st_name ||
+ ELFW(ST_BIND)(extsym->st_info) != STB_LOCAL)
+#endif
+ value += rel->r_addend;
+#endif
+
+ /* Do it! */
+ switch (arch_apply_relocation(f,targsec,symsec,intsym,rel,value))
+ {
+ case obj_reloc_ok:
+ break;
+
+ case obj_reloc_overflow:
+ errmsg = "Relocation overflow";
+ goto bad_reloc;
+ case obj_reloc_dangerous:
+ errmsg = "Dangerous relocation";
+ goto bad_reloc;
+ case obj_reloc_unhandled:
+ errmsg = "Unhandled relocation";
+ goto bad_reloc;
+ case obj_reloc_constant_gp:
+ errmsg = "Modules compiled with -mconstant-gp cannot be loaded";
+ goto bad_reloc;
+ bad_reloc:
+ if (extsym)
+ {
+ error("%s of type %ld for %s", errmsg,
+ (long)ELFW(R_TYPE)(rel->r_info),
+ strtab + extsym->st_name);
+ }
+ else
+ {
+ error("%s of type %ld", errmsg,
+ (long)ELFW(R_TYPE)(rel->r_info));
+ }
+ ret = 0;
+ break;
+ }
+ }
+ }
+
+ /* Finally, take care of the patches. */
+
+ if (f->string_patches)
+ {
+ struct obj_string_patch_struct *p;
+ struct obj_section *strsec;
+ ElfW(Addr) strsec_base;
+ strsec = obj_find_section(f, ".kstrtab");
+ strsec_base = strsec->header.sh_addr;
+
+ for (p = f->string_patches; p ; p = p->next)
+ {
+ struct obj_section *targsec = f->sections[p->reloc_secidx];
+ *(ElfW(Addr) *)(targsec->contents + p->reloc_offset)
+ = strsec_base + p->string_offset;
+ }
+ }
+
+ if (f->symbol_patches)
+ {
+ struct obj_symbol_patch_struct *p;
+
+ for (p = f->symbol_patches; p; p = p->next)
+ {
+ struct obj_section *targsec = f->sections[p->reloc_secidx];
+ *(ElfW(Addr) *)(targsec->contents + p->reloc_offset)
+ = obj_symbol_final_value(f, p->sym);
+ }
+ }
+
+ return ret;
+}
+
+int
+obj_create_image (struct obj_file *f, char *image)
+{
+ struct obj_section *sec;
+ ElfW(Addr) base = f->baseaddr;
+
+ for (sec = f->load_order; sec ; sec = sec->load_next)
+ {
+ char *secimg;
+
+ if (sec->contents == 0)
+ continue;
+
+ secimg = image + (sec->header.sh_addr - base);
+
+ /* Note that we allocated data for NOBITS sections earlier. */
+ memcpy(secimg, sec->contents, sec->header.sh_size);
+ }
+
+ return 1;
+}
diff --git a/mdk-stage1/insmod-modutils/obj/obj_s390.c b/mdk-stage1/insmod-modutils/obj/obj_s390.c
new file mode 100644
index 000000000..3da72e771
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/obj/obj_s390.c
@@ -0,0 +1,245 @@
+/* S/390 specific support for Elf loading and relocation.
+ Copyright 1996, 1997 Linux International.
+
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <string.h>
+#include <assert.h>
+
+#include <module.h>
+#include <obj.h>
+#include <util.h>
+
+
+/*======================================================================*/
+
+struct s390_got_entry
+{
+ int offset;
+ unsigned offset_done : 1;
+ unsigned reloc_done : 1;
+};
+
+struct s390_file
+{
+ struct obj_file root;
+ struct obj_section *got;
+};
+
+struct s390_symbol
+{
+ struct obj_symbol root;
+ struct s390_got_entry gotent;
+};
+
+
+/*======================================================================*/
+
+struct obj_file *
+arch_new_file (void)
+{
+ struct s390_file *f;
+ f = xmalloc(sizeof(*f));
+ f->got = NULL;
+ return &f->root;
+}
+
+struct obj_section *
+arch_new_section (void)
+{
+ return xmalloc(sizeof(struct obj_section));
+}
+
+struct obj_symbol *
+arch_new_symbol (void)
+{
+ struct s390_symbol *sym;
+ sym = xmalloc(sizeof(*sym));
+ memset(&sym->gotent, 0, sizeof(sym->gotent));
+ return &sym->root;
+}
+
+int
+arch_load_proc_section(struct obj_section *sec, int fp)
+{
+ /* Assume it's just a debugging section that we can safely
+ ignore ... */
+ sec->contents = NULL;
+
+ return 0;
+}
+
+enum obj_reloc
+arch_apply_relocation (struct obj_file *f,
+ struct obj_section *targsec,
+ struct obj_section *symsec,
+ struct obj_symbol *sym,
+ Elf32_Rela *rel,
+ Elf32_Addr v)
+{
+ struct s390_file *ifile = (struct s390_file *)f;
+ struct s390_symbol *isym = (struct s390_symbol *)sym;
+
+ Elf32_Addr *loc = (Elf32_Addr *)(targsec->contents + rel->r_offset);
+ Elf32_Addr dot = targsec->header.sh_addr + rel->r_offset;
+ Elf32_Addr got = ifile->got ? ifile->got->header.sh_addr : 0;
+
+ enum obj_reloc ret = obj_reloc_ok;
+
+ switch (ELF32_R_TYPE(rel->r_info))
+ {
+ case R_390_NONE:
+ break;
+
+ case R_390_32:
+ *loc += v;
+ break;
+
+ case R_390_PLT32:
+ case R_390_PC32:
+ *loc += v - dot;
+ break;
+
+ case R_390_GLOB_DAT:
+ case R_390_JMP_SLOT:
+ *loc = v;
+ break;
+
+ case R_390_RELATIVE:
+ *loc += f->baseaddr;
+ break;
+
+ case R_390_GOTPC:
+ assert(got != 0);
+ *loc += got - dot;
+ break;
+
+ case R_390_GOT32:
+ assert(isym != NULL);
+ if (!isym->gotent.reloc_done)
+ {
+ isym->gotent.reloc_done = 1;
+ *(Elf32_Addr *)(ifile->got->contents + isym->gotent.offset) = v;
+ }
+ *loc += isym->gotent.offset;
+ break;
+
+ case R_390_GOTOFF:
+ assert(got != 0);
+ *loc += v - got;
+ break;
+
+ default:
+ ret = obj_reloc_unhandled;
+ break;
+ }
+
+ return ret;
+}
+
+int
+arch_create_got (struct obj_file *f)
+{
+ struct s390_file *ifile = (struct s390_file *)f;
+ int i, n, offset = 0, gotneeded = 0;
+
+ n = ifile->root.header.e_shnum;
+ for (i = 0; i < n; ++i)
+ {
+ struct obj_section *relsec, *symsec, *strsec;
+ Elf32_Rel *rel, *relend;
+ Elf32_Sym *symtab;
+ const char *strtab;
+
+ relsec = ifile->root.sections[i];
+ if (relsec->header.sh_type != SHT_REL)
+ continue;
+
+ symsec = ifile->root.sections[relsec->header.sh_link];
+ strsec = ifile->root.sections[symsec->header.sh_link];
+
+ rel = (Elf32_Rel *)relsec->contents;
+ relend = rel + (relsec->header.sh_size / sizeof(Elf32_Rel));
+ symtab = (Elf32_Sym *)symsec->contents;
+ strtab = (const char *)strsec->contents;
+
+ for (; rel < relend; ++rel)
+ {
+ Elf32_Sym *extsym;
+ struct s390_symbol *intsym;
+ const char *name;
+
+ switch (ELF32_R_TYPE(rel->r_info))
+ {
+ case R_390_GOTPC:
+ case R_390_GOTOFF:
+ gotneeded = 1;
+ default:
+ continue;
+
+ case R_390_GOT32:
+ break;
+ }
+
+ extsym = &symtab[ELF32_R_SYM(rel->r_info)];
+ if (extsym->st_name)
+ name = strtab + extsym->st_name;
+ else
+ name = f->sections[extsym->st_shndx]->name;
+ intsym = (struct s390_symbol *)obj_find_symbol(&ifile->root, name);
+
+ if (!intsym->gotent.offset_done)
+ {
+ intsym->gotent.offset_done = 1;
+ intsym->gotent.offset = offset;
+ offset += 4;
+ }
+ }
+ }
+
+ if (offset > 0 || gotneeded)
+ ifile->got = obj_create_alloced_section(&ifile->root, ".got", 4, offset);
+
+ return 1;
+}
+
+int
+arch_init_module (struct obj_file *f, struct module *m)
+{
+ return 1;
+}
+
+int
+arch_finalize_section_address(struct obj_file *f, Elf32_Addr base)
+{
+ int i, n = f->header.e_shnum;
+
+ f->baseaddr = base;
+ for (i = 0; i < n; ++i)
+ f->sections[i]->header.sh_addr += base;
+ return 1;
+}
+
+int
+arch_archdata (struct obj_file *fin, struct obj_section *sec)
+{
+ return 0;
+}
diff --git a/mdk-stage1/insmod-modutils/obj/obj_sparc.c b/mdk-stage1/insmod-modutils/obj/obj_sparc.c
new file mode 100644
index 000000000..1a03c9090
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/obj/obj_sparc.c
@@ -0,0 +1,226 @@
+/* Sparc specific support for Elf loading and relocation.
+ Copyright 1996, 1997 Linux International.
+
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <stddef.h>
+#include <module.h>
+#include <obj.h>
+#include <util.h>
+
+
+/*======================================================================*/
+
+struct obj_file *
+arch_new_file (void)
+{
+ return xmalloc(sizeof(struct obj_file));
+}
+
+struct obj_section *
+arch_new_section (void)
+{
+ return xmalloc(sizeof(struct obj_section));
+}
+
+struct obj_symbol *
+arch_new_symbol (void)
+{
+ return xmalloc(sizeof(struct obj_symbol));
+}
+
+int
+arch_load_proc_section(struct obj_section *sec, int fp)
+{
+ /* Assume it's just a debugging section that we can safely
+ ignore ... */
+ sec->contents = NULL;
+
+ return 0;
+}
+
+enum obj_reloc
+arch_apply_relocation (struct obj_file *ef,
+ struct obj_section *targsec,
+ struct obj_section *symsec,
+ struct obj_symbol *sym,
+ Elf32_Rela *rel,
+ Elf32_Addr v)
+{
+ Elf32_Addr *loc = (Elf32_Addr *)(targsec->contents + rel->r_offset);
+ Elf32_Addr dot = targsec->header.sh_addr + rel->r_offset;
+
+ enum obj_reloc ret = obj_reloc_ok;
+
+ switch (ELF32_R_TYPE(rel->r_info))
+ {
+ case R_SPARC_NONE:
+ break;
+ case R_SPARC_8:
+ if (v > 0xff)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0xff) | (v & 0xff);
+ break;
+ case R_SPARC_16:
+ if (v > 0xffff)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0xffff) | (v & 0xffff);
+ break;
+ case R_SPARC_32:
+ *loc = v;
+ break;
+ case R_SPARC_DISP8:
+ v -= dot;
+ if (v > 0xff)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0xff) | (v & 0xff);
+ break;
+ case R_SPARC_DISP16:
+ v -= dot;
+ if (v > 0xffff)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0xffff) | (v & 0xffff);
+ break;
+ case R_SPARC_DISP32:
+ v -= dot;
+ *loc = v;
+ break;
+ case R_SPARC_WDISP30:
+ v -= dot;
+ if (v % 4)
+ ret = obj_reloc_dangerous;
+ *loc = (*loc & ~0x3fffffff) | (v >> 2);
+ break;
+ case R_SPARC_WDISP22:
+ v -= dot;
+ if (v % 4)
+ ret = obj_reloc_dangerous;
+ *loc = (*loc & ~0x3fffff) | ((v >> 2) & 0x3fffff);
+ break;
+ case R_SPARC_HI22:
+ *loc = (*loc & ~0x3fffff) | (v >> 10);
+ break;
+ case R_SPARC_22:
+ if (v > 0x3fffff)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0x3fffff) | (v & 0x3fffff);
+ break;
+ case R_SPARC_13:
+ if (v > 0x1fff)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0x1fff) | (v & 0x1fff);
+ break;
+ case R_SPARC_LO10:
+ *loc = (*loc & ~0x3ff) | (v & 0x3ff);
+ break;
+
+ case R_SPARC_PC10:
+ v -= dot;
+ *loc = (*loc & ~0x3ff) | (v & 0x3ff);
+ break;
+ case R_SPARC_PC22:
+ v -= dot;
+ *loc = (*loc & ~0x3fffff) | (v >> 10);
+ break;
+
+ case R_SPARC_UA32:
+ *(((char *)loc) + 0) = (char)(v >> 24);
+ *(((char *)loc) + 1) = (char)(v >> 16);
+ *(((char *)loc) + 2) = (char)(v >> 8);
+ *(((char *)loc) + 3) = (char)v;
+ break;
+
+#ifdef R_SPARC_10
+ case R_SPARC_10:
+ if (v > 0x3ff)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0x3ff) | (v & 0x3ff);
+ break;
+ case R_SPARC_11:
+ if (v > 0x7ff)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0x7ff) | (v & 0x7ff);
+ break;
+ case R_SPARC_WDISP16:
+ v -= dot;
+ if (v % 4)
+ ret = obj_reloc_dangerous;
+ *loc = (*loc & ~0x303fff) | ((v << 4) & 0x300000) | ((v >> 2) & 0x3fff);
+ break;
+ case R_SPARC_WDISP19:
+ v -= dot;
+ if (v % 4)
+ ret = obj_reloc_dangerous;
+ *loc = (*loc & ~0x7ffff) | ((v >> 2) & 0x7ffff);
+ break;
+ case R_SPARC_7:
+ if (v > 0x7f)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0x7f) | (v & 0x7f);
+ break;
+ case R_SPARC_5:
+ if (v > 0x1f)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0x1f) | (v & 0x1f);
+ break;
+ case R_SPARC_6:
+ if (v > 0x3f)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0x3f) | (v & 0x3f);
+ break;
+#endif /* R_SPARC_10 */
+
+ default:
+ ret = obj_reloc_unhandled;
+ break;
+ }
+
+ return ret;
+}
+
+int
+arch_create_got (struct obj_file *ef)
+{
+ return 1;
+}
+
+int
+arch_init_module (struct obj_file *f, struct module *mod)
+{
+ return 1;
+}
+
+int
+arch_finalize_section_address(struct obj_file *f, Elf32_Addr base)
+{
+ int i, n = f->header.e_shnum;
+
+ f->baseaddr = base;
+ for (i = 0; i < n; ++i)
+ f->sections[i]->header.sh_addr += base;
+ return 1;
+}
+
+int
+arch_archdata (struct obj_file *fin, struct obj_section *sec)
+{
+ return 0;
+}
diff --git a/mdk-stage1/insmod-modutils/obj/obj_sparc64.c b/mdk-stage1/insmod-modutils/obj/obj_sparc64.c
new file mode 100644
index 000000000..84e8d18a0
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/obj/obj_sparc64.c
@@ -0,0 +1,352 @@
+/* Sparc64 specific support for Elf loading and relocation.
+ Copyright 1997 Linux International.
+
+ Contributed by Jakub Jelinek <jj@sunsite.mff.cuni.cz>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <stddef.h>
+#include <module.h>
+#include <obj.h>
+#include <util.h>
+
+
+/*======================================================================*/
+
+struct obj_file *
+arch_new_file (void)
+{
+ return xmalloc(sizeof(struct obj_file));
+}
+
+struct obj_section *
+arch_new_section (void)
+{
+ return xmalloc(sizeof(struct obj_section));
+}
+
+struct obj_symbol *
+arch_new_symbol (void)
+{
+ return xmalloc(sizeof(struct obj_symbol));
+}
+
+#ifdef BROKEN_SPARC64_RELOCS
+
+#undef R_SPARC_PLT32
+#undef R_SPARC_HIPLT22
+#undef R_SPARC_LOPLT10
+#undef R_SPARC_PCPLT32
+#undef R_SPARC_PCPLT22
+#undef R_SPARC_PCPLT10
+#undef R_SPARC_10
+#undef R_SPARC_11
+#undef R_SPARC_64
+#undef R_SPARC_OLO10
+#undef R_SPARC_HH22
+#undef R_SPARC_HM10
+#undef R_SPARC_LM22
+#undef R_SPARC_PC_HH22
+#undef R_SPARC_PC_HM10
+#undef R_SPARC_PC_LM22
+#undef R_SPARC_WDISP16
+#undef R_SPARC_WDISP19
+#undef R_SPARC_GLOB_JMP
+#undef R_SPARC_7
+#undef R_SPARC_5
+#undef R_SPARC_6
+
+#define R_SPARC_10 24
+#define R_SPARC_11 25
+#define R_SPARC_64 26
+#define R_SPARC_OLO10 27
+#define R_SPARC_HH22 28
+#define R_SPARC_HM10 29
+#define R_SPARC_LM22 30
+#define R_SPARC_PC_HH22 31
+#define R_SPARC_PC_HM10 32
+#define R_SPARC_PC_LM22 33
+#define R_SPARC_WDISP16 34
+#define R_SPARC_WDISP19 35
+#define R_SPARC_GLOB_JMP 36
+#define R_SPARC_7 37
+#define R_SPARC_5 38
+#define R_SPARC_6 39
+
+#else
+
+#ifndef R_SPARC_64
+
+#define R_SPARC_64 32
+#define R_SPARC_OLO10 33
+#define R_SPARC_HH22 34
+#define R_SPARC_HM10 35
+#define R_SPARC_LM22 36
+#define R_SPARC_PC_HH22 37
+#define R_SPARC_PC_HM10 38
+#define R_SPARC_PC_LM22 39
+
+#endif
+
+#endif
+
+int
+arch_load_proc_section(struct obj_section *sec, int fp)
+{
+ /* Assume it's just a debugging section that we can safely
+ ignore ... */
+ sec->contents = NULL;
+
+ return 0;
+}
+
+#define ELF64_R_TYPE_ID(info) ((info) & 0xff)
+#define ELF64_R_TYPE_DATA(info) ((info) >> 8)
+
+enum obj_reloc
+arch_apply_relocation (struct obj_file *ef,
+ struct obj_section *targsec,
+ struct obj_section *symsec,
+ struct obj_symbol *sym,
+ Elf64_Rela *rel,
+ Elf64_Addr v)
+{
+ unsigned int *loc = (unsigned int *)(targsec->contents + rel->r_offset);
+ unsigned int dot = targsec->header.sh_addr + rel->r_offset;
+
+ enum obj_reloc ret = obj_reloc_ok;
+
+ switch (ELF64_R_TYPE_ID(rel->r_info))
+ {
+ case R_SPARC_NONE:
+ break;
+
+ case R_SPARC_64:
+ case R_SPARC_UA64:
+ if (! ((long) loc & 3)) {
+ /* Common in .eh_frame */
+ ((unsigned int *) loc) [0] = v >> 32;
+ ((unsigned int *) loc) [1] = v;
+ break;
+ }
+ ((unsigned char *) loc) [0] = v >> 56;
+ ((unsigned char *) loc) [1] = v >> 48;
+ ((unsigned char *) loc) [2] = v >> 40;
+ ((unsigned char *) loc) [3] = v >> 32;
+ ((unsigned char *) loc) [4] = v >> 24;
+ ((unsigned char *) loc) [5] = v >> 16;
+ ((unsigned char *) loc) [6] = v >> 8;
+ ((unsigned char *) loc) [7] = v;
+ break;
+ case R_SPARC_32:
+ case R_SPARC_UA32:
+ if (! ((long) loc & 3)) {
+ *loc = v;
+ break;
+ }
+ ((unsigned char *) loc) [0] = v >> 24;
+ ((unsigned char *) loc) [1] = v >> 16;
+ ((unsigned char *) loc) [2] = v >> 8;
+ ((unsigned char *) loc) [3] = v;
+ break;
+ case R_SPARC_16:
+ if (v > 0xffff)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0xffff) | (v & 0xffff);
+ break;
+ case R_SPARC_8:
+ if (v > 0xff)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0xff) | (v & 0xff);
+ break;
+
+ case R_SPARC_DISP32:
+ v -= dot;
+ *loc = v;
+ break;
+ case R_SPARC_DISP16:
+ v -= dot;
+ if (v > 0xffff)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0xffff) | (v & 0xffff);
+ break;
+ case R_SPARC_DISP8:
+ v -= dot;
+ if (v > 0xff)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0xff) | (v & 0xff);
+ break;
+ case R_SPARC_WDISP30:
+ v -= dot;
+ if (v % 4)
+ ret = obj_reloc_dangerous;
+ *loc = (*loc & ~0x3fffffff) | ((v >> 2) & 0x3fffffff);
+ break;
+
+ /* MEDLOW code model relocs */
+ case R_SPARC_LO10:
+ *loc = (*loc & ~0x3ff) | (v & 0x3ff);
+ break;
+ case R_SPARC_HI22:
+ *loc = (*loc & ~0x3fffff) | (v >> 10);
+ break;
+ case R_SPARC_OLO10:
+ *loc = (*loc & ~0x1fff) | (((v & 0x3ff) + ELF64_R_TYPE_DATA (rel->r_info)) & 0x1fff);
+ break;
+
+ /* MEDMID code model relocs */
+ case R_SPARC_H44:
+ *loc = (*loc & ~0x3fffff) | (v >> 22);
+ break;
+ case R_SPARC_M44:
+ *loc = (*loc & ~0x3ff) | ((v >> 12) & 0x3ff);
+ break;
+ case R_SPARC_L44:
+ *loc = (*loc & ~0xfff) | (v & 0xfff);
+ break;
+
+ /* MEDANY code model relocs */
+ case R_SPARC_HH22:
+ *loc = (*loc & ~0x3fffff) | (v >> 42);
+ break;
+ case R_SPARC_HM10:
+ *loc = (*loc & ~0x3ff) | ((v >> 32) & 0x3ff);
+ break;
+ case R_SPARC_LM22:
+ *loc = (*loc & ~0x3fffff) | ((v >> 10) & 0x3fffff);
+ break;
+
+ case R_SPARC_WDISP22:
+ v -= dot;
+ if (v % 4)
+ ret = obj_reloc_dangerous;
+ *loc = (*loc & ~0x3fffff) | ((v >> 2) & 0x3fffff);
+ break;
+ case R_SPARC_22:
+ if (v > 0x3fffff)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0x3fffff) | (v & 0x3fffff);
+ break;
+ case R_SPARC_13:
+ if (v > 0x1fff)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0x1fff) | (v & 0x1fff);
+ break;
+
+ case R_SPARC_PC10:
+ v -= dot;
+ *loc = (*loc & ~0x3ff) | (v & 0x3ff);
+ break;
+ case R_SPARC_PC22:
+ v -= dot;
+ *loc = (*loc & ~0x3fffff) | ((v >> 10) & 0x3fffff);
+ break;
+
+#ifdef R_SPARC_10
+ case R_SPARC_10:
+ if (v > 0x3ff)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0x3ff) | (v & 0x3ff);
+ break;
+ case R_SPARC_11:
+ if (v > 0x7ff)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0x7ff) | (v & 0x7ff);
+ break;
+
+#ifdef R_SPARC_64
+ case R_SPARC_PC_HH22:
+ v -= dot;
+ *loc = (*loc & ~0x3fffff) | (v >> 42);
+ break;
+ case R_SPARC_PC_HM10:
+ v -= dot;
+ *loc = (*loc & ~0x3ff) | ((v >> 32) & 0x3ff);
+ break;
+ case R_SPARC_PC_LM22:
+ v -= dot;
+ *loc = (*loc & ~0x3fffff) | ((v >> 10) & 0x3fffff);
+ break;
+#endif
+
+ case R_SPARC_WDISP16:
+ v -= dot;
+ if (v % 4)
+ ret = obj_reloc_dangerous;
+ *loc = (*loc & ~0x303fff) | ((v << 4) & 0x300000) | ((v >> 2) & 0x3fff);
+ break;
+ case R_SPARC_WDISP19:
+ v -= dot;
+ if (v % 4)
+ ret = obj_reloc_dangerous;
+ *loc = (*loc & ~0x7ffff) | ((v >> 2) & 0x7ffff);
+ break;
+ case R_SPARC_7:
+ if (v > 0x7f)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0x7f) | (v & 0x7f);
+ break;
+ case R_SPARC_5:
+ if (v > 0x1f)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0x1f) | (v & 0x1f);
+ break;
+ case R_SPARC_6:
+ if (v > 0x3f)
+ ret = obj_reloc_overflow;
+ *loc = (*loc & ~0x3f) | (v & 0x3f);
+ break;
+#endif /* R_SPARC_10 */
+
+ default:
+ ret = obj_reloc_unhandled;
+ break;
+ }
+
+ return ret;
+}
+
+int
+arch_create_got (struct obj_file *ef)
+{
+ return 1;
+}
+
+int
+arch_init_module (struct obj_file *f, struct module *mod)
+{
+ return 1;
+}
+
+int
+arch_finalize_section_address(struct obj_file *f, Elf64_Addr base)
+{
+ int i, n = f->header.e_shnum;
+
+ f->baseaddr = base;
+ for (i = 0; i < n; ++i)
+ f->sections[i]->header.sh_addr += base;
+ return 1;
+}
+
+int
+arch_archdata (struct obj_file *fin, struct obj_section *sec)
+{
+ return 0;
+}
diff --git a/mdk-stage1/insmod-modutils/util/Makefile b/mdk-stage1/insmod-modutils/util/Makefile
new file mode 100644
index 000000000..844f8c0dc
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/Makefile
@@ -0,0 +1,39 @@
+ #******************************************************************************
+ #
+ # insmod from modutils (generic)
+ #
+ # $Id$
+ #
+ # Copyright 1996, 1997 Linux International.
+ #
+ #*****************************************************************************
+
+top_dir = ../..
+
+include $(top_dir)/Makefile.common
+
+
+all: libutil.a libutil-STANDALONE.a #libutil-DIET.a
+
+clean:
+ rm -f *.o *.a
+
+
+FLAGS = -c -Wall -Os -fomit-frame-pointer -I./../include -D_GNU_SOURCE -DELF_MACHINE_H='"elf_$(ARCH).h"' -DARCH_$(ARCH) -DHAVE_WORDEXP=1 -DHAVE_GLOB=1 -DCONFIG_ROOT_CHECK_OFF=0
+
+OBJS = xmalloc.o xrealloc.o xstrcat.o xstrdup.o xsystem.o xftw.o \
+ modstat.o meta_expand.o config.o snap_shot.o arch64.o gzfiles.o sys_nim.o sys_oim.o
+
+libutil.a: $(OBJS) logger.o
+ ar cru $@ $^
+ ranlib $@
+
+libutil-STANDALONE.a: $(OBJS) logger-standalone.o
+ ar cru $@ $^
+ ranlib $@
+
+logger-standalone.o: logger.c
+ gcc $(FLAGS) $(GLIBC_INCLUDES) -o $@ -D_STANDALONE_ logger.c
+
+.c.o:
+ gcc $(FLAGS) $(GLIBC_INCLUDES) -c $<
diff --git a/mdk-stage1/insmod-modutils/util/alias.h b/mdk-stage1/insmod-modutils/util/alias.h
new file mode 100644
index 000000000..c925a04f3
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/alias.h
@@ -0,0 +1,244 @@
+/*
+ * This file is split out from config.c for easier editing
+ */
+
+/*
+ * tbpath and tbtype are used to build the complete set of paths for finding
+ * modules, but only when we search for individual directories, they are not
+ * used for [boot] and [toplevel] searches.
+ */
+static char *tbpath[] =
+{
+ "/lib/modules",
+ NULL /* marks the end of the list! */
+};
+
+char *tbtype[] =
+{
+ "kernel", /* as of 2.3.14 this must be first */
+ "fs",
+ "net",
+ "scsi",
+ "block",
+ "cdrom",
+ "ipv4",
+ "ipv6",
+ "sound",
+ "fc4",
+ "video",
+ "misc",
+ "pcmcia",
+ "atm",
+ "usb",
+ "ide",
+ "ieee1394",
+ "mtd",
+ NULL /* marks the end of the list! */
+};
+
+/*
+ * This is the list of pre-defined aliases.
+ * Each entry can be overridden by an entry in /etc/modules.conf
+ */
+char *aliaslist[] =
+{
+ "binfmt-204 binfmt_aout",
+ "binfmt-263 binfmt_aout",
+ "binfmt-264 binfmt_aout",
+ "binfmt-267 binfmt_aout",
+ "binfmt-387 binfmt_aout",
+ "binfmt-332 iBCS",
+ "binfmt--310 binfmt_java",
+
+ "block-major-1 rd",
+ "block-major-2 floppy",
+ "block-major-3 ide-probe-mod",
+ "block-major-7 loop",
+ "block-major-8 sd_mod",
+ "block-major-9 md", /* For modular RAID */
+ "block-major-11 sr_mod",
+ "block-major-13 xd",
+ "block-major-15 cdu31a",
+ "block-major-16 gscd",
+ "block-major-17 optcd",
+ "block-major-18 sjcd",
+ "block-major-20 mcdx",
+ "block-major-22 ide-probe-mod",
+ "block-major-23 mcd",
+ "block-major-24 sonycd535",
+ "block-major-25 sbpcd",
+ "block-major-26 sbpcd",
+ "block-major-27 sbpcd",
+ "block-major-29 aztcd",
+ "block-major-32 cm206",
+ "block-major-33 ide-probe-mod",
+ "block-major-34 ide-probe-mod",
+ "block-major-37 ide-tape",
+ "block-major-44 ftl", /* from David Woodhouse <dwmw2@infradead.org> */
+ "block-major-56 ide-probe-mod",
+ "block-major-57 ide-probe-mod",
+ "block-major-88 ide-probe-mod",
+ "block-major-89 ide-probe-mod",
+ "block-major-90 ide-probe-mod",
+ "block-major-91 ide-probe-mod",
+ "block-major-93 nftl", /* from David Woodhouse <dwmw2@infradead.org> */
+
+ "char-major-4 serial",
+ "char-major-5 serial",
+ "char-major-6 lp",
+ "char-major-9 st",
+ "char-major-10 off", /* was: mouse, was: misc */
+ "char-major-10-0 busmouse", /* /dev/logibm Logitech bus mouse */
+ "char-major-10-1 off", /* /dev/psaux PS/2-style mouse port */
+ "char-major-10-2 msbusmouse", /* /dev/inportbm Microsoft Inport bus mouse */
+ "char-major-10-3 atixlmouse", /* /dev/atibm ATI XL bus mouse */
+ /* /dev/jbm J-mouse */
+ /* /dev/amigamouse Amiga mouse (68k/Amiga) */
+ /* /dev/atarimouse Atari mouse */
+ /* /dev/sunmouse Sun mouse */
+ /* /dev/beep Fancy beep device */
+ /* /dev/modreq Kernel module load request */
+ "char-major-10-130 wdt", /* /dev/watchdog Watchdog timer port */
+ "char-major-10-131 wdt", /* /dev/temperature Machine internal temperature */
+ /* /dev/hwtrap Hardware fault trap */
+ /* /dev/exttrp External device trap */
+ "char-major-10-135 off", /* rtc cannot be compiled as a module */
+ "char-major-10-139 openprom", /* /dev/openprom Linux/Sparc interface */
+ "char-major-10-144 nvram", /* from Tigran Aivazian <tigran@sco.COM> */
+ "char-major-10-157 applicom", /* from David Woodhouse <dwmw2@infradead.org> */
+ "char-major-10-175 agpgart", /* /dev/agpgart GART AGP mapping access */
+ "char-major-10-184 microcode", /* Tigran Aivazian <tigran@veritas.com> */
+
+ "char-major-14 soundcore",
+ "char-major-19 cyclades",
+ "char-major-20 cyclades",
+ "char-major-21 sg",
+ "char-major-22 pcxx", /* ?? */
+ "char-major-23 pcxx", /* ?? */
+ "char-major-27 ftape",
+ "char-major-34 scc",
+ "char-major-35 tclmidi",
+ "char-major-36 netlink",
+ "char-major-37 ide-tape",
+ "char-major-48 riscom8",
+ "char-major-49 riscom8",
+ "char-major-57 esp",
+ "char-major-58 esp",
+ "char-major-63 kdebug",
+ "char-major-90 mtdchar", /* from David Woodhouse <dwmw2@infradead.org> */
+ "char-major-99 ppdev",
+ "char-major-107 3dfx", /* from Tigran Aivazian <tigran@sco.COM> */
+ "char-major-161 ircomm-tty",
+
+ "dos msdos",
+ "dummy0 dummy",
+ "dummy1 dummy",
+ "eth0 off",
+ "iso9660 isofs",
+ "md-personality-1 linear",
+ "md-personality-2 raid0",
+ "md-personality-3 raid1",
+ "md-personality-4 raid5",
+
+ "net-pf-1 unix", /* PF_UNIX 1 Unix domain sockets */
+ "net-pf-2 ipv4", /* PF_INET 2 Internet IP Protocol */
+ "net-pf-3 off", /* PF_AX25 3 Amateur Radio AX.25 */
+ "net-pf-4 ipx", /* PF_IPX 4 Novell IPX */
+ "net-pf-5 appletalk", /* PF_APPLETALK 5 Appletalk DDP */
+ "net-pf-6 off", /* PF_NETROM 6 Amateur radio NetROM */
+ /* PF_BRIDGE 7 Multiprotocol bridge */
+ /* PF_AAL5 8 Reserved for Werner's ATM */
+ /* PF_X25 9 Reserved for X.25 project */
+ /* PF_INET6 10 IP version 6 */
+
+ /* next two from <dairiki@matthews.dairiki.org> Thanks! */
+ "net-pf-17 af_packet",
+ "net-pf-19 off", /* acorn econet */
+
+ "netalias-2 ip_alias",
+ "plip0 plip",
+ "plip1 plip",
+ "cipcb0 cipcb",
+ "cipcb1 cipcb",
+ "cipcb2 cipcb",
+ "cipcb3 cipcb",
+ "ppp0 ppp",
+ "ppp1 ppp",
+ "scsi_hostadapter off", /* if not in config file */
+ "slip0 slip",
+ "slip1 slip",
+ "tty-ldisc-1 slip",
+ "tty-ldisc-3 ppp",
+ "ppp-compress-21 bsd_comp",
+ "ppp-compress-24 ppp_deflate",
+ "ppp-compress-26 ppp_deflate",
+
+#ifndef __sparc__
+ "parport_lowlevel parport_pc",
+#else
+ "parport_lowlevel parport_ax",
+#endif
+
+ "tty-ldisc-11 irtty",
+
+ "usbdevfs usbcore",
+
+ NULL /* marks the end of the list! */
+};
+
+/*
+ * This is the list of pre-defined options.
+ * Each entry can be overridden by an entry in /etc/modules.conf
+ */
+char *optlist[] =
+{
+ "dummy0 -o dummy0",
+ "dummy1 -o dummy1",
+ "sb io=0x220 irq=7 dma=1 dma16=5 mpu_io=0x330",
+ NULL /* marks the end of the list! */
+};
+
+/*
+ * This is the list of pre-defined "above"s,
+ * used for pull-in of additional modules
+ * Each entry can be overridden by an entry in /etc/modules.conf
+ */
+char *above[] =
+{
+ NULL /* marks the end of the list! */
+};
+
+/*
+ * This is the list of pre-defined "below"s,
+ * used for push-in of additional modules
+ * Each entry can be overridden by an entry in /etc/modules.conf
+ */
+char *below[] =
+{
+ NULL /* marks the end of the list! */
+};
+
+/*
+ * This is the list of pre-defined "prune"s,
+ * used to exclude paths from scan of /lib/modules.
+ * /etc/modules.conf can add entries but not remove them.
+ */
+char *prune[] =
+{
+ ".rhkmvtag",
+ "modules.dep",
+ "modules.generic_string",
+ "modules.pcimap",
+ "modules.isapnpmap",
+ "modules.usbmap",
+ "modules.parportmap",
+ "System.map",
+ ".config",
+ "build", /* symlink to source tree */
+ "vmlinux",
+ "vmlinuz",
+ "bzImage",
+ "zImage",
+ ".rhkmvtag", /* wish RedHat had told me before they did this */
+ NULL /* marks the end of the list! */
+};
diff --git a/mdk-stage1/insmod-modutils/util/arch64.c b/mdk-stage1/insmod-modutils/util/arch64.c
new file mode 100644
index 000000000..4d5ace223
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/arch64.c
@@ -0,0 +1,35 @@
+/* Misc utility functions.
+ Copyright 1996, 1997 Linux International.
+ Written by Keith Owens <kaos@ocs.com.au>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/utsname.h>
+#include "util.h"
+
+/*======================================================================*/
+
+/* Indicate if the current machine uses 64 bit architecture */
+int arch64(void)
+{
+ struct utsname u;
+ return(!uname(&u) && strstr(u.machine, "64"));
+}
diff --git a/mdk-stage1/insmod-modutils/util/config.c b/mdk-stage1/insmod-modutils/util/config.c
new file mode 100644
index 000000000..a860920f6
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/config.c
@@ -0,0 +1,1591 @@
+/*
+ * Handle the configuration, including /etc/modules.conf
+ *
+ * Copyright 1994, 1995, 1996, 1997:
+ * Jacques Gelinas <jack@solucorp.qc.ca>
+ * Björn Ekwall <bj0rn@blox.se> February 1999
+ * Keith Owens <kaos@ocs.com.au> October 1999
+ *
+ * "kernelversion" idea from the Debian release via:
+ * Wichert Akkerman <wakkerma@cs.leidenuniv.nl>
+ *
+ * Björn, inspired by Richard Henderson <rth@twiddle.net>, cleaned up
+ * the wildcard handling and started using ftw in March 1999
+ * Cleanup of hardcoded arrays: Björn Ekwall <bj0rn@blox.se> March 1999
+ * Many additional keywords: Björn Ekwall <bj0rn@blox.se> (C) March 1999
+ * Standardize on /etc/modules.conf Keith Owens <kaos@ocs.com.au> October 1999
+ *
+ * Alpha typecast:Michal Jaegermann <michal@ellpspace.math.ualberta.ca>
+ *
+ * This file is part of the Linux modutils.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Specification: /etc/modules.conf / format
+ * Modules may be located at different places in the filesystem.
+ *
+ * The file /etc/modules.conf contains different definitions to
+ * control the manipulation of modules.
+ *
+ * Standard Unix style comments and continuation line are supported.
+ * Comments begin with a # and continue until the end of the line.
+ * A line continues on the next one if the last non-white character
+ * is a \.
+ */
+/* #Specification: /etc/modules.conf / format / official name */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <limits.h>
+#include <sys/param.h>
+#include <errno.h>
+
+#include "util.h"
+#include "config.h"
+#include "alias.h"
+
+int flag_autoclean; /* set/used by modprobe and insmod */
+
+struct utsname uts_info;
+
+struct PATH_TYPE *modpath;
+int nmodpath = 0;
+static int maxpath = 0;
+
+struct EXEC_TYPE *execs;
+int nexecs = 0;
+static int maxexecs = 0;
+
+OPT_LIST *opt_list;
+static int n_opt_list;
+
+OPT_LIST *abovelist;
+static int n_abovelist;
+
+OPT_LIST *belowlist;
+static int n_belowlist;
+
+OPT_LIST *prunelist;
+static int n_prunelist;
+
+OPT_LIST *probe_list;
+static int n_probe_list;
+
+OPT_LIST *probeall_list;
+static int n_probeall_list;
+
+OPT_LIST *aliases;
+static int n_aliases;
+
+char *persistdir = "/var/lib/modules/persist";
+
+const char symprefix[] = SYMPREFIX;
+
+char *insmod_opt = NULL;
+char *config_file = NULL; /* Which file was actually used */
+time_t config_mtime;
+int root_check_off = CONFIG_ROOT_CHECK_OFF; /* Default is modules must be owned by root */
+static char *config_version; /* Hack for config_add */
+int quick = 0; /* Option -A */
+
+/* The initialization order must match the gen_file_enum order in config.h */
+struct gen_files gen_file[] = {
+ {"generic_string", NULL, 0},
+ {"pcimap", NULL, 0},
+ {"isapnpmap", NULL, 0},
+ {"usbmap", NULL, 0},
+ {"parportmap", NULL, 0},
+ {"dep", NULL, 0},
+};
+
+const int gen_file_count = sizeof(gen_file)/sizeof(gen_file[0]);
+
+int flag_verbose;
+
+unsigned long safemode;
+
+void verbose(const char *ctl,...)
+{
+ if (flag_verbose) {
+ va_list list;
+ va_start(list, ctl);
+ vprintf(ctl, list);
+ va_end(list);
+ fflush(stdout);
+ }
+}
+
+
+/*
+ * Check to see if the existing modules.xxx files need updating,
+ * based on the timestamps of the modules and the config file.
+ */
+static int check_update (const char *file, const struct stat *sb)
+{
+ int len = strlen(file);
+ int i;
+
+ if (!S_ISREG(sb->st_mode))
+ return 0;
+ for (i = 0; i < gen_file_count; ++i) {
+ if (sb->st_mtime > gen_file[i].mtime)
+ break;
+ }
+ if (i == gen_file_count)
+ return 0; /* All generated files are up to date */
+
+ if (len > 2 && !strcmp(file + len - 2, ".o"))
+ return 1;
+ else if (len > 4 && !strcmp(file + len - 4, ".mod"))
+ return 1;
+#ifdef CONFIG_USE_ZLIB
+ else if (len > 5 && !strcmp(file + len - 5, ".o.gz"))
+ return 1;
+#endif
+ return 0;
+}
+
+static int need_update (const char *force_ver, const char *base_dir)
+{
+ struct stat tmp;
+ char dep[PATH_MAX];
+ int i;
+ uname (&uts_info);
+ if (!force_ver)
+ force_ver = uts_info.release;
+
+ if (strlen (force_ver) > 50)
+ /* That's just silly. */
+ return 1;
+
+ for (i = 0; i < gen_file_count; ++i) {
+ if (stat(gen_file[i].name, &tmp))
+ return 1; /* No dependency file yet, so we need to build it. */
+ gen_file[i].mtime = tmp.st_mtime;
+ }
+
+ if (stat ("/etc/modules.conf", &tmp) &&
+ stat ("/etc/conf.modules", &tmp))
+ return 1;
+
+ for (i = 0; i < gen_file_count; ++i) {
+ if (tmp.st_mtime > gen_file[i].mtime)
+ return 1; /* Config file is newer. */
+ }
+
+ snprintf (dep, sizeof(dep), "%s/lib/modules/%s", base_dir, force_ver);
+ return xftw (dep, check_update);
+}
+
+
+/*
+ * Strip white char at the end of a string.
+ * Return the address of the last non white char + 1 (point on the '\0').
+ */
+static char *strip_end(char *str)
+{
+ int len = strlen(str);
+
+ for (str += len - 1; len > 0 && (isspace(*str)); --len, --str)
+ *str = '\0';
+ return str + 1;
+}
+
+/*
+ * Read a line of a configuration file and process continuation lines.
+ * Return buf, or NULL if EOF.
+ * Blank at the end of line are always stripped.
+ * Everything on a line following comchar is a comment.
+ *
+ * Continuation character is \
+ * Comment character is #
+ */
+char *fgets_strip(char *buf, int sizebuf, FILE * fin, int *lineno)
+{
+ int nocomment = 1; /* No comments found ? */
+ int contline = 0;
+ char *start = buf;
+ char *ret = NULL;
+ char comchar = '#';
+ char contchar = '\\';
+
+ *buf = '\0';
+
+ while (fgets(buf, sizebuf, fin) != NULL) {
+ char *end = strip_end(buf);
+ char *pt = strchr(buf, comchar);
+
+ if (pt != NULL) {
+ nocomment = 0;
+ *pt = '\0';
+ end = strip_end(buf);
+ }
+
+ if (lineno != NULL)
+ (*lineno)++;
+ ret = start;
+ if (contline) {
+ char *pt = buf;
+
+ while (isspace(*pt))
+ pt++;
+ if (pt > buf + 1) {
+ strcpy(buf + 1, pt); /* safe, backward copy */
+ buf[0] = ' ';
+ end -= (int) (pt - buf) - 1;
+ } else if (pt == buf + 1) {
+ buf[0] = ' ';
+ }
+ }
+ if (end > buf && *(end - 1) == contchar) {
+ if (end == buf + 1 || *(end - 2) != contchar) {
+ /* Continuation */
+ contline = 1;
+ end--;
+ *end = '\0';
+ buf = end;
+ } else {
+ *(end - 1) = '\0';
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static char *next_word(char *pt)
+{
+ char *match;
+ char *pt2;
+
+ /* find end of word */
+ for (pt2 = pt; *pt2 && !(isspace(*pt2)); ++pt2) {
+ if ((match = strchr("\"'`", *pt2)) != NULL) {
+ for (++pt2; *pt2 && *pt2 != *match; ++pt2) {
+ if (*pt2 == '\\' && *(pt2 + 1) == *match)
+ ++pt2;
+ }
+ }
+ }
+
+ /* skip leading whitespace before next word */
+ if (*pt2) {
+ *pt2++ = '\0'; /* terminate last word */
+ while (*pt2 && isspace(*pt2))
+ ++pt2;
+ }
+ return pt2;
+}
+
+static GLOB_LIST *addlist(GLOB_LIST *orig, GLOB_LIST *add)
+{
+ if (!orig)
+ return add;
+ /* else */
+ orig->pathv = (char **)xrealloc(orig->pathv,
+ (orig->pathc + add->pathc + 1) *
+ sizeof(char *));
+ memcpy(orig->pathv + orig->pathc, add->pathv,
+ add->pathc * sizeof(char *));
+ orig->pathc += add->pathc;
+ orig->pathv[orig->pathc] = NULL;
+ /*
+ free(add->pathv);
+ free(add);
+ */
+ return orig;
+}
+
+static void decode_list(int *n, OPT_LIST **list, char *arg, int adding,
+ char *version, int opts)
+{
+ GLOB_LIST *pg;
+ GLOB_LIST *prevlist = NULL;
+ int i, autoclean = 1;
+ int where = *n;
+ char *arg2 = next_word(arg);
+
+ if (opts && !strcmp (arg, "-k")) {
+ if (!*arg2)
+ error("Missing module argument after -k\n");
+ arg = arg2;
+ arg2 = next_word(arg);
+ autoclean = 0;
+ }
+
+ for (i = 0; i < *n; ++i) {
+ if (strcmp((*list)[i].name, arg) == 0) {
+ if (adding)
+ prevlist = (*list)[i].opts;
+ else
+ free((*list)[i].opts);
+ (*list)[i].opts = NULL;
+ where = i;
+ break;
+ }
+ }
+ if (where == *n) {
+ (*list) = (OPT_LIST *)xrealloc((*list),
+ (*n + 2) * sizeof(OPT_LIST));
+ (*list)[*n].name = xstrdup(arg);
+ (*list)[*n].autoclean = autoclean;
+ *n += 1;
+ memset(&(*list)[*n], 0, sizeof(OPT_LIST));
+ } else if (!autoclean)
+ (*list)[where].autoclean = 0;
+ pg = (GLOB_LIST *)xmalloc(sizeof(GLOB_LIST));
+ meta_expand(arg2, pg, NULL, version, ME_ALL);
+ (*list)[where].opts = addlist(prevlist, pg);
+}
+
+static void decode_exec(char *arg, int type)
+{
+ char *arg2;
+
+ execs[nexecs].when = type;
+ arg2 = next_word(arg);
+ execs[nexecs].module = xstrdup(arg);
+ execs[nexecs].cmd = xstrdup(arg2);
+ if (++nexecs >= maxexecs) {
+ maxexecs += 10;
+ execs = (struct EXEC_TYPE *)xrealloc(execs,
+ maxexecs * sizeof(struct EXEC_TYPE));
+ }
+}
+
+static int build_list(char **in, OPT_LIST **out, char *version, int opts)
+{
+ GLOB_LIST *pg;
+ int i;
+
+ for (i = 0; in[i]; ++i) {
+ char *p = xstrdup(in[i]);
+ char *pt = next_word(p);
+ char *pn = p;
+
+ *out = (OPT_LIST *)xrealloc(*out, (i + 2) * sizeof(OPT_LIST));
+ (*out)[i].autoclean = 1;
+ if (opts && !strcmp (p, "-k")) {
+ pn = pt;
+ pt = next_word(pn);
+ (*out)[i].autoclean = 0;
+ }
+ pg = (GLOB_LIST *)xmalloc(sizeof(GLOB_LIST));
+ meta_expand(pt, pg, NULL, version, ME_ALL);
+ (*out)[i].name = xstrdup(pn);
+ (*out)[i].opts = pg;
+ free(p);
+ }
+ memset(&(*out)[i], 0, sizeof(OPT_LIST));
+
+ return i;
+}
+
+/* Environment variables can override defaults, testing only */
+static void gen_file_env(struct gen_files *gf)
+{
+ if (!safemode) {
+ char *e = xmalloc(strlen(gf->base)+5), *p1 = gf->base, *p2 = e;
+ while ((*p2++ = toupper(*p1++))) ;
+ strcpy(p2-1, "PATH"); /* safe, xmalloc */
+ if ((p2 = getenv(e)) != NULL) {
+ free(gf->name);
+ gf->name = xstrdup(p2);
+ }
+ free(e);
+ }
+}
+
+/* Read a config option for a generated filename */
+static int gen_file_conf(struct gen_files *gf, int assgn, const char *parm, const char *arg)
+{
+
+ int l = strlen(gf->base);
+ if (assgn &&
+ strncmp(parm, gf->base, l) == 0 &&
+ strcmp(parm+l, "file") == 0 &&
+ !gf->name) {
+ gf->name = xstrdup(arg);
+ return(0);
+ }
+ return(1);
+}
+
+/* Check we have a name for a generated file */
+static int gen_file_check(struct gen_files *gf, GLOB_LIST *g,
+ char *base_dir, char *version)
+{
+ char tmp[PATH_MAX];
+ int ret = 0;
+ if (!gf->name) {
+ /*
+ * Specification: config file / no xxxfile parameter
+ * The default value for generated filename xxx is:
+ *
+ * xxxfile=/lib/modules/`uname -r`/modules.xxx
+ *
+ * If the config file exists but lacks an xxxfile
+ * specification, the default value is used since
+ * the system can't work without one.
+ */
+ snprintf(tmp, sizeof(tmp), "%s/lib/modules/%s/modules.%s",
+ base_dir, version, gf->base);
+ gf->name = xstrdup(tmp);
+ } else { /* xxxfile defined in modules.conf */
+ /*
+ * If we have a xxxfile definition in the configuration file
+ * we must resolve any shell meta-chars in its value.
+ */
+ if (meta_expand(gf->name, g, base_dir, version, ME_ALL))
+ ret = -1;
+ else if (!g->pathv || g->pathv[0] == NULL)
+ ret = -1;
+ else {
+ free(gf->name);
+ gf->name = xstrdup(g->pathv[0]);
+ }
+ }
+ return(ret);
+}
+
+/*
+ * Read the configuration file.
+ * If parameter "all" == 0 then ignore everything except path info
+ * Return -1 if any error.
+ * Error messages generated.
+ */
+static int do_read(int all, char *force_ver, char *base_dir, char *conf_file, int depth)
+{
+ #define MAX_LEVEL 20
+ FILE *fin;
+ GLOB_LIST g;
+ int i;
+ int assgn;
+ int drop_default_paths = 1;
+ int lineno = 0;
+ int ret = 0;
+ int state[MAX_LEVEL + 1]; /* nested "if" */
+ int level = 0;
+ char buf[3000];
+ char tmpline[100];
+ char **pathp;
+ char *envpath;
+ char *version;
+ char *type;
+ char **glb;
+ char old_name[] = "/etc/conf.modules";
+ int conf_file_specified = 0;
+
+ /*
+ * The configuration file is optional.
+ * No error is printed if it is missing.
+ * If it is missing the following content is assumed.
+ *
+ * path[boot]=/lib/modules/boot
+ *
+ * path[toplevel]=/lib/modules/`uname -r`
+ *
+ * path[toplevel]=/lib/modules/`kernelversion`
+ * (where kernelversion gives the major kernel version: "2.0", "2.2"...)
+ *
+ * path[toplevel]=/lib/modules/default
+ *
+ * path[kernel]=/lib/modules/kernel
+ * path[fs]=/lib/modules/fs
+ * path[net]=/lib/modules/net
+ * path[scsi]=/lib/modules/scsi
+ * path[block]=/lib/modules/block
+ * path[cdrom]=/lib/modules/cdrom
+ * path[ipv4]=/lib/modules/ipv4
+ * path[ipv6]=/lib/modules/ipv6
+ * path[sound]=/lib/modules/sound
+ * path[fc4]=/lib/modules/fc4
+ * path[video]=/lib/modules/video
+ * path[misc]=/lib/modules/misc
+ * path[pcmcia]=/lib/modules/pcmcia
+ * path[atm]=/lib/modules/atm
+ * path[usb]=/lib/modules/usb
+ * path[ide]=/lib/modules/ide
+ * path[ieee1394]=/lib/modules/ieee1394
+ * path[mtd]=/lib/modules/mtd
+ *
+ * The idea is that modprobe will look first if the
+ * modules are compiled for the current release of the kernel.
+ * If not found, it will look for modules that fit for the
+ * general kernelversion (2.0, 2.2 and so on).
+ * If still not found, it will look into the default release.
+ * And if still not found, it will look in the other directories.
+ *
+ * The strategy should be like this:
+ * When you install a new linux kernel, the modules should go
+ * into a directory related to the release (version) of the kernel.
+ * Then you can do a symlink "default" to this directory.
+ *
+ * Each time you compile a new kernel, the make modules_install
+ * will create a new directory, but it won't change thee default.
+ *
+ * When you get a module unrelated to the kernel distribution
+ * you can place it in one of the last three directory types.
+ *
+ * This is the default strategy. Of course you can overide
+ * this in /etc/modules.conf.
+ *
+ * 2.3.15 added a new file tree walk algorithm which made it possible to
+ * point at a top level directory and get the same behaviour as earlier
+ * versions of modutils. 2.3.16 takes this one stage further, it
+ * removes all the individual directory names from most of the scans,
+ * only pointing at the top level directory. The only exception is the
+ * last ditch scan, scanning all of /lib/modules would be a bad idea(TM)
+ * so the last ditch scan still runs individual directory names under
+ * /lib/modules.
+ *
+ * Additional syntax:
+ *
+ * [add] above module module1 ...
+ * Specify additional modules to pull in on top of a module
+ *
+ * [add] below module module1 ...
+ * Specify additional modules needed to be able to load a module
+ *
+ * [add] prune filename ...
+ *
+ * [add] probe name module1 ...
+ * When "name" is requested, modprobe tries to install each
+ * module in the list until it succeeds.
+ *
+ * [add] probeall name module1 ...
+ * When "name" is requested, modprobe tries to install all
+ * modules in the list.
+ * If any module is installed, the command has succeeded.
+ *
+ * [add] options module option_list
+ *
+ * For all of the above, the optional "add" prefix is used to
+ * add to a list instead of replacing the contents.
+ *
+ * include FILE_TO_INCLUDE
+ * This does what you expect. No limitation on include levels.
+ *
+ * persistdir=persist_directory
+ * Name the directory to save persistent data from modules.
+ *
+ * In the following WORD is a sequence if non-white characters.
+ * If ' " or ` is found in the string, all characters up to the
+ * matching ' " or ` will also be included, even whitespace.
+ * Every WORD will then be expanded w.r.t. meta-characters.
+ * If the expanded result gives more than one word, then only
+ * the first word of the result will be used.
+ *
+ *
+ * define CODE WORD
+ * Do a putenv("CODE=WORD")
+ *
+ * EXPRESSION below can be:
+ * WORD compare_op WORD
+ * where compare_op is one of == != < <= >= >
+ * The string values of the WORDs are compared
+ * or
+ * -n WORD compare_op WORD
+ * where compare_op is one of == != < <= >= >
+ * The numeric values of the WORDs are compared
+ * or
+ * WORD
+ * if the expansion of WORD fails, or if the
+ * expansion is "0" (zero), "false" or "" (empty)
+ * then the expansion has the value FALSE.
+ * Otherwise the expansion has the value TRUE
+ * or
+ * -f FILENAME
+ * Test if the file FILENAME exists
+ * or
+ * -k
+ * Test if "autoclean" (i.e. called from the kernel)
+ * or
+ * ! EXPRESSION
+ * A negated expression is also an expression
+ *
+ * if EXPRESSION
+ * any config line
+ * ...
+ * elseif EXPRESSION
+ * any config line
+ * ...
+ * else
+ * any config line
+ * ...
+ * endif
+ *
+ * The else and elseif keywords are optional.
+ * "if"-statements nest up to 20 levels.
+ */
+
+ state[0] = 1;
+
+ if (force_ver)
+ version = force_ver;
+ else
+ version = uts_info.release;
+
+ config_version = xstrdup(version);
+
+ /* Only read the default entries on the first file */
+ if (depth == 0) {
+ maxpath = 100;
+ modpath = (struct PATH_TYPE *)xmalloc(maxpath * sizeof(struct PATH_TYPE));
+ nmodpath = 0;
+
+ maxexecs = 10;
+ execs = (struct EXEC_TYPE *)xmalloc(maxexecs * sizeof(struct EXEC_TYPE));
+ nexecs = 0;
+
+ /*
+ * Build predef options
+ */
+ if (all && optlist[0])
+ n_opt_list = build_list(optlist, &opt_list, version, 1);
+
+ /*
+ * Build predef above
+ */
+ if (all && above[0])
+ n_abovelist = build_list(above, &abovelist, version, 0);
+
+ /*
+ * Build predef below
+ */
+ if (all && below[0])
+ n_belowlist = build_list(below, &belowlist, version, 0);
+
+ /*
+ * Build predef prune list
+ */
+ if (prune[0])
+ n_prunelist = build_list(prune, &prunelist, version, 0);
+
+ /*
+ * Build predef aliases
+ */
+ if (all && aliaslist[0])
+ n_aliases = build_list(aliaslist, &aliases, version, 0);
+
+ /* Order and priority is now: (MODPATH + modules.conf) || (predefs + modules.conf) */
+ if ((envpath = getenv("MODPATH")) != NULL && !safemode) {
+ size_t len;
+ char *p;
+ char *path;
+
+ /* Make a copy so's we can mung it with strtok. */
+ len = strlen(envpath) + 1;
+ p = alloca(len);
+ memcpy(p, envpath, len);
+ path = alloca(PATH_MAX);
+
+ for (p = strtok(p, ":"); p != NULL; p = strtok(NULL, ":")) {
+ len = snprintf(path, PATH_MAX, p, version);
+ modpath[nmodpath].path = xstrdup(path);
+ if ((type = strrchr(path, '/')) != NULL)
+ type += 1;
+ else
+ type = "misc";
+ modpath[nmodpath].type = xstrdup(type);
+ if (++nmodpath >= maxpath) {
+ maxpath += 100;
+ modpath = (struct PATH_TYPE *)xrealloc(modpath,
+ maxpath * sizeof(struct PATH_TYPE));
+ }
+
+ }
+ } else {
+ /*
+ * Build the default "path[type]" configuration
+ */
+ int n;
+ char *k;
+
+ /* The first entry in the path list */
+ modpath[nmodpath].type = xstrdup("boot");
+ snprintf(tmpline, sizeof(tmpline), "%s/lib/modules/boot", base_dir);
+ modpath[nmodpath].path = xstrdup(tmpline);
+ ++nmodpath;
+
+ /* The second entry in the path list, `uname -r` */
+ modpath[nmodpath].type = xstrdup("toplevel");
+ snprintf(tmpline, sizeof(tmpline), "%s/lib/modules/%s", base_dir, version);
+ modpath[nmodpath].path = xstrdup(tmpline);
+ ++nmodpath;
+
+ /* The third entry in the path list, `kernelversion` */
+ modpath[nmodpath].type = xstrdup("toplevel");
+ for (n = 0, k = version; *k; ++k) {
+ if (*k == '.' && ++n == 2)
+ break;
+ }
+ snprintf(tmpline, sizeof(tmpline), "%s/lib/modules/%.*s", base_dir,
+ (/* typecast for Alpha */ int)(k - version), version);
+ modpath[nmodpath].path = xstrdup(tmpline);
+ ++nmodpath;
+
+ /* The rest of the entries in the path list */
+ for (pathp = tbpath; *pathp; ++pathp) {
+ char **type;
+
+ for (type = tbtype; *type; ++type) {
+ char path[PATH_MAX];
+
+ snprintf(path, sizeof(path), "%s%s/%s", base_dir, *pathp, *type);
+ if (meta_expand(path, &g, NULL, version, ME_ALL))
+ return -1;
+
+ for (glb = g.pathv; glb && *glb; ++glb) {
+ modpath[nmodpath].type = xstrdup(*type);
+ modpath[nmodpath].path = *glb;
+ if (++nmodpath >= maxpath) {
+ maxpath += 100;
+ modpath = (struct PATH_TYPE *)xrealloc(modpath,
+ maxpath * sizeof(struct PATH_TYPE));
+ }
+ }
+ }
+ }
+ }
+
+ /* Environment overrides for testing only, undocumented */
+ for (i = 0; i < gen_file_count; ++i)
+ gen_file_env(gen_file+i);
+
+ } /* End of depth == 0 */
+
+ if (conf_file ||
+ ((conf_file = getenv("MODULECONFIG")) != NULL && *conf_file && !safemode)) {
+ if (!(fin = fopen(conf_file, "r"))) {
+ error("Can't open %s", conf_file);
+ return -1;
+ }
+ conf_file_specified = 1;
+ } else {
+ if (!(fin = fopen((conf_file = ETC_MODULES_CONF), "r"))) {
+ /* Fall back to non-standard name */
+ if ((fin = fopen((conf_file = old_name), "r"))) {
+ fprintf(stderr,
+ "Warning: modutils is reading from %s because\n"
+ " %s does not exist. The use of %s is\n"
+ " deprecated, please rename %s to %s\n"
+ " as soon as possible. Command\n"
+ " mv %s %s\n",
+ old_name, ETC_MODULES_CONF,
+ old_name, old_name, ETC_MODULES_CONF,
+ old_name, ETC_MODULES_CONF);
+ }
+ /* So what... use the default configuration */
+ }
+ }
+
+ if (fin) {
+ struct stat statbuf1, statbuf2;
+ if (fstat(fileno(fin), &statbuf1) == 0)
+ config_mtime = statbuf1.st_mtime;
+ config_file = xstrdup(conf_file); /* Save name actually used */
+ if (!conf_file_specified &&
+ stat(ETC_MODULES_CONF, &statbuf1) == 0 &&
+ stat(old_name, &statbuf2) == 0) {
+ /* Both /etc files exist */
+ if (statbuf1.st_dev == statbuf2.st_dev &&
+ statbuf1.st_ino == statbuf2.st_ino) {
+ if (lstat(ETC_MODULES_CONF, &statbuf1) == 0 &&
+ S_ISLNK(statbuf1.st_mode))
+ fprintf(stderr,
+ "Warning: You do not need a link from %s to\n"
+ " %s. The use of %s is deprecated,\n"
+ " please remove %s and rename %s\n"
+ " to %s as soon as possible. Commands.\n"
+ " rm %s\n"
+ " mv %s %s\n",
+ ETC_MODULES_CONF, old_name,
+ old_name, ETC_MODULES_CONF, old_name, ETC_MODULES_CONF,
+ ETC_MODULES_CONF,
+ old_name, ETC_MODULES_CONF);
+ else {
+#ifndef NO_WARN_ON_OLD_LINK
+ fprintf(stderr,
+ "Warning: You do not need a link from %s to\n"
+ " %s. The use of %s is deprecated,\n"
+ " please remove %s as soon as possible. Command\n"
+ " rm %s\n",
+ old_name, ETC_MODULES_CONF,
+ old_name, old_name,
+ old_name);
+#endif
+ }
+ }
+ else
+ fprintf(stderr,
+ "Warning: modutils is reading from %s and\n"
+ " ignoring %s. The use of %s is deprecated,\n"
+ " please remove %s as soon as possible. Command\n"
+ " rm %s\n",
+ ETC_MODULES_CONF, old_name,
+ old_name, old_name,
+ old_name);
+ }
+ }
+
+ /*
+ * Finally, decode the file
+ */
+ while (fin && fgets_strip(buf, sizeof(buf) - 1, fin, &lineno) != NULL) {
+ char *arg2;
+ char *parm = buf;
+ char *arg;
+ int one_err = 0;
+ int adding;
+
+ while (isspace(*parm))
+ parm++;
+
+ if (strncmp(parm, "add", 3) == 0) {
+ adding = 1;
+ parm += 3;
+ while (isspace(*parm))
+ parm++;
+ } else
+ adding = 0;
+
+ arg = parm;
+
+ if (*parm == '\0')
+ continue;
+
+ one_err = 1;
+
+ while (*arg > ' ' && *arg != '=')
+ arg++;
+
+ if (*arg == '=')
+ assgn = 1;
+ else
+ assgn = 0;
+ *arg++ = '\0';
+ while (isspace(*arg))
+ arg++;
+
+ /*
+ * endif
+ */
+ if (!assgn && strcmp(parm, "endif") == 0) {
+ if (level > 0)
+ --level;
+ else {
+ error("unmatched endif in line %d", lineno);
+ return -1;
+ }
+ continue;
+ }
+
+ /*
+ * else
+ */
+ if (!assgn && strcmp(parm, "else") == 0) {
+ if (level <= 0) {
+ error("else without if in line %d", lineno);
+ return -1;
+ }
+ state[level] = !state[level];
+ continue;
+ }
+
+ /*
+ * elseif
+ */
+ if (!assgn && strcmp(parm, "elseif") == 0) {
+ if (level <= 0) {
+ error("elseif without if in line %d", lineno);
+ return -1;
+ }
+ if (state[level] != 0) {
+ /*
+ * We have already found a TRUE
+ * if statement in this "chain".
+ * That's what "2" means.
+ */
+ state[level] = 2;
+ continue;
+ }
+ /* else: No TRUE if has been found, cheat */
+ /*
+ * The "if" handling increments level,
+ * but this is the _same_ level as before.
+ * So, compensate for it.
+ */
+ --level;
+ parm = "if";
+ /* Fallthru to "if" */
+ }
+
+ /*
+ * if
+ */
+ if (strcmp(parm, "if") == 0) {
+ char *cmp;
+ int not = 0;
+ int numeric = 0;
+
+ if (level >= MAX_LEVEL) {
+ error("Too many nested if's in line %d\n", lineno);
+ return -1;
+ }
+ state[++level] = 0; /* default false */
+
+ if (*arg == '!') {
+ not = 1;
+ arg = next_word(arg);
+ }
+
+ if (strncmp(arg, "-k", 2) == 0) {
+ state[level] = flag_autoclean;
+ continue;
+ }
+
+ if (strncmp(arg, "-f", 2) == 0) {
+ char *file = next_word(arg);
+ meta_expand(file, &g, NULL, version, ME_ALL);
+ if (access(g.pathc ? g.pathv[0] : file, R_OK) == 0)
+ state[level] = !not;
+ else
+ state[level] = not;
+ continue;
+ }
+
+ if (strncmp(arg, "-n", 2) == 0) {
+ numeric = 1;
+ arg = next_word(arg);
+ }
+
+
+ cmp = next_word(arg);
+ if (*cmp) {
+ GLOB_LIST g2;
+ long n1 = 0;
+ long n2 = 0;
+ char *w1 = "";
+ char *w2 = "";
+
+ arg2 = next_word(cmp);
+
+ meta_expand(arg, &g, NULL, version, ME_ALL);
+ if (g.pathc && g.pathv[0])
+ w1 = g.pathv[0];
+
+ meta_expand(arg2, &g2, NULL, version, ME_ALL);
+ if (g2.pathc && g2.pathv[0])
+ w2 = g2.pathv[0];
+
+ if (numeric) {
+ n1 = strtol(w1, NULL, 0);
+ n2 = strtol(w2, NULL, 0);
+ }
+
+ if (strcmp(cmp, "==") == 0 ||
+ strcmp(cmp, "=") == 0) {
+ if (numeric)
+ state[level] = (n1 == n2);
+ else
+ state[level] = strcmp(w1, w2) == 0;
+ } else if (strcmp(cmp, "!=") == 0) {
+ if (numeric)
+ state[level] = (n1 != n2);
+ else
+ state[level] = strcmp(w1, w2) != 0;
+ } else if (strcmp(cmp, ">=") == 0) {
+ if (numeric)
+ state[level] = (n1 >= n2);
+ else
+ state[level] = strcmp(w1, w2) >= 0;
+ } else if (strcmp(cmp, "<=") == 0) {
+ if (numeric)
+ state[level] = (n1 <= n2);
+ else
+ state[level] = strcmp(w1, w2) <= 0;
+ } else if (strcmp(cmp, ">") == 0) {
+ if (numeric)
+ state[level] = (n1 > n2);
+ else
+ state[level] = strcmp(w1, w2) > 0;
+ } else if (strcmp(cmp, "<") == 0) {
+ if (numeric)
+ state[level] = (n1 < n2);
+ else
+ state[level] = strcmp(w1, w2) < 0;
+ }
+ } else { /* Check defined value, if any */
+ /* undef or defined as
+ * "" or "0" or "false" => false
+ * defined => true
+ */
+ if (!meta_expand(arg, &g, NULL, version, ME_ALL) &&
+ g.pathc > 0 &&
+ strcmp(g.pathv[0], "0") != 0 &&
+ strcmp(g.pathv[0], "false") != 0 &&
+ strlen(g.pathv[0]) != 0)
+ state[level] = 1; /* true */
+ }
+ if (not)
+ state[level] = !state[level];
+
+ continue;
+ }
+
+ /*
+ * Should we bother?
+ */
+ if (state[level] != 1)
+ continue;
+
+ /*
+ * define
+ */
+ if (!assgn && strcmp(parm, "define") == 0) {
+ char env[PATH_MAX];
+
+ arg2 = next_word(arg);
+ meta_expand(arg2, &g, NULL, version, ME_ALL);
+ snprintf(env, sizeof(env), "%s=%s", arg, (g.pathc ? g.pathv[0] : ""));
+ putenv(env);
+ one_err = 0;
+ }
+
+ /*
+ * include
+ */
+ if (!assgn && strcmp(parm, "include") == 0) {
+ meta_expand(arg, &g, NULL, version, ME_ALL);
+
+ if (!do_read(all, version, base_dir, g.pathc ? g.pathv[0] : arg, depth+1))
+ one_err = 0;
+ else
+ error("include %s failed\n", arg);
+ }
+
+ /*
+ * above
+ */
+ else if (all && !assgn && strcmp(parm, "above") == 0) {
+ decode_list(&n_abovelist, &abovelist, arg, adding, version, 0);
+ one_err = 0;
+ }
+
+ /*
+ * below
+ */
+ else if (all && !assgn && strcmp(parm, "below") == 0) {
+ decode_list(&n_belowlist, &belowlist, arg, adding, version, 0);
+ one_err = 0;
+ }
+
+ /*
+ * prune
+ */
+ else if (all && !assgn && strcmp(parm, "prune") == 0) {
+ decode_list(&n_prunelist, &prunelist, arg, adding, version, 0);
+ one_err = 0;
+ }
+
+ /*
+ * probe
+ */
+ else if (all && !assgn && strcmp(parm, "probe") == 0) {
+ decode_list(&n_probe_list, &probe_list, arg, adding, version, 0);
+ one_err = 0;
+ }
+
+ /*
+ * probeall
+ */
+ else if (all && !assgn && strcmp(parm, "probeall") == 0) {
+ decode_list(&n_probeall_list, &probeall_list, arg, adding, version, 0);
+ one_err = 0;
+ }
+
+ /*
+ * options
+ */
+ else if (all && !assgn && strcmp(parm, "options") == 0) {
+ decode_list(&n_opt_list, &opt_list, arg, adding, version, 1);
+ one_err = 0;
+ }
+
+ /*
+ * alias
+ */
+ else if (all && !assgn && strcmp(parm, "alias") == 0) {
+ /*
+ * Replace any previous (default) definitions
+ * for the same module
+ */
+ decode_list(&n_aliases, &aliases, arg, 0, version, 0);
+ one_err = 0;
+ }
+
+ /*
+ * Specification: /etc/modules.conf
+ * The format of the commands in /etc/modules.conf are:
+ *
+ * pre-install module command
+ * install module command
+ * post-install module command
+ * pre-remove module command
+ * remove module command
+ * post-remove module command
+ *
+ * The different words are separated by tabs or spaces.
+ */
+ /*
+ * pre-install
+ */
+ else if (all && !assgn && (strcmp(parm, "pre-install") == 0)) {
+ decode_exec(arg, EXEC_PRE_INSTALL);
+ one_err = 0;
+ }
+
+ /*
+ * install
+ */
+ else if (all && !assgn && (strcmp(parm, "install") == 0)) {
+ decode_exec(arg, EXEC_INSTALL);
+ one_err = 0;
+ }
+
+ /*
+ * post-install
+ */
+ else if (all && !assgn && (strcmp(parm, "post-install") == 0)) {
+ decode_exec(arg, EXEC_POST_INSTALL);
+ one_err = 0;
+ }
+
+ /*
+ * pre-remove
+ */
+ else if (all && !assgn && (strcmp(parm, "pre-remove") == 0)) {
+ decode_exec(arg, EXEC_PRE_REMOVE);
+ one_err = 0;
+ }
+
+ /*
+ * remove
+ */
+ else if (all && !assgn && (strcmp(parm, "remove") == 0)) {
+ decode_exec(arg, EXEC_REMOVE);
+ one_err = 0;
+ }
+
+ /*
+ * post-remove
+ */
+ else if (all && !assgn && (strcmp(parm, "post-remove") == 0)) {
+ decode_exec(arg, EXEC_POST_REMOVE);
+ one_err = 0;
+ }
+
+ /*
+ * insmod_opt=
+ */
+ else if (assgn && (strcmp(parm, "insmod_opt") == 0)) {
+ insmod_opt = xstrdup(arg);
+ one_err = 0;
+ }
+
+ /*
+ * keep
+ */
+ else if (!assgn && (strcmp(parm, "keep") == 0)) {
+ drop_default_paths = 0;
+ one_err = 0;
+ }
+
+ /*
+ * path...=
+ */
+ else if (assgn && strncmp(parm, "path", 4) == 0) {
+ /*
+ * Specification: config file / path parameter
+ * The path parameter specifies a directory to
+ * search for modules.
+ * This parameter may be repeated multiple times.
+ *
+ * Note that the actual path may be defined using
+ * wildcards and other shell meta-chars, such as "*?`".
+ * For example:
+ * path[misc]=/lib/modules/1.1.5?/misc
+ *
+ * Optionally the path keyword carries a tag.
+ * This tells us a little more about the purpose of
+ * this directory and allows some automated operations.
+ * A path is marked with a tag by adding the tag,
+ * enclosed in square brackets, to the path keyword:
+ * #
+ * path[boot]=/lib/modules/boot
+ * #
+ * This case identifies the path a of directory
+ * holding modules loadable a boot time.
+ */
+
+ if (drop_default_paths) {
+ int n;
+
+ /*
+ * Specification: config file / path / default
+ *
+ * Whenever there is a path[] specification
+ * in the config file, all the default
+ * path are reset.
+ *
+ * If one instead wants to _add_ to the default
+ * set of paths, one has to have the option
+ * keep
+ * before the first path[]-specification line
+ * in the configuration file.
+ */
+ drop_default_paths = 0;
+ for (n = 0; n < nmodpath; n++) {
+ free(modpath[n].path);
+ free(modpath[n].type);
+ }
+ nmodpath = 0;
+ }
+
+ /*
+ * Get (the optional) tag
+ * If the tag is missing, the word "misc"
+ * is assumed.
+ */
+ type = "misc";
+
+ if (parm[4] == '[') {
+ char *pt_type = parm + 5;
+
+ while (*pt_type != '\0' && *pt_type != ']')
+ pt_type++;
+
+ if (*pt_type == ']' && pt_type[1] == '\0') {
+ *pt_type = '\0';
+ type = parm + 5;
+ } /* else CHECKME */
+ }
+
+ /*
+ * Handle the actual path description
+ */
+ if (meta_expand(arg, &g, base_dir, version, ME_ALL))
+ return -1;
+ for (glb = g.pathv; glb && *glb; ++glb) {
+ modpath[nmodpath].type = xstrdup(type);
+ modpath[nmodpath].path = *glb;
+ if (++nmodpath >= maxpath) {
+ maxpath += 100;
+ modpath = (struct PATH_TYPE *)xrealloc(modpath,
+ maxpath * sizeof(struct PATH_TYPE));
+ }
+ }
+ one_err = 0;
+ }
+
+ /*
+ * persistdir
+ */
+ else if (assgn && strcmp(parm, "persistdir") == 0) {
+ meta_expand(arg, &g, NULL, version, ME_ALL);
+ persistdir = xstrdup(g.pathc ? g.pathv[0] : arg);
+ one_err = 0;
+ }
+
+ /* Names for generated files in config file */
+ for (i = 0; one_err && i < gen_file_count; ++i)
+ one_err = gen_file_conf(gen_file+i, assgn, parm, arg);
+
+ /*
+ * any errors so far?
+ */
+ if (all == 0)
+ one_err = 0;
+ else if (one_err) {
+ error("Invalid line %d in %s\n\t%s",
+ lineno, conf_file, buf);
+ ret = -1;
+ }
+ }
+ if (fin)
+ fclose(fin);
+
+ if (level) {
+ error("missing endif at %s EOF", conf_file);
+ ret = -1;
+ }
+
+ if (ret)
+ return ret;
+ /* else */
+
+ /* Check we have names for generated files */
+ for (i = 0; !ret && i < gen_file_count; ++i)
+ ret = gen_file_check(gen_file+i, &g, base_dir, version);
+
+ return ret;
+}
+
+int config_read(int all, char *force_ver, char *base_dir, char *conf_file)
+{
+ int r;
+ if (modpath != NULL)
+ return 0; /* already initialized */
+
+ if (uname(&uts_info) < 0) {
+ error("Failed to find kernel name information");
+ return -1;
+ }
+
+ r = do_read(all, force_ver, base_dir, conf_file, 0);
+
+ if (quick && !r && !need_update (force_ver, base_dir))
+ exit (0);
+
+ return r;
+}
+
+/****************************************************************************/
+/*
+ * FIXME: Far too much global state. KAO.
+ */
+static int found;
+static int favail;
+static int one_only;
+static int meta_expand_type;
+char **list;
+static const char *filter_by_file;
+static char *filter_by_dir;
+
+/*
+ * Add a file name if it exist
+ */
+static int config_add(const char *file, const struct stat *sb)
+{
+ int i;
+ int npaths = 0;
+ char **paths = NULL;
+
+ if (meta_expand_type) {
+ GLOB_LIST g;
+ char **p;
+ char full[PATH_MAX];
+
+ snprintf(full, sizeof(full), "%s/%s", file, filter_by_file);
+
+ if (filter_by_dir && !strstr(full, filter_by_dir))
+ return 0;
+
+ if (meta_expand(full, &g, NULL, config_version, meta_expand_type))
+ return 1;
+ for (p = g.pathv; p && *p; ++p) {
+ paths = (char **)xrealloc(paths,
+ (npaths + 1) * sizeof(char *));
+ paths[npaths++] = *p;
+ }
+ } else { /* normal path match or match with "*" */
+ if (!S_ISREG(sb->st_mode))
+ return 0;
+
+ if (strcmp(filter_by_file, "*")) {
+ char *p;
+
+ if ((p = strrchr(file, '/')) == NULL)
+ p = (char *)file;
+ else
+ p += 1;
+
+ if (strcmp(p, filter_by_file))
+ return 0;
+ }
+ if (filter_by_dir && !strstr(file, filter_by_dir))
+ return 0;
+ paths = (char **)xmalloc(sizeof(char **));
+ *paths = xstrdup(file);
+ npaths = 1;
+ }
+
+ for (i = 0; i < npaths; ++i) {
+ struct stat sbuf;
+
+ if (S_ISDIR(sb->st_mode)) {
+ if (stat(paths[i], &sbuf) == 0)
+ sb = &sbuf;
+ }
+ if (S_ISREG(sb->st_mode) && sb->st_mode & S_IRUSR) {
+ int j;
+ char **this;
+
+ if (!root_check_off) {
+ if (sb->st_uid != 0) {
+ error("%s is not owned by root", paths[i]);
+ continue;
+ }
+ }
+
+ /* avoid duplicates */
+ for (j = 0, this = list; j < found; ++j, ++this) {
+ if (strcmp(*this, paths[i]) == 0) {
+ free(paths[i]);
+ goto next;
+ }
+ }
+
+ list[found] = paths[i];
+ if (++found >= favail)
+ list = (char **)xrealloc(list,
+ (favail += 100) * sizeof(char *));
+
+ if (one_only) {
+ for (j = i + 1; j < npaths; ++j)
+ free(paths[j]);
+ free(paths);
+ return 1; /* finish xftw */
+ }
+ }
+ next:
+ }
+
+ if (npaths > 0)
+ free(paths);
+
+ return 0;
+}
+
+/*
+ * Find modules matching the name "match" in directory of type "type"
+ * (type == NULL matches all)
+ *
+ * Return a pointer to the list of modules found (or NULL if error).
+ * Update the counter (sent as parameter).
+ */
+GLOB_LIST *config_lstmod(const char *match, const char *type, int first_only)
+{
+ /*
+ * Note:
+ * There are _no_ wildcards remaining in the path descriptions!
+ */
+ struct stat sb;
+ int i;
+ int ret = 0;
+ char *path = NULL;
+ char this[PATH_MAX];
+
+ if (!match)
+ match = "*";
+ one_only = first_only;
+ found = 0;
+ filter_by_file = match;
+ filter_by_dir = NULL;
+ if (type) {
+ char tmpdir[PATH_MAX];
+ snprintf(tmpdir, sizeof(tmpdir), "/%s/", type);
+ filter_by_dir = xstrdup(tmpdir);
+ }
+ /* In safe mode, the module name is always handled as is, without meta
+ * expansion. It might have come from an end user via kmod and must
+ * not be trusted. Even in unsafe mode, only apply globbing to the
+ * module name, not command expansion. We trust config file input so
+ * applying command expansion is safe, we do not trust command line input.
+ * This assumes that the only time the user can specify -C config file
+ * is when they run under their own authority. In particular all
+ * mechanisms that call modprobe as root on behalf of the user must
+ * run in safe mode, without letting the user supply a config filename.
+ */
+ meta_expand_type = 0;
+ if (strpbrk(match, SHELL_META) && strcmp(match, "*") && !safemode)
+ meta_expand_type = ME_GLOB|ME_BUILTIN_COMMAND;
+
+ list = (char **)xmalloc((favail = 100) * sizeof(char *));
+
+ for (i = 0; i < nmodpath; i++) {
+ path = modpath[i].path;
+ /* Special case: insmod: handle single, non-wildcard match */
+ if (first_only && strpbrk(match, SHELL_META) == NULL) {
+ /* Fix for "2.1.121 syntax */
+ snprintf(this, sizeof(this), "%s/%s/%s", path,
+ modpath[i].type, match);
+ if (stat(this, &sb) == 0 &&
+ config_add(this, &sb))
+ break;
+ /* End fix for "2.1.121 syntax */
+
+ snprintf(this, sizeof(this), "%s/%s", path, match);
+ if (stat(this, &sb) == 0 &&
+ config_add(this, &sb))
+ break;
+ }
+
+ /* Start looking */
+ if ((ret = xftw(path, config_add))) {
+ break;
+ }
+ }
+ if (ret >= 0) {
+ GLOB_LIST *g = (GLOB_LIST *)xmalloc(sizeof(GLOB_LIST));
+ g->pathc = found;
+ g->pathv = list;
+ free(filter_by_dir);
+ return g;
+ }
+ free(list);
+ free(filter_by_dir);
+ return NULL;
+}
+
+/* Given a bare module name, poke through the module path to find the file. */
+char *search_module_path(const char *base)
+{
+ GLOB_LIST *g;
+
+ if (config_read(0, NULL, "", NULL) < 0)
+ return NULL;
+ /* else */
+ g = config_lstmod(base, NULL, 1);
+ if (g == NULL || g->pathc == 0) {
+ char base_o[PATH_MAX];
+
+ snprintf(base_o, sizeof(base_o), "%s.o", base);
+ g = config_lstmod(base_o, NULL, 1);
+#ifdef CONFIG_USE_ZLIB
+ if (g == NULL || g->pathc == 0) {
+ snprintf(base_o, sizeof(base_o), "%s.o.gz", base);
+ g = config_lstmod(base_o, NULL, 1);
+ }
+#endif
+ }
+ if (g == NULL || g->pathc == 0)
+ return NULL;
+ /* else */
+ return g->pathv[0];
+}
diff --git a/mdk-stage1/insmod-modutils/util/gzfiles.c b/mdk-stage1/insmod-modutils/util/gzfiles.c
new file mode 100644
index 000000000..8d02253bb
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/gzfiles.c
@@ -0,0 +1,74 @@
+/*
+ * This simple library intends to make it transparent to read gzipped and/or
+ * standard files. This is simple enough to fit modutils' needs, but may be
+ * easily adapted to anyone's needs. It's completely free, do what you want
+ * with it . - Willy Tarreau <willy@meta-x.org> - 2000/05/05 -
+ */
+
+#ifdef CONFIG_USE_ZLIB
+
+#include <stdio.h>
+#include <zlib.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+/* redefinition of gz_stream which isn't exported by zlib */
+typedef struct gz_stream {
+ z_stream stream;
+ int z_err; /* error code for last stream operation */
+ int z_eof; /* set if end of input file */
+ FILE *file; /* .gz file */
+ Byte *inbuf; /* input buffer */
+ Byte *outbuf; /* output buffer */
+ uLong crc; /* crc32 of uncompressed data */
+ char *msg; /* error message */
+ char *path; /* path name for debugging only */
+ int transparent; /* 1 if input file is not a .gz file */
+ char mode; /* 'w' or 'r' */
+ long startpos; /* start of compressed data in file (header skipped) */
+} gz_stream;
+
+/* maximum number of simultaneous open files, also greater file descriptor number */
+#define MAXFD 64
+
+/* this static list is assumed to be filled with NULLs at runtime */
+static gzFile gzf_fds[MAXFD];
+
+/* returns the filedesc of the opened file. */
+int gzf_open(const char *name, int mode) {
+ int fd;
+ gzFile g;
+
+ if ((g=gzopen(name, "rb")) != NULL) {
+ fd=fileno(((gz_stream*)g)->file);
+ gzf_fds[fd]=g;
+ }
+ else if ((fd=open(name, mode)) != -1) {
+ gzf_fds[fd]=NULL; /* NULL means not GZ mode */
+ }
+ return fd;
+}
+
+off_t gzf_lseek(int fd, off_t offset, int whence) {
+ if (fd<0 || fd>=MAXFD || gzf_fds[fd]==NULL)
+ return lseek(fd, offset, whence);
+ else
+ return gzseek(gzf_fds[fd], offset, whence);
+}
+
+int gzf_read(int fd, void *buf, size_t count) {
+ if (fd<0 || fd>=MAXFD || gzf_fds[fd]==NULL)
+ return read(fd, buf, count);
+ else
+ return gzread(gzf_fds[fd], buf, count);
+}
+
+void gzf_close(int fd) {
+ if (fd<0 || fd>=MAXFD || gzf_fds[fd]==NULL)
+ close(fd);
+ else
+ gzclose(gzf_fds[fd]);
+}
+#endif
+
diff --git a/mdk-stage1/insmod-modutils/util/logger.c b/mdk-stage1/insmod-modutils/util/logger.c
new file mode 100644
index 000000000..3b790df5a
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/logger.c
@@ -0,0 +1,163 @@
+/* Error logging facilities.
+ Copyright 1996, 1997 Linux International.
+
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ident "$Id$"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <syslog.h>
+
+#include "util.h"
+
+/*======================================================================*/
+
+int errors;
+const char *error_file;
+int log;
+
+#define STOREMSG
+#ifdef STOREMSG
+struct cbuf {
+ struct cbuf *next;
+ int type;
+ char *msg;
+} *head, *tail;
+
+static void savemsg(int type, char *msg)
+{
+ struct cbuf *me = (struct cbuf *)xmalloc(sizeof(struct cbuf));
+ char *s = xstrdup(msg);
+
+ me->next = NULL;
+ me->type = type;
+ me->msg = s;
+
+ if (tail)
+ tail->next = me;
+ else
+ head = me;
+ tail = me;
+}
+
+#endif /* STOREMSG */
+
+static void dumpmsg(void)
+{
+ for (;head; head = head->next)
+ syslog(head->type, "%s", head->msg);
+}
+
+void setsyslog(const char *program)
+{
+ openlog(program, LOG_CONS, LOG_DAEMON);
+#ifdef STOREMSG
+ atexit(dumpmsg);
+#endif
+ log = 1;
+}
+
+
+
+#ifdef _STANDALONE_
+static int silent;
+
+const char *program_name;
+
+void error(const char *fmt,...)
+{
+ va_list args;
+
+ if (silent)
+ ;
+ else if (log) {
+ char buf[1024];
+ int n;
+
+ if (error_file)
+ n = snprintf(buf, sizeof(buf), "%s: ", error_file);
+ else
+ n = 0;
+ va_start(args, fmt);
+ vsnprintf(buf + n, sizeof(buf) - n, fmt, args);
+ va_end(args);
+#ifdef STOREMSG
+ savemsg(LOG_ERR, buf);
+#else
+ syslog(LOG_ERR, "%s", buf);
+#endif
+ } else {
+ if (error_file)
+ fprintf(stderr, "%s: ", error_file);
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ putc('\n', stderr);
+ }
+
+ errors++;
+}
+
+void lprintf(const char *fmt,...)
+{
+ va_list args;
+
+ if (silent);
+ else if (log) {
+ char buf[1024];
+ va_start(args, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+#ifdef STOREMSG
+ savemsg(LOG_INFO, buf);
+#else
+ syslog(LOG_INFO, "%s", buf);
+#endif
+ } else {
+ va_start(args, fmt);
+ vfprintf(stdout, fmt, args);
+ va_end(args);
+ putchar('\n');
+ }
+}
+
+#else /* _STANDALONE_ */
+#include "../../log.h"
+void error(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ vlog_message(s, p);
+ va_end(p);
+}
+
+void lprintf(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ vlog_message(s, p);
+ va_end(p);
+}
+#endif
diff --git a/mdk-stage1/insmod-modutils/util/meta_expand.c b/mdk-stage1/insmod-modutils/util/meta_expand.c
new file mode 100644
index 000000000..41fb4024c
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/meta_expand.c
@@ -0,0 +1,339 @@
+/*
+ * Handle expansion of meta charaters
+ *
+ * Copyright 1999 Björn Ekwall <bj0rn@blox.se>
+ *
+ * "kernelversion" idea from the Debian release via:
+ * Wichert Akkerman <wakkerma@cs.leidenuniv.nl>
+ *
+ * Use wordexp(): idea from Tim Waugh <tim@cyberelk.demon.co.uk>
+ *
+ * Alpha typecast: Michal Jaegermann <michal@ellpspace.math.ualberta.ca>
+ *
+ * This file is part of the Linux modutils.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_WORDEXP
+#undef HAVE_WORDEXP
+#define HAVE_WORDEXP 0
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <ctype.h>
+#if HAVE_WORDEXP
+#include <wordexp.h>
+#elif HAVE_GLOB
+#include <glob.h>
+#endif
+#include "util.h"
+
+/*
+ * Split into words delimited by whitespace,
+ * handle remaining quotes though...
+ * If strip_quotes != 0 then strip one level of quotes from the line.
+ */
+static void split_line(GLOB_LIST *g, char *line, int strip_quotes)
+{
+ int len;
+ char *d;
+ char *e;
+ char *p;
+ char tmpline[PATH_MAX];
+
+ for (p = line; *p; p = e) {
+ /* Skip leading whitespace */
+ while (*p && isspace(*p))
+ ++p;
+
+ /* find end of word */
+ d = tmpline;
+ for (e = p; *e && !(isspace(*e)); ++e) {
+ char match;
+
+ /* Quote handling */
+ switch (*e) {
+ case '\\':
+ if (!strip_quotes)
+ *d++ = *e;
+ break;
+
+ case '"':
+ case '\'':
+ match = *e;
+ if (!strip_quotes)
+ *d++ = *e;
+ for (++e; *e && *e != match; ++e) {
+ *d++ = *e;
+ if (*e == '\\' && *(e + 1) == match)
+ *d++ = *++e;
+ }
+ if (!strip_quotes)
+ *d++ = *e;
+ break;
+
+ default:
+ *d++ = *e;
+ break;
+ }
+ }
+
+ if ((len = (int)(d - tmpline)) > 0) {
+ char *str = xmalloc(len + 1);
+ strncpy(str, tmpline, len);
+ str[len] = '\0';
+ g->pathv = (char **)xrealloc(g->pathv,
+ (g->pathc + 2) * sizeof(char *));
+ g->pathv[g->pathc++] = str;
+ }
+ }
+
+ if (g->pathc)
+ g->pathv[g->pathc] = NULL;
+}
+
+static int glob_it(char *pt, GLOB_LIST *g)
+{
+#if HAVE_WORDEXP
+ wordexp_t w;
+
+ memset(&w, 0, sizeof(w));
+ if (wordexp(pt, &w, WRDE_UNDEF)) {
+ /*
+ error("wordexp %s failed", pt);
+ */
+ return -1;
+ }
+ /* else */
+ g->pathc = w.we_wordc;
+ g->pathv = w.we_wordv;
+
+ return 0;
+#elif HAVE_GLOB /* but not wordexp */
+ glob_t w;
+
+ memset(&w, 0, sizeof(w));
+ if (glob(pt, GLOB_NOSORT, NULL, &w)) {
+ /*
+ error("glob %s failed", pt);
+ */
+ return -1;
+ }
+ /* else */
+ if (w.gl_pathc && strpbrk(w.gl_pathv[0], SHELL_META)) {
+ globfree(&w);
+ return -1;
+ }
+ g->pathc = w.gl_pathc;
+ g->pathv = w.gl_pathv;
+
+ return 0;
+#else /* Neither wordexp nor glob */
+ return -1;
+#endif
+}
+
+/*
+ * Expand the string (including meta-character) to a list of matches
+ *
+ * Return 0 if OK else -1
+ */
+int meta_expand(char *pt, GLOB_LIST *g, char *base_dir, char *version, int type)
+{
+ FILE *fin;
+ int len = 0;
+ char *line = NULL;
+ char *p, *p1;
+ char tmpline[PATH_MAX + 1];
+ char wrk[sizeof(tmpline)];
+ char tmpcmd[2*sizeof(tmpline)+20]; /* room for /bin/echo "text" */
+
+ g->pathc = 0;
+ g->pathv = NULL;
+
+ /*
+ * Take care of version dependent expansions
+ * Needed for forced version handling
+ */
+ if ((p = strchr(pt, '`')) != NULL && (type & ME_BUILTIN_COMMAND)) {
+ do {
+ char *s;
+
+ for (s = p + 1; isspace(*s); ++s)
+ ;
+
+ if (strncmp(s, "uname -r", 8) == 0) {
+ while (*s && (*s != '`'))
+ ++s;
+ if (*s == '`') {
+ *p = '\0';
+ snprintf(wrk, sizeof(wrk), "%s%s%s",
+ pt,
+ version,
+ s + 1);
+ *p = '`';
+ }
+ strcpy(tmpline, wrk); /* safe, same size */
+ pt = tmpline;
+ } else if (strncmp(s, "kernelversion", 13) == 0) {
+ while (*s && (*s != '`'))
+ ++s;
+ if (*s == '`') {
+ int n;
+ char *k;
+
+ *p = '\0';
+ for (n = 0, k = version; *k; ++k) {
+ if (*k == '.' && ++n == 2)
+ break;
+ }
+ snprintf(wrk, sizeof(wrk), "%s%.*s%s",
+ pt,
+ /* typecast for Alpha */
+ (int)(k - version),
+ version,
+ s + 1);
+ *p = '`';
+ strcpy(tmpline, wrk); /* safe, same size */
+ pt = tmpline;
+ }
+ } else
+ break;
+ } while ((p = strchr(pt, '`')) != NULL);
+ }
+
+ /*
+ * Any remaining meta-chars?
+ */
+ if (strpbrk(pt, SHELL_META) == NULL) {
+ /*
+ * No meta-chars.
+ * Split into words, delimited by whitespace.
+ */
+ snprintf(wrk, sizeof(wrk), "%s%s", (base_dir ? base_dir : ""), pt);
+ strcpy(tmpline, wrk); /* safe, same size */
+ if ((p = strtok(tmpline, " \t\n")) != NULL) {
+ while (p) {
+ g->pathv = (char **)xrealloc(g->pathv,
+ (g->pathc + 2) * sizeof(char *));
+ g->pathv[g->pathc++] = xstrdup(p);
+ p = strtok(NULL, " \t\n");
+ }
+ }
+ if (g->pathc)
+ g->pathv[g->pathc] = NULL;
+ return 0;
+ }
+ /* else */
+ /*
+ * Handle remaining meta-chars
+ */
+
+ /*
+ * Just plain quotes?
+ */
+ if (strpbrk(pt, "&();|<>$`!{}[]~=+:?*") == NULL &&
+ (p = strpbrk(pt, "\"'\\"))) {
+ split_line(g, pt, 1);
+ return 0;
+ }
+
+ if (strpbrk(pt, "&();|<>$`\"'\\!{}~+:[]~?*") == NULL) {
+ /* Only "=" remaining, should be module options */
+ split_line(g, pt, 0);
+ return 0;
+ }
+
+ /*
+ * If there are meta-characters and
+ * if they are only shell glob meta-characters: do globbing
+ */
+#if HAVE_WORDEXP
+ if (strpbrk(pt, "&();|<>`\"'\\!{}~=+:") == NULL &&
+ strpbrk(pt, "$[]~?*"))
+#else
+ if (strpbrk(pt, "&();|<>$`\"'\\!{}~=+:") == NULL &&
+ strpbrk(pt, "[]~?*"))
+#endif
+ if ((type & ME_GLOB) && glob_it(pt, g) == 0)
+ return 0;
+
+ if (strpbrk(pt, "&();|<>$`\"'\\!{}~+:[]~?*") == NULL) {
+ /* Only "=" remaining, should be module options */
+ split_line(g, pt, 0);
+ return 0;
+ }
+
+ /*
+ * Last resort: Use "echo".
+ * DANGER: Applying shell expansion to user supplied input is a
+ * major security risk. Modutils code should only do meta
+ * expansion via shell commands for trusted data. Basically
+ * this means only for data in the config file. Even that
+ * assumes that the user cannot run modprobe as root with
+ * their own config file. Programs (including the kernel)
+ * that invoke modprobe as root with user supplied input must
+ * pass exactly one user supplied parameter and must set
+ * safe mode.
+ */
+ if (!(type & ME_SHELL_COMMAND))
+ return 0;
+ snprintf(wrk, sizeof(wrk), "%s%s", (base_dir ? base_dir : ""), pt);
+ strcpy(tmpline, wrk); /* safe, same size */
+ snprintf(tmpcmd, sizeof(tmpcmd), "/bin/echo \"");
+ for (p = tmpline, p1 = tmpcmd + strlen(tmpcmd); *p; ++p, ++p1) {
+ if (*p == '"' || *p == '\\')
+ *p1++ = '\\';
+ *p1 = *p;
+ }
+ *p1++ = '"';
+ *p1++ = '\0';
+ if (p1 - tmpcmd > sizeof(tmpcmd)) {
+ error("tmpcmd overflow, should never happen");
+ exit(1);
+ }
+ if ((fin = popen(tmpcmd, "r")) == NULL) {
+ error("Can't execute: %s", tmpcmd);
+ return -1;
+ }
+ /* else */
+
+ /*
+ * Collect the result
+ */
+ while (fgets(tmpcmd, PATH_MAX, fin) != NULL) {
+ int l = strlen(tmpcmd);
+
+ line = (char *)xrealloc(line, len + l + 1);
+ line[len] = '\0';
+ strcat(line + len, tmpcmd); /* safe, realloc */
+ len += l;
+ }
+ pclose(fin);
+
+ if (line) {
+ /* shell used to strip one set of quotes. Paranoia code in
+ * 2.3.20 stops that strip so we do it ourselves.
+ */
+ split_line(g, line, 1);
+ free(line);
+ }
+
+ return 0;
+}
diff --git a/mdk-stage1/insmod-modutils/util/modstat.c b/mdk-stage1/insmod-modutils/util/modstat.c
new file mode 100644
index 000000000..ad82306c0
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/modstat.c
@@ -0,0 +1,419 @@
+/*
+ * Get kernel symbol table(s) and other relevant module info.
+ *
+ * Add module_name_list and l_module_name_list.
+ * Keith Owens <kaos@ocs.com.au> November 1999.
+ * Björn Ekwall <bj0rn@blox.se> in February 1999 (C)
+ * Initial work contributed by Richard Henderson <rth@tamu.edu>
+ *
+ * This file is part of the Linux modutils.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "util.h"
+#include "module.h"
+#include "obj.h"
+#include "modstat.h"
+
+struct module_stat *module_stat;
+size_t n_module_stat;
+char *module_name_list;
+size_t l_module_name_list;
+struct module_symbol *ksyms;
+size_t nksyms;
+int k_new_syscalls;
+
+static void *old_kernsym;
+
+/************************************************************************/
+static void drop(void)
+{
+ /*
+ * Clean the slate for multiple runs
+ */
+ if (module_stat) {
+ struct module_stat *m;
+ int i;
+
+ for (i = 0, m = module_stat; i < n_module_stat; ++i, ++m) {
+ if (m->syms)
+ free(m->syms);
+ if (m->refs)
+ free(m->refs);
+ }
+ free(module_stat);
+ module_stat = NULL;
+ n_module_stat = 0;
+ }
+ if (module_name_list) {
+ free(module_name_list);
+ module_name_list = NULL;
+ l_module_name_list = 0;
+ }
+ if (ksyms) {
+ free(ksyms);
+ ksyms = NULL;
+ nksyms = 0;
+ }
+ if (old_kernsym) {
+ free(old_kernsym);
+ old_kernsym = NULL;
+ }
+}
+
+static int new_get_kernel_info(int type)
+{
+ struct module_stat *modules;
+ struct module_stat *m;
+ struct module_symbol *syms;
+ struct module_symbol *s;
+ size_t ret;
+ size_t bufsize;
+ size_t nmod;
+ size_t nsyms;
+ size_t i;
+ size_t j;
+ char *module_names;
+ char *mn;
+
+ drop();
+
+ /*
+ * Collect the loaded modules
+ */
+ module_names = xmalloc(bufsize = 256);
+ while (query_module(NULL, QM_MODULES, module_names, bufsize, &ret)) {
+ if (errno != ENOSPC) {
+ error("QM_MODULES: %m\n");
+ return 0;
+ }
+ module_names = xrealloc(module_names, bufsize = ret);
+ }
+ module_name_list = module_names;
+ l_module_name_list = bufsize;
+ n_module_stat = nmod = ret;
+ module_stat = modules = xmalloc(nmod * sizeof(struct module_stat));
+ memset(modules, 0, nmod * sizeof(struct module_stat));
+
+ /* Collect the info from the modules */
+ for (i = 0, mn = module_names, m = modules;
+ i < nmod;
+ ++i, ++m, mn += strlen(mn) + 1) {
+ struct module_info info;
+
+ m->name = mn;
+ if (query_module(mn, QM_INFO, &info, sizeof(info), &ret)) {
+ if (errno == ENOENT) {
+ /* The module was removed out from underneath us. */
+ m->flags = NEW_MOD_DELETED;
+ continue;
+ }
+ /* else oops */
+ error("module %s: QM_INFO: %m", mn);
+ return 0;
+ }
+
+ m->addr = info.addr;
+
+ if (type & K_INFO) {
+ m->size = info.size;
+ m->flags = info.flags;
+ m->usecount = info.usecount;
+ m->modstruct = info.addr;
+ }
+
+ if (type & K_REFS) {
+ int mm;
+ char *mrefs;
+ char *mr;
+
+ mrefs = xmalloc(bufsize = 64);
+ while (query_module(mn, QM_REFS, mrefs, bufsize, &ret)) {
+ if (errno != ENOSPC) {
+ error("QM_REFS: %m");
+ return 1;
+ }
+ mrefs = xrealloc(mrefs, bufsize = ret);
+ }
+ for (j = 0, mr = mrefs;
+ j < ret;
+ ++j, mr += strlen(mr) + 1) {
+ for (mm = 0; mm < i; ++mm) {
+ if (strcmp(mr, module_stat[mm].name) == 0) {
+ m->nrefs += 1;
+ m->refs = xrealloc(m->refs, m->nrefs * sizeof(struct module_stat **));
+ m->refs[m->nrefs - 1] = module_stat + mm;
+ break;
+ }
+ }
+ }
+ free(mrefs);
+ }
+
+ if (type & K_SYMBOLS) { /* Want info about symbols */
+ syms = xmalloc(bufsize = 1024);
+ while (query_module(mn, QM_SYMBOLS, syms, bufsize, &ret)) {
+ if (errno == ENOSPC) {
+ syms = xrealloc(syms, bufsize = ret);
+ continue;
+ }
+ if (errno == ENOENT) {
+ /*
+ * The module was removed out
+ * from underneath us.
+ */
+ m->flags = NEW_MOD_DELETED;
+ free(syms);
+ goto next;
+ } else {
+ error("module %s: QM_SYMBOLS: %m", mn);
+ return 0;
+ }
+ }
+ nsyms = ret;
+
+ m->nsyms = nsyms;
+ m->syms = syms;
+
+ /* Convert string offsets to string pointers */
+ for (j = 0, s = syms; j < nsyms; ++j, ++s)
+ s->name += (unsigned long) syms;
+ }
+ next:
+ }
+
+ if (type & K_SYMBOLS) { /* Want info about symbols */
+ /* Collect the kernel's symbols. */
+ syms = xmalloc(bufsize = 16 * 1024);
+ while (query_module(NULL, QM_SYMBOLS, syms, bufsize, &ret)) {
+ if (errno != ENOSPC) {
+ error("kernel: QM_SYMBOLS: %m");
+ return 0;
+ }
+ syms = xrealloc(syms, bufsize = ret);
+ }
+ nksyms = nsyms = ret;
+ ksyms = syms;
+
+ /* Convert string offsets to string pointers */
+ for (j = 0, s = syms; j < nsyms; ++j, ++s)
+ s->name += (unsigned long) syms;
+ }
+
+ return 1;
+}
+
+#ifdef COMPAT_2_0
+/************************************************************************/
+
+#define mscan(offs,siz,ptr) \
+ if (lseek(kmem_fd, (off_t)(offs), SEEK_SET) == -1 || \
+ read(kmem_fd, (ptr), (siz)) != (siz)) { \
+ if (kmem_fd != -1) \
+ close(kmem_fd); \
+ error("kmem: %m"); \
+ return 0; \
+ }
+
+#define OLD_MOD_RUNNING 1
+#define OLD_MOD_DELETED 2
+#define OLD_MOD_VISITED 0x20000000
+
+/* Fetch all the symbols and divvy them up as appropriate for the modules. */
+static int old_get_kernel_info(int type)
+{
+ struct old_kernel_sym *kernsym;
+ struct old_kernel_sym *k;
+ struct module_stat *module;
+ struct module_stat *mod;
+ struct module_symbol *s = NULL;
+ int kmem_fd = -1;
+ int nkernsym;
+ int nmod;
+ int nm;
+ int nms;
+ int i;
+
+ drop();
+ module_name_list = xmalloc(1);
+ *module_name_list = '\0';
+
+ if ((nkernsym = get_kernel_syms(NULL)) < 0) {
+ error("get_kernel_syms: %m");
+ return 0;
+ }
+ kernsym = k = xmalloc(nkernsym * sizeof(struct old_kernel_sym));
+ old_kernsym = kernsym;
+ if (get_kernel_syms(kernsym) != nkernsym) {
+ error("inconsistency with get_kernel_syms -- is someone else "
+ "playing with modules?");
+ free(kernsym);
+ return 0;
+ }
+
+ /* Number of modules */
+ for (k = kernsym, nmod = 0, i = 0; i < nkernsym; ++i, ++k) {
+ if (k->name[0] == '#') {
+ if (k->name[1]) {
+ ++nmod;
+ i = strlen(k->name+1) + 1;
+ module_name_list =
+ xrealloc(module_name_list,
+ l_module_name_list + i);
+ strcpy(module_name_list+l_module_name_list, /* safe, xrealloc */
+ k->name+1);
+ l_module_name_list += i; /* NUL separated strings */
+ }
+ else
+ break;
+ }
+ }
+ module_stat = mod = module = xmalloc(nmod * sizeof(struct module_stat));
+ memset(module, 0, nmod * sizeof(struct module_stat));
+ n_module_stat = nmod;
+
+ /*
+ * Will we need kernel internal info?
+ */
+ if ((type & K_INFO) || (type & K_REFS)) {
+ if ((kmem_fd = open("/dev/kmem", O_RDONLY)) < 0) {
+ perror("ksyms: open /dev/kmem");
+ return 0;
+ }
+ }
+
+ /*
+ * Collect the module information.
+ */
+ for (k = kernsym, nm = 0, i = 0; i < nkernsym; ++i, ++k) {
+ if (k->name[0] == '#') {
+ struct old_kernel_sym *p;
+ struct old_module info;
+
+ if (k->name[1] == '\0')
+ break; /* kernel resident symbols follow */
+ /* else normal module */
+
+ module = mod++;
+ ++nm;
+ module->name = k->name + 1;
+ module->modstruct = k->value;
+
+ if ((type & K_INFO) || (type & K_REFS)) {
+ long tmp;
+ /*
+ * k->value is the address of the
+ * struct old_module
+ * in the kernel (for use via /dev/kmem)
+ */
+ mscan(k->value, sizeof(info), &info);
+ module->addr = info.addr;
+ module->size = info.size * getpagesize();
+
+ mscan(info.addr, sizeof(long), &tmp);
+ module->flags = info.state &
+ (OLD_MOD_RUNNING | OLD_MOD_DELETED);
+ module->flags |= NEW_MOD_USED_ONCE; /* Cheat */
+ if (tmp & OLD_MOD_AUTOCLEAN)
+ module->flags |= NEW_MOD_AUTOCLEAN;
+ if (tmp & OLD_MOD_VISITED)
+ module->flags |= NEW_MOD_VISITED;
+
+ module->usecount = tmp & ~(OLD_MOD_AUTOCLEAN | OLD_MOD_VISITED);
+ }
+
+ if ((type & K_REFS) && info.ref) {
+ struct old_module_ref mr;
+ int j;
+ unsigned long ref = info.ref;
+
+ do {
+ mscan(ref, sizeof(struct old_module_ref), &mr);
+ for (j = 0; j < nm -1; ++j) {
+ if (mr.module == module_stat[j].modstruct) {
+ module->nrefs += 1;
+ module->refs = xrealloc(module->refs, module->nrefs * sizeof(struct module_stat **));
+ module->refs[module->nrefs - 1] = module_stat + j;
+ break;
+ }
+ }
+ } while ((ref = mr.next) != 0);
+ }
+
+ if (!(type & K_SYMBOLS))
+ continue;
+ /*
+ * Find out how many symbols this module has.
+ */
+ for (nms = 0, p = k+1; p->name[0] != '#'; ++p)
+ ++nms;
+ s = xmalloc(nms * sizeof(struct module_symbol));
+ module->syms = s;
+ module->nsyms = nms;
+ } else if (type & K_SYMBOLS) { /* Want info about symbols */
+ s->name = (unsigned long) k->name;
+ s->value = k->value;
+ ++s;
+ }
+ }
+ if ((type & K_INFO) || (type & K_REFS)) {
+ if (kmem_fd != -1)
+ close(kmem_fd);
+ }
+
+ /*
+ * Kernel resident symbols follows
+ */
+ if (type & K_SYMBOLS) { /* Want info about symbols */
+ if (k->name[0] == '#')
+ ++k;
+ nksyms = nkernsym - (k - kernsym);
+ if (nksyms) {
+ ksyms = s = xmalloc(nksyms * sizeof(struct module_symbol));
+ for (i = 0; i < nksyms; ++i, ++k) {
+ if (k->name[0] != '#') {
+ s->name = (unsigned long) k->name;
+ s->value = k->value;
+ ++s;
+ }
+ }
+ nksyms = s - ksyms;
+ } else
+ ksyms = NULL;
+ }
+
+ return 1;
+}
+#endif /* COMPAT_2_0 */
+
+int get_kernel_info(int type)
+{
+ k_new_syscalls = !query_module(NULL, 0, NULL, 0, NULL);
+
+#ifdef COMPAT_2_0
+ if (!k_new_syscalls)
+ return old_get_kernel_info(type);
+#endif /* COMPAT_2_0 */
+
+ return new_get_kernel_info(type);
+}
diff --git a/mdk-stage1/insmod-modutils/util/snap_shot.c b/mdk-stage1/insmod-modutils/util/snap_shot.c
new file mode 100644
index 000000000..ae0cc7c79
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/snap_shot.c
@@ -0,0 +1,154 @@
+/* Take a snap shot of ksyms and modules for Oops debugging
+ Copyright 1999 Linux International.
+
+ Contributed by Keith Owens <kaos@ocs.com.au>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ident "$Id$"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "module.h"
+#include "obj.h"
+#include "modstat.h"
+#include "util.h"
+
+static char snap_dir[] = "/var/log/ksymoops";
+
+/* If snap_dir exists, take a snap shot of ksyms and modules to snap_dir.
+ * Prefix the files with the equivalent of
+ * date +%Y%m%d%T%M%S | sed -e 's/://g'
+ */
+void snap_shot(const char *module_names, int n_module_names)
+{
+ char file[] = "ccyymmddhhmmss.modules", buffer[4096];
+ static char *infile[] = { "/proc/ksyms", "/proc/modules" };
+ static char *suffix[] = { "ksyms", "modules" };
+ struct tm *local;
+ time_t t;
+ int i, l;
+ FILE *in, *out;
+
+ if (module_names) {
+ /* Only snap shot if the list of modules has changed.
+ * Otherwise auto cleanup takes a snap shot every time
+ * and ends up with a large snap shot directory.
+ */
+ char *new_module_names;
+ size_t n_new_module_names;
+ get_kernel_info(0);
+ new_module_names = module_name_list;
+ n_new_module_names = n_module_stat;
+ if (n_module_names && n_new_module_names == n_module_names) {
+ while (n_module_names) {
+ if (strcmp(module_names, new_module_names))
+ break; /* difference detected */
+ i = strlen(module_names) + 1;
+ module_names += i;
+ new_module_names += i;
+ --n_module_names;
+ }
+ }
+ if (!n_module_names)
+ return; /* no difference, no need for snap shot */
+ }
+
+ if (chdir(snap_dir))
+ return;
+ t = time(NULL);
+ local = localtime(&t);
+ for (i = 0; i < sizeof(infile)/sizeof(infile[0]); ++i) {
+ snprintf(file, sizeof(file), "%04d%02d%02d%02d%02d%02d.%s",
+ local->tm_year+1900,
+ local->tm_mon + 1,
+ local->tm_mday,
+ local->tm_hour,
+ local->tm_min,
+ local->tm_sec,
+ suffix[i]);
+ out = fopen(file, "w");
+ if (!out) {
+ error("cannot create %s/%s %m", snap_dir, file);
+ return;
+ }
+ in = fopen(infile[i], "r");
+ if (!in) {
+ error("cannot open %s %m", infile[i]);
+ return;
+ }
+ while ((l = fread(buffer, 1, sizeof(buffer), in)) > 0) {
+ if (fwrite(buffer, l, 1, out) != 1) {
+ error("unable to write to %s %m", file);
+ fclose(in);
+ fclose(out);
+ return;
+ }
+ }
+ if (ferror(in))
+ error("unable to read from %s %m", infile[i]);
+ fclose(in);
+ fclose(out);
+ }
+}
+
+/* If snap_dir exists, log a message to snap_dir. The log file is called the
+ * equivalent of date +%Y%m%d | sed -e 's/://g'. Each line is prefixed with
+ * timestamp down to seconds and followed by a newline.
+ */
+void snap_shot_log(const char *fmt,...)
+{
+ char date[] = "ccyymmdd", file[] = "ccyymmdd.log", stamp[] = "ccyymmdd hhmmss";
+ struct tm *local;
+ time_t t;
+ FILE *log;
+ va_list args;
+ int save_errno = errno;
+
+ if (chdir(snap_dir))
+ return;
+ t = time(NULL);
+ local = localtime(&t);
+ snprintf(date, sizeof(date), "%04d%02d%02d",
+ local->tm_year+1900,
+ local->tm_mon + 1,
+ local->tm_mday);
+ snprintf(file, sizeof(file), "%s.log", date);
+ log = fopen(file, "a");
+ if (!log) {
+ error("cannot create %s/%s %m", snap_dir, file);
+ return;
+ }
+ snprintf(stamp, sizeof(stamp), "%s %02d%02d%02d",
+ date,
+ local->tm_hour,
+ local->tm_min,
+ local->tm_sec);
+ fprintf(log, "%s ", stamp);
+ va_start(args, fmt);
+ errno = save_errno; /* fmt may use %m */
+ vfprintf(log, fmt, args);
+ va_end(args);
+ fprintf(log, "\n");
+ fclose(log);
+}
diff --git a/mdk-stage1/insmod-modutils/util/sys_cm.c b/mdk-stage1/insmod-modutils/util/sys_cm.c
new file mode 100644
index 000000000..851fb709e
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/sys_cm.c
@@ -0,0 +1,88 @@
+/* Functions for the Linux module syscall interface.
+ Copyright 1996, 1997 Linux International.
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <stdlib.h>
+#include <errno.h>
+
+#include "module.h"
+
+/* Kernel headers before 2.1.mumble need this on the Alpha to get
+ _syscall* defined. */
+#define __LIBRARY__
+
+#include <asm/unistd.h>
+
+
+/*======================================================================*/
+
+#if defined(__i386__) || defined(__m68k__) || defined(__arm__)
+
+#define __NR__create_module __NR_create_module
+static inline _syscall2(long, _create_module, const char *, name, size_t, size)
+
+unsigned long create_module(const char *name, size_t size)
+{
+ /* Why all this fuss?
+
+ In linux 2.1, the address returned by create module point in
+ kernel space which is now mapped at the top of user space (at
+ 0xc0000000 on i386). This looks like a negative number for a
+ long. The normal syscall macro of linux 2.0 (and all libc compile
+ with linux 2.0 or below) consider that the return value is a
+ negative number and consider it is an error number (A kernel
+ convention, return value are positive or negative, indicating the
+ error number).
+
+ By checking the value of errno, we know if we have been fooled by
+ the syscall2 macro and we fix it. */
+
+ long ret = _create_module(name, size);
+ if (ret == -1 && errno > 125)
+ {
+ ret = -errno;
+ errno = 0;
+ }
+ return ret;
+}
+
+#elif defined(__alpha__)
+
+/* Alpha doesn't have the same problem, exactly, but a bug in older
+ kernels fails to clear the error flag. Clear it here explicitly. */
+
+#define __NR__create_module __NR_create_module
+static inline _syscall4(unsigned long, _create_module, const char *, name,
+ size_t, size, size_t, dummy, size_t, err);
+
+unsigned long create_module(const char *name, size_t size)
+{
+ return _create_module(name, size, 0, 0);
+}
+
+#else
+
+/* Sparc, MIPS, (and Alpha, but that's another problem) don't mistake
+ return values for errors due to the nature of the system call. */
+
+_syscall2(unsigned long, create_module, const char *, name, size_t, size)
+
+#endif
diff --git a/mdk-stage1/insmod-modutils/util/sys_dm.c b/mdk-stage1/insmod-modutils/util/sys_dm.c
new file mode 100644
index 000000000..a166a30f4
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/sys_dm.c
@@ -0,0 +1,37 @@
+/* Functions for the Linux module syscall interface.
+ Copyright 1996, 1997 Linux International.
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <stdlib.h>
+#include <errno.h>
+
+#include "module.h"
+
+/* Kernel headers before 2.1.mumble need this on the Alpha to get
+ _syscall* defined. */
+#define __LIBRARY__
+
+#include <asm/unistd.h>
+
+
+/*======================================================================*/
+
+_syscall1(int, delete_module, const char *, name)
diff --git a/mdk-stage1/insmod-modutils/util/sys_gks.c b/mdk-stage1/insmod-modutils/util/sys_gks.c
new file mode 100644
index 000000000..f71772c71
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/sys_gks.c
@@ -0,0 +1,37 @@
+/* Functions for the Linux module syscall interface.
+ Copyright 1996, 1997 Linux International.
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <stdlib.h>
+#include <errno.h>
+
+#include "module.h"
+
+/* Kernel headers before 2.1.mumble need this on the Alpha to get
+ _syscall* defined. */
+#define __LIBRARY__
+
+#include <asm/unistd.h>
+
+
+/*======================================================================*/
+
+_syscall1(int, get_kernel_syms, struct old_kernel_sym *, ksyms)
diff --git a/mdk-stage1/insmod-modutils/util/sys_nim.c b/mdk-stage1/insmod-modutils/util/sys_nim.c
new file mode 100644
index 000000000..bbe42135c
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/sys_nim.c
@@ -0,0 +1,53 @@
+/* Functions for the Linux module syscall interface.
+ Copyright 1996, 1997 Linux International.
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <stdlib.h>
+#include <errno.h>
+
+#include "module.h"
+
+/* Kernel headers before 2.1.mumble need this on the Alpha to get
+ _syscall* defined. */
+#define __LIBRARY__
+
+#include <asm/unistd.h>
+
+
+/*======================================================================*/
+
+#ifndef CONFIG_USE_SYSCALL
+
+extern int init_module(const char *name, const struct module *info);
+
+int
+sys_init_module(const char *name, const struct module *info)
+{
+ return init_module(name, info);
+}
+
+#else
+
+#define __NR_sys_init_module __NR_init_module
+_syscall2(int, sys_init_module, const char *, name,
+ const struct module *, info)
+
+#endif
diff --git a/mdk-stage1/insmod-modutils/util/sys_oim.c b/mdk-stage1/insmod-modutils/util/sys_oim.c
new file mode 100644
index 000000000..73ac6be52
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/sys_oim.c
@@ -0,0 +1,40 @@
+/* Functions for the Linux module syscall interface.
+ Copyright 1996, 1997 Linux International.
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <stdlib.h>
+#include <errno.h>
+
+#include "module.h"
+
+/* Kernel headers before 2.1.mumble need this on the Alpha to get
+ _syscall* defined. */
+#define __LIBRARY__
+
+#include <asm/unistd.h>
+
+
+/*======================================================================*/
+
+#define __NR_old_sys_init_module __NR_init_module
+_syscall5(int, old_sys_init_module, const char *, name, char *, code,
+ unsigned, codesize, struct old_mod_routines *, routines,
+ struct old_symbol_table *, symtab)
diff --git a/mdk-stage1/insmod-modutils/util/sys_qm.c b/mdk-stage1/insmod-modutils/util/sys_qm.c
new file mode 100644
index 000000000..119a219a2
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/sys_qm.c
@@ -0,0 +1,56 @@
+/* Functions for the Linux module syscall interface.
+ Copyright 1996, 1997 Linux International.
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <stdlib.h>
+#include <errno.h>
+
+#include "module.h"
+
+/* Kernel headers before 2.1.mumble need this on the Alpha to get
+ _syscall* defined. */
+#define __LIBRARY__
+
+#include <asm/unistd.h>
+
+
+/*======================================================================*/
+
+/* I am fucking tired of the "this doesn't build on 2.0.x" questions.
+ But if you ask, we still officially require 2.1.x to build. */
+#if !defined(__NR_query_module)
+# if defined(__i386__)
+# define __NR_query_module 167
+# elif defined(__alpha__)
+# define __NR_query_module 347
+# elif defined(__sparc__)
+# define __NR_query_module 184
+# elif defined(__mc68000__)
+# define __NR_query_module 167
+# elif defined(__arm__)
+# define __NR_query_module (__NR_SYSCALL_BASE + 167)
+# elif defined(__mips__)
+# define __NR_query_module 4187
+# endif
+#endif
+
+_syscall5(int, query_module, const char *, name, int, which,
+ void *, buf, size_t, bufsize, size_t *, ret);
diff --git a/mdk-stage1/insmod-modutils/util/xftw.c b/mdk-stage1/insmod-modutils/util/xftw.c
new file mode 100644
index 000000000..fe764a63c
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/xftw.c
@@ -0,0 +1,422 @@
+/*
+ * modutils specific implementation of ftw().
+ *
+ * Copyright 2000:
+ * Keith Owens <kaos@ocs.com.au> August 2000
+ *
+ * This file is part of the Linux modutils.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ modutils requires special processing during the file tree walk
+ of /lib/modules/<version> and any paths that the user specifies.
+ The standard ftw() does a blind walk of all paths and can end
+ up following the build symlink down the kernel source tree.
+ Although nftw() has the option to get more control such as not
+ automatically following symbolic links, even that is not enough
+ for modutils. The requirements are:
+
+ Paths must be directories or symlinks to directories.
+
+ Each directory is read and sorted into alphabetical order
+ before processing.
+
+ A directory is type 1 iff it was specified on a path statement
+ (either explicit or default) and the directory contains a
+ subdirectory with one of the known names and the directory name
+ does not end with "/kernel". Otherwise it is type 2.
+
+ In a type 1 directory, walk the kernel subdirectory if it exists,
+ then the old known names in their historical order then any
+ remaining directory entries in alphabetical order and finally any
+ non-directory entries in alphabetical order.
+
+ Entries in a type 1 directory are filtered against the "prune"
+ list. A type 1 directory can contain additional files which
+ are not modules nor symlinks to modules. The prune list skips
+ known additional files, if a distribution wants to store
+ additional text files in the top level directory they should be
+ added to the prune list.
+
+ A type 2 directory must contain only modules or symlinks to
+ modules. They are processed in alphabetical order, without
+ pruning. Symlinks to directories are an error in type 2
+ directories.
+
+ The user function is not called for type 1 directories, nor for
+ pruned entries. It is called for type 2 directories and their
+ contents. It is also called for any files left in a type 1
+ directory after pruning and processing type 2 subdirectories.
+ The user function never sees symlinks, they are resolved before
+ calling the function.
+
+ Why have different directory types? The original file tree
+ walk was not well defined. Some users specified each directory
+ individually, others just pointed at the top level directory.
+ Either version worked until the "build" symlink was added. Now
+ users who specify the top level directory end up running the
+ entire kernel source tree looking for modules, not nice. We
+ cannot just ignore symlinks because pcmcia uses symlinks to
+ modules for backwards compatibility.
+
+ Type 1 is when a user specifies the top level directory which needs
+ special processing, type 2 is individual subdirectories. But the
+ only way to tell the difference is by looking at the contents. The
+ "/kernel" directory introduced in 2.3.12 either contains nothing
+ (old make modules_install) or contains all the kernel modules using
+ the same tree structure as the source. Because "/kernel" can
+ contain old names but is really a type 2 directory, it is detected
+ as a special case.
+ */
+
+#include <dirent.h>
+#include <errno.h>
+#include <limits.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include "util.h"
+#include "config.h"
+
+extern char *tbpath[];
+
+extern OPT_LIST *prune_list;
+extern int n_prune_list;
+
+extern char *tbtype[];
+
+struct xftw_dirent {
+ struct stat statbuf;
+ char *name;
+ char *fullname;
+};
+
+#define XFTW_MAXDEPTH 64 /* Maximum directory depth handled */
+
+typedef struct {
+ struct xftw_dirent *contents;
+ int size;
+ int used;
+} xftw_tree_t;
+
+static xftw_tree_t tree[XFTW_MAXDEPTH];
+
+/* Free all data for one tree level */
+static void xftw_free_tree(int depth)
+{
+ int i;
+ xftw_tree_t *t = tree+depth;
+ for (i = 0; i < t->size; ++i) {
+ free(t->contents[i].name);
+ free(t->contents[i].fullname);
+ }
+ free(t->contents);
+ t->contents = NULL;
+ t->size = 0;
+ t->used = 0;
+}
+
+/* Increment dirents used at this depth, resizing if necessary */
+static void xftw_add_dirent(int depth)
+{
+ xftw_tree_t *t = tree+depth;
+ int i, size = t->size;
+ if (++t->used < size)
+ return;
+ size += 10; /* arbitrary increment */
+ t->contents = xrealloc(t->contents, size*sizeof(*(t->contents)));
+ for (i = t->size; i < size; ++i) {
+ memset(&(t->contents[i].statbuf), 0, sizeof(t->contents[i].statbuf));
+ t->contents[i].name = NULL;
+ t->contents[i].fullname = NULL;
+ }
+ t->size = size;
+}
+
+/* Concatenate directory name and entry name into one string.
+ * Note: caller must free result or leak.
+ */
+static char *xftw_dir_name(const char *directory, const char *entry)
+{
+ int i = strlen(directory);
+ char *name;
+ if (entry)
+ i += strlen(entry);
+ i += 2;
+ name = xmalloc(i);
+ strcpy(name, directory); /* safe, xmalloc */
+ if (*directory && entry)
+ strcat(name, "/"); /* safe, xmalloc */
+ if (entry)
+ strcat(name, entry); /* safe, xmalloc */
+ return(name);
+}
+
+/* Call the user function for a directory entry */
+static int xftw_do_name(const char *directory, const char *entry, struct stat *sb, xftw_func_t funcptr)
+{
+ int ret = 0;
+ char *name = xftw_dir_name(directory, entry);
+
+ if (S_ISLNK(sb->st_mode)) {
+ char real[PATH_MAX], *newname;
+ verbose("resolving %s symlink to ", name);
+ if (!(newname = realpath(name, real))) {
+ if (errno == ENOENT) {
+ verbose("%s: does not exist, dangling symlink ignored\n", real);
+ goto cleanup;
+ }
+ perror("... failed");
+ goto cleanup;
+ }
+ verbose("%s ", newname);
+ if (lstat(newname, sb)) {
+ error("lstat on %s failed ", newname);
+ perror("");
+ goto cleanup;
+ }
+ free(name);
+ name = xstrdup(newname);
+ }
+
+ if (!S_ISREG(sb->st_mode) &&
+ !S_ISDIR(sb->st_mode)) {
+ error("%s is not plain file nor directory\n", name);
+ goto cleanup;
+ }
+
+ verbose("user function %s\n", name);
+ ret = (*funcptr)(name, sb);
+cleanup:
+ free(name);
+ return(ret);
+}
+
+/* Sort directory entries into alphabetical order */
+static int xftw_sortdir(const void *a, const void *b)
+{
+ return(strcmp(((struct xftw_dirent *)a)->name, ((struct xftw_dirent *)b)->name));
+}
+
+/* Read a directory and sort it, ignoring "." and ".." */
+static int xftw_readdir(const char *directory, int depth)
+{
+ DIR *d;
+ struct dirent *ent;
+ verbose("xftw_readdir %s\n", directory);
+ if (!(d = opendir(directory))) {
+ perror(directory);
+ return(1);
+ }
+ while ((ent = readdir(d))) {
+ char *name;
+ struct xftw_dirent *f;
+ if (strcmp(ent->d_name, ".") == 0 ||
+ strcmp(ent->d_name, "..") == 0)
+ continue;
+ name = xftw_dir_name(directory, ent->d_name);
+ xftw_add_dirent(depth);
+ f = tree[depth].contents+tree[depth].used-1;
+ f->name = xstrdup(ent->d_name);
+ f->fullname = name; /* do not free name, it is in use */
+ if (lstat(name, &(f->statbuf))) {
+ perror(name);
+ return(1);
+ }
+ }
+ closedir(d);
+ qsort(tree[depth].contents, tree[depth].used, sizeof(*(tree[0].contents)), &xftw_sortdir);
+ return(0);
+}
+
+/* Process a type 2 directory */
+int xftw_type2(const char *directory, const char *entry, int depth, xftw_func_t funcptr)
+{
+ int ret, i;
+ xftw_tree_t *t = tree+depth;
+ struct stat statbuf;
+ char *dirname = xftw_dir_name(directory, entry);
+
+ verbose("type 2 %s\n", dirname);
+ if (depth > XFTW_MAXDEPTH) {
+ error("xftw_type2 exceeded maxdepth\n");
+ ret = 1;
+ goto cleanup;
+ }
+ if ((ret = xftw_readdir(dirname, depth)))
+ goto cleanup;
+
+ t = tree+depth;
+ /* user function sees type 2 directories */
+ if ((ret = lstat(dirname, &statbuf)) ||
+ (ret = xftw_do_name("", dirname, &statbuf, funcptr)))
+ goto cleanup;
+
+ /* user sees all contents of type 2 directory, no pruning */
+ for (i = 0; i < t->used; ++i) {
+ struct xftw_dirent *c = t->contents+i;
+ if (S_ISLNK(c->statbuf.st_mode)) {
+ if (!stat(c->name, &(c->statbuf))) {
+ if (S_ISDIR(c->statbuf.st_mode)) {
+ error("symlink to directory is not allowed, %s ignored\n", c->name);
+ *(c->name) = '\0'; /* ignore it */
+ }
+ }
+ }
+ if (!*(c->name))
+ continue;
+ if (S_ISDIR(c->statbuf.st_mode)) {
+ /* recursion is the curse of the programming classes */
+ ret = xftw_type2(dirname, c->name, depth+1, funcptr);
+ if (ret)
+ goto cleanup;
+ }
+ else if ((ret = xftw_do_name(dirname, c->name, &(c->statbuf), funcptr)))
+ goto cleanup;
+ *(c->name) = '\0'; /* processed */
+ }
+
+ ret = 0;
+cleanup:
+ free(dirname);
+ return(ret);
+}
+
+/* Only external visible function. Decide on the type of directory and
+ * process accordingly.
+ */
+int xftw(const char *directory, xftw_func_t funcptr)
+{
+ struct stat statbuf;
+ int ret, i, j, type;
+ xftw_tree_t *t;
+ struct xftw_dirent *c;
+
+ verbose("xftw starting at %s ", directory);
+ if (lstat(directory, &statbuf)) {
+ verbose("lstat on %s failed\n", directory);
+ return(0);
+ }
+ if (S_ISLNK(statbuf.st_mode)) {
+ char real[PATH_MAX];
+ verbose("resolving symlink to ");
+ if (!(directory = realpath(directory, real))) {
+ if (errno == ENOENT) {
+ verbose("%s: does not exist, dangling symlink ignored\n", real);
+ return(0);
+ }
+ perror("... failed");
+ return(-1);
+ }
+ verbose("%s ", directory);
+ if (lstat(directory, &statbuf)) {
+ error("lstat on %s failed ", directory);
+ perror("");
+ return(-1);
+ }
+ }
+ if (!S_ISDIR(statbuf.st_mode)) {
+ error("%s is not a directory\n", directory);
+ return(-1);
+ }
+ verbose("\n");
+
+ /* All returns after this point must be via cleanup */
+
+ if ((ret = xftw_readdir(directory, 0)))
+ goto cleanup;
+
+ t = tree; /* depth 0 */
+ type = 2;
+ for (i = 0 ; type == 2 && i < t->used; ++i) {
+ c = t->contents+i;
+ for (j = 0; tbtype[j]; ++j) {
+ if (strcmp(c->name, tbtype[j]) == 0 &&
+ S_ISDIR(c->statbuf.st_mode)) {
+ const char *p = directory + strlen(directory) - 1;
+ if (*p == '/')
+ --p;
+ if (p - directory >= 6 && strncmp(p-6, "/kernel", 7) == 0)
+ continue; /* "/kernel" path is a special case, type 2 */
+ type = 1; /* known subdirectory */
+ break;
+ }
+ }
+ }
+
+ if (type == 1) {
+ OPT_LIST *p;
+ /* prune entries in type 1 directories only */
+ for (i = 0 ; i < t->used; ++i) {
+ for (p = prunelist; p->name; ++p) {
+ c = t->contents+i;
+ if (strcmp(p->name, c->name) == 0) {
+ verbose("pruned %s\n", c->name);
+ *(c->name) = '\0'; /* ignore */
+ }
+ }
+ }
+ /* run known subdirectories first in historical order, "kernel" is now top of list */
+ for (i = 0 ; i < t->used; ++i) {
+ c = t->contents+i;
+ for (j = 0; tbtype[j]; ++j) {
+ if (*(c->name) &&
+ strcmp(c->name, tbtype[j]) == 0 &&
+ S_ISDIR(c->statbuf.st_mode)) {
+ if ((ret = xftw_type2(directory, c->name, 1, funcptr)))
+ goto cleanup;
+ *(c->name) = '\0'; /* processed */
+ }
+ }
+ }
+ /* any other directories left, in alphabetical order */
+ for (i = 0 ; i < t->used; ++i) {
+ c = t->contents+i;
+ if (*(c->name) &&
+ S_ISDIR(c->statbuf.st_mode)) {
+ if ((ret = xftw_type2(directory, c->name, 1, funcptr)))
+ goto cleanup;
+ *(c->name) = '\0'; /* processed */
+ }
+ }
+ /* anything else is passed to the user function */
+ for (i = 0 ; i < t->used; ++i) {
+ c = t->contents+i;
+ if (*(c->name)) {
+ verbose("%s found in type 1 directory %s\n", c->name, directory);
+ if ((ret = xftw_do_name(directory, c->name, &(c->statbuf), funcptr)))
+ goto cleanup;
+ *(c->name) = '\0'; /* processed */
+ }
+ }
+ }
+ else {
+ /* type 2 */
+ xftw_free_tree(0);
+ if ((ret = xftw_type2(directory, NULL, 0, funcptr)))
+ goto cleanup;
+ }
+
+ /* amazing, it all worked */
+ ret = 0;
+cleanup:
+ for (i = 0; i < XFTW_MAXDEPTH; ++i)
+ xftw_free_tree(i);
+ return(ret);
+}
diff --git a/mdk-stage1/insmod-modutils/util/xmalloc.c b/mdk-stage1/insmod-modutils/util/xmalloc.c
new file mode 100644
index 000000000..9113d47fe
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/xmalloc.c
@@ -0,0 +1,39 @@
+/* Misc utility functions.
+ Copyright 1996, 1997 Linux International.
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <stdlib.h>
+#include "util.h"
+
+
+/*======================================================================*/
+
+void *
+xmalloc(size_t size)
+{
+ void *ptr = malloc(size);
+ if (!ptr)
+ {
+ error("Out of memory");
+ exit(1);
+ }
+ return ptr;
+}
diff --git a/mdk-stage1/insmod-modutils/util/xrealloc.c b/mdk-stage1/insmod-modutils/util/xrealloc.c
new file mode 100644
index 000000000..d287486f7
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/xrealloc.c
@@ -0,0 +1,39 @@
+/* Misc utility functions.
+ Copyright 1996, 1997 Linux International.
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <stdlib.h>
+#include "util.h"
+
+
+/*======================================================================*/
+
+void *
+xrealloc(void *old, size_t size)
+{
+ void *ptr = realloc(old, size);
+ if (!ptr)
+ {
+ error("Out of memory");
+ exit(1);
+ }
+ return ptr;
+}
diff --git a/mdk-stage1/insmod-modutils/util/xstrcat.c b/mdk-stage1/insmod-modutils/util/xstrcat.c
new file mode 100644
index 000000000..abb075c83
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/xstrcat.c
@@ -0,0 +1,40 @@
+/* Misc utility functions.
+ Copyright 2000 Keith Owens <kaos@ocs.com.au>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id"
+
+#include <stdlib.h>
+#include <string.h>
+#include "util.h"
+
+
+/*======================================================================*/
+
+char *
+xstrcat(char *dest, const char *src, size_t size)
+{
+ int ldest = strlen(dest);
+ int lsrc = strlen(src);
+ if ((size - ldest - 1) < lsrc) {
+ error("xstrcat: destination overflow");
+ exit(1);
+ }
+ memcpy(dest+ldest, src, lsrc+1);
+ return(dest);
+}
diff --git a/mdk-stage1/insmod-modutils/util/xstrdup.c b/mdk-stage1/insmod-modutils/util/xstrdup.c
new file mode 100644
index 000000000..11b289eb0
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/xstrdup.c
@@ -0,0 +1,41 @@
+/* Misc utility functions.
+ Copyright 1996, 1997 Linux International.
+ Contributed by Richard Henderson <rth@tamu.edu>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id$"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "util.h"
+
+
+/*======================================================================*/
+
+char *
+xstrdup(const char *s)
+{
+ char *n = strdup(s);
+ if (!n)
+ {
+ error("Out of memory");
+ exit(1);
+ }
+ return n;
+}
diff --git a/mdk-stage1/insmod-modutils/util/xsystem.c b/mdk-stage1/insmod-modutils/util/xsystem.c
new file mode 100644
index 000000000..edb995268
--- /dev/null
+++ b/mdk-stage1/insmod-modutils/util/xsystem.c
@@ -0,0 +1,51 @@
+/* Misc utility functions.
+ Copyright 2000 Keith Owens <kaos@ocs.com.au>
+
+ This file is part of the Linux modutils.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ident "$Id"
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <unistd.h>
+
+
+/*======================================================================*/
+
+/* Clone of the system() function From Steven's Advanced Programming in a Unix
+ * Environment. Modified to use *argv[] and execvp to avoid shell expansion
+ * problems, modutils runs as root so system() is unsafe.
+ */
+
+int
+xsystem(const char *file, char *const argv[])
+{
+ pid_t pid;
+ int status;
+ if ((pid = fork()) < 0)
+ return(-1);
+ if (pid == 0) {
+ execvp(file, argv);
+ _exit(127);
+ }
+ while (waitpid(pid, &status, 0) < 0) {
+ if (errno != EINTR)
+ return(-1);
+ }
+ return(status);
+}
diff --git a/mdk-stage1/insmod.h b/mdk-stage1/insmod.h
new file mode 100644
index 000000000..d91f239cf
--- /dev/null
+++ b/mdk-stage1/insmod.h
@@ -0,0 +1,20 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 MandrakeSoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef _INSMOD_INTERFACE_H_
+#define _INSMOD_INTERFACE_H_
+
+int insmod_call(char * full_filename, char * params);
+
+#endif
diff --git a/mdk-stage1/modules.c b/mdk-stage1/modules.c
index 1b85fa7c8..2788315f8 100644
--- a/mdk-stage1/modules.c
+++ b/mdk-stage1/modules.c
@@ -25,7 +25,7 @@
#include <unistd.h>
#include <string.h>
#include <stdio.h>
-#include "insmod-busybox/insmod.h"
+#include "insmod.h"
#include "stage1.h"
#include "log.h"
#include "mar/mar-extract-only.h"
diff --git a/mdk-stage1/stage1.c b/mdk-stage1/stage1.c
index 64753bdcf..8956a2a7f 100644
--- a/mdk-stage1/stage1.c
+++ b/mdk-stage1/stage1.c
@@ -45,7 +45,7 @@
#include "tools.h"
#include "automatic.h"
#include "mount.h"
-#include "insmod-busybox/insmod.h"
+#include "insmod.h"
#ifdef ENABLE_PCMCIA
#include "pcmcia/pcmcia.h"