# Copyright 2024 NXP

#SPDX-License-Identifier: BSD-3-Clause

#-- Special case script. Should be used then board connection parameters used, 
#-- but board initialization not required or not possible (under Linux)
#-- thus 'board_init()' is empty
 
import sys
import os

from gdb_extensions.flash.scripts.elfparser import ElfFile


def get_abs_path(path):
    abs_path = os.path.abspath(path)
    if os.path.isfile(abs_path):
        return abs_path
    return None

def get_elf_sections(file_debug, init_script, soc_name):

    abs_path = get_abs_path(file_debug)
    if abs_path is None:
         raise Exception("File " + file_debug + " does not exist.") 
    abs_path = abs_path.replace("\\", "/")
    file = ElfFile(abs_path)
    
    if file is None:
        raise Exception("F-ERROR: This file format is not supported.")

    # Import SRAM memory range from memory regions script
    scripts_dir = os.path.dirname(init_script)
    memory_regions = None
    for filename in os.listdir(scripts_dir):
        if "_memory_regions.py" in filename:
            from importlib import import_module
            sys.path.append(scripts_dir)
            module_name = os.path.splitext(os.path.basename(filename))[0]
            memory_regions = import_module(module_name)
            break
   
    if memory_regions is None:
        raise Exception("F-ERROR: Error in receiveing SoC memory regions.")
        
    # This is currently supported only for S32K3x boards
    global sram_ranges
    sram_ranges = memory_regions.get_sram(soc_name)
    program_headers = _extract_prog_headers(file) 
    
    section_list = []
    for header in program_headers:
        for hd in header:
            section_list.append(hd.section)
            size = hd.get_size()
            data = hd.section.read_data_chunk(0, size)
            with open(file_debug.replace(".elf", "." + str(hd.section.sec_index)), 'wb') as f:
                f.write(data)
                
    return section_list
            

# for internal usage
class ElfSector:
    sector = None
    section = None

    def __init__(self, sector, section):
        self.sector = sector
        self.section = section

    def get_size(self):
        return self.section.size

    def get_addr(self):
        return self.section.addr - self.sector.vaddr + self.sector.paddr

    def __str__(self):
        return "" \
            + "sector     %s\n" % self.sector \
            + "section     %s\n" % self.section           

def _extract_prog_headers(file):
    from gdb_extensions.flash.scripts.elfparser import ProgType
    #scan all prog headers. If it PT_LOAD and fit in sram try to find sections
    return [_find_sram_section(x, file) for x in file.iter_prog_headers()
            if (x.prog_type is ProgType.PT_LOAD)]
            
def _find_sram_section(p_head, file):
    from gdb_extensions.flash.scripts.elfparser import SectionFlag
    return [ElfSector(p_head, x) for x in file.iter_section_headers()
            if (p_head.vaddr <= x.addr) and (p_head.vaddr + p_head.filesz >= x.addr + x.size)
            and x.size != 0 and (x.flags & SectionFlag.SHF_ALLOC is SectionFlag.SHF_ALLOC) and 
            _is_sram(x.addr, x.size)]
            
def _is_sram(address, size):
    global sram_ranges
    for sram in sram_ranges:
        if address >= sram.start and (address + size) <= (sram.start + sram.length):
            return True
    return False
    
def get_pc(file_debug):
    abs_path = get_abs_path(file_debug)
    if abs_path:
        abs_path = abs_path.replace("\\", "/")
    file = ElfFile(abs_path)
    if file is None:
        raise Exception("F-ERROR: This file format is not supported.")

    return file.elf_header.entry
