1#!/usr/bin/env python3
2#
3# Copyright (c) 2022, Nordic Semiconductor ASA
4#
5# SPDX-License-Identifier: Apache-2.0
6
7'''
8Script to generate image information files.
9
10This script creates a image information header which can be included by a
11second build system.
12This allows a second stage build system to use image information from a Zephyr
13build by including the generated header.
14
15Information included in the image information header:
16- Number of segments in the image
17- LMA address of each segment
18- VMA address of each segment
19- LMA adjusted of each segment if the LMA addresses has been adjusted after linking
20- Size of each segment
21'''
22
23import argparse
24import re
25from elftools.elf.elffile import ELFFile
26
27
28def write_header(filename, segments, adjusted_lma):
29    content = []
30
31    filename_we = re.sub(r'[\W]','_', filename).upper()
32    content.append(f'#ifndef {filename_we}_H')
33    content.append(f'#define {filename_we}_H')
34    content.append(f'')
35    content.append(f'#define SEGMENT_NUM {len(segments)}')
36    content.append(f'#define ADJUSTED_LMA {adjusted_lma}')
37
38    for idx, segment in enumerate(segments):
39        segment_header = segment['segment'].header
40        hex_lma_addr = hex(segment_header.p_paddr)
41        hex_vma_addr = hex(segment_header.p_vaddr)
42        hex_size = hex(segment_header.p_filesz)
43
44        content.append(f'')
45        content.append(f'#define SEGMENT_LMA_ADDRESS_{idx} {hex_lma_addr}')
46        content.append(f'#define SEGMENT_VMA_ADDRESS_{idx} {hex_vma_addr}')
47        content.append(f'#define SEGMENT_SIZE_{idx} {hex_size}')
48
49    content.append(f'')
50    content.append(f'#endif /* {filename_we}_H */')
51
52    with open(filename, 'w') as out_file:
53        out_file.write('\n'.join(content))
54
55
56def read_segments(filename):
57    elffile = ELFFile(open(filename, 'rb'))
58    segments = list()
59    for segment_idx in range(elffile.num_segments()):
60        segments.insert(segment_idx, dict())
61        segments[segment_idx]['segment'] = elffile.get_segment(segment_idx)
62    return segments
63
64
65def main():
66    parser = argparse.ArgumentParser(description='''
67    Process ELF file and extract image information.
68    Create header file with extracted image information which can be included
69    in other build systems.''', allow_abbrev=False)
70
71    parser.add_argument('--header-file', required=True,
72                        help="""Header file to write with image data.""")
73    parser.add_argument('--elf-file', required=True,
74                        help="""ELF File to process.""")
75    parser.add_argument('--adjusted-lma', required=False, default=0,
76                        help="""Adjusted LMA address value.""")
77    args = parser.parse_args()
78
79    segments = read_segments(args.elf_file)
80    write_header(args.header_file, segments, args.adjusted_lma)
81
82
83if __name__ == "__main__":
84    main()
85