diff options
author | Sylvain Munaut <tnt@246tNt.com> | 2010-03-11 21:06:47 +0100 |
---|---|---|
committer | Sylvain Munaut <tnt@246tNt.com> | 2010-04-28 10:13:50 +0200 |
commit | 3b5cc0824de719c9dd5e5686ec25c57cc2fc2bb8 (patch) | |
tree | cf512bb126381f5f6978106b8dd033b95f8bdcbc /src/target_dsp | |
parent | f1278ad9da228145925fd613d28c082dbf2806d6 (diff) |
target_dsp/calypso: Add a script to convert dump output into usable COFF
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
Diffstat (limited to 'src/target_dsp')
-rwxr-xr-x | src/target_dsp/calypso/dump2coff.py | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/src/target_dsp/calypso/dump2coff.py b/src/target_dsp/calypso/dump2coff.py new file mode 100755 index 00000000..67a49e8e --- /dev/null +++ b/src/target_dsp/calypso/dump2coff.py @@ -0,0 +1,261 @@ +#!/usr/bin/env python + +from collections import namedtuple +import re +import sys +import struct + +DATA = 0 +DATA = 1 + + +class Section(object): + + DATA = 0 + CODE = 1 + + STYP_NOLOAD = 0x0002 + STYP_TEXT = 0x0020 + STYP_DATA = 0x0040 + STYP_BSS = 0x0080 + + def __init__(self, name, type, start, size, data=None): + self.name = name + self.type = type + self.start = start + self.size = size + self.data = data + + @property + def flags(self): + if self.type == Section.DATA: + return Section.STYP_DATA if self.data else Section.STYP_BSS + else: + return Section.STYP_TEXT if self.data else Section.STYP_NOLOAD + + +class CalypsoCOFF(object): + + F_RELFLG = 0x0001 # Relocation information stripped from the file + F_EXEC = 0x0002 # File is executable (i.e., no unresolved external references) + F_LNNO = 0x0004 # Line numbers stripped from the file + F_LSYMS = 0x0010 # Local symbols stripped from the file + F_LITTLE = 0x0100 # Little endian + + def __init__(self, data_seg_base=0x80000000): + self.sections = {} + self.data_seg_base = data_seg_base + self.ver_magic = 0x00c1 + self.tgt_magic = 0x0098 + self.flags = \ + CalypsoCOFF.F_RELFLG | \ + CalypsoCOFF.F_EXEC | \ + CalypsoCOFF.F_LNNO | \ + CalypsoCOFF.F_LSYMS | \ + CalypsoCOFF.F_LITTLE + + def _data_pack(self, d): + return ''.join(struct.pack('<H', x) for x in d) + + def save(self, filename): + # Formats + HDR_FILE = '<HHlllHHH' + HDR_SECTIONS = '<8sLLllllHHHcc' + + # Optional header + oh = '' + + # File header + fh = struct.pack(HDR_FILE, + self.ver_magic, # unsigned short f_ver_magic; /* version magic number */ + len(self.sections), # unsigned short f_nscns; /* number of section */ + 0, # long f_timdat; /* time and date stamp */ + 0, # long f_symptr; /* file ptr to symbol table */ + 0, # long f_nsyms; /* number entries in the sym table */ + len(oh), # unsigned short f_opthdr; /* size of optional header */ + self.flags, # unsigned short f_flags; /* flags */ + self.tgt_magic, # unsigned short f_tgt_magic; /* target magic number */ + ) + + # File header size + #sections * sizeof(section header) + dptr = struct.calcsize(HDR_FILE) + len(oh) + len(self.sections) * struct.calcsize(HDR_SECTIONS) + + # Section headers + sh = [] + sd = [] + + sk = lambda x: self.data_seg_base + x.start if x.type==Section.DATA else x.start + + for s in sorted(self.sections.values(), key=sk): + # Values + if s.type == Section.DATA: + mp = 0x80 + sa = s.start + else: + mp = 0 + sa = s.start + sptr = dptr if s.data else 0 + + # Header + sh.append(struct.pack(HDR_SECTIONS, + s.name, # char[8] s_name; /* 8-character null padded section name */ + sa, # long int s_paddr; /* Physical address of section */ + sa, # long int s_vaddr; /* Virtual address of section */ + s.size, # long int s_size; /* Section size in bytes */ + sptr, # long int s_scnptr; /* File pointer to raw data */ + 0, # long int s_relptr; /* File pointer to relocation entries */ + 0, # long int s_lnnoptr;/* File pointer to line number entries */ + 0, # unsigned short s_nreloc; /* Number of relocation entrie */ + 0, # unsigned short s_nlnno; /* Number of line number entries */ + s.flags,# unsigned short s_flags; /* Flags (see ``Section header flags'') */ + '\x00', # / + chr(mp),# char s_mempage;/* Memory page number */ + )) + + # Data + if s.data: + sd.append(self._data_pack(s.data)) + dptr += s.size * 2 + + # Write the thing + f = open(filename, 'wb') + + f.write(fh) + f.write(oh) + f.write(''.join(sh)) + f.write(''.join(sd)) + + f.close() + + def add_section(self, name, type, addr, size, data=None): + self.sections[name] = Section(name, type, addr, size, data=data) + + +# ---------------------------------------------------------------------------- +# Dump loading +# ---------------------------------------------------------------------------- + +RE_DUMP_HDR = re.compile( + r"^DSP dump: (\w*) \[([0-9a-fA-F]{5})-([0-9a-fA-F]{5})\]$" +) + + +def _file_strip_gen(f): + while True: + l = f.readline() + if not l: + return + yield l.strip() + + +def dump_load_section(fg, sa, ea): + data = [] + ca = sa + for l in fg: + if not l: + break + + ra = int(l[0:5], 16) + if ra != ca: + raise ValueError('Invalid dump address %05x != %05x', ra, ca) + + v = l[8:].split() + if len(v) != 16: + raise ValueError('Invalid dump format') + + v = [int(x,16) for x in v] + data.extend(v) + + ca += 0x10 + + if ca != ea: + raise ValueError('Missing dump data %05x != %05x', ra, ea) + + return data + + +def dump_load(filename): + # Open file + f = open(filename, 'r') + fg = _file_strip_gen(f) + + # Scan line by line for a dump header line + sections = [] + + for l in fg: + m = RE_DUMP_HDR.match(l) + if not m: + continue + + name = m.group(1) + sa = int(m.group(2), 16) + ea = int(m.group(3), 16) + 1 + + sections.append(( + name, sa, ea, + dump_load_section(fg, sa, ea), + )) + + # Done + f.close() + + return sections + + +# ---------------------------------------------------------------------------- +# Main +# ---------------------------------------------------------------------------- + +def main(pname, dump_filename, out_filename): + + # Section to place in the COFF + sections = [ + # name type start size + ('.regs', Section.DATA, 0x00000, 0x0060), + ('.scratch', Section.DATA, 0x00060, 0x0020), + ('.drom', Section.DATA, 0x09000, 0x5000), + ('.pdrom', Section.CODE, 0x0e000, 0x2000), + ('.prom0', Section.CODE, 0x07000, 0x7000), + ('.prom1', Section.CODE, 0x18000, 0x8000), + ('.prom2', Section.CODE, 0x28000, 0x8000), + ('.prom3', Section.CODE, 0x38000, 0x2000), + ('.daram0', Section.DATA, 0x00080, 0x0780), + ('.api', Section.DATA, 0x00800, 0x2000), + ('.daram1', Section.DATA, 0x02800, 0x4800), + ] + + # COFF name -> dump name + dump_mapping = { + # '.regs' : 'Registers', + '.drom' : 'DROM', + '.pdrom' : 'PDROM', + '.prom0' : 'PROM0', + '.prom1' : 'PROM1', + '.prom2' : 'PROM2', + '.prom3' : 'PROM3', + } + + # Load the dump + dump_sections = dict([(s[0], s) for s in dump_load(dump_filename)]) + + # Create the COFF + coff = CalypsoCOFF() + + # Add each section (with data if we have some) + for name, type, start, size in sections: + # Dumped data ? + d_data = None + if (name in dump_mapping) and (dump_mapping[name] in dump_sections): + d_name, d_sa, d_ea, d_data = dump_sections[dump_mapping[name]] + + # Add sections + coff.add_section(name, type, start, size, d_data) + + # Save result + coff.save(out_filename) + + return 0 + + +if __name__ == '__main__': + sys.exit(main(*sys.argv)) |