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