@@ -10,7 +10,7 @@
HOST_EXTRACFLAGS += -I$(srctree)/tools/include
-hostprogs-$(CONFIG_KALLSYMS) += kallsyms
+hostprogs-$(CONFIG_KALLSYMS) += kallsyms patchfile
hostprogs-$(CONFIG_LOGO) += pnmtologo
hostprogs-$(CONFIG_VT) += conmakehash
hostprogs-$(CONFIG_IKCONFIG) += bin2c
new file mode 100644
@@ -0,0 +1,24 @@
+#!/bin/bash
+# find the file offset of a section in a ELF file
+# objdump --section-headers elf-file |
+# gawk -f elf_file_offset filesize=SIZE section=SECTIONNAME
+# gawk needed for strtonum()
+#Idx Name Size VMA LMA File off Algn
+# 4 .kallsyms 001fd648 ffffffff81b1c068 0000000001b1c068 00d1c068 2**3
+
+$2 == section {
+ old = strtonum("0x" $3)
+ new = strtonum(filesize)
+ if (old < new) {
+ print "Not enough padding in vmlinux for new kallsyms, missing",new-old > "/dev/stderr"
+ print "Please lower (=increase) PAD_RATIO in kallsyms.c"
+ exit 1
+ }
+ print "0x" $6
+ # XXX doesn't exit in gawk 4.1.0 ?!?
+ #exit(0)
+}
+#END {
+# print section " not found" > "/dev/stderr"
+# exit 1
+#}
@@ -192,15 +192,19 @@ static int symbol_valid_tr(struct sym_entry *s)
{
size_t i;
struct text_range *tr;
+ int valid = 0;
for (i = 0; i < ARRAY_SIZE(text_ranges); ++i) {
tr = &text_ranges[i];
+ if (tr->start && tr->end)
+ valid++;
+
if (s->addr >= tr->start && s->addr <= tr->end)
return 1;
}
- return 0;
+ return valid ? 0 : 1;
}
static int symbol_valid(struct sym_entry *s)
@@ -242,11 +246,13 @@ static int symbol_valid(struct sym_entry *s)
* the kallsyms data are added. If these symbols move then
* they may get dropped in pass 2, which breaks the kallsyms
* rules.
+ * But don't do this for predicted fake symbols with 0 value.
*/
- if ((s->addr == text_range_text->end &&
+ if (((s->addr == text_range_text->end &&
strcmp((char *)s->sym + offset, text_range_text->etext)) ||
(s->addr == text_range_inittext->end &&
strcmp((char *)s->sym + offset, text_range_inittext->etext)))
+ && text_range_text->end != 0)
return 0;
}
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
#
# link vmlinux
#
@@ -85,11 +85,13 @@ kallsyms()
if [ -n "${CONFIG_ARM}" ] && [ -n "${CONFIG_PAGE_OFFSET}" ]; then
kallsymopt="${kallsymopt} --page-offset=$CONFIG_PAGE_OFFSET"
fi
+ kallsymopt="${kallsymopt} $3"
local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \
${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}"
${NM} -n ${1} | \
+ awk 'NF == 3 { print}' |
scripts/kallsyms ${kallsymopt} | \
${CC} ${aflags} -c -o ${2} -x assembler-with-cpp -
}
@@ -166,51 +168,43 @@ ${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init
kallsymso=""
kallsyms_vmlinux=""
-if [ -n "${CONFIG_KALLSYMS}" ]; then
-
- # kallsyms support
- # Generate section listing all symbols and add it into vmlinux
- # It's a three step process:
- # 1) Link .tmp_vmlinux1 so it has all symbols and sections,
- # but __kallsyms is empty.
- # Running kallsyms on that gives us .tmp_kallsyms1.o with
- # the right size
- # 2) Link .tmp_vmlinux2 so it now has a __kallsyms section of
- # the right size, but due to the added section, some
- # addresses have shifted.
- # From here, we generate a correct .tmp_kallsyms2.o
- # 2a) We may use an extra pass as this has been necessary to
- # woraround some alignment related bugs.
- # KALLSYMS_EXTRA_PASS=1 is used to trigger this.
- # 3) The correct ${kallsymso} is linked into the final vmlinux.
- #
- # a) Verify that the System.map from vmlinux matches the map from
- # ${kallsymso}.
-
- kallsymso=.tmp_kallsyms2.o
- kallsyms_vmlinux=.tmp_vmlinux2
-
- # step 1
- vmlinux_link "" .tmp_vmlinux1
- kallsyms .tmp_vmlinux1 .tmp_kallsyms1.o
-
- # step 2
- vmlinux_link .tmp_kallsyms1.o .tmp_vmlinux2
- kallsyms .tmp_vmlinux2 .tmp_kallsyms2.o
-
- # step 2a
- if [ -n "${KALLSYMS_EXTRA_PASS}" ]; then
- kallsymso=.tmp_kallsyms3.o
- kallsyms_vmlinux=.tmp_vmlinux3
-
- vmlinux_link .tmp_kallsyms2.o .tmp_vmlinux3
-
- kallsyms .tmp_vmlinux3 .tmp_kallsyms3.o
- fi
+
+if [ -n "${CONFIG_KALLSYMS}" ] ; then
+ # Generate kallsyms from the top level object files
+ # this is slightly off, and has wrong addresses,
+ # but gives us the conservative max length of the kallsyms
+ # table to link in something with the size.
+ info KALLSYMS1 .tmp_kallsyms1.o
+ kallsyms "${KBUILD_VMLINUX_INIT} ${KBUILD_VMLINUX_MAIN}" \
+ .tmp_kallsyms1.o \
+ "--pad-file=.kallsyms_pad"
+ kallsymsso=.tmp_kallsyms1.o
fi
info LD vmlinux
-vmlinux_link "${kallsymso}" vmlinux
+vmlinux_link "${kallsymsso}" vmlinux
+if [ -n "${CONFIG_KALLSYMS}" ] ; then
+ # Now regenerate the kallsyms table and patch it into the
+ # previously linked file. We tell kallsyms to pad it
+ # to the previous length, so that no symbol changes.
+ info KALLSYMS2 .tmp_kallsyms2.o
+ kallsyms vmlinux .tmp_kallsyms2.o $(<.kallsyms_pad)
+
+ info OBJCOPY .tmp_kallsyms2.bin
+ ${OBJCOPY} -O binary .tmp_kallsyms2.o .tmp_kallsyms2.bin
+
+ info PATCHFILE vmlinux
+ EF=scripts/elf_file_offset
+ if [ ! -r $EF ] ; then EF=source/$EF ; fi
+ OFF=$(${OBJDUMP} --section-headers vmlinux |
+ gawk -f $EF \
+ -v section=.kallsyms -v filesize=$(stat -c%s .tmp_kallsyms2.bin) )
+ if [ -z "$OFF" ] ; then
+ echo "Cannot find .kallsyms section in vmlinux binary"
+ exit 1
+ fi
+ scripts/patchfile vmlinux $OFF .tmp_kallsyms2.bin
+fi
if [ -n "${CONFIG_BUILDTIME_EXTABLE_SORT}" ]; then
info SORTEX vmlinux
@@ -220,17 +214,5 @@ fi
info SYSMAP System.map
mksysmap vmlinux System.map
-# step a (see comment above)
-if [ -n "${CONFIG_KALLSYMS}" ]; then
- mksysmap ${kallsyms_vmlinux} .tmp_System.map
-
- if ! cmp -s System.map .tmp_System.map; then
- echo >&2 Inconsistent kallsyms data
- echo >&2 Try "make KALLSYMS_EXTRA_PASS=1" as a workaround
- cleanup
- exit 1
- fi
-fi
-
# We made a new kernel - delete old version file
rm -f .old_version
new file mode 100644
@@ -0,0 +1,81 @@
+/* Patch file at specific offset
+ * patchfile file-to-patch offset patch-file [len-of-patch]
+ */
+#define _GNU_SOURCE 1
+#include <sys/mman.h>
+#include <unistd.h>
+#include <sys/fcntl.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#define ROUNDUP(x, y) (((x) + (y) - 1) & ~((y) - 1))
+
+static void *mmapfile(char *file, size_t *size)
+{
+ int pagesize = sysconf(_SC_PAGESIZE);
+ int fd = open(file, O_RDONLY);
+ void *res = NULL;
+ struct stat st;
+
+ *size = 0;
+ if (fd < 0)
+ return NULL;
+ if (fstat(fd, &st) >= 0) {
+ *size = st.st_size;
+ res = mmap(NULL, ROUNDUP(st.st_size, pagesize),
+ PROT_READ, MAP_SHARED,
+ fd, 0);
+ if (res == (void *)-1)
+ res = NULL;
+ }
+ close(fd);
+ return res;
+}
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: patchfile file-to-patch offset file-to-patch-in\n");
+ exit(1);
+}
+
+static size_t get_num(char *s)
+{
+ char *endp;
+ size_t v = strtoul(s, &endp, 0);
+ if (s == endp)
+ usage();
+ return v;
+}
+
+int main(int ac, char **av)
+{
+ char *patch;
+ size_t patchsize;
+ int infd;
+ size_t offset;
+
+ if (ac != 5 && ac != 4)
+ usage();
+ offset = get_num(av[2]);
+ patch = mmapfile(av[3], &patchsize);
+ if (av[4]) {
+ size_t newsize = get_num(av[4]);
+ if (newsize > patchsize)
+ fprintf(stderr, "kallsyms: warning, size larger than patch\n");
+ if (newsize < patchsize)
+ patchsize = newsize;
+ }
+ infd = open(av[1], O_RDWR);
+ if (infd < 0) {
+ fprintf(stderr, "Cannot open %s\n", av[1]);
+ exit(1);
+ }
+ if (pwrite(infd, patch, patchsize, offset) != patchsize) {
+ fprintf(stderr, "Cannot write patch to %s\n", av[1]);
+ exit(1);
+ }
+ close(infd);
+ return 0;
+}