xref: /dpdk/buildtools/coff.py (revision 5031436f459e197da1fec087564026ec29d94227)
1*5031436fSDmitry Kozlyuk# SPDX-License-Identifier: BSD-3-Clause
2*5031436fSDmitry Kozlyuk# Copyright (c) 2020 Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>
3*5031436fSDmitry Kozlyuk
4*5031436fSDmitry Kozlyukimport ctypes
5*5031436fSDmitry Kozlyuk
6*5031436fSDmitry Kozlyuk# x86_64 little-endian
7*5031436fSDmitry KozlyukCOFF_MAGIC = 0x8664
8*5031436fSDmitry Kozlyuk
9*5031436fSDmitry Kozlyuk# Names up to this length are stored immediately in symbol table entries.
10*5031436fSDmitry KozlyukCOFF_NAMELEN = 8
11*5031436fSDmitry Kozlyuk
12*5031436fSDmitry Kozlyuk# Special "section numbers" changing the meaning of symbol table entry.
13*5031436fSDmitry KozlyukCOFF_SN_UNDEFINED = 0
14*5031436fSDmitry KozlyukCOFF_SN_ABSOLUTE = -1
15*5031436fSDmitry KozlyukCOFF_SN_DEBUG = -2
16*5031436fSDmitry Kozlyuk
17*5031436fSDmitry Kozlyuk
18*5031436fSDmitry Kozlyukclass CoffFileHeader(ctypes.LittleEndianStructure):
19*5031436fSDmitry Kozlyuk    _pack_ = True
20*5031436fSDmitry Kozlyuk    _fields_ = [
21*5031436fSDmitry Kozlyuk        ("magic", ctypes.c_uint16),
22*5031436fSDmitry Kozlyuk        ("section_count", ctypes.c_uint16),
23*5031436fSDmitry Kozlyuk        ("timestamp", ctypes.c_uint32),
24*5031436fSDmitry Kozlyuk        ("symbol_table_offset", ctypes.c_uint32),
25*5031436fSDmitry Kozlyuk        ("symbol_count", ctypes.c_uint32),
26*5031436fSDmitry Kozlyuk        ("optional_header_size", ctypes.c_uint16),
27*5031436fSDmitry Kozlyuk        ("flags", ctypes.c_uint16),
28*5031436fSDmitry Kozlyuk    ]
29*5031436fSDmitry Kozlyuk
30*5031436fSDmitry Kozlyuk
31*5031436fSDmitry Kozlyukclass CoffName(ctypes.Union):
32*5031436fSDmitry Kozlyuk    class Reference(ctypes.LittleEndianStructure):
33*5031436fSDmitry Kozlyuk        _pack_ = True
34*5031436fSDmitry Kozlyuk        _fields_ = [
35*5031436fSDmitry Kozlyuk            ("zeroes", ctypes.c_uint32),
36*5031436fSDmitry Kozlyuk            ("offset", ctypes.c_uint32),
37*5031436fSDmitry Kozlyuk        ]
38*5031436fSDmitry Kozlyuk
39*5031436fSDmitry Kozlyuk    Immediate = ctypes.c_char * 8
40*5031436fSDmitry Kozlyuk
41*5031436fSDmitry Kozlyuk    _pack_ = True
42*5031436fSDmitry Kozlyuk    _fields_ = [
43*5031436fSDmitry Kozlyuk        ("immediate", Immediate),
44*5031436fSDmitry Kozlyuk        ("reference", Reference),
45*5031436fSDmitry Kozlyuk    ]
46*5031436fSDmitry Kozlyuk
47*5031436fSDmitry Kozlyuk
48*5031436fSDmitry Kozlyukclass CoffSection(ctypes.LittleEndianStructure):
49*5031436fSDmitry Kozlyuk    _pack_ = True
50*5031436fSDmitry Kozlyuk    _fields_ = [
51*5031436fSDmitry Kozlyuk        ("name", CoffName),
52*5031436fSDmitry Kozlyuk        ("physical_address", ctypes.c_uint32),
53*5031436fSDmitry Kozlyuk        ("physical_address", ctypes.c_uint32),
54*5031436fSDmitry Kozlyuk        ("size", ctypes.c_uint32),
55*5031436fSDmitry Kozlyuk        ("data_offset", ctypes.c_uint32),
56*5031436fSDmitry Kozlyuk        ("relocations_offset", ctypes.c_uint32),
57*5031436fSDmitry Kozlyuk        ("line_numbers_offset", ctypes.c_uint32),
58*5031436fSDmitry Kozlyuk        ("relocation_count", ctypes.c_uint16),
59*5031436fSDmitry Kozlyuk        ("line_number_count", ctypes.c_uint16),
60*5031436fSDmitry Kozlyuk        ("flags", ctypes.c_uint32),
61*5031436fSDmitry Kozlyuk    ]
62*5031436fSDmitry Kozlyuk
63*5031436fSDmitry Kozlyuk
64*5031436fSDmitry Kozlyukclass CoffSymbol(ctypes.LittleEndianStructure):
65*5031436fSDmitry Kozlyuk    _pack_ = True
66*5031436fSDmitry Kozlyuk    _fields_ = [
67*5031436fSDmitry Kozlyuk        ("name", CoffName),
68*5031436fSDmitry Kozlyuk        ("value", ctypes.c_uint32),
69*5031436fSDmitry Kozlyuk        ("section_number", ctypes.c_int16),
70*5031436fSDmitry Kozlyuk        ("type", ctypes.c_uint16),
71*5031436fSDmitry Kozlyuk        ("storage_class", ctypes.c_uint8),
72*5031436fSDmitry Kozlyuk        ("auxiliary_count", ctypes.c_uint8),
73*5031436fSDmitry Kozlyuk    ]
74*5031436fSDmitry Kozlyuk
75*5031436fSDmitry Kozlyuk
76*5031436fSDmitry Kozlyukclass Symbol:
77*5031436fSDmitry Kozlyuk    def __init__(self, image, symbol: CoffSymbol):
78*5031436fSDmitry Kozlyuk        self._image = image
79*5031436fSDmitry Kozlyuk        self._coff = symbol
80*5031436fSDmitry Kozlyuk
81*5031436fSDmitry Kozlyuk    @property
82*5031436fSDmitry Kozlyuk    def name(self):
83*5031436fSDmitry Kozlyuk        if self._coff.name.reference.zeroes:
84*5031436fSDmitry Kozlyuk            return decode_asciiz(bytes(self._coff.name.immediate))
85*5031436fSDmitry Kozlyuk
86*5031436fSDmitry Kozlyuk        offset = self._coff.name.reference.offset
87*5031436fSDmitry Kozlyuk        offset -= ctypes.sizeof(ctypes.c_uint32)
88*5031436fSDmitry Kozlyuk        return self._image.get_string(offset)
89*5031436fSDmitry Kozlyuk
90*5031436fSDmitry Kozlyuk    def get_value(self, offset):
91*5031436fSDmitry Kozlyuk        section_number = self._coff.section_number
92*5031436fSDmitry Kozlyuk
93*5031436fSDmitry Kozlyuk        if section_number == COFF_SN_UNDEFINED:
94*5031436fSDmitry Kozlyuk            return None
95*5031436fSDmitry Kozlyuk
96*5031436fSDmitry Kozlyuk        if section_number == COFF_SN_DEBUG:
97*5031436fSDmitry Kozlyuk            return None
98*5031436fSDmitry Kozlyuk
99*5031436fSDmitry Kozlyuk        if section_number == COFF_SN_ABSOLUTE:
100*5031436fSDmitry Kozlyuk            return bytes(ctypes.c_uint32(self._coff.value))
101*5031436fSDmitry Kozlyuk
102*5031436fSDmitry Kozlyuk        section_data = self._image.get_section_data(section_number)
103*5031436fSDmitry Kozlyuk        section_offset = self._coff.value + offset
104*5031436fSDmitry Kozlyuk        return section_data[section_offset:]
105*5031436fSDmitry Kozlyuk
106*5031436fSDmitry Kozlyuk
107*5031436fSDmitry Kozlyukclass Image:
108*5031436fSDmitry Kozlyuk    def __init__(self, data):
109*5031436fSDmitry Kozlyuk        header = CoffFileHeader.from_buffer_copy(data)
110*5031436fSDmitry Kozlyuk        header_size = ctypes.sizeof(header) + header.optional_header_size
111*5031436fSDmitry Kozlyuk
112*5031436fSDmitry Kozlyuk        sections_desc = CoffSection * header.section_count
113*5031436fSDmitry Kozlyuk        sections = sections_desc.from_buffer_copy(data, header_size)
114*5031436fSDmitry Kozlyuk
115*5031436fSDmitry Kozlyuk        symbols_desc = CoffSymbol * header.symbol_count
116*5031436fSDmitry Kozlyuk        symbols = symbols_desc.from_buffer_copy(data, header.symbol_table_offset)
117*5031436fSDmitry Kozlyuk
118*5031436fSDmitry Kozlyuk        strings_offset = header.symbol_table_offset + ctypes.sizeof(symbols)
119*5031436fSDmitry Kozlyuk        strings = Image._parse_strings(data[strings_offset:])
120*5031436fSDmitry Kozlyuk
121*5031436fSDmitry Kozlyuk        self._data = data
122*5031436fSDmitry Kozlyuk        self._header = header
123*5031436fSDmitry Kozlyuk        self._sections = sections
124*5031436fSDmitry Kozlyuk        self._symbols = symbols
125*5031436fSDmitry Kozlyuk        self._strings = strings
126*5031436fSDmitry Kozlyuk
127*5031436fSDmitry Kozlyuk    @staticmethod
128*5031436fSDmitry Kozlyuk    def _parse_strings(data):
129*5031436fSDmitry Kozlyuk        full_size = ctypes.c_uint32.from_buffer_copy(data)
130*5031436fSDmitry Kozlyuk        header_size = ctypes.sizeof(full_size)
131*5031436fSDmitry Kozlyuk        return data[header_size : full_size.value]
132*5031436fSDmitry Kozlyuk
133*5031436fSDmitry Kozlyuk    @property
134*5031436fSDmitry Kozlyuk    def symbols(self):
135*5031436fSDmitry Kozlyuk        i = 0
136*5031436fSDmitry Kozlyuk        while i < self._header.symbol_count:
137*5031436fSDmitry Kozlyuk            symbol = self._symbols[i]
138*5031436fSDmitry Kozlyuk            yield Symbol(self, symbol)
139*5031436fSDmitry Kozlyuk            i += symbol.auxiliary_count + 1
140*5031436fSDmitry Kozlyuk
141*5031436fSDmitry Kozlyuk    def get_section_data(self, number):
142*5031436fSDmitry Kozlyuk        # section numbers are 1-based
143*5031436fSDmitry Kozlyuk        section = self._sections[number - 1]
144*5031436fSDmitry Kozlyuk        base = section.data_offset
145*5031436fSDmitry Kozlyuk        return self._data[base : base + section.size]
146*5031436fSDmitry Kozlyuk
147*5031436fSDmitry Kozlyuk    def get_string(self, offset):
148*5031436fSDmitry Kozlyuk        return decode_asciiz(self._strings[offset:])
149*5031436fSDmitry Kozlyuk
150*5031436fSDmitry Kozlyuk
151*5031436fSDmitry Kozlyukdef decode_asciiz(data):
152*5031436fSDmitry Kozlyuk    index = data.find(b'\x00')
153*5031436fSDmitry Kozlyuk    end = index if index >= 0 else len(data)
154*5031436fSDmitry Kozlyuk    return data[:end].decode()
155