1#!/usr/bin/env python3
2#
3# Copyright (c) 2017 Intel Corporation.
4#
5# SPDX-License-Identifier: Apache-2.0
6#
7
8"""
9This script scans a specified object file and generates a header file
10that defined macros for the offsets of various found structure members
11(particularly symbols ending with ``_OFFSET`` or ``_SIZEOF``), primarily
12intended for use in assembly code.
13"""
14
15import argparse
16import sys
17
18from elftools.elf.elffile import ELFFile
19from elftools.elf.sections import SymbolTableSection
20
21
22def get_symbol_table(obj):
23    for section in obj.iter_sections():
24        if isinstance(section, SymbolTableSection):
25            return section
26
27    raise LookupError("Could not find symbol table")
28
29
30def gen_offset_header(input_name, input_file, output_file):
31    include_guard = "__GEN_OFFSETS_H__"
32    output_file.write(
33        f"""/* THIS FILE IS AUTO GENERATED.  PLEASE DO NOT EDIT.
34 *
35 * This header file provides macros for the offsets of various structure
36 * members.  These offset macros are primarily intended to be used in
37 * assembly code.
38 */
39
40#ifndef {include_guard}
41#define {include_guard}\n\n"""
42    )
43
44    obj = ELFFile(input_file)
45    for sym in get_symbol_table(obj).iter_symbols():
46        if isinstance(sym.name, bytes):
47            sym.name = str(sym.name, 'ascii')
48
49        if not sym.name.endswith(('_OFFSET', '_SIZEOF')):
50            continue
51        if sym.entry['st_shndx'] != 'SHN_ABS':
52            continue
53        if sym.entry['st_info']['bind'] != 'STB_GLOBAL':
54            continue
55
56        output_file.write(f"#define {sym.name} 0x{sym.entry['st_value']:x}\n")
57
58    output_file.write(f"\n#endif /* {include_guard} */\n")
59
60    return 0
61
62
63if __name__ == '__main__':
64    parser = argparse.ArgumentParser(
65        description=__doc__,
66        formatter_class=argparse.RawDescriptionHelpFormatter,
67        allow_abbrev=False,
68    )
69
70    parser.add_argument("-i", "--input", required=True, help="Input object file")
71    parser.add_argument("-o", "--output", required=True, help="Output header file")
72
73    args = parser.parse_args()
74
75    with open(args.input, 'rb') as input_file, open(args.output, 'w') as output_file:
76        ret = gen_offset_header(args.input, input_file, output_file)
77
78    sys.exit(ret)
79