scripts: generate image info header file

This commit adds the `gen_image_info.py` script which supports creation
of a header file with image information from the EFL file.

This version populates the header file with:
- Number of segments in the image
- LMA address of each segment
- VMA address of each segment
- Size of each segment

The header file can be used by a secondary build system which needs this
information.

Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index af6c8cc..092b9ad 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1576,6 +1576,19 @@
     )
 endif()
 
+if(CONFIG_BUILD_OUTPUT_INFO_HEADER)
+  list(APPEND
+    post_build_commands
+    COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/gen_image_info.py
+    --elf-file=${KERNEL_ELF_NAME}
+    --header-file=${PROJECT_BINARY_DIR}/include/public/zephyr_image_info.h
+    )
+  list(APPEND
+    post_build_byproducts
+    ${PROJECT_BINARY_DIR}/include/public/zephyr_image_info.h
+    )
+endif()
+
 # Generate and use MCUboot related artifacts as needed.
 if(CONFIG_BOOTLOADER_MCUBOOT)
   include(${CMAKE_CURRENT_LIST_DIR}/cmake/mcuboot.cmake)
diff --git a/CODEOWNERS b/CODEOWNERS
index bc64c6c..04f7c19 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -658,6 +658,7 @@
 /scripts/pylib/twister/expr_parser.py     @nashif
 /scripts/schemas/twister/                 @nashif
 /scripts/gen_app_partitions.py            @dcpleung @nashif
+scripts/gen_image_info.py                 @tejlmand
 /scripts/get_maintainer.py                @nashif
 /scripts/dts/                             @mbolivar-nordic @galak
 /scripts/release/                         @nashif
diff --git a/Kconfig.zephyr b/Kconfig.zephyr
index d2d3e0a..9d43b6b 100644
--- a/Kconfig.zephyr
+++ b/Kconfig.zephyr
@@ -494,6 +494,17 @@
 	  Build a stripped binary zephyr/zephyr.strip in the build directory.
 	  The name of this file can be customized with CONFIG_KERNEL_BIN_NAME.
 
+config BUILD_OUTPUT_INFO_HEADER
+	bool "Create a image information header"
+	help
+	  Create an image information header which will contain image
+	  information from the Zephyr binary.
+	  Example of information contained in the header file:
+	  - Number of segments in the image
+	  - LMA address of each segment
+	  - VMA address of each segment
+	  - Size of each segment
+
 config APPLICATION_DEFINED_SYSCALL
 	bool "Scan application folder for any syscall definition"
 	help
diff --git a/scripts/gen_image_info.py b/scripts/gen_image_info.py
new file mode 100644
index 0000000..aad71b1
--- /dev/null
+++ b/scripts/gen_image_info.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2022, Nordic Semiconductor ASA
+#
+# SPDX-License-Identifier: Apache-2.0
+
+'''
+Script to generate image information files.
+
+This script creates a image information header which can be included by a
+second build system.
+This allows a second stage build system to use image information from a Zephyr
+build by including the generated header.
+
+Information included in the image information header:
+- Number of segments in the image
+- LMA address of each segment
+- VMA address of each segment
+- Size of each segment
+'''
+
+import argparse
+from elftools.elf.elffile import ELFFile
+
+
+def write_header(filename, segments):
+    content = []
+
+    filename_we = filename.split('.h')[0].upper()
+    content.append(f'#ifndef {filename_we}_H')
+    content.append(f'#define {filename_we}_H')
+    content.append(f'')
+    content.append(f'#define SEGMENT_NUM {len(segments)}')
+
+    for idx, segment in enumerate(segments):
+        segment_header = segment['segment'].header
+        hex_lma_addr = hex(segment_header.p_paddr)
+        hex_vma_addr = hex(segment_header.p_vaddr)
+        hex_size = hex(segment_header.p_filesz)
+
+        content.append(f'')
+        content.append(f'#define SEGMENT_LMA_ADDRESS_{idx} {hex_lma_addr}')
+        content.append(f'#define SEGMENT_VMA_ADDRESS_{idx} {hex_vma_addr}')
+        content.append(f'#define SEGMENT_SIZE_{idx} {hex_size}')
+
+    content.append(f'')
+    content.append(f'#endif /* {filename_we}_H */')
+
+    with open(filename, 'w') as out_file:
+        out_file.write('\n'.join(content))
+
+
+def read_segments(filename):
+    elffile = ELFFile(open(filename, 'rb'))
+    segments = list()
+    for segment_idx in range(elffile.num_segments()):
+        segments.insert(segment_idx, dict())
+        segments[segment_idx]['segment'] = elffile.get_segment(segment_idx)
+    return segments
+
+
+def main():
+    parser = argparse.ArgumentParser(description='''
+    Process ELF file and extract image information.
+    Create header file with extracted image information which can be included
+    in other build systems.''')
+
+    parser.add_argument('--header-file', required=True,
+                        help="""Header file to write with image data.""")
+    parser.add_argument('--elf-file', required=True,
+                        help="""ELF File to process.""")
+    args = parser.parse_args()
+
+    segments = read_segments(args.elf_file)
+    write_header(args.header_file, segments)
+
+
+if __name__ == "__main__":
+    main()