1#!/usr/bin/env python
2#
3# SPDX-FileCopyrightText: 2016 Cesanta Software Limited
4#
5# SPDX-License-Identifier: GPL-2.0-or-later
6#
7# SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD
8
9import argparse
10import base64
11import json
12import os
13import os.path
14import sys
15
16sys.path.append("..")
17import esptool  # noqa: E402
18
19THIS_DIR = os.path.dirname(__file__)
20BUILD_DIR = os.path.join(THIS_DIR, "build")
21
22
23def wrap_stub(elf_file):
24    """Wrap an ELF file into a stub JSON dict"""
25    print("Wrapping ELF file %s..." % elf_file)
26
27    e = esptool.bin_image.ELFFile(elf_file)
28
29    text_section = e.get_section(".text")
30    stub = {
31        "entry": e.entrypoint,
32        "text": text_section.data,
33        "text_start": text_section.addr,
34    }
35    try:
36        data_section = e.get_section(".data")
37        stub["data"] = data_section.data
38        stub["data_start"] = data_section.addr
39    except ValueError:
40        pass
41
42    for s in e.nobits_sections:
43        if s.name == ".bss":
44            stub["bss_start"] = s.addr
45
46    # Pad text with NOPs to mod 4.
47    if len(stub["text"]) % 4 != 0:
48        stub["text"] += (4 - (len(stub["text"]) % 4)) * "\0"
49
50    print(
51        "Stub text: %d @ 0x%08x, data: %d @ 0x%08x, entry @ 0x%x"
52        % (
53            len(stub["text"]),
54            stub["text_start"],
55            len(stub.get("data", "")),
56            stub.get("data_start", 0),
57            stub["entry"],
58        ),
59        file=sys.stderr,
60    )
61
62    return stub
63
64
65def write_json_files(stubs_dict):
66    class BytesEncoder(json.JSONEncoder):
67        def default(self, obj):
68            if isinstance(obj, bytes):
69                return base64.b64encode(obj).decode("ascii")
70            return json.JSONEncoder.default(self, obj)
71
72    for filename, stub_data in stubs_dict.items():
73        with open(os.path.join(BUILD_DIR, filename), "w") as outfile:
74            json.dump(stub_data, outfile, cls=BytesEncoder, indent=4)
75
76
77def stub_name(filename):
78    """Return a dictionary key for the stub with filename 'filename'"""
79    return os.path.splitext(os.path.basename(filename))[0] + ".json"
80
81
82if __name__ == "__main__":
83    parser = argparse.ArgumentParser()
84    parser.add_argument("elf_files", nargs="+", help="Stub ELF files to convert")
85    args = parser.parse_args()
86
87    stubs = dict(
88        (stub_name(elf_file), wrap_stub(elf_file)) for elf_file in args.elf_files
89    )
90    write_json_files(stubs)
91