forked from arti/vt1200
dwt/loader: COFF loader places GSPLNK images and runs them via create_process
This commit is contained in:
1 parent
dcca6bee4d
commit
139d89a10c
42 files changed
+3822
No files matched your search
Executable
+200
@@ -0,0 +1,200 @@
|
||||
#!/usr/bin/env python3
|
||||
"""coff.py -- TI TMS34010 GSP COFF reader for the VT1200 loader work.
|
||||
|
||||
GSPLNK 2.00 emits the "TI COFF" described in the 1987 Assembler Tools guide,
|
||||
Appendix A. All section addresses and sizes in the section headers are in
|
||||
BITS (the TMS34010 is bit-addressed); file offsets (scnptr/relptr/symptr) are
|
||||
in BYTES.
|
||||
|
||||
Commands
|
||||
coff.py summary FILE... dump header, optional header, sections,
|
||||
symbols (with aux entries) and relocations
|
||||
coff.py raw ABS1 ABS2 extract each section from two absolute
|
||||
outputs and report byte differences
|
||||
coff.py manifest FILE print shell-ish KEY=VALUE lines for one file
|
||||
|
||||
The loader itself parses the same structures in assembly; this script is the
|
||||
reference and the evidence generator.
|
||||
"""
|
||||
import struct
|
||||
import sys
|
||||
|
||||
MAGIC = 0x0090
|
||||
OPTHDR_MAGIC = 0x0108
|
||||
|
||||
RELOC_NAMES = {
|
||||
0x00: "R-ABS",
|
||||
0x10: "R-RELWORD",
|
||||
0x11: "R-RELLONG",
|
||||
0x18: "R-OCRLONG",
|
||||
0x19: "R-GSPPCR16",
|
||||
}
|
||||
|
||||
SECTION_FLAGS = {
|
||||
0x20: "text",
|
||||
0x40: "data",
|
||||
0x80: "bss",
|
||||
}
|
||||
|
||||
|
||||
class CoffError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def parse(path):
|
||||
d = open(path, "rb").read()
|
||||
if len(d) < 20:
|
||||
raise CoffError("%s: shorter than a COFF file header" % path)
|
||||
magic, nscns, timdat, symptr, nsyms, opthdr, flags = struct.unpack_from(
|
||||
"<HHIIIHH", d, 0)
|
||||
if magic != MAGIC:
|
||||
raise CoffError("%s: magic %#06x, expected %#06x"
|
||||
% (path, magic, MAGIC))
|
||||
opt = None
|
||||
if opthdr:
|
||||
if 20 + opthdr > len(d):
|
||||
raise CoffError("%s: optional header past EOF" % path)
|
||||
# TI COFF optional header: magic, vstamp, textsize, datasize, bsssize,
|
||||
# entry, textstart, datastart (all sizes/addresses in bits).
|
||||
opt = struct.unpack_from("<HHIIIIII", d, 20)
|
||||
base = 20 + opthdr
|
||||
secs = []
|
||||
for i in range(nscns):
|
||||
off = base + i * 40
|
||||
if off + 40 > len(d):
|
||||
raise CoffError("%s: section header %d past EOF" % (path, i))
|
||||
raw = d[off:off + 40]
|
||||
name = raw[:8].rstrip(b"\0").decode("latin1")
|
||||
(paddr, vaddr, size, scnptr, relptr, lnnoptr, nreloc, nlnno,
|
||||
sflags) = struct.unpack_from("<IIIIIIHHI", d, off + 8)
|
||||
relocs = []
|
||||
for r in range(nreloc):
|
||||
ro = relptr + r * 10
|
||||
if ro + 10 > len(d):
|
||||
raise CoffError("%s: relocation %d past EOF" % (path, r))
|
||||
raddr, symidx, rtype = struct.unpack_from("<IIH", d, ro)
|
||||
relocs.append((raddr, symidx, rtype))
|
||||
secs.append(dict(index=i + 1, name=name, paddr=paddr, vaddr=vaddr,
|
||||
size=size, scnptr=scnptr, relptr=relptr,
|
||||
lnnoptr=lnnoptr, nreloc=nreloc, nlnno=nlnno,
|
||||
flags=sflags, relocs=relocs, raw=raw))
|
||||
syms = []
|
||||
i = 0
|
||||
while i < nsyms:
|
||||
off = symptr + i * 18
|
||||
if off + 18 > len(d):
|
||||
raise CoffError("%s: symbol %d past EOF" % (path, i))
|
||||
e = d[off:off + 18]
|
||||
name = e[:8].rstrip(b"\0").decode("latin1", "replace")
|
||||
val, secno, stype, sclass, naux = struct.unpack_from("<IHhBB", e, 8)
|
||||
aux = d[off + 18:off + 18 + naux * 18]
|
||||
syms.append(dict(index=i, name=name, value=val, secno=secno,
|
||||
type=stype, sclass=sclass, naux=naux, aux=aux))
|
||||
i += 1 + naux
|
||||
return dict(path=path, size=len(d), magic=magic, nscns=nscns,
|
||||
timdat=timdat, symptr=symptr, nsyms=nsyms, opthdr=opthdr,
|
||||
flags=flags, opt=opt, sections=secs, symbols=syms, data=d)
|
||||
|
||||
|
||||
def summary(path):
|
||||
c = parse(path)
|
||||
print("== %s (%d bytes)" % (path, c["size"]))
|
||||
print(" file hdr: magic=%#06x nscns=%d symptr=%#x nsyms=%d "
|
||||
"opthdr=%d flags=%#06x"
|
||||
% (c["magic"], c["nscns"], c["symptr"], c["nsyms"], c["opthdr"],
|
||||
c["flags"]))
|
||||
if c["opt"]:
|
||||
magic, vstamp, tsize, dsize, bsize, entry, tstart, dstart = c["opt"]
|
||||
print(" optional: magic=%#06x vstamp=%#06x text=%#x bits "
|
||||
"data=%#x bits bss=%#x bits entry=%#010x textstart=%#010x "
|
||||
"datastart=%#010x"
|
||||
% (magic, vstamp, tsize, dsize, bsize, entry, tstart, dstart))
|
||||
print(" optional: sizes in bytes text=%d data=%d bss=%d; "
|
||||
"entry in bits=%s"
|
||||
% (tsize // 8, dsize // 8, bsize // 8,
|
||||
"0 (no -e global symbol)" if entry == 0 else hex(entry)))
|
||||
for s in c["sections"]:
|
||||
fl = ",".join(v for k, v in SECTION_FLAGS.items() if s["flags"] & k)
|
||||
print(" sec %d %-8s paddr=%010x vaddr=%010x size=%#x bits (%d B) "
|
||||
"scnptr=%#x nreloc=%d flags=%#x%s"
|
||||
% (s["index"], s["name"], s["paddr"], s["vaddr"], s["size"],
|
||||
s["size"] // 8, s["scnptr"], s["nreloc"], s["flags"],
|
||||
(" [" + fl + "]") if fl else ""))
|
||||
for raddr, symidx, rtype in s["relocs"]:
|
||||
print(" reloc at %#x sym=%d type=%#x %s"
|
||||
% (raddr, symidx, rtype,
|
||||
RELOC_NAMES.get(rtype, "?")))
|
||||
for sym in c["symbols"]:
|
||||
if sym["naux"]:
|
||||
print(" sym[%d] %-10s value=%010x sec=%d class=%d naux=%d"
|
||||
% (sym["index"], sym["name"], sym["value"], sym["secno"],
|
||||
sym["sclass"], sym["naux"]))
|
||||
else:
|
||||
print(" sym[%d] %-10s value=%010x sec=%d class=%d"
|
||||
% (sym["index"], sym["name"], sym["value"], sym["secno"],
|
||||
sym["sclass"]))
|
||||
print()
|
||||
|
||||
|
||||
def section_bytes(c, name):
|
||||
for s in c["sections"]:
|
||||
if s["name"] == name:
|
||||
return s, c["data"][s["scnptr"]:s["scnptr"] + s["size"] // 8]
|
||||
return None, None
|
||||
|
||||
|
||||
def raw(paths):
|
||||
if len(paths) != 2:
|
||||
raise SystemExit("coff.py raw: need exactly two files")
|
||||
a, b = parse(paths[0]), parse(paths[1])
|
||||
for name in (".text", ".data", ".bss"):
|
||||
sa, ba = section_bytes(a, name)
|
||||
sb, bb = section_bytes(b, name)
|
||||
if sa is None or sb is None:
|
||||
continue
|
||||
print("== %s: %d vs %d bytes" % (name, len(ba), len(bb)))
|
||||
n = min(len(ba), len(bb))
|
||||
bad = [i for i in range(n) if ba[i] != bb[i]]
|
||||
print(" differing bytes: %d" % (len(bad) + abs(len(ba) - len(bb))))
|
||||
for i in bad[:24]:
|
||||
print(" %#06x: %02x -> %02x" % (i, ba[i], bb[i]))
|
||||
print()
|
||||
|
||||
|
||||
def manifest(path):
|
||||
c = parse(path)
|
||||
print("COFF=%s" % path)
|
||||
print("SIZE=%d" % c["size"])
|
||||
print("NSECTIONS=%d" % c["nscns"])
|
||||
if c["opt"]:
|
||||
_, _, tsize, dsize, bsize, entry, tstart, dstart = c["opt"]
|
||||
print("ENTRY=%#010x" % entry)
|
||||
print("TEXTSTART=%#010x" % tstart)
|
||||
print("DATASTART=%#010x" % dstart)
|
||||
print("TEXTSIZE_BITS=%d" % tsize)
|
||||
print("DATASIZE_BITS=%d" % dsize)
|
||||
print("BSSSIZE_BITS=%d" % bsize)
|
||||
for s in c["sections"]:
|
||||
key = s["name"].lstrip(".").upper() or ("SEC%d" % s["index"])
|
||||
print("%s_PADDR=%#010x" % (key, s["paddr"]))
|
||||
print("%s_SIZE_BITS=%d" % (key, s["size"]))
|
||||
print("%s_NRELOC=%d" % (key, s["nreloc"]))
|
||||
|
||||
|
||||
def main(argv):
|
||||
if len(argv) < 3:
|
||||
raise SystemExit(__doc__)
|
||||
cmd = argv[1]
|
||||
if cmd == "summary":
|
||||
for p in argv[2:]:
|
||||
summary(p)
|
||||
elif cmd == "raw":
|
||||
raw(argv[2:])
|
||||
elif cmd == "manifest":
|
||||
manifest(argv[2])
|
||||
else:
|
||||
raise SystemExit(__doc__)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main(sys.argv)
|
||||
Reference in new issue
Block a user