localedef: Update LC_MONETARY handling (Bug 28845)
[glibc.git] / scripts / tst-elf-edit.py
bloba514179bbfbdf420817aee2577525b5fc970ce23
1 #!/usr/bin/python3
2 # ELF editor for load align tests.
3 # Copyright (C) 2022 Free Software Foundation, Inc.
4 # Copyright The GNU Toolchain Authors.
5 # This file is part of the GNU C Library.
7 # The GNU C Library is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU Lesser General Public
9 # License as published by the Free Software Foundation; either
10 # version 2.1 of the License, or (at your option) any later version.
12 # The GNU C Library is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 # Lesser General Public License for more details.
17 # You should have received a copy of the GNU Lesser General Public
18 # License along with the GNU C Library; if not, see
19 # <https://www.gnu.org/licenses/>.
21 import argparse
22 import os
23 import sys
24 import struct
26 EI_NIDENT=16
28 EI_MAG0=0
29 ELFMAG0=b'\x7f'
30 EI_MAG1=1
31 ELFMAG1=b'E'
32 EI_MAG2=2
33 ELFMAG2=b'L'
34 EI_MAG3=3
35 ELFMAG3=b'F'
37 EI_CLASS=4
38 ELFCLASSNONE=b'0'
39 ELFCLASS32=b'\x01'
40 ELFCLASS64=b'\x02'
42 EI_DATA=5
43 ELFDATA2LSB=b'\x01'
44 ELFDATA2MSB=b'\x02'
46 ET_DYN=3
48 PT_LOAD=1
50 def elf_types_fmts(e_ident):
51 endian = '<' if e_ident[EI_DATA] == ELFDATA2LSB else '>'
52 addr = 'I' if e_ident[EI_CLASS] == ELFCLASS32 else 'Q'
53 off = 'I' if e_ident[EI_CLASS] == ELFCLASS32 else 'Q'
54 return (endian, addr, off)
56 class Elf_Ehdr:
57 def __init__(self, e_ident):
58 endian, addr, off = elf_types_fmts(e_ident)
59 self.fmt = '{0}HHI{1}{2}{2}IHHHHHH'.format(endian, addr, off)
60 self.len = struct.calcsize(self.fmt)
62 def read(self, f):
63 buf = f.read(self.len)
64 if not buf:
65 error('{}: header too small'.format(f.name))
66 data = struct.unpack(self.fmt, buf)
67 self.e_type = data[0]
68 self.e_machine = data[1]
69 self.e_version = data[2]
70 self.e_entry = data[3]
71 self.e_phoff = data[4]
72 self.e_shoff = data[5]
73 self.e_flags = data[6]
74 self.e_ehsize = data[7]
75 self.e_phentsize= data[8]
76 self.e_phnum = data[9]
77 self.e_shstrndx = data[10]
80 class Elf_Phdr:
81 def __init__(self, e_ident):
82 endian, addr, off = elf_types_fmts(e_ident)
83 self.ei_class = e_ident[EI_CLASS]
84 if self.ei_class == ELFCLASS32:
85 self.fmt = '{0}I{2}{1}{1}IIII'.format(endian, addr, off)
86 else:
87 self.fmt = '{0}II{2}{1}{1}QQQ'.format(endian, addr, off)
88 self.len = struct.calcsize(self.fmt)
90 def read(self, f):
91 buf = f.read(self.len)
92 if len(buf) < self.len:
93 error('{}: program header too small'.format(f.name))
94 data = struct.unpack(self.fmt, buf)
95 if self.ei_class == ELFCLASS32:
96 self.p_type = data[0]
97 self.p_offset = data[1]
98 self.p_vaddr = data[2]
99 self.p_paddr = data[3]
100 self.p_filesz = data[4]
101 self.p_memsz = data[5]
102 self.p_flags = data[6]
103 self.p_align = data[7]
104 else:
105 self.p_type = data[0]
106 self.p_flags = data[1]
107 self.p_offset = data[2]
108 self.p_vaddr = data[3]
109 self.p_paddr = data[4]
110 self.p_filesz = data[5]
111 self.p_memsz = data[6]
112 self.p_align = data[7]
114 def write(self, f):
115 if self.ei_class == ELFCLASS32:
116 data = struct.pack(self.fmt,
117 self.p_type,
118 self.p_offset,
119 self.p_vaddr,
120 self.p_paddr,
121 self.p_filesz,
122 self.p_memsz,
123 self.p_flags,
124 self.p_align)
125 else:
126 data = struct.pack(self.fmt,
127 self.p_type,
128 self.p_flags,
129 self.p_offset,
130 self.p_vaddr,
131 self.p_paddr,
132 self.p_filesz,
133 self.p_memsz,
134 self.p_align)
135 f.write(data)
138 def error(msg):
139 print(msg, file=sys.stderr)
140 sys.exit(1)
143 def elf_edit_align(phdr, align):
144 if align == 'half':
145 phdr.p_align = phdr.p_align >> 1
146 else:
147 phdr.p_align = int(align)
150 def elf_edit(f, align):
151 ei_nident_fmt = 'c' * EI_NIDENT
152 ei_nident_len = struct.calcsize(ei_nident_fmt)
154 data = f.read(ei_nident_len)
155 if len(data) < ei_nident_len:
156 error('{}: e_nident too small'.format(f.name))
157 e_ident = struct.unpack(ei_nident_fmt, data)
159 if e_ident[EI_MAG0] != ELFMAG0 \
160 or e_ident[EI_MAG1] != ELFMAG1 \
161 or e_ident[EI_MAG2] != ELFMAG2 \
162 or e_ident[EI_MAG3] != ELFMAG3:
163 error('{}: bad ELF header'.format(f.name))
165 if e_ident[EI_CLASS] != ELFCLASS32 \
166 and e_ident[EI_CLASS] != ELFCLASS64:
167 error('{}: unsupported ELF class: {}'.format(f.name, e_ident[EI_CLASS]))
169 if e_ident[EI_DATA] != ELFDATA2LSB \
170 and e_ident[EI_DATA] != ELFDATA2MSB: \
171 error('{}: unsupported ELF data: {}'.format(f.name, e_ident[EI_DATA]))
173 ehdr = Elf_Ehdr(e_ident)
174 ehdr.read(f)
175 if ehdr.e_type != ET_DYN:
176 error('{}: not a shared library'.format(f.name))
178 phdr = Elf_Phdr(e_ident)
179 for i in range(0, ehdr.e_phnum):
180 f.seek(ehdr.e_phoff + i * phdr.len)
181 phdr.read(f)
182 if phdr.p_type == PT_LOAD:
183 elf_edit_align(phdr, align)
184 f.seek(ehdr.e_phoff + i * phdr.len)
185 phdr.write(f)
186 break
189 def get_parser():
190 parser = argparse.ArgumentParser(description=__doc__)
191 parser.add_argument('-a', dest='align', required=True,
192 help='How to set the LOAD alignment')
193 parser.add_argument('output',
194 help='ELF file to edit')
195 return parser
198 def main(argv):
199 parser = get_parser()
200 opts = parser.parse_args(argv)
201 with open(opts.output, 'r+b') as fout:
202 elf_edit(fout, opts.align)
205 if __name__ == '__main__':
206 main(sys.argv[1:])