83eb767c0b731aa49739c3b0822b471b5cde472d
[deliverable/binutils-gdb.git] / gdb / osabi.c
1 /* OS ABI variant handling for GDB.
2 Copyright 2001, 2002 Free Software Foundation, Inc.
3
4 This file is part of GDB.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21 #include "defs.h"
22 #include "osabi.h"
23
24 #include "elf-bfd.h"
25
26
27 /* This table matches the indices assigned to enum gdb_osabi. Keep
28 them in sync. */
29 static const char * const gdb_osabi_names[] =
30 {
31 "<unknown>",
32
33 "SVR4",
34 "GNU/Hurd",
35 "Solaris",
36 "OSF/1",
37 "GNU/Linux",
38 "FreeBSD a.out",
39 "FreeBSD ELF",
40 "NetBSD a.out",
41 "NetBSD ELF",
42 "Windows CE",
43 "DJGPP",
44 "NetWare",
45 "Irix",
46 "LynxOS",
47
48 "ARM EABI v1",
49 "ARM EABI v2",
50 "ARM APCS",
51
52 "<invalid>"
53 };
54
55 const char *
56 gdbarch_osabi_name (enum gdb_osabi osabi)
57 {
58 if (osabi >= GDB_OSABI_UNKNOWN && osabi < GDB_OSABI_INVALID)
59 return gdb_osabi_names[osabi];
60
61 return gdb_osabi_names[GDB_OSABI_INVALID];
62 }
63
64 /* Handler for a given architecture/OS ABI pair. There should be only
65 one handler for a given OS ABI each architecture family. */
66 struct gdb_osabi_handler
67 {
68 struct gdb_osabi_handler *next;
69 enum bfd_architecture arch;
70 enum gdb_osabi osabi;
71 void (*init_osabi)(struct gdbarch_info, struct gdbarch *);
72 };
73
74 static struct gdb_osabi_handler *gdb_osabi_handler_list;
75
76 void
77 gdbarch_register_osabi (enum bfd_architecture arch, enum gdb_osabi osabi,
78 void (*init_osabi)(struct gdbarch_info,
79 struct gdbarch *))
80 {
81 struct gdb_osabi_handler **handler_p;
82
83 /* Registering an OS ABI handler for "unknown" is not allowed. */
84 if (osabi == GDB_OSABI_UNKNOWN)
85 {
86 internal_error
87 (__FILE__, __LINE__,
88 "gdbarch_register_osabi: An attempt to register a handler for "
89 "OS ABI \"%s\" for architecture %s was made. The handler will "
90 "not be registered",
91 gdbarch_osabi_name (osabi),
92 bfd_printable_arch_mach (arch, 0));
93 return;
94 }
95
96 for (handler_p = &gdb_osabi_handler_list; *handler_p != NULL;
97 handler_p = &(*handler_p)->next)
98 {
99 if ((*handler_p)->arch == arch
100 && (*handler_p)->osabi == osabi)
101 {
102 internal_error
103 (__FILE__, __LINE__,
104 "gdbarch_register_osabi: A handler for OS ABI \"%s\" "
105 "has already been registered for architecture %s",
106 gdbarch_osabi_name (osabi),
107 bfd_printable_arch_mach (arch, 0));
108 /* If user wants to continue, override previous definition. */
109 (*handler_p)->init_osabi = init_osabi;
110 return;
111 }
112 }
113
114 (*handler_p)
115 = (struct gdb_osabi_handler *) xmalloc (sizeof (struct gdb_osabi_handler));
116 (*handler_p)->next = NULL;
117 (*handler_p)->arch = arch;
118 (*handler_p)->osabi = osabi;
119 (*handler_p)->init_osabi = init_osabi;
120 }
121 \f
122
123 /* Sniffer to find the OS ABI for a given file's architecture and flavour.
124 It is legal to have multiple sniffers for each arch/flavour pair, to
125 disambiguate one OS's a.out from another, for example. The first sniffer
126 to return something other than GDB_OSABI_UNKNOWN wins, so a sniffer should
127 be careful to claim a file only if it knows for sure what it is. */
128 struct gdb_osabi_sniffer
129 {
130 struct gdb_osabi_sniffer *next;
131 enum bfd_architecture arch; /* bfd_arch_unknown == wildcard */
132 enum bfd_flavour flavour;
133 enum gdb_osabi (*sniffer)(bfd *);
134 };
135
136 static struct gdb_osabi_sniffer *gdb_osabi_sniffer_list;
137
138 void
139 gdbarch_register_osabi_sniffer (enum bfd_architecture arch,
140 enum bfd_flavour flavour,
141 enum gdb_osabi (*sniffer_fn)(bfd *))
142 {
143 struct gdb_osabi_sniffer *sniffer;
144
145 sniffer =
146 (struct gdb_osabi_sniffer *) xmalloc (sizeof (struct gdb_osabi_sniffer));
147 sniffer->arch = arch;
148 sniffer->flavour = flavour;
149 sniffer->sniffer = sniffer_fn;
150
151 sniffer->next = gdb_osabi_sniffer_list;
152 gdb_osabi_sniffer_list = sniffer;
153 }
154 \f
155
156 enum gdb_osabi
157 gdbarch_lookup_osabi (bfd *abfd)
158 {
159 struct gdb_osabi_sniffer *sniffer;
160 enum gdb_osabi osabi, match;
161 int match_specific;
162
163 match = GDB_OSABI_UNKNOWN;
164 match_specific = 0;
165
166 for (sniffer = gdb_osabi_sniffer_list; sniffer != NULL;
167 sniffer = sniffer->next)
168 {
169 if ((sniffer->arch == bfd_arch_unknown /* wildcard */
170 || sniffer->arch == bfd_get_arch (abfd))
171 && sniffer->flavour == bfd_get_flavour (abfd))
172 {
173 osabi = (*sniffer->sniffer) (abfd);
174 if (osabi < GDB_OSABI_UNKNOWN || osabi >= GDB_OSABI_INVALID)
175 {
176 internal_error
177 (__FILE__, __LINE__,
178 "gdbarch_lookup_osabi: invalid OS ABI (%d) from sniffer "
179 "for architecture %s flavour %d",
180 (int) osabi,
181 bfd_printable_arch_mach (bfd_get_arch (abfd), 0),
182 (int) bfd_get_flavour (abfd));
183 }
184 else if (osabi != GDB_OSABI_UNKNOWN)
185 {
186 /* A specific sniffer always overrides a generic sniffer.
187 Croak on multiple match if the two matches are of the
188 same class. If the user wishes to continue, we'll use
189 the first match. */
190 if (match != GDB_OSABI_UNKNOWN)
191 {
192 if ((match_specific && sniffer->arch != bfd_arch_unknown)
193 || (!match_specific && sniffer->arch == bfd_arch_unknown))
194 {
195 internal_error
196 (__FILE__, __LINE__,
197 "gdbarch_lookup_osabi: multiple %sspecific OS ABI "
198 "match for architecture %s flavour %d: first "
199 "match \"%s\", second match \"%s\"",
200 match_specific ? "" : "non-",
201 bfd_printable_arch_mach (bfd_get_arch (abfd), 0),
202 (int) bfd_get_flavour (abfd),
203 gdbarch_osabi_name (match),
204 gdbarch_osabi_name (osabi));
205 }
206 else if (sniffer->arch != bfd_arch_unknown)
207 {
208 match = osabi;
209 match_specific = 1;
210 }
211 }
212 else
213 {
214 match = osabi;
215 if (sniffer->arch != bfd_arch_unknown)
216 match_specific = 1;
217 }
218 }
219 }
220 }
221
222 return match;
223 }
224
225 void
226 gdbarch_init_osabi (struct gdbarch_info info, struct gdbarch *gdbarch,
227 enum gdb_osabi osabi)
228 {
229 struct gdb_osabi_handler *handler;
230 bfd *abfd = info.abfd;
231 const struct bfd_arch_info *arch_info = gdbarch_bfd_arch_info (gdbarch);
232
233 if (osabi == GDB_OSABI_UNKNOWN)
234 {
235 /* Don't complain about an unknown OSABI. Assume the user knows
236 what they are doing. */
237 return;
238 }
239
240 for (handler = gdb_osabi_handler_list; handler != NULL;
241 handler = handler->next)
242 {
243 if (handler->arch == bfd_get_arch (abfd)
244 && handler->osabi == osabi)
245 {
246 (*handler->init_osabi) (info, gdbarch);
247 return;
248 }
249 }
250
251 /* We assume that if GDB_MULTI_ARCH is less than GDB_MULTI_ARCH_TM
252 that an ABI variant can be supported by overriding definitions in
253 the tm-file. */
254 if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL)
255 fprintf_filtered
256 (gdb_stderr,
257 "A handler for the OS ABI \"%s\" is not built into this "
258 "configuration of GDB. "
259 "Attempting to continue with the default %s settings",
260 gdbarch_osabi_name (osabi),
261 bfd_printable_arch_mach (arch_info->arch, arch_info->mach));
262 }
263 \f
264
265 /* Generic sniffer for ELF flavoured files. */
266
267 void
268 generic_elf_osabi_sniff_abi_tag_sections (bfd *abfd, asection *sect, void *obj)
269 {
270 enum gdb_osabi *os_ident_ptr = obj;
271 const char *name;
272 unsigned int sectsize;
273
274 name = bfd_get_section_name (abfd, sect);
275 sectsize = bfd_section_size (abfd, sect);
276
277 /* .note.ABI-tag notes, used by GNU/Linux and FreeBSD. */
278 if (strcmp (name, ".note.ABI-tag") == 0 && sectsize > 0)
279 {
280 unsigned int name_length, data_length, note_type;
281 char *note;
282
283 /* If the section is larger than this, it's probably not what we are
284 looking for. */
285 if (sectsize > 128)
286 sectsize = 128;
287
288 note = alloca (sectsize);
289
290 bfd_get_section_contents (abfd, sect, note,
291 (file_ptr) 0, (bfd_size_type) sectsize);
292
293 name_length = bfd_h_get_32 (abfd, note);
294 data_length = bfd_h_get_32 (abfd, note + 4);
295 note_type = bfd_h_get_32 (abfd, note + 8);
296
297 if (name_length == 4 && data_length == 16 && note_type == NT_GNU_ABI_TAG
298 && strcmp (note + 12, "GNU") == 0)
299 {
300 int os_number = bfd_h_get_32 (abfd, note + 16);
301
302 switch (os_number)
303 {
304 case GNU_ABI_TAG_LINUX:
305 *os_ident_ptr = GDB_OSABI_LINUX;
306 break;
307
308 case GNU_ABI_TAG_HURD:
309 *os_ident_ptr = GDB_OSABI_HURD;
310 break;
311
312 case GNU_ABI_TAG_SOLARIS:
313 *os_ident_ptr = GDB_OSABI_SOLARIS;
314 break;
315
316 default:
317 internal_error
318 (__FILE__, __LINE__,
319 "generic_elf_osabi_sniff_abi_tag_sections: unknown OS number %d",
320 os_number);
321 }
322 return;
323 }
324 else if (name_length == 8 && data_length == 4
325 && note_type == NT_FREEBSD_ABI_TAG
326 && strcmp (note + 12, "FreeBSD") == 0)
327 {
328 /* XXX Should we check the version here? Probably not
329 necessary yet. */
330 *os_ident_ptr = GDB_OSABI_FREEBSD_ELF;
331 }
332 return;
333 }
334
335 /* .note.netbsd.ident notes, used by NetBSD. */
336 if (strcmp (name, ".note.netbsd.ident") == 0 && sectsize > 0)
337 {
338 unsigned int name_length, data_length, note_type;
339 char *note;
340
341 /* If the section is larger than this, it's probably not what we are
342 looking for. */
343 if (sectsize > 128)
344 sectsize = 128;
345
346 note = alloca (sectsize);
347
348 bfd_get_section_contents (abfd, sect, note,
349 (file_ptr) 0, (bfd_size_type) sectsize);
350
351 name_length = bfd_h_get_32 (abfd, note);
352 data_length = bfd_h_get_32 (abfd, note + 4);
353 note_type = bfd_h_get_32 (abfd, note + 8);
354
355 if (name_length == 7 && data_length == 4 && note_type == NT_NETBSD_IDENT
356 && strcmp (note + 12, "NetBSD") == 0)
357 {
358 /* XXX Should we check the version here? Probably not
359 necessary yet. */
360 *os_ident_ptr = GDB_OSABI_NETBSD_ELF;
361 }
362 return;
363 }
364 }
365
366 static enum gdb_osabi
367 generic_elf_osabi_sniffer (bfd *abfd)
368 {
369 unsigned int elfosabi;
370 enum gdb_osabi osabi = GDB_OSABI_UNKNOWN;
371
372 elfosabi = elf_elfheader (abfd)->e_ident[EI_OSABI];
373
374 switch (elfosabi)
375 {
376 case ELFOSABI_NONE:
377 /* When elfosabi is ELFOSABI_NONE (0), then the ELF structures in the
378 file are conforming to the base specification for that machine
379 (there are no OS-specific extensions). In order to determine the
380 real OS in use we must look for OS notes that have been added. */
381 bfd_map_over_sections (abfd,
382 generic_elf_osabi_sniff_abi_tag_sections,
383 &osabi);
384 break;
385
386 case ELFOSABI_FREEBSD:
387 osabi = GDB_OSABI_FREEBSD_ELF;
388 break;
389
390 case ELFOSABI_NETBSD:
391 osabi = GDB_OSABI_NETBSD_ELF;
392 break;
393
394 case ELFOSABI_LINUX:
395 osabi = GDB_OSABI_LINUX;
396 break;
397
398 case ELFOSABI_HURD:
399 osabi = GDB_OSABI_HURD;
400 break;
401
402 case ELFOSABI_SOLARIS:
403 osabi = GDB_OSABI_SOLARIS;
404 break;
405 }
406
407 if (osabi == GDB_OSABI_UNKNOWN)
408 {
409 /* The FreeBSD folks have been naughty; they stored the string
410 "FreeBSD" in the padding of the e_ident field of the ELF
411 header to "brand" their ELF binaries in FreeBSD 3.x. */
412 if (strcmp (&elf_elfheader (abfd)->e_ident[8], "FreeBSD") == 0)
413 osabi = GDB_OSABI_FREEBSD_ELF;
414 }
415
416 return osabi;
417 }
418 \f
419
420 void
421 _initialize_gdb_osabi (void)
422 {
423 if (strcmp (gdb_osabi_names[GDB_OSABI_INVALID], "<invalid>") != 0)
424 internal_error
425 (__FILE__, __LINE__,
426 "_initialize_gdb_osabi: gdb_osabi_names[] is inconsistent");
427
428 /* Register a generic sniffer for ELF flavoured files. */
429 gdbarch_register_osabi_sniffer (bfd_arch_unknown,
430 bfd_target_elf_flavour,
431 generic_elf_osabi_sniffer);
432 }
This page took 0.05073 seconds and 4 git commands to generate.