esp-idf/components/esp_rom/gen_gdbinit.py

74 lines
3.1 KiB
Python

#!/usr/bin/env python
#
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import json
import os
import sys
from textwrap import indent
IDF_PATH = os.getenv('IDF_PATH', '')
ROMS_JSON = os.path.join(IDF_PATH, 'tools', 'idf_py_actions', 'roms.json') # type: ignore
# Direct string extraction and comparison is not feasible due to:
# 1. ROM ELF binaries for esp32XX chips are little-endian. The byte order in
# the binary may differ from the system's endianness. We must ensure the
# bytes are read correctly for the system where the script runs.
# 2. GDB lacks built-in string comparison functionality. To work around this,
# strings are converted to numeric values for comparison.
def get_rom_if_condition_str(date_addr: int, date_str: str) -> str:
r = []
for i in range(0, len(date_str), 4):
value = hex(int.from_bytes(bytes(date_str[i:i + 4], 'utf-8'), 'little'))
r.append(f'(*(int*) {hex(date_addr + i)}) == {value}')
return 'if ' + ' && '.join(r)
def generate_gdbinit_rom_add_symbols(target: str) -> str:
base_ident = ' '
rom_elfs_dir = os.getenv('ESP_ROM_ELF_DIR')
if not rom_elfs_dir:
raise EnvironmentError(
'ESP_ROM_ELF_DIR environment variable is not defined. Please try to run IDF "install" and "export" scripts.')
if os.name == 'nt':
# convert to posix-path for windows
rom_elfs_dir = rom_elfs_dir.replace('\\', '/')
with open(ROMS_JSON, 'r') as f:
roms = json.load(f)
if target not in roms:
msg_body = f'Warning: ROM ELF is not supported yet for "{target}".' # noqa: E713
return f'echo {msg_body}\\n\n'
r = ['', f'# Load {target} ROM ELF symbols']
r.append('define target hookpost-remote')
r.append('set confirm off')
# Since GDB does not have 'else if' statement than we use nested 'if..else' instead.
for i, k in enumerate(roms[target], 1):
indent_str = base_ident * i
rom_file = f'{target}_rev{k["rev"]}_rom.elf'
build_date_addr = int(k['build_date_str_addr'], base=16)
r.append(indent(f'# if $_streq((char *) {hex(build_date_addr)}, "{k["build_date_str"]}")', indent_str))
r.append(indent(get_rom_if_condition_str(build_date_addr, k['build_date_str']), indent_str))
r.append(indent(f'add-symbol-file {rom_elfs_dir}{rom_file}', indent_str + base_ident))
r.append(indent('else', indent_str))
if i == len(roms[target]):
# In case no one known ROM ELF fits - print warning
indent_str += base_ident
msg_body = f'Warning: Unknown {target} ROM revision.'
r.append(indent(f'echo {msg_body}\\n', indent_str))
# Close 'else' operators
for i in range(len(roms[target]), 0, -1):
r.append(indent('end', base_ident * i))
r.append('set confirm on')
r.append('end')
return '\n'.join(r)[1:]
if __name__ == '__main__':
if len(sys.argv) != 2:
raise ValueError('Please pass only one argument (target).')
target = sys.argv[1]
gdbinit_lines = generate_gdbinit_rom_add_symbols(target)
print(gdbinit_lines)