+ if (sublen > slen)
+ return 1;
+
+ return memcmp(s + slen - sublen, sub, sublen);
+}
+
+/* if sym is empty or point to a string
+ * like ".[0-9]+" then return 1.
+ * This is the optional prefix added by ld to some sections
+ */
+static int number_prefix(const char *sym)
+{
+ if (*sym++ == '\0')
+ return 1;
+ if (*sym != '.')
+ return 0;
+ do {
+ char c = *sym++;
+ if (c < '0' || c > '9')
+ return 0;
+ } while (*sym);
+ return 1;
+}
+
+/* The pattern is an array of simple patterns.
+ * "foo" will match an exact string equal to "foo"
+ * "foo*" will match a string that begins with "foo"
+ * "foo$" will match a string equal to "foo" or "foo.1"
+ * where the '1' can be any number including several digits.
+ * The $ syntax is for sections where ld append a dot number
+ * to make section name unique.
+ */
+int match(const char *sym, const char * const pat[])
+{
+ const char *p;
+ while (*pat) {
+ p = *pat++;
+ const char *endp = p + strlen(p) - 1;
+
+ /* "foo*" */
+ if (*endp == '*') {
+ if (strncmp(sym, p, strlen(p) - 1) == 0)
+ return 1;
+ }
+ /* "foo$" */
+ else if (*endp == '$') {
+ if (strncmp(sym, p, strlen(p) - 1) == 0) {
+ if (number_prefix(sym + strlen(p) - 1))
+ return 1;
+ }
+ }
+ /* no wildcards */
+ else {
+ if (strcmp(p, sym) == 0)
+ return 1;
+ }
+ }
+ /* no match */
+ return 0;
+}
+
+/*
+ * Functions used only during module init is marked __init and is stored in
+ * a .init.text section. Likewise data is marked __initdata and stored in
+ * a .init.data section.
+ * If this section is one of these sections return 1
+ * See include/linux/init.h for the details
+ */
+static int init_section(const char *name)
+{
+ if (strcmp(name, ".init") == 0)
+ return 1;
+ if (strncmp(name, ".init.", strlen(".init.")) == 0)
+ return 1;
+ return 0;
+}
+
+/*
+ * Functions used only during module exit is marked __exit and is stored in
+ * a .exit.text section. Likewise data is marked __exitdata and stored in
+ * a .exit.data section.
+ * If this section is one of these sections return 1
+ * See include/linux/init.h for the details
+ **/
+static int exit_section(const char *name)
+{
+ if (strcmp(name, ".exit.text") == 0)
+ return 1;
+ if (strcmp(name, ".exit.data") == 0)
+ return 1;
+ return 0;
+
+}
+
+/*
+ * Data sections are named like this:
+ * .data | .data.rel | .data.rel.*
+ * Return 1 if the specified section is a data section
+ */
+static int data_section(const char *name)
+{
+ if ((strcmp(name, ".data") == 0) ||
+ (strcmp(name, ".data.rel") == 0) ||
+ (strncmp(name, ".data.rel.", strlen(".data.rel.")) == 0))
+ return 1;
+ else
+ return 0;
+}
+
+/* sections that we do not want to do full section mismatch check on */
+static const char *section_white_list[] =
+ { ".debug*", ".stab*", ".note*", ".got*", ".toc*", NULL };
+
+#define INIT_DATA_SECTIONS ".init.data$"
+#define EXIT_DATA_SECTIONS ".exit.data$"
+
+#define INIT_TEXT_SECTIONS ".init.text$"
+#define EXIT_TEXT_SECTIONS ".exit.text$"
+
+#define INIT_SECTIONS INIT_DATA_SECTIONS, INIT_TEXT_SECTIONS
+#define EXIT_SECTIONS EXIT_DATA_SECTIONS, EXIT_TEXT_SECTIONS
+
+#define DATA_SECTIONS ".data$"
+#define TEXT_SECTIONS ".text$"
+
+struct sectioncheck {
+ const char *fromsec[20];
+ const char *tosec[20];
+};