This patch provides an alternative to the pre-exisiting kallsyms code. That code, from a kernel debugger perspective at least, suffers from incomplete information, making it impossible to (a) disambiguate multiple static functions of the same name (in different source files), (b) determine a complete set of attributes for a symbol (namely, the symbol's size, but also its type, which gets converted to an nm-like one-character representation), and (c) retain full section information This new approach basically makes handling core kernel and module symbols the same, by retrieving the kernel's section, symbol, and string tables rather than parsing the system map. At once it adds the functionality to strip unneeded symbols from modules, which results in non-neglectable space savings for typical distributions (which large amounts of modules). Note that with certain recent, but broken binutils versions (2.16.90*, 2.16.91* up to and including 2.16.91.0.3) this can only be built without CONFIG_MODVERSIONS. Signed-Off-By: Jan Beulich --- 2.6.14/Makefile 2005-10-28 02:02:08.000000000 +0200 +++ 2.6.14-kallsyms/Makefile 2005-11-04 16:20:57.000000000 +0100 @@ -160,15 +160,19 @@ LOCALVERSION = $(subst $(space),, \ KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)$(LOCALVERSION) +HOSTARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ + -e s/arm.*/arm/ -e s/sa110/arm/ \ + -e s/s390x/s390/ -e s/parisc64/parisc/ ) + # SUBARCH tells the usermode build what the underlying arch is. That is set # first, and if a usermode build is happening, the "ARCH=um" on the command # line overrides the setting of ARCH below. If a native build is happening, # then ARCH is assigned, getting whatever value it gets normally, and # SUBARCH is subsequently ignored. -SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ - -e s/arm.*/arm/ -e s/sa110/arm/ \ - -e s/s390x/s390/ -e s/parisc64/parisc/ ) +ifeq ($(SUBARCH),) +SUBARCH := $(if $(filter-out um,$(ARCH)),$(ARCH),$(HOSTARCH)) +endif # Cross compiling and selecting different set of gcc/bin-utils # --------------------------------------------------------------------------- @@ -327,6 +331,7 @@ NM = $(CROSS_COMPILE)nm STRIP = $(CROSS_COMPILE)strip OBJCOPY = $(CROSS_COMPILE)objcopy OBJDUMP = $(CROSS_COMPILE)objdump +READELF = $(CROSS_COMPILE)readelf AWK = awk GENKSYMS = scripts/genksyms/genksyms DEPMOD = /sbin/depmod @@ -729,24 +734,108 @@ endef # Generate .S file with all kernel symbols quiet_cmd_kallsyms = KSYM $@ - cmd_kallsyms = $(NM) -n $< | $(KALLSYMS) \ - $(if $(CONFIG_KALLSYMS_ALL),--all-symbols) > $@ -.tmp_kallsyms1.o .tmp_kallsyms2.o .tmp_kallsyms3.o: %.o: %.S scripts FORCE +ifdef CONFIG_KALLSYMS_TRADITIONAL + +cmd_kallsyms = { test $* -eq 0 || $(NM) -n $<; } | $(KALLSYMS) $(if $(CONFIG_KALLSYMS_ALL),--all-symbols) >$@ + +kallsyms-strip-ext := + +else + +cmd_kallsyms = { test $* -eq 0 || $(NM) -n $<; } | $(KALLSYMS) -$$(expr $* + 1) >$@ + +kallsyms-strip-src := $(if $(CONFIG_KALLSYMS_STRIP_GENERATED),$(srctree)/$(KALLSYMS)) +kallsyms-strip-src += $(if $(CONFIG_KALLSYMS_STRIP_GENERATED),$(wildcard $(srctree)/arch/$(ARCH)/kallsyms)) +kallsyms-strip-src += $(if $(CONFIG_KALLSYMS_ALL),,.tmp_data) +kallsyms-strip-src := $(strip $(kallsyms-strip-src)) +kallsyms-strip-ext := $(if $(kallsyms-strip-src),.stripped) + +quiet_cmd_ktab = KTAB $@ +define cmd_ktab + if [ $* -eq 0 ]; then \ + echo "placeholder" >$@; \ + else \ + rm -f $@; \ + $(READELF) -SW $< | while read idx name type addr offs size more; do \ + if [ "$(suffix $@)" = "$$name" ]; then \ + tail -c+$$((0x$$offs+1)) <$< | head -c $$((0x$$size)) >$@; \ + break; \ + fi; \ + done; \ + test -s $@; \ + fi +endef + +quiet_cmd_kshdr = KSHDR $@ +define cmd_kshdr + if [ $* -eq 0 ]; then \ + echo "placeholder" >$@; \ + else \ + nsect= ;: grab this from the first decimal number; \ + osect= ;: grab this from the first hexadecimal number; \ + for i in $$($(READELF) -S $< | egrep '^[^]\[()]*$$'); \ + do \ + test -z "$$nsect" && nsect=$$(echo $${i%:*} | egrep '^[[:digit:]]+$$'); \ + test -z "$$osect" && osect=$$(echo $${i%:*} | egrep '^0[xX][[:xdigit:]]+$$'); \ + done; \ + zsect= ;: grab this from the last number that is followed by a unit specification; \ + for i in $$($(READELF) -h $< | egrep ':[[:space:]]+[[:digit:]]+[[:space:]]+\(.*\)'); \ + do \ + val=$$(echo $$i | egrep '^([[:digit:]]+|0[xX][[:xdigit:]]+)$$'); \ + test -n "$$val" && zsect=$$val; \ + done; \ + tail -c+$$((osect+1)) <$< | head -c $$((nsect*zsect)) >$@; \ + fi +endef + +quiet_cmd_kstrip = STRIP $< +cmd_kstrip = $(OBJCOPY) $(addprefix --strip-symbols ,$(filter %.strip,$^)) -w $< $@ + +.tmp_kallsyms%.symtab: .tmp_vmlinux%$(kallsyms-strip-ext) + $(call cmd,ktab) + +.tmp_kallsyms%.strtab: .tmp_vmlinux%$(kallsyms-strip-ext) + $(call cmd,ktab) + +.tmp_kallsyms%.sections: .tmp_vmlinux%$(kallsyms-strip-ext) + $(call cmd,kshdr) + +.tmp_kallsyms%.shstrtab: .tmp_vmlinux%$(kallsyms-strip-ext) + $(call cmd,ktab) + +.tmp_vmlinux%.stripped: .tmp_vmlinux% $(addsuffix .strip,$(kallsyms-strip-src)) $(objtree)/include/linux/autoconf.h + $(call cmd,kstrip) + +.tmp_data.strip: .tmp_vmlinux1 $(objtree)/include/linux/autoconf.h + $(Q)$(NM) $< | sed -n 's,[[:xdigit:]]\+[[:space:]]\+[^tT][[:space:]]\+\(.*\),\1,p' \ + | while read i; do case $$i in \ + $(addsuffix $(close);;, \ + $(shell cat $(addsuffix .strip,$(filter $(srctree)/%,$(kallsyms-strip-src))) /dev/null \ + | sed 's,\([;|&<>()$$\\]\),\\\1,g')) \ + *) echo $$i;; \ + esac; done >$@ + +endif # CONFIG_KALLSYMS_TRADITIONAL + +$(foreach n,0 1 2 3,.tmp_kallsyms$(n).o): AFLAGS+=-Wa,--strip-local-absolute +$(foreach n,0 1 2 3,.tmp_kallsyms$(n).o): %.o: %.S $(if $(CONFIG_KALLSYMS_TRADITIONAL),,%.symtab %.strtab %.sections %.shstrtab) scripts FORCE $(call if_changed_dep,as_o_S) -.tmp_kallsyms%.S: .tmp_vmlinux% $(KALLSYMS) +.tmp_kallsyms%.S: .tmp_vmlinux%$(kallsyms-strip-ext) $(KALLSYMS) $(objtree)/include/linux/autoconf.h $(call cmd,kallsyms) -# .tmp_vmlinux1 must be complete except kallsyms, so update vmlinux version -.tmp_vmlinux1: $(vmlinux-lds) $(vmlinux-all) FORCE - $(call if_changed_rule,ksym_ld) +.tmp_vmlinux0$(kallsyms-strip-ext): + $(Q)echo "placeholder" >$@ -.tmp_vmlinux2: $(vmlinux-lds) $(vmlinux-all) .tmp_kallsyms1.o FORCE - $(call if_changed,vmlinux__) +.tmp_vmlinux1: .tmp_kallsyms0.o +.tmp_vmlinux2: .tmp_kallsyms1.o +.tmp_vmlinux3: .tmp_kallsyms2.o -.tmp_vmlinux3: $(vmlinux-lds) $(vmlinux-all) .tmp_kallsyms2.o FORCE - $(call if_changed,vmlinux__) +.tmp_vmlinux%: LDFLAGS_vmlinux += -S +# .tmp_vmlinux1 must be complete except kallsyms, so update vmlinux version +.tmp_vmlinux%: $(vmlinux-lds) $(vmlinux-all) FORCE + $(if $(filter 1,$*),$(call if_changed_rule,ksym_ld),$(call if_changed,vmlinux__)) # Needs to visit scripts/ before $(KALLSYMS) can be used. $(KALLSYMS): scripts ; @@ -980,7 +1069,7 @@ endif # CONFIG_MODULES # Directories & files removed with 'make clean' CLEAN_DIRS += $(MODVERDIR) CLEAN_FILES += vmlinux System.map \ - .tmp_kallsyms* .tmp_version .tmp_vmlinux* .tmp_System.map + .tmp_data* .tmp_kallsyms* .tmp_version .tmp_vmlinux* .tmp_System.map # Directories & files removed with 'make mrproper' MRPROPER_DIRS += include/config include2 --- 2.6.14/arch/alpha/defconfig 2005-10-28 02:02:08.000000000 +0200 +++ 2.6.14-kallsyms/arch/alpha/defconfig 2005-09-07 12:36:02.000000000 +0200 @@ -32,6 +32,7 @@ CONFIG_LOG_BUF_SHIFT=14 # CONFIG_IKCONFIG is not set # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_TRADITIONAL=y CONFIG_KALLSYMS_ALL=y # CONFIG_KALLSYMS_EXTRA_PASS is not set CONFIG_FUTEX=y --- 2.6.14/arch/frv/defconfig 2005-10-28 02:02:08.000000000 +0200 +++ 2.6.14-kallsyms/arch/frv/defconfig 2005-09-07 12:34:09.000000000 +0200 @@ -33,6 +33,7 @@ CONFIG_SYSCTL=y # CONFIG_IKCONFIG is not set CONFIG_EMBEDDED=y CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_TRADITIONAL=y # CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_EXTRA_PASS is not set CONFIG_PRINTK=y --- 2.6.14/arch/i386/defconfig 2005-10-28 02:02:08.000000000 +0200 +++ 2.6.14-kallsyms/arch/i386/defconfig 2005-09-07 12:32:14.000000000 +0200 @@ -28,6 +28,8 @@ CONFIG_HOTPLUG=y # CONFIG_IKCONFIG is not set # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_TRADITIONAL=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set CONFIG_FUTEX=y CONFIG_EPOLL=y CONFIG_IOSCHED_NOOP=y --- 2.6.14/arch/i386/kernel/entry.S 2005-10-28 02:02:08.000000000 +0200 +++ 2.6.14-kallsyms/arch/i386/kernel/entry.S 2005-11-04 16:45:13.000000000 +0100 @@ -129,6 +129,7 @@ ENTRY(ret_from_fork) GET_THREAD_INFO(%ebp) popl %eax jmp syscall_exit +END(ret_from_fork) /* * Return to user mode is not as complex as all this looks, @@ -156,6 +157,7 @@ ENTRY(resume_userspace) # int/exception return? jne work_pending jmp restore_all +END(ret_from_exception) #ifdef CONFIG_PREEMPT ENTRY(resume_kernel) @@ -170,6 +172,7 @@ need_resched: jz restore_all call preempt_schedule_irq jmp need_resched +END(resume_kernel) #endif /* SYSENTER_RETURN points to after the "sysenter" instruction in @@ -219,6 +222,7 @@ sysenter_past_esp: xorl %ebp,%ebp sti sysexit +ENDPROC(sysenter_entry) # system call handler stub @@ -293,6 +297,7 @@ ldt_ss: .align 4 .long 1b,iret_exc .previous +ENDPROC(system_call) # perform work that needs to be done immediately before resumption ALIGN @@ -330,6 +335,7 @@ work_notifysig_v86: xorl %edx, %edx call do_notify_resume jmp resume_userspace +END(work_pending) # perform syscall exit tracing ALIGN @@ -345,6 +351,7 @@ syscall_trace_entry: cmpl $(nr_syscalls), %eax jnae syscall_call jmp syscall_exit +END(syscall_trace_entry) # perform syscall exit tracing ALIGN @@ -357,6 +364,7 @@ syscall_exit_work: movl $1, %edx call do_syscall_trace jmp resume_userspace +END(syscall_exit_work) ALIGN syscall_fault: @@ -365,11 +373,13 @@ syscall_fault: GET_THREAD_INFO(%ebp) movl $-EFAULT,EAX(%esp) jmp resume_userspace +END(syscall_fault) ALIGN syscall_badsys: movl $-ENOSYS,EAX(%esp) jmp resume_userspace +END(syscall_badsys) #define FIXUP_ESPFIX_STACK \ movl %esp, %eax; \ @@ -398,19 +408,24 @@ syscall_badsys: */ .data ENTRY(interrupt) -.text +.previous -vector=0 ENTRY(irq_entries_start) +vector=0 .rept NR_IRQS ALIGN 1: pushl $vector-256 jmp common_interrupt -.data + .data .long 1b -.text -vector=vector+1 + .previous + vector=vector+1 .endr +END(irq_entries_start) + +.data +END(interrupt) +.previous ALIGN common_interrupt: @@ -418,6 +433,7 @@ common_interrupt: movl %esp,%eax call do_IRQ jmp ret_from_intr +ENDPROC(common_interrupt) #define BUILD_INTERRUPT(name, nr) \ ENTRY(name) \ @@ -425,7 +441,8 @@ ENTRY(name) \ SAVE_ALL \ movl %esp,%eax; \ call smp_/**/name; \ - jmp ret_from_intr; + jmp ret_from_intr; \ +ENDPROC(name) /* The include is where all of the SMP etc. interrupts come from */ #include "entry_arch.h" @@ -433,6 +450,7 @@ ENTRY(name) \ ENTRY(divide_error) pushl $0 # no error code pushl $do_divide_error +END(divide_error) ALIGN error_code: pushl %ds @@ -459,16 +477,19 @@ error_code: movl %esp,%eax # pt_regs pointer call *%edi jmp ret_from_exception +ENDPROC(error_code) ENTRY(coprocessor_error) pushl $0 pushl $do_coprocessor_error jmp error_code +END(coprocessor_error) ENTRY(simd_coprocessor_error) pushl $0 pushl $do_simd_coprocessor_error jmp error_code +END(simd_coprocessor_error) ENTRY(device_not_available) pushl $-1 # mark this as an int @@ -484,6 +505,7 @@ device_not_available_emulate: call math_emulate addl $4, %esp jmp ret_from_exception +END(device_not_available) /* * Debug traps and NMI can happen at the one SYSENTER instruction @@ -518,6 +540,7 @@ debug_stack_correct: movl %esp,%eax # pt_regs pointer call do_debug jmp ret_from_exception +END(debug) .previous .text /* * NMI is doubly nasty. It can happen _while_ we're handling @@ -590,6 +613,7 @@ nmi_16bit_stack: .align 4 .long 1b,iret_exc .previous +ENDPROC(nmi) KPROBE_ENTRY(int3) pushl $-1 # mark this as an int @@ -598,52 +622,63 @@ KPROBE_ENTRY(int3) movl %esp,%eax # pt_regs pointer call do_int3 jmp ret_from_exception +END(int3) .previous .text ENTRY(overflow) pushl $0 pushl $do_overflow jmp error_code +END(overflow) ENTRY(bounds) pushl $0 pushl $do_bounds jmp error_code +END(bounds) ENTRY(invalid_op) pushl $0 pushl $do_invalid_op jmp error_code +END(invalid_op) ENTRY(coprocessor_segment_overrun) pushl $0 pushl $do_coprocessor_segment_overrun jmp error_code +END(coprocessor_segment_overrun) ENTRY(invalid_TSS) pushl $do_invalid_TSS jmp error_code +END(invalid_TSS) ENTRY(segment_not_present) pushl $do_segment_not_present jmp error_code +END(segment_not_present) ENTRY(stack_segment) pushl $do_stack_segment jmp error_code +END(stack_segment) KPROBE_ENTRY(general_protection) pushl $do_general_protection jmp error_code +END(general_protection) .previous .text ENTRY(alignment_check) pushl $do_alignment_check jmp error_code +END(alignment_check) KPROBE_ENTRY(page_fault) pushl $do_page_fault jmp error_code +END(page_fault) .previous .text #ifdef CONFIG_X86_MCE @@ -651,12 +686,14 @@ ENTRY(machine_check) pushl $0 pushl machine_check_vector jmp error_code +END(machine_check) #endif ENTRY(spurious_interrupt_bug) pushl $0 pushl $do_spurious_interrupt_bug jmp error_code +END(spurious_interrupt_bug) #include "syscall_table.S" --- 2.6.14/arch/ia64/Makefile 2005-10-28 02:02:08.000000000 +0200 +++ 2.6.14-kallsyms/arch/ia64/Makefile 2005-09-07 11:52:28.000000000 +0200 @@ -9,7 +9,6 @@ # NM := $(CROSS_COMPILE)nm -B -READELF := $(CROSS_COMPILE)readelf export AWK --- 2.6.14/arch/ia64/defconfig 2005-10-28 02:02:08.000000000 +0200 +++ 2.6.14-kallsyms/arch/ia64/defconfig 2005-09-07 12:34:27.000000000 +0200 @@ -29,6 +29,7 @@ CONFIG_IKCONFIG_PROC=y # CONFIG_CPUSETS is not set # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_TRADITIONAL=y CONFIG_KALLSYMS_ALL=y # CONFIG_KALLSYMS_EXTRA_PASS is not set CONFIG_PRINTK=y --- 2.6.14/arch/m68k/defconfig 2005-10-28 02:02:08.000000000 +0200 +++ 2.6.14-kallsyms/arch/m68k/defconfig 2005-09-07 12:34:56.000000000 +0200 @@ -32,6 +32,7 @@ CONFIG_KOBJECT_UEVENT=y # CONFIG_IKCONFIG is not set # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_TRADITIONAL=y # CONFIG_KALLSYMS_EXTRA_PASS is not set CONFIG_PRINTK=y CONFIG_BUG=y --- 2.6.14/arch/mips/defconfig 2005-10-28 02:02:08.000000000 +0200 +++ 2.6.14-kallsyms/arch/mips/defconfig 2005-09-07 12:35:22.000000000 +0200 @@ -32,6 +32,7 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_EMBEDDED=y CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_TRADITIONAL=y # CONFIG_KALLSYMS_EXTRA_PASS is not set CONFIG_FUTEX=y CONFIG_EPOLL=y --- 2.6.14/arch/ppc64/defconfig 2005-10-28 02:02:08.000000000 +0200 +++ 2.6.14-kallsyms/arch/ppc64/defconfig 2005-09-07 12:36:57.000000000 +0200 @@ -41,6 +41,7 @@ CONFIG_CPUSETS=y CONFIG_INITRAMFS_SOURCE="" # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_TRADITIONAL=y # CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_EXTRA_PASS is not set CONFIG_PRINTK=y --- 2.6.14/arch/s390/defconfig 2005-10-28 02:02:08.000000000 +0200 +++ 2.6.14-kallsyms/arch/s390/defconfig 2005-09-07 12:35:46.000000000 +0200 @@ -37,6 +37,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_INITRAMFS_SOURCE="" # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_TRADITIONAL=y # CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_EXTRA_PASS is not set CONFIG_PRINTK=y --- 2.6.14/arch/sparc/defconfig 2005-10-28 02:02:08.000000000 +0200 +++ 2.6.14-kallsyms/arch/sparc/defconfig 2005-09-07 12:37:27.000000000 +0200 @@ -28,7 +28,9 @@ CONFIG_LOG_BUF_SHIFT=14 # CONFIG_IKCONFIG is not set # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_TRADITIONAL=y # CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set CONFIG_FUTEX=y CONFIG_EPOLL=y CONFIG_IOSCHED_NOOP=y --- 2.6.14/arch/sparc64/defconfig 2005-10-28 02:02:08.000000000 +0200 +++ 2.6.14-kallsyms/arch/sparc64/defconfig 2005-09-07 12:37:48.000000000 +0200 @@ -30,6 +30,7 @@ CONFIG_KOBJECT_UEVENT=y # CONFIG_IKCONFIG is not set # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_TRADITIONAL=y # CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_EXTRA_PASS is not set CONFIG_FUTEX=y --- 2.6.14/arch/um/defconfig 2005-10-28 02:02:08.000000000 +0200 +++ 2.6.14-kallsyms/arch/um/defconfig 2005-09-07 12:33:51.000000000 +0200 @@ -70,6 +70,7 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_TRADITIONAL=y # CONFIG_KALLSYMS_ALL is not set CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_PRINTK=y --- 2.6.14/arch/x86_64/defconfig 2005-10-28 02:02:08.000000000 +0200 +++ 2.6.14-kallsyms/arch/x86_64/defconfig 2005-09-07 12:38:00.000000000 +0200 @@ -43,6 +43,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_INITRAMFS_SOURCE="" # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_TRADITIONAL=y CONFIG_KALLSYMS_ALL=y # CONFIG_KALLSYMS_EXTRA_PASS is not set CONFIG_PRINTK=y --- 2.6.14/arch/x86_64/kernel/entry.S 2005-10-28 02:02:08.000000000 +0200 +++ 2.6.14-kallsyms/arch/x86_64/kernel/entry.S 2005-11-07 14:56:02.000000000 +0100 @@ -153,6 +153,7 @@ rff_trace: GET_THREAD_INFO(%rcx) jmp rff_action CFI_ENDPROC +END(ret_from_fork) /* * System call entry. Upto 6 arguments in registers are supported. @@ -281,6 +282,7 @@ tracesys: RESTORE_REST jmp ret_from_sys_call CFI_ENDPROC +END(system_call) /* * Syscall return path ending with IRET. @@ -359,6 +361,7 @@ int_restore_rest: cli jmp int_with_check CFI_ENDPROC +END(int_ret_from_sys_call) /* * Certain special system calls that need to save a complete full stack frame. @@ -370,6 +373,7 @@ int_restore_rest: leaq \func(%rip),%rax leaq -ARGOFFSET+8(%rsp),\arg /* 8 for return address */ jmp ptregscall_common +END(\label) .endm CFI_STARTPROC @@ -399,6 +403,7 @@ ENTRY(ptregscall_common) CFI_REL_OFFSET rip, 0 ret CFI_ENDPROC +END(ptregscall_common) ENTRY(stub_execve) CFI_STARTPROC @@ -429,6 +434,7 @@ exec_32bit: RESTORE_REST jmp int_ret_from_sys_call CFI_ENDPROC +END(stub_execve) /* * sigreturn is special because it needs to restore all registers on return. @@ -446,6 +452,7 @@ ENTRY(stub_rt_sigreturn) RESTORE_REST jmp int_ret_from_sys_call CFI_ENDPROC +END(stub_rt_sigreturn) /* * initial frame state for interrupts and exceptions @@ -596,6 +603,7 @@ retint_kernel: jmp exit_intr #endif CFI_ENDPROC +END(common_interrupt) /* * APIC interrupts. @@ -611,14 +619,17 @@ retint_kernel: ENTRY(thermal_interrupt) apicinterrupt THERMAL_APIC_VECTOR,smp_thermal_interrupt +END(thermal_interrupt) #ifdef CONFIG_SMP ENTRY(reschedule_interrupt) apicinterrupt RESCHEDULE_VECTOR,smp_reschedule_interrupt +END(reschedule_interrupt) .macro INVALIDATE_ENTRY num ENTRY(invalidate_interrupt\num) apicinterrupt INVALIDATE_TLB_VECTOR_START+\num,smp_invalidate_interrupt +END(invalidate_interrupt\num) .endm INVALIDATE_ENTRY 0 @@ -632,17 +643,21 @@ ENTRY(invalidate_interrupt\num) ENTRY(call_function_interrupt) apicinterrupt CALL_FUNCTION_VECTOR,smp_call_function_interrupt +END(call_function_interrupt) #endif #ifdef CONFIG_X86_LOCAL_APIC ENTRY(apic_timer_interrupt) apicinterrupt LOCAL_TIMER_VECTOR,smp_apic_timer_interrupt +END(apic_timer_interrupt) ENTRY(error_interrupt) apicinterrupt ERROR_APIC_VECTOR,smp_error_interrupt +END(error_interrupt) ENTRY(spurious_interrupt) apicinterrupt SPURIOUS_APIC_VECTOR,smp_spurious_interrupt +END(spurious_interrupt) #endif /* @@ -770,6 +785,7 @@ error_kernelspace: cmpq $gs_change,RIP(%rsp) je error_swapgs jmp error_sti +END(error_entry) /* Reload gs selector with exception handling */ /* edi: new selector */ @@ -787,6 +803,7 @@ gs_change: CFI_ADJUST_CFA_OFFSET -8 ret CFI_ENDPROC +ENDPROC(load_gs_index) .section __ex_table,"a" .align 8 @@ -840,7 +857,7 @@ ENTRY(kernel_thread) UNFAKE_STACK_FRAME ret CFI_ENDPROC - +ENDPROC(kernel_thread) child_rip: /* @@ -853,6 +870,7 @@ child_rip: # exit xorl %edi, %edi call do_exit +ENDPROC(child_rip) /* * execve(). This function needs to use IRET, not SYSRET, to set up all state properly. @@ -882,19 +900,24 @@ ENTRY(execve) UNFAKE_STACK_FRAME ret CFI_ENDPROC +ENDPROC(execve) KPROBE_ENTRY(page_fault) errorentry do_page_fault +END(page_fault) .previous .text ENTRY(coprocessor_error) zeroentry do_coprocessor_error +END(coprocessor_error) ENTRY(simd_coprocessor_error) zeroentry do_simd_coprocessor_error +END(simd_coprocessor_error) ENTRY(device_not_available) zeroentry math_state_restore +END(device_not_available) /* runs on exception stack */ KPROBE_ENTRY(debug) @@ -904,6 +927,7 @@ KPROBE_ENTRY(debug) paranoidentry do_debug jmp paranoid_exit CFI_ENDPROC +END(debug) .previous .text /* runs on exception stack */ @@ -954,25 +978,32 @@ paranoid_schedule: cli jmp paranoid_userspace CFI_ENDPROC +END(nmi) KPROBE_ENTRY(int3) zeroentry do_int3 +END(int3) .previous .text ENTRY(overflow) zeroentry do_overflow +END(overflow) ENTRY(bounds) zeroentry do_bounds +END(bounds) ENTRY(invalid_op) zeroentry do_invalid_op +END(invalid_op) ENTRY(coprocessor_segment_overrun) zeroentry do_coprocessor_segment_overrun +END(coprocessor_segment_overrun) ENTRY(reserved) zeroentry do_reserved +END(reserved) /* runs on exception stack */ ENTRY(double_fault) @@ -980,12 +1011,15 @@ ENTRY(double_fault) paranoidentry do_double_fault jmp paranoid_exit CFI_ENDPROC +END(double_fault) ENTRY(invalid_TSS) errorentry do_invalid_TSS +END(invalid_TSS) ENTRY(segment_not_present) errorentry do_segment_not_present +END(segment_not_present) /* runs on exception stack */ ENTRY(stack_segment) @@ -993,19 +1027,24 @@ ENTRY(stack_segment) paranoidentry do_stack_segment jmp paranoid_exit CFI_ENDPROC +END(stack_segment) KPROBE_ENTRY(general_protection) errorentry do_general_protection +END(general_protection) .previous .text ENTRY(alignment_check) errorentry do_alignment_check +END(alignment_check) ENTRY(divide_error) zeroentry do_divide_error +END(divide_error) ENTRY(spurious_interrupt_bug) zeroentry do_spurious_interrupt_bug +END(spurious_interrupt_bug) #ifdef CONFIG_X86_MCE /* runs on exception stack */ @@ -1016,10 +1055,12 @@ ENTRY(machine_check) paranoidentry do_machine_check jmp paranoid_exit CFI_ENDPROC +END(machine_check) #endif ENTRY(call_debug) zeroentry do_call_debug +END(call_debug) ENTRY(call_softirq) CFI_STARTPROC @@ -1038,3 +1079,4 @@ ENTRY(call_softirq) CFI_ADJUST_CFA_OFFSET -8 ret CFI_ENDPROC +ENDPROC(call_softirq) --- 2.6.14/include/linux/kallsyms.h 2005-10-28 02:02:08.000000000 +0200 +++ 2.6.14-kallsyms/include/linux/kallsyms.h 2005-11-04 16:19:34.000000000 +0100 @@ -19,6 +19,25 @@ const char *kallsyms_lookup(unsigned lon unsigned long *offset, char **modname, char *namebuf); +#ifdef CONFIG_MODULES + +#if defined(Elf_Shdr) && defined(Elf_Sym) +char kallsyms_elf_type(const Elf_Sym *sym, + const Elf_Shdr *sechdrs, + const char *secstrings); +#endif + +struct module; +void module_init_done(struct module *); + +unsigned long kallsyms_find_symname(struct module *, const char *); + +const char *kallsyms_get_ksymbol(struct module *, + unsigned long addr, + unsigned long *size, + unsigned long *offset); +#endif + /* Replace "%s" in format with address, if found */ extern void __print_symbol(const char *fmt, unsigned long address); @@ -64,4 +83,12 @@ do { \ __print_symbol(fmt, addr); \ } while(0) +#if defined(CONFIG_KALLSYMS) && !defined(CONFIG_KALLSYMS_TRADITIONAL) +void kallsyms_early_init(void); +void kallsyms_init_done(void); +#else +#define kallsyms_early_init() ((void)0) +#define kallsyms_init_done() ((void)0) +#endif + #endif /*_LINUX_KALLSYMS_H*/ --- 2.6.14/include/linux/linkage.h 2005-10-28 02:02:08.000000000 +0200 +++ 2.6.14-kallsyms/include/linux/linkage.h 2005-11-07 10:44:38.000000000 +0100 @@ -39,6 +39,16 @@ ALIGN; \ name: +#ifdef CONFIG_KALLSYMS +#define ENDPROC(name) \ + .type name, @function; \ + END(name) +#define END(name) \ + .size name, .-name +#else +#define ENDPROC(name) +#define END(name) +#endif #endif --- 2.6.14/include/linux/module.h 2005-10-28 02:02:08.000000000 +0200 +++ 2.6.14-kallsyms/include/linux/module.h 2005-11-04 16:19:34.000000000 +0100 @@ -301,7 +301,14 @@ struct module /* We keep the symbol and string tables for kallsyms. */ Elf_Sym *symtab; unsigned long num_symtab; - char *strtab; + const char *strtab; + +# ifndef CONFIG_KALLSYMS_TRADITIONAL + /* And also the sections and their string table. */ + Elf_Shdr *sections; + unsigned long num_sections; + const char *shstrtab; +# endif /* Section attributes */ struct module_sect_attrs *sect_attrs; --- 2.6.14/init/Kconfig 2005-10-28 02:02:08.000000000 +0200 +++ 2.6.14-kallsyms/init/Kconfig 2005-11-07 10:51:19.000000000 +0100 @@ -272,9 +272,19 @@ config KALLSYMS symbolic stack backtraces. This increases the size of the kernel somewhat, as all symbols have to be loaded into the kernel image. +config KALLSYMS_TRADITIONAL + bool "Traditional kallsyms symbol table format" + depends on KALLSYMS + default !MODULES + help + Say N here if you want the kernel symbol table to be consistent with + that loadable modules use (i.e. the ELF symbol table extracted from + the kernel binary). + config KALLSYMS_ALL bool "Include all symbols in kallsyms" depends on DEBUG_KERNEL && KALLSYMS + default DEBUG_KERNEL help Normally kallsyms only contains the symbols of functions, for nicer OOPS messages. Some debuggers can use kallsyms for other @@ -283,6 +293,13 @@ config KALLSYMS_ALL Say N. +config KALLSYMS_STRIP_GENERATED + bool "Strip machine generated symbols from kallsyms" if KALLSYMS_ALL + depends on KALLSYMS && !KALLSYMS_TRADITIONAL + default y + help + Say N if you want kallsyms to retain even machine generated symbols. + config KALLSYMS_EXTRA_PASS bool "Do an extra kallsyms pass" depends on KALLSYMS --- 2.6.14/init/main.c 2005-10-28 02:02:08.000000000 +0200 +++ 2.6.14-kallsyms/init/main.c 2005-11-07 10:53:53.000000000 +0100 @@ -481,6 +481,7 @@ asmlinkage void __init start_kernel(void &unknown_bootoption); sort_main_extable(); trap_init(); + kallsyms_early_init(); rcu_init(); init_IRQ(); pidhash_init(); @@ -708,6 +709,7 @@ static int init(void * unused) * we're essentially up and running. Get rid of the * initmem segments and start the user-mode stuff.. */ + kallsyms_init_done(); free_initmem(); unlock_kernel(); system_state = SYSTEM_RUNNING; --- 2.6.14/kernel/kallsyms.c 2005-10-28 02:02:08.000000000 +0200 +++ 2.6.14-kallsyms/kernel/kallsyms.c 2005-11-08 12:22:46.000000000 +0100 @@ -11,8 +11,8 @@ * Changed the compression method from stem compression to "table lookup" * compression (see scripts/kallsyms.c for a more complete description) */ -#include #include +#include #include #include #include @@ -28,15 +28,42 @@ #define all_var 0 #endif -/* These will be re-linked against their real values during the second link stage */ -extern unsigned long kallsyms_addresses[] __attribute__((weak)); -extern unsigned long kallsyms_num_syms __attribute__((weak,section("data"))); -extern u8 kallsyms_names[] __attribute__((weak)); +#ifdef CONFIG_KALLSYMS_TRADITIONAL +extern const unsigned long kallsyms_addresses[]; +extern const unsigned long kallsyms_num_syms __attribute__((section("data"))); +extern const u8 kallsyms_names[]; + +extern const u8 kallsyms_token_table[]; +extern const u16 kallsyms_token_index[]; -extern u8 kallsyms_token_table[] __attribute__((weak)); -extern u16 kallsyms_token_index[] __attribute__((weak)); +extern const unsigned long kallsyms_markers[]; +#else +extern Elf_Shdr kallsyms_sections[]; +extern Elf_Sym kallsyms_symtab[]; +extern const char kallsyms_shstrtab[], kallsyms_strtab[]; +# ifdef CONFIG_MODULES +struct module kallsyms_kernel_module = { + .module_core = _text, + .module_init = __init_begin, + .symtab = kallsyms_symtab, + .strtab = kallsyms_strtab, + .sections = kallsyms_sections, + .shstrtab = kallsyms_shstrtab +}; +# else +const void*const kallsyms_module_core = _text; +const void*const kallsyms_module_init = __init_begin; +size_t kallsyms_core_size = 0, kallsyms_init_size = 0; +static size_t kallsyms_core_text_size, kallsyms_init_text_size; +size_t kallsyms_num_sections = 0, kallsyms_num_symtab = 0; +# define KALLSYMS_VAR(mod, var) kallsyms_##var +# endif +# define kallsyms_num_syms KALLSYMS_VAR(&kallsyms_kernel_module, num_symtab) +#endif -extern unsigned long kallsyms_markers[] __attribute__((weak)); +#ifdef CONFIG_MODULES +# define KALLSYMS_VAR(mod, var) (mod)->var +#endif static inline int is_kernel_inittext(unsigned long addr) { @@ -68,12 +95,36 @@ static inline int is_kernel(unsigned lon return in_gate_area_no_task(addr); } +static inline int within(unsigned long addr, const void *start, unsigned long size) +{ + return ((void *)addr >= start && (void *)addr < start + size); +} + +#if defined(CONFIG_MODULES) || !defined(CONFIG_KALLSYMS_TRADITIONAL) +# ifndef CONFIG_MODULES +static inline +# define kallsyms_find_symname(m, n) kallsyms_find_symname(n) +# endif +unsigned long kallsyms_find_symname( + struct module *mod, + const char *name) +{ + unsigned long i; + + for (i = 0; i < KALLSYMS_VAR(mod, num_symtab); i++) + if (strcmp(name, KALLSYMS_VAR(mod, strtab) + KALLSYMS_VAR(mod, symtab)[i].st_name) == 0) + return KALLSYMS_VAR(mod, symtab)[i].st_value; + return 0; +} +#endif + +#ifdef CONFIG_KALLSYMS_TRADITIONAL /* expand a compressed symbol data into the resulting uncompressed string, given the offset to where the symbol is in the compressed stream */ static unsigned int kallsyms_expand_symbol(unsigned int off, char *result) { int len, skipped_first = 0; - u8 *tptr, *data; + const u8 *tptr, *data; /* get the compressed symbol length from the first symbol byte */ data = &kallsyms_names[off]; @@ -121,7 +172,7 @@ static char kallsyms_get_symbol_type(uns * kallsyms array */ static unsigned int get_symbol_offset(unsigned long pos) { - u8 *name; + const u8 *name; int i; /* use the closest marker we have. We have markers every 256 positions, @@ -137,10 +188,12 @@ static unsigned int get_symbol_offset(un return name - kallsyms_names; } +#endif /* Lookup the address for this symbol. Returns 0 if not found. */ unsigned long kallsyms_lookup_name(const char *name) { +#ifdef CONFIG_KALLSYMS_TRADITIONAL char namebuf[KSYM_NAME_LEN+1]; unsigned long i; unsigned int off; @@ -151,10 +204,78 @@ unsigned long kallsyms_lookup_name(const if (strcmp(namebuf, name) == 0) return kallsyms_addresses[i]; } +#else + unsigned long kaddr = kallsyms_find_symname(&kallsyms_kernel_module, name); + + if (kaddr) + return kaddr; +#endif return module_kallsyms_lookup_name(name); } EXPORT_SYMBOL_GPL(kallsyms_lookup_name); +#if defined(CONFIG_MODULES) || !defined(CONFIG_KALLSYMS_TRADITIONAL) +/* + * This ignores the intensely annoying "mapping symbols" found + * in ARM ELF files: $a, $t and $d. + */ +static inline int is_arm_mapping_symbol(const char *str) +{ +#ifdef CONFIG_ARM + return str[0] == '$' && strchr("atd", str[1]) + && (str[2] == '\0' || str[2] == '.'); +#else + return 0; +#endif +} + +# ifndef CONFIG_MODULES +static inline +# define kallsyms_get_ksymbol(m, a, s, o) kallsyms_get_ksymbol(a, s, o) +# endif +const char *kallsyms_get_ksymbol(struct module *mod, + unsigned long addr, + unsigned long *size, + unsigned long *offset) +{ + unsigned long i, best = 0; + unsigned long nextval; + + /* At worse, next value is at end of module */ + if (within(addr, KALLSYMS_VAR(mod, module_init), KALLSYMS_VAR(mod, init_size))) + nextval = (unsigned long)KALLSYMS_VAR(mod, module_init) + KALLSYMS_VAR(mod, init_text_size); + else + nextval = (unsigned long)KALLSYMS_VAR(mod, module_core) + KALLSYMS_VAR(mod, core_text_size); + + /* Scan for closest preceeding symbol, and next symbol. (ELF + starts real symbols at 1). */ + for (i = 1; i < KALLSYMS_VAR(mod, num_symtab); i++) { + if (KALLSYMS_VAR(mod, symtab)[i].st_shndx == SHN_UNDEF) + continue; + + /* We ignore unnamed symbols: they're uninformative + * and inserted at a whim. */ + if (KALLSYMS_VAR(mod, symtab)[i].st_value <= addr + && KALLSYMS_VAR(mod, symtab)[i].st_value > KALLSYMS_VAR(mod, symtab)[best].st_value + && *(KALLSYMS_VAR(mod, strtab) + KALLSYMS_VAR(mod, symtab)[i].st_name) != '\0' + && !is_arm_mapping_symbol(KALLSYMS_VAR(mod, strtab) + KALLSYMS_VAR(mod, symtab)[i].st_name)) + best = i; + if (KALLSYMS_VAR(mod, symtab)[i].st_value > addr + && KALLSYMS_VAR(mod, symtab)[i].st_value < nextval + && *(KALLSYMS_VAR(mod, strtab) + KALLSYMS_VAR(mod, symtab)[i].st_name) != '\0' + && !is_arm_mapping_symbol(KALLSYMS_VAR(mod, strtab) + KALLSYMS_VAR(mod, symtab)[i].st_name)) + nextval = KALLSYMS_VAR(mod, symtab)[i].st_value; + } + + if (!best) + return NULL; + + *size = nextval - KALLSYMS_VAR(mod, symtab)[best].st_value; + *offset = addr - KALLSYMS_VAR(mod, symtab)[best].st_value; + return KALLSYMS_VAR(mod, strtab) + KALLSYMS_VAR(mod, symtab)[best].st_name; +} +#endif + /* * Lookup an address * - modname is set to NULL if it's in the kernel @@ -167,18 +288,18 @@ const char *kallsyms_lookup(unsigned lon unsigned long *offset, char **modname, char *namebuf) { - unsigned long i, low, high, mid; const char *msym; - /* This kernel should never had been booted. */ - BUG_ON(!kallsyms_addresses); - namebuf[KSYM_NAME_LEN] = 0; namebuf[0] = 0; - if ((all_var && is_kernel(addr)) || - (!all_var && (is_kernel_text(addr) || is_kernel_inittext(addr) || - is_kernel_extratext(addr)))) { + if (all_var + ? is_kernel(addr) + : is_kernel_text(addr) + || is_kernel_inittext(addr) + || is_kernel_extratext(addr)) { +#ifdef CONFIG_KALLSYMS_TRADITIONAL + unsigned long i, low, high, mid; unsigned long symbol_end = 0; /* do a binary search on the sorted kallsyms_addresses array */ @@ -219,6 +340,10 @@ const char *kallsyms_lookup(unsigned lon *modname = NULL; *offset = addr - kallsyms_addresses[low]; return namebuf; +#else + *modname = NULL; + return kallsyms_get_ksymbol(&kallsyms_kernel_module, addr, symbolsize, offset); +#endif } /* see if it's in a module */ @@ -236,30 +361,46 @@ void __print_symbol(const char *fmt, uns const char *name; unsigned long offset, size; char namebuf[KSYM_NAME_LEN+1]; - char buffer[sizeof("%s+%#lx/%#lx [%s]") + KSYM_NAME_LEN + - 2*(BITS_PER_LONG*3/10) + MODULE_NAME_LEN + 1]; name = kallsyms_lookup(address, &size, &offset, &modname, namebuf); - if (!name) - sprintf(buffer, "0x%lx", address); - else { - if (modname) - sprintf(buffer, "%s+%#lx/%#lx [%s]", name, offset, - size, modname); - else - sprintf(buffer, "%s+%#lx/%#lx", name, offset, size); + if (!name) { + char addrstr[sizeof("0x%lx") + (BITS_PER_LONG*3/10)]; + + sprintf(addrstr, "0x%lx", address); + printk(fmt, addrstr); + return; + } + + if (modname) { + /* This is pretty small. */ + char buffer[sizeof("%s+%#lx/%#lx [%s]") + + strlen(name) + 2*(BITS_PER_LONG*3/10) + + strlen(modname)]; + + sprintf(buffer, "%s+%#lx/%#lx [%s]", + name, offset, size, modname); + printk(fmt, buffer); + } else { + char buffer[sizeof("%s+%#lx/%#lx") + + strlen(name) + 2*(BITS_PER_LONG*3/10)]; + + sprintf(buffer, "%s+%#lx/%#lx", name, offset, size); + printk(fmt, buffer); } - printk(fmt, buffer); } /* To avoid using get_symbol_offset for every symbol, we carry prefix along. */ struct kallsym_iter { +#ifdef CONFIG_KALLSYMS_TRADITIONAL loff_t pos; +#endif struct module *owner; unsigned long value; +#ifdef CONFIG_KALLSYMS_TRADITIONAL unsigned int nameoff; /* If iterating in core kernel symbols */ +#endif char type; char name[KSYM_NAME_LEN+1]; }; @@ -271,9 +412,9 @@ static void upcase_if_global(struct kall iter->type += 'A' - 'a'; } -static int get_ksymbol_mod(struct kallsym_iter *iter) +static int get_ksymbol_mod(struct kallsym_iter *iter, loff_t pos) { - iter->owner = module_get_kallsym(iter->pos - kallsyms_num_syms, + iter->owner = module_get_kallsym(pos, &iter->value, &iter->type, iter->name); if (iter->owner == NULL) @@ -283,6 +424,7 @@ static int get_ksymbol_mod(struct kallsy return 1; } +#ifdef CONFIG_KALLSYMS_TRADITIONAL /* Returns space to next name. */ static unsigned long get_ksymbol_core(struct kallsym_iter *iter) { @@ -304,26 +446,87 @@ static void reset_iter(struct kallsym_it iter->nameoff = get_symbol_offset(new_pos); iter->pos = new_pos; } +#else +# define reset_iter(iter, new_pos) ((void)((iter)->name[0] = '\0')) +#endif /* Returns false if pos at or past end of file. */ static int update_iter(struct kallsym_iter *iter, loff_t pos) { /* Module symbols can be accessed randomly. */ - if (pos >= kallsyms_num_syms) { - iter->pos = pos; - return get_ksymbol_mod(iter); - } + if (pos >= kallsyms_num_syms) + return get_ksymbol_mod(iter, pos - kallsyms_num_syms); +#ifdef CONFIG_KALLSYMS_TRADITIONAL /* If we're not on the desired position, reset to new position. */ if (pos != iter->pos) reset_iter(iter, pos); iter->nameoff += get_ksymbol_core(iter); iter->pos++; +#else + iter->owner = NULL; + iter->value = KALLSYMS_VAR(&kallsyms_kernel_module, symtab)[pos].st_value; + iter->type = KALLSYMS_VAR(&kallsyms_kernel_module, symtab)[pos].st_other; + strncpy(iter->name, + KALLSYMS_VAR(&kallsyms_kernel_module, strtab) + KALLSYMS_VAR(&kallsyms_kernel_module, symtab)[pos].st_name, + 127); + upcase_if_global(iter); +#endif return 1; } +#if defined(CONFIG_MODULES) || !defined(CONFIG_KALLSYMS_TRADITIONAL) +# ifndef ARCH_SHF_SMALL +# define ARCH_SHF_SMALL 0 +# endif +/* As per nm */ +# ifndef CONFIG_MODULES +static inline __init +# endif +char kallsyms_elf_type(const Elf_Sym *sym, + const Elf_Shdr *sechdrs, + const char *secstrings) +{ + if (ELF_ST_BIND(sym->st_info) == STB_WEAK) { + if (ELF_ST_TYPE(sym->st_info) == STT_OBJECT) + return 'v'; + else + return 'w'; + } + if (sym->st_shndx == SHN_UNDEF) + return 'U'; + if (sym->st_shndx == SHN_ABS) + return 'a'; + if (sym->st_shndx >= SHN_LORESERVE) + return '?'; + if (sechdrs) { + if (sechdrs[sym->st_shndx].sh_flags & SHF_EXECINSTR) + return 't'; + if (sechdrs[sym->st_shndx].sh_flags & SHF_ALLOC + && sechdrs[sym->st_shndx].sh_type != SHT_NOBITS) { + if (!(sechdrs[sym->st_shndx].sh_flags & SHF_WRITE)) + return 'r'; + else if (sechdrs[sym->st_shndx].sh_flags & ARCH_SHF_SMALL) + return 'g'; + else + return 'd'; + } + if (sechdrs[sym->st_shndx].sh_type == SHT_NOBITS) { + if (sechdrs[sym->st_shndx].sh_flags & ARCH_SHF_SMALL) + return 's'; + else + return 'b'; + } + if (strncmp(secstrings + sechdrs[sym->st_shndx].sh_name, + ".debug", strlen(".debug")) == 0) + return 'n'; + } + return '?'; +} +#endif + static void *s_next(struct seq_file *m, void *p, loff_t *pos) { (*pos)++; @@ -417,4 +620,73 @@ static int __init kallsyms_init(void) } __initcall(kallsyms_init); + +#ifndef CONFIG_KALLSYMS_TRADITIONAL + +extern const size_t kallsyms_size_sections, kallsyms_size_symtab; +extern const size_t kallsyms_size_shstrtab, kallsyms_size_strtab; + +void __init kallsyms_early_init() { + Elf_Shdr*section; + Elf_Sym*symbol; + + KALLSYMS_VAR(&kallsyms_kernel_module, core_size) = _end - _text; + KALLSYMS_VAR(&kallsyms_kernel_module, core_text_size) = _etext - _stext; + KALLSYMS_VAR(&kallsyms_kernel_module, init_size) = __init_end - __init_begin; + KALLSYMS_VAR(&kallsyms_kernel_module, init_text_size) = _einittext - _sinittext; + + BUG_ON(kallsyms_size_sections <= sizeof(*kallsyms_sections)); + BUG_ON(kallsyms_size_sections % sizeof(*kallsyms_sections)); + BUG_ON(kallsyms_size_shstrtab <= 0); + BUG_ON(*kallsyms_shstrtab); + BUG_ON(kallsyms_shstrtab[kallsyms_size_shstrtab - 1]); + for(section = kallsyms_sections + 1; (unsigned long)section < (unsigned long)kallsyms_sections + kallsyms_size_sections; ++section) + if(section->sh_name >= kallsyms_size_shstrtab) + section->sh_name = 0; + KALLSYMS_VAR(&kallsyms_kernel_module, num_sections) = kallsyms_size_sections / sizeof(*kallsyms_sections); + + BUG_ON(kallsyms_size_symtab <= sizeof(*kallsyms_symtab)); + BUG_ON(kallsyms_size_symtab % sizeof(*kallsyms_symtab)); + BUG_ON(kallsyms_size_strtab <= 0); + BUG_ON(*kallsyms_strtab); + BUG_ON(kallsyms_strtab[kallsyms_size_strtab - 1]); + for(symbol = kallsyms_symtab + 1; (unsigned long)symbol < (unsigned long)kallsyms_symtab + kallsyms_size_symtab; ++symbol) { + if(symbol->st_name >= kallsyms_size_strtab) + symbol->st_name = 0; + symbol->st_other = kallsyms_elf_type(symbol, kallsyms_sections, kallsyms_shstrtab); + } + KALLSYMS_VAR(&kallsyms_kernel_module, num_symtab) = kallsyms_size_symtab / sizeof(*kallsyms_symtab); +} + + +void __init kallsyms_init_done() { +# ifdef CONFIG_MODULES + module_init_done(&kallsyms_kernel_module); +# else + Elf_Shdr*section; + const Elf_Sym*src; + Elf_Sym*dst; + + for(section = kallsyms_sections + 1; (unsigned long)section < (unsigned long)kallsyms_sections + kallsyms_size_sections; ++section) + if(section->sh_addr >= (unsigned long)__init_begin + && (section->sh_size + ? section->sh_addr + section->sh_size - 1 + : section->sh_addr) < (unsigned long)__init_end) + section->sh_addr = 0; + for(src = dst = kallsyms_symtab + 1; (unsigned long)src < (unsigned long)kallsyms_symtab + kallsyms_size_symtab; ++src) { + if(!src->st_shndx || !src->st_name) + continue; + if(src->st_shndx < kallsyms_num_sections + && !kallsyms_sections[src->st_shndx].sh_addr) + continue; + if(src != dst) + *dst = *src; + ++dst; + } + kallsyms_num_symtab = dst - kallsyms_symtab; +# endif +} + +#endif /* CONFIG_KALLSYMS_TRADITIONAL */ + EXPORT_SYMBOL(__print_symbol); --- 2.6.14/kernel/module.c 2005-10-28 02:02:08.000000000 +0200 +++ 2.6.14-kallsyms/kernel/module.c 2005-11-04 16:19:34.000000000 +0100 @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -1163,6 +1164,8 @@ static int __unlink_module(void *_mod) return 0; } +static void cleanup_kallsyms(struct module *); + /* Free a module, remove from lists, etc (must hold module mutex). */ static void free_module(struct module *mod) { @@ -1177,6 +1180,8 @@ static void free_module(struct module *m /* Module unload stuff */ module_unload_free(mod); + cleanup_kallsyms(mod); + /* This may be NULL, but that's OK */ module_free(mod, mod->module_init); kfree(mod->args); @@ -1425,49 +1430,9 @@ int is_exported(const char *name, const return 0; } -/* As per nm */ -static char elf_type(const Elf_Sym *sym, - Elf_Shdr *sechdrs, - const char *secstrings, - struct module *mod) -{ - if (ELF_ST_BIND(sym->st_info) == STB_WEAK) { - if (ELF_ST_TYPE(sym->st_info) == STT_OBJECT) - return 'v'; - else - return 'w'; - } - if (sym->st_shndx == SHN_UNDEF) - return 'U'; - if (sym->st_shndx == SHN_ABS) - return 'a'; - if (sym->st_shndx >= SHN_LORESERVE) - return '?'; - if (sechdrs[sym->st_shndx].sh_flags & SHF_EXECINSTR) - return 't'; - if (sechdrs[sym->st_shndx].sh_flags & SHF_ALLOC - && sechdrs[sym->st_shndx].sh_type != SHT_NOBITS) { - if (!(sechdrs[sym->st_shndx].sh_flags & SHF_WRITE)) - return 'r'; - else if (sechdrs[sym->st_shndx].sh_flags & ARCH_SHF_SMALL) - return 'g'; - else - return 'd'; - } - if (sechdrs[sym->st_shndx].sh_type == SHT_NOBITS) { - if (sechdrs[sym->st_shndx].sh_flags & ARCH_SHF_SMALL) - return 's'; - else - return 'b'; - } - if (strncmp(secstrings + sechdrs[sym->st_shndx].sh_name, - ".debug", strlen(".debug")) == 0) - return 'n'; - return '?'; -} - static void add_kallsyms(struct module *mod, - Elf_Shdr *sechdrs, + const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, unsigned int symindex, unsigned int strindex, const char *secstrings) @@ -1476,23 +1441,125 @@ static void add_kallsyms(struct module * mod->symtab = (void *)sechdrs[symindex].sh_addr; mod->num_symtab = sechdrs[symindex].sh_size / sizeof(Elf_Sym); - mod->strtab = (void *)sechdrs[strindex].sh_addr; + mod->strtab = (const void *)sechdrs[strindex].sh_addr; + + if (mod->num_symtab > 1 + && sechdrs[strindex].sh_size > 0 + && !*mod->strtab + && !mod->strtab[sechdrs[strindex].sh_size - 1]) { + /* Set types up while we still have access to sections. */ + for (i = 1; i < mod->num_symtab; i++) { + if (mod->symtab[i].st_name >= sechdrs[strindex].sh_size) + mod->symtab[i].st_name = 0; + mod->symtab[i].st_other + = kallsyms_elf_type(&mod->symtab[i], sechdrs, secstrings); + } + } + else { + mod->symtab = NULL; + mod->num_symtab = 0; + mod->strtab = NULL; + } - /* Set types up while we still have access to sections. */ - for (i = 0; i < mod->num_symtab; i++) - mod->symtab[i].st_info - = elf_type(&mod->symtab[i], sechdrs, secstrings, mod); +# ifndef CONFIG_KALLSYMS_TRADITIONAL + if (hdr->e_shnum > 1 + && sechdrs[hdr->e_shstrndx].sh_size > 0 + && !*secstrings + && !secstrings[sechdrs[hdr->e_shstrndx].sh_size - 1]) { + if (hdr->e_shnum < PAGE_SIZE / sizeof(*sechdrs)) + mod->sections = kmalloc(hdr->e_shnum * sizeof(*sechdrs), GFP_KERNEL); + else + mod->sections = vmalloc(hdr->e_shnum * sizeof(*sechdrs)); + } + else + mod->sections = NULL; + if (mod->sections) { + mod->num_sections = hdr->e_shnum; + memset(mod->sections, 0, sizeof(*mod->sections)); + mod->shstrtab = (const void *)sechdrs[hdr->e_shstrndx].sh_addr; + for (i = 1; i < mod->num_sections; ++i) { + mod->sections[i] = sechdrs[i]; + if (mod->sections[i].sh_name >= sechdrs[hdr->e_shstrndx].sh_size) + mod->sections[i].sh_name = 0; + if (!(mod->sections[i].sh_flags & SHF_ALLOC)) + mod->sections[i].sh_addr = 0; + } + } + else { + mod->num_sections = 0; + mod->shstrtab = NULL; + } +#endif +} + +static void cleanup_kallsyms(struct module *mod) +{ +# ifndef CONFIG_KALLSYMS_TRADITIONAL + if (mod->num_sections) { + if (mod->num_sections < PAGE_SIZE / sizeof(*mod->sections)) + kfree(mod->sections); + else + vfree(mod->sections); + mod->num_sections = 0; + } +# endif + mod->num_symtab = 0; } #else static inline void add_kallsyms(struct module *mod, - Elf_Shdr *sechdrs, + const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, unsigned int symindex, unsigned int strindex, const char *secstrings) { } + +static inline void cleanup_kallsyms(struct module *mod) +{ +} #endif /* CONFIG_KALLSYMS */ +#ifndef CONFIG_KALLSYMS +static inline +#endif +void module_init_done(struct module *mod) +{ +#ifdef CONFIG_KALLSYMS + if (mod->init_size) { + const Elf_Sym*src; + Elf_Sym*dst; +# ifndef CONFIG_KALLSYMS_TRADITIONAL + Elf_Shdr*section; + + for(section = mod->sections + 1; section < mod->sections + mod->num_sections; ++section) + if(section->sh_entsize & INIT_OFFSET_MASK) + section->sh_addr = 0; +# endif + for(src = dst = mod->symtab + 1; src < mod->symtab + mod->num_symtab; ++src) { + if(!src->st_shndx || !src->st_name) + continue; +# ifndef CONFIG_KALLSYMS_TRADITIONAL + if(src->st_shndx < mod->num_sections + && !mod->sections[src->st_shndx].sh_addr) + continue; +# else + if(src->st_value >= (unsigned long)mod->module_init + && src->st_value < (unsigned long)mod->module_init + mod->init_size) + continue; +# endif + if(src != dst) + *dst = *src; + ++dst; + } + mod->num_symtab = dst - mod->symtab; + } +#endif + mod->module_init = NULL; + mod->init_size = 0; + mod->init_text_size = 0; +} + /* Allocate and load the module: note that size of section 0 is always zero, and we rely on this for optional sections. */ static struct module *load_module(void __user *umod, @@ -1531,7 +1598,8 @@ static struct module *load_module(void _ if (memcmp(hdr->e_ident, ELFMAG, 4) != 0 || hdr->e_type != ET_REL || !elf_check_arch(hdr) - || hdr->e_shentsize != sizeof(*sechdrs)) { + || hdr->e_shentsize != sizeof(*sechdrs) + || !hdr->e_shstrndx) { err = -ENOEXEC; goto free_hdr; } @@ -1555,6 +1623,10 @@ static struct module *load_module(void _ /* Internal symbols and strings. */ if (sechdrs[i].sh_type == SHT_SYMTAB) { + if (symindex) { + err = -ENOEXEC; + goto free_hdr; + } symindex = i; strindex = sechdrs[i].sh_link; strtab = (char *)hdr + sechdrs[strindex].sh_offset; @@ -1566,6 +1638,11 @@ static struct module *load_module(void _ #endif } + if (!symindex || !strindex) { + err = -ENOEXEC; + goto free_hdr; + } + modindex = find_sec(hdr, sechdrs, secstrings, ".gnu.linkonce.this_module"); if (!modindex) { @@ -1597,9 +1674,14 @@ static struct module *load_module(void _ /* Don't keep modinfo section */ sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC; #ifdef CONFIG_KALLSYMS + mod->num_symtab = 0; /* Keep symbol and string tables for decoding later. */ sechdrs[symindex].sh_flags |= SHF_ALLOC; sechdrs[strindex].sh_flags |= SHF_ALLOC; +# ifndef CONFIG_KALLSYMS_TRADITIONAL + mod->num_sections = 0; + sechdrs[hdr->e_shstrndx].sh_flags |= SHF_ALLOC; +# endif #endif /* Check module struct version now, before we try to use module. */ @@ -1775,7 +1857,7 @@ static struct module *load_module(void _ percpu_modcopy(mod->percpu, (void *)sechdrs[pcpuindex].sh_addr, sechdrs[pcpuindex].sh_size); - add_kallsyms(mod, sechdrs, symindex, strindex, secstrings); + add_kallsyms(mod, hdr, sechdrs, symindex, strindex, secstrings); err = module_finalize(hdr, sechdrs, mod); if (err < 0) @@ -1843,6 +1925,7 @@ static struct module *load_module(void _ module_arch_cleanup(mod); cleanup: module_unload_free(mod); + cleanup_kallsyms(mod); module_free(mod, mod->module_init); free_core: module_free(mod, mod->module_core); @@ -1934,9 +2017,7 @@ sys_init_module(void __user *umod, /* Drop initial reference. */ module_put(mod); module_free(mod, mod->module_init); - mod->module_init = NULL; - mod->init_size = 0; - mod->init_text_size = 0; + module_init_done(mod); up(&module_mutex); return 0; @@ -1948,58 +2029,6 @@ static inline int within(unsigned long a } #ifdef CONFIG_KALLSYMS -/* - * This ignores the intensely annoying "mapping symbols" found - * in ARM ELF files: $a, $t and $d. - */ -static inline int is_arm_mapping_symbol(const char *str) -{ - return str[0] == '$' && strchr("atd", str[1]) - && (str[2] == '\0' || str[2] == '.'); -} - -static const char *get_ksymbol(struct module *mod, - unsigned long addr, - unsigned long *size, - unsigned long *offset) -{ - unsigned int i, best = 0; - unsigned long nextval; - - /* At worse, next value is at end of module */ - if (within(addr, mod->module_init, mod->init_size)) - nextval = (unsigned long)mod->module_init+mod->init_text_size; - else - nextval = (unsigned long)mod->module_core+mod->core_text_size; - - /* Scan for closest preceeding symbol, and next symbol. (ELF - starts real symbols at 1). */ - for (i = 1; i < mod->num_symtab; i++) { - if (mod->symtab[i].st_shndx == SHN_UNDEF) - continue; - - /* We ignore unnamed symbols: they're uninformative - * and inserted at a whim. */ - if (mod->symtab[i].st_value <= addr - && mod->symtab[i].st_value > mod->symtab[best].st_value - && *(mod->strtab + mod->symtab[i].st_name) != '\0' - && !is_arm_mapping_symbol(mod->strtab + mod->symtab[i].st_name)) - best = i; - if (mod->symtab[i].st_value > addr - && mod->symtab[i].st_value < nextval - && *(mod->strtab + mod->symtab[i].st_name) != '\0' - && !is_arm_mapping_symbol(mod->strtab + mod->symtab[i].st_name)) - nextval = mod->symtab[i].st_value; - } - - if (!best) - return NULL; - - *size = nextval - mod->symtab[best].st_value; - *offset = addr - mod->symtab[best].st_value; - return mod->strtab + mod->symtab[best].st_name; -} - /* For kallsyms to ask for address resolution. NULL means not found. We don't lock, as this is used for oops resolution and races are a lesser concern. */ @@ -2014,7 +2043,7 @@ const char *module_address_lookup(unsign if (within(addr, mod->module_init, mod->init_size) || within(addr, mod->module_core, mod->core_size)) { *modname = mod->name; - return get_ksymbol(mod, addr, size, offset); + return kallsyms_get_ksymbol(mod, addr, size, offset); } } return NULL; @@ -2031,7 +2060,7 @@ struct module *module_get_kallsym(unsign list_for_each_entry(mod, &modules, list) { if (symnum < mod->num_symtab) { *value = mod->symtab[symnum].st_value; - *type = mod->symtab[symnum].st_info; + *type = mod->symtab[symnum].st_other; strncpy(namebuf, mod->strtab + mod->symtab[symnum].st_name, 127); @@ -2044,16 +2073,6 @@ struct module *module_get_kallsym(unsign return NULL; } -static unsigned long mod_find_symname(struct module *mod, const char *name) -{ - unsigned int i; - - for (i = 0; i < mod->num_symtab; i++) - if (strcmp(name, mod->strtab+mod->symtab[i].st_name) == 0) - return mod->symtab[i].st_value; - return 0; -} - /* Look for this name: can be of form module:name. */ unsigned long module_kallsyms_lookup_name(const char *name) { @@ -2065,11 +2084,11 @@ unsigned long module_kallsyms_lookup_nam if ((colon = strchr(name, ':')) != NULL) { *colon = '\0'; if ((mod = find_module(name)) != NULL) - ret = mod_find_symname(mod, colon+1); + ret = kallsyms_find_symname(mod, colon+1); *colon = ':'; } else { list_for_each_entry(mod, &modules, list) - if ((ret = mod_find_symname(mod, name)) != 0) + if ((ret = kallsyms_find_symname(mod, name)) != 0) break; } return ret; --- 2.6.14/scripts/Kbuild.include 2005-10-28 02:02:08.000000000 +0200 +++ 2.6.14-kallsyms/scripts/Kbuild.include 2005-11-07 11:12:52.000000000 +0100 @@ -5,6 +5,8 @@ comma := , empty := space := $(empty) $(empty) +open := ( +close := ) ### # The temporary file to save gcc -MD generated dependencies must not --- 2.6.14/scripts/Makefile 2005-10-28 02:02:08.000000000 +0200 +++ 2.6.14-kallsyms/scripts/Makefile 2005-11-04 16:19:35.000000000 +0100 @@ -8,6 +8,7 @@ # conmakehash: Create arrays for initializing the kernel console tables hostprogs-$(CONFIG_KALLSYMS) += kallsyms +HOSTCFLAGS_kallsyms.o := -D ARCH_$(SUBARCH) hostprogs-$(CONFIG_LOGO) += pnmtologo hostprogs-$(CONFIG_VT) += conmakehash hostprogs-$(CONFIG_PROM_CONSOLE) += conmakehash --- 2.6.14/scripts/Makefile.build 2005-10-28 02:02:08.000000000 +0200 +++ 2.6.14-kallsyms/scripts/Makefile.build 2005-11-08 12:29:46.000000000 +0100 @@ -156,23 +156,26 @@ else # are done. # o otherwise, we calculate symbol versions using the good old # genksyms on the preprocessed source and postprocess them in a way -# that they are usable as a linker script -# o generate .o from .tmp_.o using the linker to -# replace the unresolved symbols __crc_exported_symbol with -# the actual value of the checksum generated by genksyms +# that they are usable as assembly source +# o recompile .o from .c forcing inclusion of assembler +# directives defining the actual values of __crc_*, followed by +# objcopy-ing them to force these symbols to be local to permit +# stripping them during the final module linking stage. cmd_cc_o_c = $(CC) $(c_flags) -c -o $(@D)/.tmp_$(@F) $< cmd_modversions = \ if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then \ - $(CPP) -D__GENKSYMS__ $(c_flags) $< \ - | $(GENKSYMS) \ - > $(@D)/.tmp_$(@F:.o=.ver); \ - \ - $(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) \ - -T $(@D)/.tmp_$(@F:.o=.ver); \ - rm -f $(@D)/.tmp_$(@F) $(@D)/.tmp_$(@F:.o=.ver); \ + if $(CPP) -D__GENKSYMS__ $(c_flags) $< \ + | $(GENKSYMS) -a > $(@D)/.tmp_$(@F:.o=.ver) \ + && $(CC) $(c_flags) -c -w -include $(@D)/.tmp_$(@F:.o=.ver) -o $@ $< \ + && $(OBJCOPY) -L '__crc_*' -w $@; then \ + rm -f $(@D)/.tmp_$(@F); \ + else \ + rm -f $@; exit 1; \ + fi; \ else \ mv -f $(@D)/.tmp_$(@F) $@; \ + rm -f $(@D)/.tmp_$(@F:.o=.ver); \ fi; endif @@ -183,6 +186,12 @@ define rule_cc_o_c $(cmd_cc_o_c); \ $(cmd_modversions) \ scripts/basic/fixdep $(depfile) $@ '$(subst ','\'',$(cmd_cc_o_c))' > $(@D)/.$(@F).tmp; \ + if [ -r $(@D)/.tmp_$(@F:.o=.ver) ]; then \ + echo >> $(@D)/.$(@F).tmp; \ + echo '$@: $(GENKSYMS)' >> $(@D)/.$(@F).tmp; \ + echo '$(GENKSYMS):: ;' >> $(@D)/.$(@F).tmp; \ + rm $(@D)/.tmp_$(@F:.o=.ver); \ + fi; \ rm -f $(depfile); \ mv -f $(@D)/.$(@F).tmp $(@D)/.$(@F).cmd endef --- 2.6.14/scripts/Makefile.modinst 2005-10-28 02:02:08.000000000 +0200 +++ 2.6.14-kallsyms/scripts/Makefile.modinst 2005-11-04 16:19:35.000000000 +0100 @@ -17,7 +17,8 @@ __modinst: $(modules) @: quiet_cmd_modules_install = INSTALL $@ - cmd_modules_install = mkdir -p $(2); cp $@ $(2) + cmd_modules_install = mkdir -p $(2); \ + cp $(firstword $(wildcard $@s) $@) $(2)/$(basename $(@F)).ko # Modules built outside the kernel source tree go into extra by default INSTALL_MOD_DIR ?= extra --- 2.6.14/scripts/Makefile.modpost 2005-10-28 02:02:08.000000000 +0200 +++ 2.6.14-kallsyms/scripts/Makefile.modpost 2005-11-04 16:19:35.000000000 +0100 @@ -41,9 +41,33 @@ include scripts/Makefile.lib symverfile := $(objtree)/Module.symvers +ifdef CONFIG_KALLSYMS + +ifdef CONFIG_KALLSYMS_TRADITIONAL + +kallsyms-strip-src := + +else + +kallsyms-strip-src := $(if $(CONFIG_KALLSYMS_STRIP_GENERATED),$(srctree)/scripts/kallsyms.strip) +kallsyms-strip-src += $(if $(CONFIG_KALLSYMS_STRIP_GENERATED),$(wildcard $(srctree)/arch/$(ARCH)/kallsyms.strip)) +# binutils up to at least 2.15 do not permit stripping symbols by name while +# retaining those that are needed by relocations... +# kallsyms-strip-src += $(if $(CONFIG_KALLSYMS_ALL),,data) + +endif + +ko := $(if $(strip $(kallsyms-strip-src)),.kos,.ko) + +else + +ko := .kos + +endif + # Step 1), find all modules listed in $(MODVERDIR)/ __modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod))) -modules := $(patsubst %.o,%.ko, $(wildcard $(__modules:.ko=.o))) +modules := $(patsubst %.o,%$(ko), $(wildcard $(__modules:.ko=.o))) _modpost: $(modules) @@ -58,12 +82,12 @@ quiet_cmd_modpost = MODPOST $(filter-out FORCE,$^) .PHONY: __modpost -__modpost: $(wildcard vmlinux) $(modules:.ko=.o) FORCE +__modpost: $(wildcard vmlinux) $(modules:$(ko)=.o) FORCE $(call cmd,modpost) # Declare generated files as targets for modpost $(symverfile): __modpost ; -$(modules:.ko=.mod.c): __modpost ; +$(modules:$(ko)=.mod.c): __modpost ; # Step 5), compile all *.mod.c files @@ -75,19 +99,51 @@ quiet_cmd_cc_o_c = CC $@ cmd_cc_o_c = $(CC) $(c_flags) $(CFLAGS_MODULE) \ -c -o $@ $< -$(modules:.ko=.mod.o): %.mod.o: %.mod.c FORCE +$(modules:$(ko)=.mod.o): %.mod.o: %.mod.c FORCE $(call if_changed_dep,cc_o_c) -targets += $(modules:.ko=.mod.o) +targets += $(modules:$(ko)=.mod.o) # Step 6), final link of the modules quiet_cmd_ld_ko_o = LD [M] $@ cmd_ld_ko_o = $(LD) $(LDFLAGS) $(LDFLAGS_MODULE) -o $@ \ $(filter-out FORCE,$^) -$(modules): %.ko :%.o %.mod.o FORCE +ifeq ($(ko),.ko) + +$(modules): %.ko: %.o %.mod.o FORCE + $(Q)rm -f $@s + $(call if_changed,ld_ko_o) + +else + +$(patsubst %$(ko),%.ko,$(modules)): %.ko: %.o %.mod.o FORCE $(call if_changed,ld_ko_o) +# Step 7), strip as many symbols from the modules as feasible +quiet_cmd_strip_kos_ko = STRIP $< +ifdef CONFIG_KALLSYMS +cmd_strip_kos_ko = $(OBJCOPY) --strip-debug $(addprefix --strip-symbols ,$(filter %.strip,$^)) -w $< $@ +else +cmd_strip_kos_ko = $(OBJCOPY) --strip-debug --strip-unneeded $< $@ +endif + +%$(ko): %.ko $(filter %.strip,$(kallsyms-strip-src)) $(if $(filter data,$(kallsyms-strip-src)),.data_%.strip) FORCE + $(call if_changed,strip_kos_ko) + +.PRECIOUS: .data_%.strip +.data_%.strip: %.ko .config + $(Q)$(NM) $< | sed -n 's,[[:xdigit:]]\+[[:space:]]\+[^tT][[:space:]]\+\(.*\),\1,p' \ + | while read i; do case $$i in \ + $(addsuffix $(close);;,$(shell cat $(filter $(srctree)/%,$(kallsyms-strip-src)) \ + | sed 's,\([;|&<>()$$\\]\),\\\1,g')) \ + *) echo $$i;; \ + esac; done >$@ + +targets += $(patsubst %$(ko),%.ko,$(modules)) + +endif + targets += $(modules) --- 2.6.14/scripts/genksyms/genksyms.c 2005-10-28 02:02:08.000000000 +0200 +++ 2.6.14-kallsyms/scripts/genksyms/genksyms.c 2005-11-04 16:19:35.000000000 +0100 @@ -43,7 +43,7 @@ FILE *debugfile; int cur_line = 1; char *cur_filename, *output_directory; -int flag_debug, flag_dump_defs, flag_warnings; +int flag_debug, flag_dump_defs, flag_warnings, flag_inline_asm; static int errors; static int nsyms; @@ -457,8 +457,16 @@ export_symbol(const char *name) if (flag_dump_defs) fputs(">\n", debugfile); - /* Used as a linker script. */ - printf("__crc_%s = 0x%08lx ;\n", name, crc); + if (!flag_inline_asm) + { + /* Used as a linker script. */ + printf("__crc_%s = 0x%08lx ;\n", name, crc); + } + else + { + /* Used as inline assembly. */ + printf("__asm__(\".equiv __crc_%s, 0x%08lx\");\n", name, crc); + } } } @@ -529,6 +537,7 @@ main(int argc, char **argv) #ifdef __GNU_LIBRARY__ struct option long_opts[] = { + {"asm", 0, 0, 'a'}, {"debug", 0, 0, 'd'}, {"warnings", 0, 0, 'w'}, {"quiet", 0, 0, 'q'}, @@ -538,13 +547,16 @@ main(int argc, char **argv) {0, 0, 0, 0} }; - while ((o = getopt_long(argc, argv, "dwqVDk:p:", + while ((o = getopt_long(argc, argv, "adwqVDk:p:", &long_opts[0], NULL)) != EOF) #else /* __GNU_LIBRARY__ */ - while ((o = getopt(argc, argv, "dwqVDk:p:")) != EOF) + while ((o = getopt(argc, argv, "adwqVDk:p:")) != EOF) #endif /* __GNU_LIBRARY__ */ switch (o) { + case 'a': + flag_inline_asm = 1; + break; case 'd': flag_debug++; break; --- 2.6.14/scripts/kallsyms.c 2005-10-28 02:02:08.000000000 +0200 +++ 2.6.14-kallsyms/scripts/kallsyms.c 2005-11-07 11:55:11.000000000 +0100 @@ -30,6 +30,7 @@ #include #include #include +#include #define KSYM_NAME_LEN 127 @@ -43,6 +44,7 @@ struct sym_entry { static struct sym_entry *table; static unsigned int table_size, table_cnt; +static long stage; static unsigned long long _stext, _etext, _sinittext, _einittext, _sextratext, _eextratext; static int all_symbols = 0; static char symbol_prefix_char = '\0'; @@ -56,7 +58,7 @@ unsigned char best_table_len[256]; static void usage(void) { - fprintf(stderr, "Usage: kallsyms [--all-symbols] [--symbol-prefix=] < in.map > out.S\n"); + fprintf(stderr, "Usage: kallsyms [stage] [--all-symbols] [--symbol-prefix=] < in.map > out.S\n"); exit(1); } @@ -66,8 +68,12 @@ static void usage(void) */ static inline int is_arm_mapping_symbol(const char *str) { +#if defined(ARCH_arm) || defined(ARCH_arm26) return str[0] == '$' && strchr("atd", str[1]) && (str[2] == '\0' || str[2] == '.'); +#else + return 0; +#endif } static int read_symbol(FILE *in, struct sym_entry *s) @@ -138,13 +144,6 @@ static int symbol_valid(struct sym_entry * specified so exclude them to get a stable symbol list. */ static char *special_symbols[] = { - "kallsyms_addresses", - "kallsyms_num_syms", - "kallsyms_names", - "kallsyms_markers", - "kallsyms_token_table", - "kallsyms_token_index", - /* Exclude linker generated symbols which vary between passes */ "_SDA_BASE_", /* ppc */ "_SDA2_BASE_", /* ppc */ @@ -176,7 +175,8 @@ static int symbol_valid(struct sym_entry } /* Exclude symbols which vary between passes. */ - if (strstr((char *)s->sym + offset, "_compiled.")) + if (strstr((char *)s->sym + offset, "_compiled.") + || strncmp((char *)s->sym + offset, "__compound_literal.", 19) == 0) return 0; for (i = 0; special_symbols[i]; i++) @@ -258,7 +258,42 @@ static void write_src(void) printf("#define ALGN .align 4\n"); printf("#endif\n"); - printf(".data\n"); + printf(".section .rodata, \"a\"\n"); + + if (stage) { + static struct { + const char*name; + unsigned writeable:1; + unsigned aligned:1; + } const what[] = { + {"sections", 1, 1}, + {"symtab", 1, 1}, + {"strtab", 0, 0}, + {"shstrtab", 0, 0} + }; + + for (i = 0; i < sizeof(what)/sizeof(*what); ++i) { + if (what[i].writeable) + printf(".data\n"); + printf(".globl kallsyms_%s, kallsyms_size_%s\n", what[i].name, what[i].name); + if (what[i].aligned) + printf("\tALGN\n"); + printf("kallsyms_%s:\n", what[i].name); + printf(".incbin \".tmp_kallsyms%ld.%s\"\n", labs(stage) - 1, what[i].name); + printf(".equ __kallsyms_size_%s, . - kallsyms_%s\n", what[i].name, what[i].name); + if (what[i].writeable) + printf(".previous\n"); + printf("\n"); + } + printf("\tALGN\n"); + for (i = 0; i < sizeof(what)/sizeof(*what); ++i) { + printf("kallsyms_size_%s:\n", what[i].name); + printf("\tPTR\t__kallsyms_size_%s\n", what[i].name); + } + printf("\n"); + } + if (stage < 0) + return; output_label("kallsyms_addresses"); for (i = 0; i < table_cnt; i++) { @@ -472,25 +507,28 @@ static void optimize_token_table(void) int main(int argc, char **argv) { - if (argc >= 2) { - int i; - for (i = 1; i < argc; i++) { - if(strcmp(argv[i], "--all-symbols") == 0) - all_symbols = 1; - else if (strncmp(argv[i], "--symbol-prefix=", 16) == 0) { - char *p = &argv[i][16]; - /* skip quote */ - if ((*p == '"' && *(p+2) == '"') || (*p == '\'' && *(p+2) == '\'')) - p++; - symbol_prefix_char = *p; - } else - usage(); - } - } else if (argc != 1) - usage(); + int i; + + for (i = 1; i < argc; i++) { + if(strcmp(argv[i], "--all-symbols") == 0) + all_symbols = 1; + else if (strncmp(argv[i], "--symbol-prefix=", 16) == 0) { + char *p = &argv[i][16]; + + /* skip quote */ + if ((*p == '"' || *p == '\'') && p[2] == *p) + p++; + symbol_prefix_char = *p; + } else if ((stage = strtol(argv[i], argv + i, 0)) == 0 + || stage >= LONG_MAX + || stage <= LONG_MIN + || *argv[i]) + usage(); + } read_map(stdin); - optimize_token_table(); + if (stage >= 0 && table_cnt) + optimize_token_table(); write_src(); return 0; --- 2.6.14/scripts/kallsyms.strip 1970-01-01 01:00:00.000000000 +0100 +++ 2.6.14-kallsyms/scripts/kallsyms.strip 2005-03-21 16:34:09.000000000 +0100 @@ -0,0 +1,18 @@ +<*> +__compound_literal[$.][0-9]* +__crc_[a-zA-Z_]* +__exitcall_[a-zA-Z_]* +__func__[$.][0-9]* +__FUNCTION__[$.][0-9]* +gcc[0-9]_compiled[$.] +__initcall_[a-zA-Z_]* +__kcrctab_[a-zA-Z_]* +__kstrtab_[a-zA-Z_]* +__ksymtab_[a-zA-Z_]* +__mod_[a-zA-Z_]*[0-9] +__module_depends +__param_[a-zA-Z_]* +__pci_fixup_[A-Z]* +__PRETTY_FUNCTION__[$.][0-9]* +__setup_[a-zA-Z_0-9]* +____versions