xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/testsuite/gdb.arch/s390-multiarch.c (revision 8b657b0747480f8989760d71343d6dd33f8d4cf9)
1 /* Copyright 2013-2023 Free Software Foundation, Inc.
2 
3    This file is part of GDB.
4 
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 3 of the License, or
8    (at your option) any later version.
9 
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14 
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17 
18 #include <errno.h>
19 #include <stdarg.h>
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 
24 typedef struct
25 {
26   unsigned char	e_ident[16];
27   uint16_t	e_type;
28   uint16_t	e_machine;
29   uint32_t	e_version;
30   uint32_t	e_entry;
31   uint32_t	e_phoff;
32   uint32_t	e_shoff;
33   uint32_t	e_flags;
34   uint16_t	e_ehsize;
35   uint16_t	e_phentsize;
36   uint16_t	e_phnum;
37   uint16_t	e_shentsize;
38   uint16_t	e_shnum;
39   uint16_t	e_shstrndx;
40 } Elf32_Ehdr;
41 
42 typedef struct
43 {
44   unsigned char	e_ident[16];
45   uint16_t	e_type;
46   uint16_t	e_machine;
47   uint32_t	e_version;
48   uint64_t	e_entry;
49   uint64_t	e_phoff;
50   uint64_t	e_shoff;
51   uint32_t	e_flags;
52   uint16_t	e_ehsize;
53   uint16_t	e_phentsize;
54   uint16_t	e_phnum;
55   uint16_t	e_shentsize;
56   uint16_t	e_shnum;
57   uint16_t	e_shstrndx;
58 } Elf64_Ehdr;
59 
60 typedef struct
61 {
62   uint32_t	p_type;
63   uint32_t	p_offset;
64   uint32_t	p_vaddr;
65   uint32_t	p_paddr;
66   uint32_t	p_filesz;
67   uint32_t	p_memsz;
68   uint32_t	p_flags;
69   uint32_t	p_align;
70 } Elf32_Phdr;
71 
72 typedef struct
73 {
74   uint32_t	p_type;
75   uint32_t	p_flags;
76   uint64_t	p_offset;
77   uint64_t	p_vaddr;
78   uint64_t	p_paddr;
79   uint64_t	p_filesz;
80   uint64_t	p_memsz;
81   uint64_t	p_align;
82 } Elf64_Phdr;
83 
84 struct elfbuf
85 {
86   const char *path;
87   unsigned char *buf;
88   size_t len;
89   enum { ELFCLASS32 = 1,
90 	 ELFCLASS64 = 2 } ei_class;
91 };
92 
93 #define ELFBUF_EHDR_LEN(elf)					\
94   ((elf)->ei_class == ELFCLASS32 ? sizeof (Elf32_Ehdr) :	\
95    sizeof (Elf64_Ehdr))
96 
97 #define ELFBUF_EHDR(elf, memb)			\
98   ((elf)->ei_class == ELFCLASS32 ?		\
99    ((Elf32_Ehdr *) (elf)->buf)->memb		\
100    : ((Elf64_Ehdr *) (elf)->buf)->memb)
101 
102 #define ELFBUF_PHDR_LEN(elf)					\
103   ((elf)->ei_class == ELFCLASS32 ? sizeof (Elf32_Phdr) :	\
104    sizeof (Elf64_Phdr))
105 
106 #define ELFBUF_PHDR(elf, idx, memb)				\
107   ((elf)->ei_class == ELFCLASS32 ?				\
108    ((Elf32_Phdr *) &(elf)->buf[((Elf32_Ehdr *)(elf)->buf)	\
109 			       ->e_phoff])[idx].memb		\
110    : ((Elf64_Phdr *) &(elf)->buf[((Elf64_Ehdr *)(elf)->buf)	\
111 				 ->e_phoff])[idx].memb)
112 
113 static void
114 exit_with_msg(const char *fmt, ...)
115 {
116   va_list ap;
117 
118   fflush (stdout);
119   va_start (ap, fmt);
120   vfprintf (stderr, fmt, ap);
121   va_end (ap);
122 
123   if (errno)
124     {
125       fputs (": ", stderr);
126       perror (NULL);
127     }
128   else
129     fputc ('\n', stderr);
130   exit (1);
131 }
132 
133 static void
134 read_file (unsigned char **buf_ptr, size_t *len_ptr, FILE *fp)
135 {
136   size_t len = 0;
137   size_t size = 1024;
138   size_t chunk;
139   unsigned char *buf = malloc (size);
140 
141   while ((chunk = fread (buf + len, 1, size - len, fp)) == size - len)
142     {
143       len = size;
144       size *= 2;
145       buf = realloc (buf, size);
146     }
147   len += chunk;
148   *buf_ptr = buf;
149   *len_ptr = len;
150 }
151 
152 static void
153 write_file (unsigned char *buf, size_t len, FILE *fp)
154 {
155   fwrite (buf, 1, len, fp);
156 }
157 
158 static void
159 elfbuf_init_from_file (struct elfbuf *elf, const char *path)
160 {
161   FILE *fp = fopen (path, "rb");
162   unsigned char *buf;
163   size_t len;
164 
165   if (fp == NULL)
166     exit_with_msg ("%s", path);
167 
168   read_file (&buf, &len, fp);
169   fclose (fp);
170 
171   /* Validate ELF identification. */
172   if (len < 16
173       || buf[0] != 0x7f || buf[1] != 0x45 || buf[2] != 0x4c || buf[3] != 0x46
174       || buf[4] < 1 || buf[4] > 2 || buf[5] < 1 || buf[5] > 2)
175     exit_with_msg ("%s: unsupported or invalid ELF file", path);
176 
177   elf->path = path;
178   elf->buf = buf;
179   elf->len = len;
180   elf->ei_class = buf[4];
181 
182   if (ELFBUF_EHDR_LEN (elf) > len
183       || ELFBUF_EHDR (elf, e_phoff) > len
184       || ELFBUF_EHDR (elf, e_phnum) > ((len - ELFBUF_EHDR (elf, e_phoff))
185 				       / ELFBUF_PHDR_LEN (elf)) )
186     exit_with_msg ("%s: unexpected end of data", path);
187 
188   if (ELFBUF_EHDR (elf, e_phentsize) != ELFBUF_PHDR_LEN (elf))
189     exit_with_msg ("%s: inconsistent ELF header", path);
190 }
191 
192 static void
193 elfbuf_write_to_file (struct elfbuf *elf, const char *path)
194 {
195   FILE *fp = fopen (path, "wb");
196 
197   if (fp == NULL)
198     exit_with_msg ("%s", path);
199 
200   write_file (elf->buf, elf->len, fp);
201   fclose (fp);
202 }
203 
204 /* In the auxv note starting at OFFSET with size LEN, mask the hwcap
205    field using the HWCAP_MASK. */
206 
207 static void
208 elfbuf_handle_auxv (struct elfbuf *elf, size_t offset, size_t len,
209 		    unsigned long hwcap_mask)
210 {
211   size_t i;
212   uint32_t *auxv32 = (uint32_t *) (elf->buf + offset);
213   uint64_t *auxv64 = (uint64_t *) auxv32;
214   size_t entry_size = elf->ei_class == ELFCLASS32 ?
215     sizeof (auxv32[0]) : sizeof (auxv64[0]);
216 
217   for (i = 0; i < len / entry_size; i++)
218     {
219       uint64_t auxv_type = elf->ei_class == ELFCLASS32 ?
220 	auxv32[2 * i] : auxv64[2 * i];
221 
222       if (auxv_type == 0)
223 	break;
224       if (auxv_type != 16)
225 	continue;
226 
227       if (elf->ei_class == ELFCLASS32)
228 	auxv32[2 * i + 1] &= (uint32_t) hwcap_mask;
229       else
230 	auxv64[2 * i + 1] &= (uint64_t) hwcap_mask;
231     }
232 }
233 
234 /* In the note segment starting at OFFSET with size LEN, make notes
235    with type NOTE_TYPE unrecognizable by GDB.  Also, mask the hwcap
236    field of any auxv notes using the HWCAP_MASK. */
237 
238 static void
239 elfbuf_handle_note_segment (struct elfbuf *elf, size_t offset, size_t len,
240 			    unsigned note_type, unsigned long hwcap_mask)
241 {
242   size_t pos = 0;
243 
244   while (pos + 12 < len)
245     {
246       uint32_t *note = (uint32_t *) (elf->buf + offset + pos);
247       size_t desc_pos = pos + 12 + ((note[0] + 3) & ~3);
248       size_t next_pos = desc_pos + ((note[1] + 3) & ~3);
249 
250       if (desc_pos > len || next_pos > len)
251 	exit_with_msg ("%s: corrupt notes data", elf->path);
252 
253       if (note[2] == note_type)
254 	note[2] |= 0xff000000;
255       else if (note[2] == 6 && hwcap_mask != 0)
256 	elfbuf_handle_auxv (elf, offset + desc_pos, note[1],
257 			    hwcap_mask);
258       pos = next_pos;
259     }
260 }
261 
262 static void
263 elfbuf_handle_core_notes (struct elfbuf *elf, unsigned note_type,
264 			  unsigned long hwcap_mask)
265 {
266   unsigned ph_idx;
267 
268   if (ELFBUF_EHDR (elf, e_type) != 4)
269     exit_with_msg ("%s: not a core file", elf->path);
270 
271   /* Iterate over program headers. */
272   for (ph_idx = 0; ph_idx != ELFBUF_EHDR (elf, e_phnum); ph_idx++)
273     {
274       size_t offset = ELFBUF_PHDR (elf, ph_idx, p_offset);
275       size_t filesz = ELFBUF_PHDR (elf, ph_idx, p_filesz);
276 
277       if (offset > elf->len || filesz > elf->len - offset)
278 	exit_with_msg ("%s: unexpected end of data", elf->path);
279 
280       /* Deal with NOTE segments only. */
281       if (ELFBUF_PHDR (elf, ph_idx, p_type) != 4)
282 	continue;
283       elfbuf_handle_note_segment (elf, offset, filesz, note_type,
284 				  hwcap_mask);
285     }
286 }
287 
288 int
289 main (int argc, char *argv[])
290 {
291   unsigned note_type;
292   unsigned long hwcap_mask = 0;
293   struct elfbuf elf;
294 
295   if (argc < 4)
296     {
297       abort ();
298     }
299 
300   if (sscanf (argv[3], "%u", &note_type) != 1)
301     exit_with_msg ("%s: bad command line arguments\n", argv[0]);
302 
303   if (argc >= 5)
304     {
305       if (sscanf (argv[4], "%lu", &hwcap_mask) != 1)
306 	exit_with_msg ("%s: bad command line arguments\n", argv[0]);
307     }
308 
309   elfbuf_init_from_file (&elf, argv[1]);
310   elfbuf_handle_core_notes (&elf, note_type, hwcap_mask);
311   elfbuf_write_to_file (&elf, argv[2]);
312 
313   return 0;
314 }
315