From d8da4f9b9cb9a62011aff48bae3439d6da3ba12b Mon Sep 17 00:00:00 2001 From: Simon Kuenzer Date: Fri, 15 Sep 2023 12:57:10 +0200 Subject: [PATCH] lib/uklibid: Embedded library information This commit introduces the `.uk_libinfo` section which is used to store additional library information in library object files. We define the data structure of the section and declare it as layout version 1. For each library the build system will generate a single header and each header can contain an individual number of records to store values. Layout version 1 also supports storing of information related to the image as a whole and not to a specific library. A single header is created for global information, which differs from the library headers in that it does not contain a record for a library name (LIBNAME). When a final Unikraft image is linked, the individual sections of each library are merged into one section. By default, a minimal set of library and global information is enabled. The motivation behind this is that library objects are instrumented with uk_libinfo from now on. In a future commit, the build system could provide an option to remove this section from (non-debug) images if it is not used by Unikraft code itself. Signed-off-by: Simon Kuenzer Reviewed-by: Michalis Pappas Reviewed-by: Robert Kuban Approved-by: Razvan Deaconescu GitHub-Closes: #1117 --- lib/uklibid/Config.uk | 65 +++++++++++++++++++- lib/uklibid/Makefile.uk | 6 ++ lib/uklibid/include/uk/libid/info.h | 93 +++++++++++++++++++++++++++++ lib/uklibid/infosec.ld | 9 +++ lib/uklibid/libinfo.S | 59 ++++++++++++++++++ 5 files changed, 230 insertions(+), 2 deletions(-) create mode 100644 lib/uklibid/include/uk/libid/info.h create mode 100644 lib/uklibid/infosec.ld create mode 100644 lib/uklibid/libinfo.S diff --git a/lib/uklibid/Config.uk b/lib/uklibid/Config.uk index 059757d6f..c9aa63383 100644 --- a/lib/uklibid/Config.uk +++ b/lib/uklibid/Config.uk @@ -1,6 +1,6 @@ -config LIBUKLIBID +menuconfig LIBUKLIBID bool "uklibid: Library identifier" - default n + default y # FIXME: We actually depend on but lib/ukdebug also # depends on us. If we specify the dependency here, it creates a # circular dependency that KConfig doesn't like. However, we @@ -8,3 +8,64 @@ config LIBUKLIBID # build, so we comment out the dependency here. Of course, this # is not accurate. #select LIBUKDEBUG + +if LIBUKLIBID +config LIBUKLIBID_INFO + bool "Embedded library metadata" + default y + + if LIBUKLIBID_INFO + menu "Global metadata" + config LIBUKLIBID_INFO_UKFULLVERSION + bool "Full unikraft version" + default y + help + If enabled, the full Unikraft version including + Git SHA is embedded. Otherwise, only the short + Unikraft version is stored. + + config LIBUKLIBID_INFO_UKCODENAME + bool "Unikraft codename" + help + If enabled, the Unikraft release codename is + stored as part of the global metadata + information. + + config LIBUKLIBID_INFO_COMPILER + bool "Compiler (CC) information" + help + Enables storing the C compiler ($(CC)) that was + used for during compilation for the unikernel + image. + endmenu + + menu "Per library metadata" + config LIBUKLIBID_INFO_LIB_UKVERSION + bool "Unikraft version" + help + If enabled, the Unikraft version is included + to each library. + + config LIBUKLIBID_INFO_LIB_UKFULLVERSION + bool "Full version" + depends on LIBUKLIBID_INFO_LIB_UKVERSION + help + Instead of the short Unikraft version, the full + Unikraft version including Git SHA is embedded + to each library. + + config LIBUKLIBID_INFO_LIB_UKCODENAME + bool "Unikraft codename" + help + If enabled, the Unikraft release codename is + stored as part of each library metadata + information. + + config LIBUKLIBID_INFO_LIB_COMPILER + bool "Compiler (CC) information" + default y + help + Enables storing the C compiler ($(CC)) that was + used for each library. + endmenu +endif diff --git a/lib/uklibid/Makefile.uk b/lib/uklibid/Makefile.uk index 2090a1267..3d94d938e 100644 --- a/lib/uklibid/Makefile.uk +++ b/lib/uklibid/Makefile.uk @@ -38,4 +38,10 @@ LIBUKLIBID_SRCS-y += $(LIBUKLIBID_BASE)/exportsyms.awk>.uk LIBUKLIBID_EXPORTSYMS_AWKINCLUDES-y += $(LIBUKLIBID_BUILD)/libraries.in LIBUKLIBID_EXPORTS-y += $(LIBUKLIBID_BUILD)/exportsyms.uk +EACHOLIB_SRCS-$(CONFIG_LIBUKLIBID_INFO) += $(LIBUKLIBID_BASE)/libinfo.S|libuklibid +ASFLAGS += -D__LIBUKLIBID_COMPILER__="$(CC_INFO)" +LIBUKLIBID_SRCS-$(CONFIG_LIBUKLIBID_INFO) += $(LIBUKLIBID_BASE)/infosec.ld +LIBUKLIBID_SRCS-$(CONFIG_LIBUKLIBID_INFO) += $(LIBUKLIBID_BASE)/libinfo.S|global +LIBUKLIBID_LIBINFO_GLOBAL_FLAGS-y += -D__GLOBALINFO__ + UK_PREPARE-$(CONFIG_LIBUKLIBID) += $(LIBUKLIBID_BUILD)/libraries.in.new diff --git a/lib/uklibid/include/uk/libid/info.h b/lib/uklibid/include/uk/libid/info.h new file mode 100644 index 000000000..9168d3b03 --- /dev/null +++ b/lib/uklibid/include/uk/libid/info.h @@ -0,0 +1,93 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright (c) 2023, Unikraft GmbH and The Unikraft Authors. + * Licensed under the BSD-3-Clause License (the "License"). + * You may not use this file except in compliance with the License. + */ +#ifndef __UK_LIBID_INFO_H__ +#define __UK_LIBID_INFO_H__ + +#include +#include + +/* + * Library information is stored in the special section " .uk_libinfo". For + * each library there is one `struct uk_libid_info_hdr` generated. Each header + * can contain multiple `struct uk_libid_info_rec` records. A library name + * record (`UKLI_REC_LIBNAME`) is the only mandatory record type for each + * library. + * Additionally, a single header is created for global information, which + * differs from the library headers in that it does not contain a record for a + * library name. + * + * Layout for each information header: + * + * _____________ + * +--------------------------+ \ + * | struct uk_libid_info_hdr | | + * | | > hdr->len + * +--------------------------+ | + * | struct uk_libid_info_rec | | + * +--------------------------+ -. | + * | struct uk_libid_info_rec | > rec->len | + * | | | | + * +--------------------------+ -` | + * : . . . : : + * +--------------------------+ | + * | struct uk_libid_info_rec | | + * | | | + * +--------------------------+ ____________/ + */ + +/* + * NOTE: The layout version needs only be updated if the structs + * `uk_libid_info_rec` and `uk_libid_info_hdr` are updated. + */ + #define UKLI_LAYOUT 0x0001 + +/* + * NOTE: In order to keep backwards compatibility with pre-compiled + * libraries, this list should only be extended with new entries. + */ +#define UKLI_REC_LIBNAME 0x0001 /* C-string, absent for global hdr */ +#define UKLI_REC_COMMENT 0x0002 /* C-string */ +#define UKLI_REC_VERSION 0x0003 /* C-string */ +#define UKLI_REC_LICENSE 0x0004 /* C-string */ +#define UKLI_REC_GITDESC 0x0005 /* C-string */ +#define UKLI_REC_UKVERSION 0x0006 /* C-string, Unikraft version only */ +#define UKLI_REC_UKFULLVERSION 0x0007 /* C-string, UK version with gitsha */ +#define UKLI_REC_UKCODENAME 0x0008 /* C-string */ +#define UKLI_REC_UKCONFIG 0x0009 /* binary data */ +#define UKLI_REC_UKCONFIGGZ 0x000A /* binary data */ +#define UKLI_REC_COMPILER 0x000B /* C-string */ +#define UKLI_REC_COMPILEDATE 0x000C /* C-string */ +#define UKLI_REC_COMPILEDBY 0x000D /* C-string */ +#define UKLI_REC_COMPILEDBYASSOC 0x000E /* C-string */ +#define UKLI_REC_COMPILEOPTS 0x000F /* __u32 flags */ + +#if !__ASSEMBLY__ +#ifdef __cplusplus +extern "C" { +#endif + +struct uk_libid_info_rec { + __u16 type; /* record type */ + __u32 len; /* including record header */ + char data[]; /* raw data */ +} __packed __align(1); + +/* + * NOTE: Due to binary cross-compatibility, the sizes, offsets, data types and + * meanings must remain the same regardless of the layout version: + * `len` and `version`. + */ +struct uk_libid_info_hdr { + __u32 len; /* including header */ + __u16 version; /* layout version */ + struct uk_libid_info_rec recs[]; +} __packed __align(1); + +#ifdef __cplusplus +} +#endif +#endif /* !__ASSEMBLY__ */ +#endif /* __UK_LIBID_INFO_H__ */ diff --git a/lib/uklibid/infosec.ld b/lib/uklibid/infosec.ld new file mode 100644 index 000000000..7639c2b21 --- /dev/null +++ b/lib/uklibid/infosec.ld @@ -0,0 +1,9 @@ +SECTIONS +{ + . = ALIGN(1); + .uk_libinfo : + { + KEEP (*(.uk_libinfo)) + } +} +INSERT AFTER .rodata; diff --git a/lib/uklibid/libinfo.S b/lib/uklibid/libinfo.S new file mode 100644 index 000000000..bde6e74ec --- /dev/null +++ b/lib/uklibid/libinfo.S @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright (c) 2023, Unikraft GmbH and The Unikraft Authors. + * Licensed under the BSD-3-Clause License (the "License"). + * You may not use this file except in compliance with the License. + */ +#include +#include +#include + +#define RECORD(type, data) \ + .align 1 ; \ +1: .__u16 type /* type */ ; \ + .__u32 2f - 1b /* len */ ; \ + data /* data[] */ ; \ +2: .align 1 + +.pushsection .uk_libinfo, "a" + .align 1 +3: .__u32 4f - 3b /* len */ + .__u16 UKLI_LAYOUT /* version */ + +#if __GLOBALINFO__ + /* Only one global header per unikernel is generated */ + /* NOTE: Global metadata do not have a libname record */ +#if CONFIG_LIBUKLIBID_INFO_UKFULLVERSION + RECORD(UKLI_REC_UKFULLVERSION, .asciz STRINGIFY(UK_FULLVERSION)) +#else /* !CONFIG_LIBUKLIBID_INFO_UKFULLVERSION */ + RECORD(UKLI_REC_UKVERSION, .asciz STRINGIFY(UK_VERSION)) +#endif /* !CONFIG_LIBUKLIBID_INFO_UKFULLVERSION */ +#if CONFIG_LIBUKLIBID_INFO_UKCODENAME + RECORD(UKLI_REC_UKCODENAME, .asciz STRINGIFY(UK_CODENAME)) +#endif /* CONFIG_LIBUKLIBID_INFO_UKCODENAME */ +#if CONFIG_LIBUKLIBID_INFO_COMPILER + RECORD(UKLI_REC_COMPILER, + .asciz STRINGIFY(__LIBUKLIBID_COMPILER__)) +#endif /* CONFIG_LIBUKLIBID_INFO_COMPILER */ + +#else /* !__GLOBALINFO__ */ + /* Records per library */ + /* NOTE: The libname record is mandatory */ + RECORD(UKLI_REC_LIBNAME, .asciz STRINGIFY(__LIBNAME__)) +#if CONFIG_LIBUKLIBID_INFO_LIB_UKVERSION +#if CONFIG_LIBUKLIBID_INFO_LIB_UKFULLVERSION + RECORD(UKLI_REC_UKFULLVERSION, .asciz STRINGIFY(UK_FULLVERSION)) +#else /* !CONFIG_LIBUKLIBID_INFO_LIB_UKVERSION */ + RECORD(UKLI_REC_UKVERSION, .asciz STRINGIFY(UK_VERSION)) +#endif /* !CONFIG_LIBUKLIBID_INFO_LIB_UKVERSION */ +#endif /* CONFIG_LIBUKLIBID_INFO_LIB_UKVERSION */ +#if CONFIG_LIBUKLIBID_INFO_LIB_UKCODENAME + RECORD(UKLI_REC_UKCODENAME, .asciz STRINGIFY(UK_CODENAME)) +#endif /* CONFIG_LIBUKLIBID_INFO_LIB_UKCODENAME */ +#if CONFIG_LIBUKLIBID_INFO_LIB_COMPILER + RECORD(UKLI_REC_COMPILER, + .asciz STRINGIFY(__LIBUKLIBID_COMPILER__)) +#endif /* CONFIG_LIBUKLIBID_INFO_COMPILER */ +#endif /* !__GLOBALINFO__ */ + +4: .align 1 +.popsection -- 2.39.5