From patchwork Wed Apr 13 21:09:49 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Konrad Rzeszutek Wilk X-Patchwork-Id: 8828731 Return-Path: X-Original-To: patchwork-xen-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 883AC9F3A0 for ; Wed, 13 Apr 2016 21:12:59 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 9CBBD201F2 for ; Wed, 13 Apr 2016 21:12:53 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 07D6D20103 for ; Wed, 13 Apr 2016 21:12:50 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1aqS3s-00079i-Uo; Wed, 13 Apr 2016 21:10:56 +0000 Received: from mail6.bemta14.messagelabs.com ([193.109.254.103]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1aqS3r-00077R-PX for xen-devel@lists.xenproject.org; Wed, 13 Apr 2016 21:10:55 +0000 Received: from [193.109.254.147] by server-10.bemta-14.messagelabs.com id D7/C6-02972-FD5BE075; Wed, 13 Apr 2016 21:10:55 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFupkkeJIrShJLcpLzFFi42LpnVTnqntvK1+ 4waWTTBbft0xmcmD0OPzhCksAYxRrZl5SfkUCa0b/r2esBVfXM1Y8nLyLsYHxeitjFyMXh5BA B5PEnbkNLBDON0aJky96oDIbGSW2Tuhg7WLkBHK6GSXOXtSEsIskrrT2MXcxcnCwCZhIvFnlC BIWEVjOKPHiTB5IL7PATaBBa9awgySEBRwlGrruM4HYLAKqEm0bL4PN5BVwl5i37Q07yBwJAT mJBRfSQcKcIOHX75kgVrlJXHq7B6xcQsBYov3tRbYJjPwLGBlWMWoUpxaVpRbpGprpJRVlpme U5CZm5ugaGpro5aYWFyemp+YkJhXrJefnbmIEBlE9AwPjDsavpz0PMUpyMCmJ8pqs4gsX4kvK T6nMSCzOiC8qzUktPsQow8GhJMH7YAtQTrAoNT21Ii0zBxjOMGkJDh4lEd44YEgL8RYXJOYWZ 6ZDpE4xKkqJ86qDJARAEhmleXBtsBi6xCgrJczLyMDAIMRTkFqUm1mCKv+KUZyDUUkYYgpPZl 4J3PRXQIuZgBaXveMFWVySiJCSamCcWvIm9MHGjwanSwXWvmuquHGoreR62MKsHJY3b3gD5O7 2u0zOd9M/1sy/7ED8wXwGVa6qqa58n3YkLbRfvY87fbutvspqRwvdsw9SF6vk8zzencj88dL5 OcE7vqt3vIzSrXrHsNVg/dyW9T8Z2nYFvJbuULH4w/c3NT3tyLXbOqZb1kyybnqlxFKckWiox VxUnAgAeQb1fJwCAAA= X-Env-Sender: konrad@char.us.oracle.com X-Msg-Ref: server-11.tower-27.messagelabs.com!1460581852!26860100!1 X-Originating-IP: [141.146.126.69] X-SpamReason: No, hits=0.0 required=7.0 tests=sa_preprocessor: VHJ1c3RlZCBJUDogMTQxLjE0Ni4xMjYuNjkgPT4gMjc3MjE4\n X-StarScan-Received: X-StarScan-Version: 8.28; banners=-,-,- X-VirusChecked: Checked Received: (qmail 19940 invoked from network); 13 Apr 2016 21:10:53 -0000 Received: from aserp1040.oracle.com (HELO aserp1040.oracle.com) (141.146.126.69) by server-11.tower-27.messagelabs.com with DHE-RSA-AES256-GCM-SHA384 encrypted SMTP; 13 Apr 2016 21:10:53 -0000 Received: from aserv0022.oracle.com (aserv0022.oracle.com [141.146.126.234]) by aserp1040.oracle.com (Sentrion-MTA-4.3.2/Sentrion-MTA-4.3.2) with ESMTP id u3DLA91V003610 (version=TLSv1 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Wed, 13 Apr 2016 21:10:09 GMT Received: from aserv0122.oracle.com (aserv0122.oracle.com [141.146.126.236]) by aserv0022.oracle.com (8.13.8/8.13.8) with ESMTP id u3DLA9s2006405 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Wed, 13 Apr 2016 21:10:09 GMT Received: from abhmp0009.oracle.com (abhmp0009.oracle.com [141.146.116.15]) by aserv0122.oracle.com (8.13.8/8.13.8) with ESMTP id u3DLA9bP024143; Wed, 13 Apr 2016 21:10:09 GMT Received: from char.us.oracle.com (/10.137.176.158) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Wed, 13 Apr 2016 14:10:08 -0700 Received: by char.us.oracle.com (Postfix, from userid 1000) id 6C9126A0126; Wed, 13 Apr 2016 17:10:06 -0400 (EDT) From: Konrad Rzeszutek Wilk To: konrad@kernel.org, xen-devel@lists.xenproject.org, sasha.levin@oracle.com, andrew.cooper3@citrix.com, ross.lagerwall@citrix.com, mpohlack@amazon.de Date: Wed, 13 Apr 2016 17:09:49 -0400 Message-Id: <1460581796-30071-19-git-send-email-konrad.wilk@oracle.com> X-Mailer: git-send-email 2.5.0 In-Reply-To: <1460581796-30071-1-git-send-email-konrad.wilk@oracle.com> References: <1460581796-30071-1-git-send-email-konrad.wilk@oracle.com> X-Source-IP: aserv0022.oracle.com [141.146.126.234] Cc: Julien Grall , Stefano Stabellini , Keir Fraser , Jan Beulich , Konrad Rzeszutek Wilk Subject: [Xen-devel] [PATCH v8 18/25] build_id: Provide ld-embedded build-ids X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch enables the Elf to be built with the build-id and provide in the Xen hypervisor the code to extract it. The man-page for ld --build-id says it is: "Request the creation of a ".note.gnu.build-id" ELF note section or a ".build-id" COFF section. The contents of the note are unique bits identifying this linked file. style can be "uuid" to use 128 random bits, "sha1" to use a 160-bit SHA1 hash on the normative parts of the output contents, ..." One can also retrieve the value of the build-id by doing 'readelf -n xen-syms'. For EFI builds we re-use the same build-id that the xen-syms was built with. The version of ld that first implemented --build-id is v2.18. We check for to see if the linker supports the --build-id parameter and if so use it. For x86 we have two binaries - the xen-syms and the xen - an smaller version with lots of sections removed. To make it possible for readelf -n xen we also modify mkelf32 and xen.lds.S to include the PT_NOTE ELF section. The EFI binary is more complicated. We only build one type of binary and expanding the amount of sections the EFI binary has to include an .note one is pointless - as there is no concept of PT_NOTE. The best we can do is move this .note in the .rodata section. Further development wise should move it to .buildid section so that DataDirectory debug data nor CodeView can view it. (The author has no clue what those are). Note that in earlier patches the linker script had: __note_gnu_build_id_start = .; *(.rodata.note.gnu.build-id) __note_gnu_build_id_end = .; *(.note) *(.note.*) Which meant you could have different ELF notes _outside_ the __note_gnu_build_id_end. However for EFI builds we take the whole .note* section and jam it in the EFI to be between __note_gnu_build_id_start and __note_gnu_build_id_end. To not make this happend we make on the ELF build the section be called .note.gnu.build-id (instead of just .note). If there is a need for a different type of note other folks can add it as a different section name. Note that we do call --binary-id=sha1 on all linker invocations. We have to do to enforce that the symbol offsets don't changes (the side effect is that we we would have multiple binary ids - except that the last one is the final one). Without this working the symbol table embedded in Xen ends up incorrect - some of the values it contains would be offset by the size of the included build id. This obviously causes problems when resolving symbols. We also define the NT_GNU_BUILD_ID in the elfstructs.h as we need to use it in various places. Suggested-by: Andrew Cooper Signed-off-by: Martin Pohlack Signed-off-by: Konrad Rzeszutek Wilk Acked-by: Julien Grall Reviewed-by: Andrew Cooper --- Cc: Stefano Stabellini Cc: Julien Grall Cc: Keir Fraser Cc: Jan Beulich Cc: Andrew Cooper v1: Rebase it on Martin's initial patch v2: Move it to XENVER hypercall v3: Fix EFI building (Ross's fix) Don't use the third argument for length. Use new structure for XENVER_build_id with variable buf. Include Ross's fix. Include detection of bin-utils for build-id support, add probing for size, and return -EPERM for XSM denied calls. Build xen_build_id under ARM, required adding ELFSIZE in proper file. Rebase on top XSM version class. v4: Include the build-id .note in the xen ELF binary. s/build_id/build_id_linker/ For EFI build, moved the --build-id values in .data section Rebase on staging. Split patch in two. Always do --build-id call. Include the .note in .rodata. USe const void * and ssize_t Use -S to make build_id.o and objcopy differently (Andrew suggested) v5: Put back the #ifdef LOCK_PROFILE on ARM. (Bad change). Move the _erodata around. s/ssize_t/unsigned int/ v6: Redid it per Jan's review. v7: Move build-id note in .rodata.note for EFI builds only. Move build-id note in .rodata for EFI builds only. Retain it in .note. Change name of object file used by EFI builds to notes.o Make on ELF builds the PT_NOTE section name be .note.gnu.build-id and ingest that in ELF build. Define NT_GNU_BUILD_ID in elfstructs.h v8: s/num_phdrs/notes_phdrs/ Added Andrew's Reviewed-by --- --- Config.mk | 11 ++++ xen/arch/arm/Makefile | 2 +- xen/arch/arm/xen.lds.S | 15 ++++- xen/arch/x86/Makefile | 30 ++++++++-- xen/arch/x86/boot/mkelf32.c | 129 ++++++++++++++++++++++++++++++++++++++----- xen/arch/x86/xen.lds.S | 28 ++++++++++ xen/common/version.c | 50 +++++++++++++++++ xen/include/xen/elfstructs.h | 3 + xen/include/xen/version.h | 1 + 9 files changed, 247 insertions(+), 22 deletions(-) diff --git a/Config.mk b/Config.mk index 79eb2bd..db70638 100644 --- a/Config.mk +++ b/Config.mk @@ -126,6 +126,17 @@ endef check-$(gcc) = $(call cc-ver-check,CC,0x040100,"Xen requires at least gcc-4.1") $(eval $(check-y)) +ld-ver-build-id = $(shell $(1) --build-id 2>&1 | \ + grep -q unrecognized && echo n || echo y) + +export XEN_HAS_BUILD_ID ?= n +ifeq ($(call ld-ver-build-id,$(LD)),n) +build_id_linker := +else +CFLAGS += -DBUILD_ID +build_id_linker := --build-id=sha1 +endif + # as-insn: Check whether assembler supports an instruction. # Usage: cflags-y += $(call as-insn "insn",option-yes,option-no) as-insn = $(if $(shell echo 'void _(void) { asm volatile ( $(2) ); }' \ diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile index 0afa414..fcae290 100644 --- a/xen/arch/arm/Makefile +++ b/xen/arch/arm/Makefile @@ -92,7 +92,7 @@ $(TARGET)-syms: prelink.o xen.lds $(BASEDIR)/common/symbols-dummy.o $(NM) -pa --format=sysv $(@D)/.$(@F).1 \ | $(BASEDIR)/tools/symbols --sysv --sort >$(@D)/.$(@F).1.S $(MAKE) -f $(BASEDIR)/Rules.mk $(@D)/.$(@F).1.o - $(LD) $(LDFLAGS) -T xen.lds -N prelink.o \ + $(LD) $(LDFLAGS) -T xen.lds -N prelink.o $(build_id_linker) \ $(@D)/.$(@F).1.o -o $@ rm -f $(@D)/.$(@F).[0-9]* diff --git a/xen/arch/arm/xen.lds.S b/xen/arch/arm/xen.lds.S index 9909595..1f010bd 100644 --- a/xen/arch/arm/xen.lds.S +++ b/xen/arch/arm/xen.lds.S @@ -22,6 +22,9 @@ OUTPUT_ARCH(FORMAT) PHDRS { text PT_LOAD /* XXX should be AT ( XEN_PHYS_START ) */ ; +#if defined(BUILD_ID) + note PT_NOTE ; +#endif } SECTIONS { @@ -57,10 +60,18 @@ SECTIONS *(.lockprofile.data) __lock_profile_end = .; #endif - - _erodata = .; /* End of read-only data */ } :text +#if defined(BUILD_ID) + . = ALIGN(4); + .note.gnu.build-id : { + __note_gnu_build_id_start = .; + *(.note.gnu.build-id) + __note_gnu_build_id_end = .; + } :note :text +#endif + _erodata = .; /* End of read-only data */ + .data : { /* Data */ . = ALIGN(PAGE_SIZE); *(.data.page_aligned) diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index da5a135..485f681 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -76,6 +76,12 @@ efi-y := $(shell if [ ! -r $(BASEDIR)/include/xen/compile.h -o \ -O $(BASEDIR)/include/xen/compile.h ]; then \ echo '$(TARGET).efi'; fi) +ifneq ($(build_id_linker),) +notes_phdrs = --notes +else +notes_phdrs = +endif + ifdef CONFIG_XSPLICE all_symbols = --all-symbols ifdef CONFIG_FAST_SYMBOL_LOOKUP @@ -87,7 +93,8 @@ endif $(TARGET): $(TARGET)-syms $(efi-y) boot/mkelf32 ./boot/mkelf32 $(TARGET)-syms $(TARGET) 0x100000 \ - `$(NM) -nr $(TARGET)-syms | head -n 1 | sed -e 's/^\([^ ]*\).*/0x\1/'` + `$(NM) -nr $(TARGET)-syms | head -n 1 | sed -e 's/^\([^ ]*\).*/0x\1/'` \ + $(notes_phdrs) .PHONY: tests tests: @@ -121,22 +128,28 @@ $(BASEDIR)/common/symbols-dummy.o: $(MAKE) -f $(BASEDIR)/Rules.mk -C $(BASEDIR)/common symbols-dummy.o $(TARGET)-syms: prelink.o xen.lds $(BASEDIR)/common/symbols-dummy.o - $(LD) $(LDFLAGS) -T xen.lds -N prelink.o \ + $(LD) $(LDFLAGS) -T xen.lds -N prelink.o $(build_id_linker) \ $(BASEDIR)/common/symbols-dummy.o -o $(@D)/.$(@F).0 $(NM) -pa --format=sysv $(@D)/.$(@F).0 \ | $(BASEDIR)/tools/symbols $(all_symbols) --sysv --sort \ >$(@D)/.$(@F).0.S $(MAKE) -f $(BASEDIR)/Rules.mk $(@D)/.$(@F).0.o - $(LD) $(LDFLAGS) -T xen.lds -N prelink.o \ + $(LD) $(LDFLAGS) -T xen.lds -N prelink.o $(build_id_linker) \ $(@D)/.$(@F).0.o -o $(@D)/.$(@F).1 $(NM) -pa --format=sysv $(@D)/.$(@F).1 \ | $(BASEDIR)/tools/symbols $(all_symbols) --sysv --sort --warn-dup \ >$(@D)/.$(@F).1.S $(MAKE) -f $(BASEDIR)/Rules.mk $(@D)/.$(@F).1.o - $(LD) $(LDFLAGS) -T xen.lds -N prelink.o \ + $(LD) $(LDFLAGS) -T xen.lds -N prelink.o $(build_id_linker) \ $(@D)/.$(@F).1.o -o $@ rm -f $(@D)/.$(@F).[0-9]* +note.o: $(TARGET)-syms + $(OBJCOPY) -O binary --only-section=.note.gnu.build-id $(BASEDIR)/xen-syms $@.bin + $(OBJCOPY) -I binary -O elf64-x86-64 -B i386:x86-64 \ + --rename-section=.data=.note.gnu.build-id -S $@.bin $@ + rm -f $@.bin + EFI_LDFLAGS = $(patsubst -m%,-mi386pep,$(LDFLAGS)) --subsystem=10 EFI_LDFLAGS += --image-base=$(1) --stack=0,0 --heap=0,0 --strip-debug EFI_LDFLAGS += --section-alignment=0x200000 --file-alignment=0x20 @@ -149,6 +162,13 @@ $(TARGET).efi: VIRT_BASE = 0x$(shell $(NM) efi/relocs-dummy.o | sed -n 's, A VIR $(TARGET).efi: ALT_BASE = 0x$(shell $(NM) efi/relocs-dummy.o | sed -n 's, A ALT_START$$,,p') # Don't use $(wildcard ...) here - at least make 3.80 expands this too early! $(TARGET).efi: guard = $(if $(shell echo efi/dis* | grep disabled),:) +ifneq ($(build_id_linker),) +$(TARGET).efi: note.o +note_file := note.o +else +note_file := +endif + $(TARGET).efi: prelink-efi.o efi.lds efi/relocs-dummy.o $(BASEDIR)/common/symbols-dummy.o efi/mkreloc $(foreach base, $(VIRT_BASE) $(ALT_BASE), \ $(guard) $(LD) $(call EFI_LDFLAGS,$(base)) -T efi.lds -N $< efi/relocs-dummy.o \ @@ -165,7 +185,7 @@ $(TARGET).efi: prelink-efi.o efi.lds efi/relocs-dummy.o $(BASEDIR)/common/symbol | $(guard) $(BASEDIR)/tools/symbols $(all_symbols) --sysv --sort >$(@D)/.$(@F).1s.S $(guard) $(MAKE) -f $(BASEDIR)/Rules.mk $(@D)/.$(@F).1r.o $(@D)/.$(@F).1s.o $(guard) $(LD) $(call EFI_LDFLAGS,$(VIRT_BASE)) -T efi.lds -N $< \ - $(@D)/.$(@F).1r.o $(@D)/.$(@F).1s.o -o $@ + $(@D)/.$(@F).1r.o $(@D)/.$(@F).1s.o $(note_file) -o $@ if $(guard) false; then rm -f $@; echo 'EFI support disabled'; fi rm -f $(@D)/.$(@F).[0-9]* diff --git a/xen/arch/x86/boot/mkelf32.c b/xen/arch/x86/boot/mkelf32.c index 993a7ee..fce1716 100644 --- a/xen/arch/x86/boot/mkelf32.c +++ b/xen/arch/x86/boot/mkelf32.c @@ -45,9 +45,9 @@ static Elf32_Ehdr out_ehdr = { 0, /* e_flags */ sizeof(Elf32_Ehdr), /* e_ehsize */ sizeof(Elf32_Phdr), /* e_phentsize */ - 1, /* e_phnum */ + 1, /* modify based on num_phdrs */ /* e_phnum */ sizeof(Elf32_Shdr), /* e_shentsize */ - 3, /* e_shnum */ + 3, /* modify based on num_phdrs */ /* e_shnum */ 2 /* e_shstrndx */ }; @@ -61,8 +61,20 @@ static Elf32_Phdr out_phdr = { PF_R|PF_W|PF_X, /* p_flags */ 64 /* p_align */ }; +static Elf32_Phdr note_phdr = { + PT_NOTE, /* p_type */ + DYNAMICALLY_FILLED, /* p_offset */ + DYNAMICALLY_FILLED, /* p_vaddr */ + DYNAMICALLY_FILLED, /* p_paddr */ + DYNAMICALLY_FILLED, /* p_filesz */ + DYNAMICALLY_FILLED, /* p_memsz */ + PF_R, /* p_flags */ + 4 /* p_align */ +}; static u8 out_shstrtab[] = "\0.text\0.shstrtab"; +/* If num_phdrs >= 2, we need to tack the .note. */ +static u8 out_shstrtab_extra[] = ".note\0"; static Elf32_Shdr out_shdr[] = { { 0 }, @@ -90,6 +102,23 @@ static Elf32_Shdr out_shdr[] = { } }; +/* + * The 17 points to the '.note' in the out_shstrtab and out_shstrtab_extra + * laid out in the file. + */ +static Elf32_Shdr out_shdr_note = { + 17, /* sh_name */ + SHT_NOTE, /* sh_type */ + 0, /* sh_flags */ + DYNAMICALLY_FILLED, /* sh_addr */ + DYNAMICALLY_FILLED, /* sh_offset */ + DYNAMICALLY_FILLED, /* sh_size */ + 0, /* sh_link */ + 0, /* sh_info */ + 4, /* sh_addralign */ + 0 /* sh_entsize */ +}; + /* Some system header files define these macros and pollute our namespace. */ #undef swap16 #undef swap32 @@ -228,21 +257,22 @@ static void do_read(int fd, void *data, int len) int main(int argc, char **argv) { u64 final_exec_addr; - u32 loadbase, dat_siz, mem_siz; + u32 loadbase, dat_siz, mem_siz, note_base, note_sz, offset; char *inimage, *outimage; int infd, outfd; char buffer[1024]; int bytes, todo, i; + int num_phdrs = 1; Elf32_Ehdr in32_ehdr; Elf64_Ehdr in64_ehdr; Elf64_Phdr in64_phdr; - if ( argc != 5 ) + if ( argc < 5 ) { fprintf(stderr, "Usage: mkelf32 " - " \n"); + " [--notes]\n"); return 1; } @@ -250,6 +280,8 @@ int main(int argc, char **argv) outimage = argv[2]; loadbase = strtoul(argv[3], NULL, 16); final_exec_addr = strtoull(argv[4], NULL, 16); + if ( argv[5] && (!strcmp(argv[5], "--notes")) ) + num_phdrs = 2; infd = open(inimage, O_RDONLY); if ( infd == -1 ) @@ -285,11 +317,10 @@ int main(int argc, char **argv) (int)in64_ehdr.e_phentsize, (int)sizeof(in64_phdr)); return 1; } - - if ( in64_ehdr.e_phnum != 1 ) + if ( in64_ehdr.e_phnum != num_phdrs ) { - fprintf(stderr, "Expect precisly 1 program header; found %d.\n", - (int)in64_ehdr.e_phnum); + fprintf(stderr, "Expect precisly %d program header; found %d.\n", + num_phdrs, (int)in64_ehdr.e_phnum); return 1; } @@ -304,6 +335,32 @@ int main(int argc, char **argv) /*mem_siz = (u32)in64_phdr.p_memsz;*/ mem_siz = (u32)(final_exec_addr - in64_phdr.p_vaddr); + note_sz = note_base = offset = 0; + if ( num_phdrs > 1 ) + { + offset = in64_phdr.p_offset; + note_base = in64_phdr.p_vaddr; + + (void)lseek(infd, in64_ehdr.e_phoff+sizeof(in64_phdr), SEEK_SET); + do_read(infd, &in64_phdr, sizeof(in64_phdr)); + endianadjust_phdr64(&in64_phdr); + + (void)lseek(infd, offset, SEEK_SET); + + note_sz = in64_phdr.p_memsz; + note_base = in64_phdr.p_vaddr - note_base; + + if ( in64_phdr.p_offset > dat_siz || offset > in64_phdr.p_offset ) + { + fprintf(stderr, "Expected .note section within .text section!\n" \ + "Offset %ld not within %d!\n", + in64_phdr.p_offset, dat_siz); + return 1; + } + /* Gets us the absolute offset within the .text section. */ + offset = in64_phdr.p_offset - offset; + } + /* * End the image on a page boundary. This gets round alignment bugs * in the boot- or chain-loader (e.g., kexec on the XenoBoot CD). @@ -322,6 +379,31 @@ int main(int argc, char **argv) out_shdr[1].sh_size = dat_siz; out_shdr[2].sh_offset = RAW_OFFSET + dat_siz + sizeof(out_shdr); + if ( num_phdrs > 1 ) + { + /* We have two of them! */ + out_ehdr.e_phnum = num_phdrs; + /* Extra .note section. */ + out_ehdr.e_shnum++; + + /* Fill out the PT_NOTE program header. */ + note_phdr.p_vaddr = note_base; + note_phdr.p_paddr = note_base; + note_phdr.p_filesz = note_sz; + note_phdr.p_memsz = note_sz; + note_phdr.p_offset = offset; + + /* Tack on the .note\0 */ + out_shdr[2].sh_size += sizeof(out_shstrtab_extra); + /* And move it past the .note section. */ + out_shdr[2].sh_offset += sizeof(out_shdr_note); + + /* Fill out the .note section. */ + out_shdr_note.sh_size = note_sz; + out_shdr_note.sh_addr = note_base; + out_shdr_note.sh_offset = RAW_OFFSET + offset; + } + outfd = open(outimage, O_WRONLY|O_CREAT|O_TRUNC, 0775); if ( outfd == -1 ) { @@ -335,8 +417,14 @@ int main(int argc, char **argv) endianadjust_phdr32(&out_phdr); do_write(outfd, &out_phdr, sizeof(out_phdr)); - - if ( (bytes = RAW_OFFSET - sizeof(out_ehdr) - sizeof(out_phdr)) < 0 ) + + if ( num_phdrs > 1 ) + { + endianadjust_phdr32(¬e_phdr); + do_write(outfd, ¬e_phdr, sizeof(note_phdr)); + } + + if ( (bytes = RAW_OFFSET - sizeof(out_ehdr) - (num_phdrs * sizeof(out_phdr)) ) < 0 ) { fprintf(stderr, "Header overflow.\n"); return 1; @@ -355,9 +443,22 @@ int main(int argc, char **argv) endianadjust_shdr32(&out_shdr[i]); do_write(outfd, &out_shdr[0], sizeof(out_shdr)); - do_write(outfd, out_shstrtab, sizeof(out_shstrtab)); - do_write(outfd, buffer, 4-((sizeof(out_shstrtab)+dat_siz)&3)); - + if ( num_phdrs > 1 ) + { + endianadjust_shdr32(&out_shdr_note); + /* Append the .note section. */ + do_write(outfd, &out_shdr_note, sizeof(out_shdr_note)); + /* The normal strings - .text\0.. */ + do_write(outfd, out_shstrtab, sizeof(out_shstrtab)); + /* Our .note */ + do_write(outfd, out_shstrtab_extra, sizeof(out_shstrtab_extra)); + do_write(outfd, buffer, 4-((sizeof(out_shstrtab)+sizeof(out_shstrtab_extra)+dat_siz)&3)); + } + else + { + do_write(outfd, out_shstrtab, sizeof(out_shstrtab)); + do_write(outfd, buffer, 4-((sizeof(out_shstrtab)+dat_siz)&3)); + } close(infd); close(outfd); diff --git a/xen/arch/x86/xen.lds.S b/xen/arch/x86/xen.lds.S index 5eb825e..b3d880f 100644 --- a/xen/arch/x86/xen.lds.S +++ b/xen/arch/x86/xen.lds.S @@ -31,6 +31,9 @@ OUTPUT_ARCH(i386:x86-64) PHDRS { text PT_LOAD ; +#if defined(BUILD_ID) && !defined(EFI) + note PT_NOTE ; +#endif } SECTIONS { @@ -79,6 +82,16 @@ SECTIONS *(.rodata) *(.rodata.*) +#if defined(BUILD_ID) && defined(EFI) +/* + * No mechanism to put an PT_NOTE in the EFI file - so put + * it in .rodata section. (notes.o supplies us with .note.gnu.build-id). + */ + . = ALIGN(4); + __note_gnu_build_id_start = .; + *(.note.gnu.build-id) + __note_gnu_build_id_end = .; +#endif . = ALIGN(8); /* Exception table */ __start___ex_table = .; @@ -99,6 +112,21 @@ SECTIONS _erodata = .; } :text +#if defined(BUILD_ID) && !defined(EFI) +/* + * What a strange section name. The reason is that on ELF builds this section + * is extracted to notes.o (which then is ingested in the EFI file). But the + * compiler may want to inject other things in the .note which we don't care + * about - hence this unique name. + */ + . = ALIGN(4); + .note.gnu.build-id : { + __note_gnu_build_id_start = .; + *(.note.gnu.build-id) + __note_gnu_build_id_end = .; + } :note :text +#endif + #ifdef EFI . = ALIGN(MB(2)); #else diff --git a/xen/common/version.c b/xen/common/version.c index fc9bf42..01d9409 100644 --- a/xen/common/version.c +++ b/xen/common/version.c @@ -1,4 +1,9 @@ #include +#include +#include +#include +#include +#include #include const char *xen_compile_date(void) @@ -61,6 +66,51 @@ const char *xen_deny(void) return ""; } +static const void *build_id_p; +static unsigned int build_id_len; + +int xen_build_id(const void **p, unsigned int *len) +{ + if ( !build_id_len ) + return -ENODATA; + + *len = build_id_len; + *p = build_id_p; + + return 0; +} + +#ifdef BUILD_ID +/* Defined in linker script. */ +extern const Elf_Note __note_gnu_build_id_start[], __note_gnu_build_id_end[]; + +static int __init xen_build_init(void) +{ + const Elf_Note *n = __note_gnu_build_id_start; + + /* --build-id invoked with wrong parameters. */ + if ( __note_gnu_build_id_end <= &n[0] ) + return -ENODATA; + + /* Check for full Note header. */ + if ( &n[1] > __note_gnu_build_id_end ) + return -ENODATA;; + + /* Check if we really have a build-id. */ + if ( NT_GNU_BUILD_ID != n->type ) + return -ENODATA; + + /* Sanity check, name should be "GNU" for ld-generated build-id. */ + if ( strncmp(ELFNOTE_NAME(n), "GNU", n->namesz) != 0 ) + return -ENODATA; + + build_id_len = n->descsz; + build_id_p = ELFNOTE_DESC(n); + + return 0; +} +__initcall(xen_build_init); +#endif /* * Local variables: * mode: C diff --git a/xen/include/xen/elfstructs.h b/xen/include/xen/elfstructs.h index be55985..5babac7 100644 --- a/xen/include/xen/elfstructs.h +++ b/xen/include/xen/elfstructs.h @@ -40,6 +40,9 @@ typedef uint32_t Elf64_Word; typedef int64_t Elf64_Sxword; typedef uint64_t Elf64_Xword; +/* Unique build id string format when using --build-id. */ +#define NT_GNU_BUILD_ID 3 + /* * e_ident[] identification indexes * See http://www.caldera.com/developers/gabi/2000-07-17/ch4.eheader.html diff --git a/xen/include/xen/version.h b/xen/include/xen/version.h index 2015c0b..400160f 100644 --- a/xen/include/xen/version.h +++ b/xen/include/xen/version.h @@ -13,5 +13,6 @@ const char *xen_extra_version(void); const char *xen_changeset(void); const char *xen_banner(void); const char *xen_deny(void); +int xen_build_id(const void **p, unsigned int *len); #endif /* __XEN_VERSION_H__ */