daily update
[deliverable/binutils-gdb.git] / bfd / elf-attrs.c
CommitLineData
104d59d1
JM
1/* ELF attributes support (based on ARM EABI attributes).
2 Copyright 2005, 2006, 2007
3 Free Software Foundation, Inc.
4
5 This file is part of BFD, the Binary File Descriptor library.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
cd123cb7 9 the Free Software Foundation; either version 3 of the License, or
104d59d1
JM
10 (at your option) any later version.
11
12 This program 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
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
cd123cb7
NC
19 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20 MA 02110-1301, USA. */
104d59d1
JM
21
22#include "sysdep.h"
23#include "bfd.h"
24#include "libiberty.h"
25#include "libbfd.h"
26#include "elf-bfd.h"
27
28/* Return the number of bytes needed by I in uleb128 format. */
29static int
30uleb128_size (unsigned int i)
31{
32 int size;
33 size = 1;
34 while (i >= 0x80)
35 {
36 i >>= 7;
37 size++;
38 }
39 return size;
40}
41
42/* Return TRUE if the attribute has the default value (0/""). */
43static bfd_boolean
44is_default_attr (obj_attribute *attr)
45{
46 if ((attr->type & 1) && attr->i != 0)
47 return FALSE;
48 if ((attr->type & 2) && attr->s && *attr->s)
49 return FALSE;
50
51 return TRUE;
52}
53
54/* Return the size of a single attribute. */
55static bfd_vma
56obj_attr_size (int tag, obj_attribute *attr)
57{
58 bfd_vma size;
59
60 if (is_default_attr (attr))
61 return 0;
62
63 size = uleb128_size (tag);
64 if (attr->type & 1)
65 size += uleb128_size (attr->i);
66 if (attr->type & 2)
67 size += strlen ((char *)attr->s) + 1;
68 return size;
69}
70
71/* Return the vendor name for a given object attributes section. */
72static const char *
73vendor_obj_attr_name (bfd *abfd, int vendor)
74{
75 return (vendor == OBJ_ATTR_PROC
76 ? get_elf_backend_data (abfd)->obj_attrs_vendor
77 : "gnu");
78}
79
80/* Return the size of the object attributes section for VENDOR
81 (OBJ_ATTR_PROC or OBJ_ATTR_GNU), or 0 if there are no attributes
82 for that vendor to record and the vendor is OBJ_ATTR_GNU. */
83static bfd_vma
84vendor_obj_attr_size (bfd *abfd, int vendor)
85{
86 bfd_vma size;
87 obj_attribute *attr;
88 obj_attribute_list *list;
89 int i;
90 const char *vendor_name = vendor_obj_attr_name (abfd, vendor);
91
92 if (!vendor_name)
93 return 0;
94
95 attr = elf_known_obj_attributes (abfd)[vendor];
96 size = 0;
97 for (i = 4; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++)
98 size += obj_attr_size (i, &attr[i]);
99
100 for (list = elf_other_obj_attributes (abfd)[vendor];
101 list;
102 list = list->next)
103 size += obj_attr_size (list->tag, &list->attr);
104
105 /* <size> <vendor_name> NUL 0x1 <size> */
106 return ((size || vendor == OBJ_ATTR_PROC)
107 ? size + 10 + strlen (vendor_name)
108 : 0);
109}
110
111/* Return the size of the object attributes section. */
112bfd_vma
113bfd_elf_obj_attr_size (bfd *abfd)
114{
115 bfd_vma size;
116
117 size = vendor_obj_attr_size (abfd, OBJ_ATTR_PROC);
118 size += vendor_obj_attr_size (abfd, OBJ_ATTR_GNU);
119
120 /* 'A' <sections for each vendor> */
121 return (size ? size + 1 : 0);
122}
123
124/* Write VAL in uleb128 format to P, returning a pointer to the
125 following byte. */
126static bfd_byte *
127write_uleb128 (bfd_byte *p, unsigned int val)
128{
129 bfd_byte c;
130 do
131 {
132 c = val & 0x7f;
133 val >>= 7;
134 if (val)
135 c |= 0x80;
136 *(p++) = c;
137 }
138 while (val);
139 return p;
140}
141
142/* Write attribute ATTR to butter P, and return a pointer to the following
143 byte. */
144static bfd_byte *
145write_obj_attribute (bfd_byte *p, int tag, obj_attribute *attr)
146{
147 /* Suppress default entries. */
148 if (is_default_attr (attr))
149 return p;
150
151 p = write_uleb128 (p, tag);
152 if (attr->type & 1)
153 p = write_uleb128 (p, attr->i);
154 if (attr->type & 2)
155 {
156 int len;
157
158 len = strlen (attr->s) + 1;
159 memcpy (p, attr->s, len);
160 p += len;
161 }
162
163 return p;
164}
165
166/* Write the contents of the object attributes section (length SIZE)
167 for VENDOR to CONTENTS. */
168static void
169vendor_set_obj_attr_contents (bfd *abfd, bfd_byte *contents, bfd_vma size,
170 int vendor)
171{
172 bfd_byte *p;
173 obj_attribute *attr;
174 obj_attribute_list *list;
175 int i;
176 const char *vendor_name = vendor_obj_attr_name (abfd, vendor);
177 size_t vendor_length = strlen (vendor_name) + 1;
178
179 p = contents;
180 bfd_put_32 (abfd, size, p);
181 p += 4;
182 memcpy (p, vendor_name, vendor_length);
183 p += vendor_length;
184 *(p++) = Tag_File;
185 bfd_put_32 (abfd, size - 4 - vendor_length, p);
186 p += 4;
187
188 attr = elf_known_obj_attributes (abfd)[vendor];
189 for (i = 4; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++)
190 p = write_obj_attribute (p, i, &attr[i]);
191
192 for (list = elf_other_obj_attributes (abfd)[vendor];
193 list;
194 list = list->next)
195 p = write_obj_attribute (p, list->tag, &list->attr);
196}
197
198/* Write the contents of the object attributes section to CONTENTS. */
199void
200bfd_elf_set_obj_attr_contents (bfd *abfd, bfd_byte *contents, bfd_vma size)
201{
202 bfd_byte *p;
203 int vendor;
204 bfd_vma my_size;
205
206 p = contents;
207 *(p++) = 'A';
208 my_size = 1;
209 for (vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; vendor++)
210 {
211 bfd_vma vendor_size = vendor_obj_attr_size (abfd, vendor);
212 if (vendor_size)
213 vendor_set_obj_attr_contents (abfd, p, vendor_size, vendor);
214 p += vendor_size;
215 my_size += vendor_size;
216 }
217
218 if (size != my_size)
219 abort ();
220}
221
222/* Allocate/find an object attribute. */
223static obj_attribute *
224elf_new_obj_attr (bfd *abfd, int vendor, int tag)
225{
226 obj_attribute *attr;
227 obj_attribute_list *list;
228 obj_attribute_list *p;
229 obj_attribute_list **lastp;
230
231
232 if (tag < NUM_KNOWN_OBJ_ATTRIBUTES)
233 {
234 /* Knwon tags are preallocated. */
235 attr = &elf_known_obj_attributes (abfd)[vendor][tag];
236 }
237 else
238 {
239 /* Create a new tag. */
240 list = (obj_attribute_list *)
241 bfd_alloc (abfd, sizeof (obj_attribute_list));
242 memset (list, 0, sizeof (obj_attribute_list));
243 list->tag = tag;
244 /* Keep the tag list in order. */
245 lastp = &elf_other_obj_attributes (abfd)[vendor];
246 for (p = *lastp; p; p = p->next)
247 {
248 if (tag < p->tag)
249 break;
250 lastp = &p->next;
251 }
252 list->next = *lastp;
253 *lastp = list;
254 attr = &list->attr;
255 }
256
257 return attr;
258}
259
260/* Return the value of an integer object attribute. */
261int
262bfd_elf_get_obj_attr_int (bfd *abfd, int vendor, int tag)
263{
264 obj_attribute_list *p;
265
266 if (tag < NUM_KNOWN_OBJ_ATTRIBUTES)
267 {
268 /* Knwon tags are preallocated. */
269 return elf_known_obj_attributes (abfd)[vendor][tag].i;
270 }
271 else
272 {
273 for (p = elf_other_obj_attributes (abfd)[vendor];
274 p;
275 p = p->next)
276 {
277 if (tag == p->tag)
278 return p->attr.i;
279 if (tag < p->tag)
280 break;
281 }
282 return 0;
283 }
284}
285
286/* Add an integer object attribute. */
287void
288bfd_elf_add_obj_attr_int (bfd *abfd, int vendor, int tag, unsigned int i)
289{
290 obj_attribute *attr;
291
292 attr = elf_new_obj_attr (abfd, vendor, tag);
293 attr->type = 1;
294 attr->i = i;
295}
296
297/* Duplicate an object attribute string value. */
298char *
299_bfd_elf_attr_strdup (bfd *abfd, const char * s)
300{
301 char * p;
302 int len;
303
304 len = strlen (s) + 1;
305 p = (char *) bfd_alloc (abfd, len);
306 return memcpy (p, s, len);
307}
308
309/* Add a string object attribute. */
310void
311bfd_elf_add_obj_attr_string (bfd *abfd, int vendor, int tag, const char *s)
312{
313 obj_attribute *attr;
314
315 attr = elf_new_obj_attr (abfd, vendor, tag);
316 attr->type = 2;
317 attr->s = _bfd_elf_attr_strdup (abfd, s);
318}
319
320/* Add a Tag_compatibility object attribute. */
321void
322bfd_elf_add_obj_attr_compat (bfd *abfd, int vendor, unsigned int i,
323 const char *s)
324{
325 obj_attribute_list *list;
326 obj_attribute_list *p;
327 obj_attribute_list **lastp;
328
329 list = (obj_attribute_list *)
330 bfd_alloc (abfd, sizeof (obj_attribute_list));
331 memset (list, 0, sizeof (obj_attribute_list));
332 list->tag = Tag_compatibility;
333 list->attr.type = 3;
334 list->attr.i = i;
335 list->attr.s = _bfd_elf_attr_strdup (abfd, s);
336
337 lastp = &elf_other_obj_attributes (abfd)[vendor];
338 for (p = *lastp; p; p = p->next)
339 {
340 int cmp;
341 if (p->tag != Tag_compatibility)
342 break;
343 cmp = strcmp(s, p->attr.s);
344 if (cmp < 0 || (cmp == 0 && i < p->attr.i))
345 break;
346 lastp = &p->next;
347 }
348 list->next = *lastp;
349 *lastp = list;
350}
351
352/* Copy the object attributes from IBFD to OBFD. */
353void
354_bfd_elf_copy_obj_attributes (bfd *ibfd, bfd *obfd)
355{
356 obj_attribute *in_attr;
357 obj_attribute *out_attr;
358 obj_attribute_list *list;
359 int i;
360 int vendor;
361
362 for (vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; vendor++)
363 {
364 in_attr = &elf_known_obj_attributes (ibfd)[vendor][4];
365 out_attr = &elf_known_obj_attributes (obfd)[vendor][4];
366 for (i = 4; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++)
367 {
368 out_attr->type = in_attr->type;
369 out_attr->i = in_attr->i;
370 if (in_attr->s && *in_attr->s)
371 out_attr->s = _bfd_elf_attr_strdup (obfd, in_attr->s);
372 in_attr++;
373 out_attr++;
374 }
375
376 for (list = elf_other_obj_attributes (ibfd)[vendor];
377 list;
378 list = list->next)
379 {
380 in_attr = &list->attr;
381 switch (in_attr->type)
382 {
383 case 1:
384 bfd_elf_add_obj_attr_int (obfd, vendor, list->tag, in_attr->i);
385 break;
386 case 2:
387 bfd_elf_add_obj_attr_string (obfd, vendor, list->tag,
388 in_attr->s);
389 break;
390 case 3:
391 bfd_elf_add_obj_attr_compat (obfd, vendor, in_attr->i,
392 in_attr->s);
393 break;
394 default:
395 abort ();
396 }
397 }
398 }
399}
400
401/* Determine whether a GNU object attribute tag takes an integer, a
402 string or both. */
403static int
404gnu_obj_attrs_arg_type (int tag)
405{
406 /* Except for Tag_compatibility, for GNU attributes we follow the
407 same rule ARM ones > 32 follow: odd-numbered tags take strings
408 and even-numbered tags take integers. In addition, tag & 2 is
409 nonzero for architecture-independent tags and zero for
410 architecture-dependent ones. */
411 if (tag == Tag_compatibility)
412 return 3;
413 else
414 return (tag & 1) != 0 ? 2 : 1;
415}
416
417/* Determine what arguments an attribute tag takes. */
418int
419_bfd_elf_obj_attrs_arg_type (bfd *abfd, int vendor, int tag)
420{
421 switch (vendor)
422 {
423 case OBJ_ATTR_PROC:
424 return get_elf_backend_data (abfd)->obj_attrs_arg_type (tag);
425 break;
426 case OBJ_ATTR_GNU:
427 return gnu_obj_attrs_arg_type (tag);
428 break;
429 default:
430 abort ();
431 }
432}
433
434/* Parse an object attributes section. */
435void
436_bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr)
437{
438 bfd_byte *contents;
439 bfd_byte *p;
440 bfd_vma len;
441 const char *std_section;
442
443 contents = bfd_malloc (hdr->sh_size);
444 if (!contents)
445 return;
446 if (!bfd_get_section_contents (abfd, hdr->bfd_section, contents, 0,
447 hdr->sh_size))
448 {
449 free (contents);
450 return;
451 }
452 p = contents;
453 std_section = get_elf_backend_data (abfd)->obj_attrs_vendor;
454 if (*(p++) == 'A')
455 {
456 len = hdr->sh_size - 1;
457 while (len > 0)
458 {
459 int namelen;
460 bfd_vma section_len;
461 int vendor;
462
463 section_len = bfd_get_32 (abfd, p);
464 p += 4;
465 if (section_len > len)
466 section_len = len;
467 len -= section_len;
468 namelen = strlen ((char *)p) + 1;
469 section_len -= namelen + 4;
470 if (std_section && strcmp ((char *)p, std_section) == 0)
471 vendor = OBJ_ATTR_PROC;
472 else if (strcmp ((char *)p, "gnu") == 0)
473 vendor = OBJ_ATTR_GNU;
474 else
475 {
476 /* Other vendor section. Ignore it. */
477 p += namelen + section_len;
478 continue;
479 }
480
481 p += namelen;
482 while (section_len > 0)
483 {
484 int tag;
485 unsigned int n;
486 unsigned int val;
487 bfd_vma subsection_len;
488 bfd_byte *end;
489
490 tag = read_unsigned_leb128 (abfd, p, &n);
491 p += n;
492 subsection_len = bfd_get_32 (abfd, p);
493 p += 4;
494 if (subsection_len > section_len)
495 subsection_len = section_len;
496 section_len -= subsection_len;
497 subsection_len -= n + 4;
498 end = p + subsection_len;
499 switch (tag)
500 {
501 case Tag_File:
502 while (p < end)
503 {
504 int type;
505
506 tag = read_unsigned_leb128 (abfd, p, &n);
507 p += n;
508 type = _bfd_elf_obj_attrs_arg_type (abfd, vendor, tag);
509 switch (type)
510 {
511 case 3:
512 val = read_unsigned_leb128 (abfd, p, &n);
513 p += n;
514 bfd_elf_add_obj_attr_compat (abfd, vendor, val,
515 (char *)p);
516 p += strlen ((char *)p) + 1;
517 break;
518 case 2:
519 bfd_elf_add_obj_attr_string (abfd, vendor, tag,
520 (char *)p);
521 p += strlen ((char *)p) + 1;
522 break;
523 case 1:
524 val = read_unsigned_leb128 (abfd, p, &n);
525 p += n;
526 bfd_elf_add_obj_attr_int (abfd, vendor, tag, val);
527 break;
528 default:
529 abort ();
530 }
531 }
532 break;
533 case Tag_Section:
534 case Tag_Symbol:
535 /* Don't have anywhere convenient to attach these.
536 Fall through for now. */
537 default:
538 /* Ignore things we don't kow about. */
539 p += subsection_len;
540 subsection_len = 0;
541 break;
542 }
543 }
544 }
545 }
546 free (contents);
547}
548
549/* Merge common object attributes from IBFD into OBFD. Raise an error
550 if there are conflicting attributes. Any processor-specific
551 attributes have already been merged. This must be called from the
552 bfd_elfNN_bfd_merge_private_bfd_data hook for each individual
553 target, along with any target-specific merging. Because there are
554 no common attributes other than Tag_compatibility at present, and
555 non-"gnu" Tag_compatibility is not expected in "gnu" sections, this
556 is not presently called for targets without their own
557 attributes. */
558
559bfd_boolean
560_bfd_elf_merge_object_attributes (bfd *ibfd, bfd *obfd)
561{
562 obj_attribute *in_attr;
563 obj_attribute *out_attr;
564 obj_attribute_list *in_list;
565 obj_attribute_list *out_list;
566 int vendor;
567
568 /* The only common attribute is currently Tag_compatibility,
569 accepted in both processor and "gnu" sections. */
570 for (vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; vendor++)
571 {
572 in_list = elf_other_obj_attributes (ibfd)[vendor];
573 out_list = elf_other_obj_attributes (ibfd)[vendor];
574 while (in_list && in_list->tag == Tag_compatibility)
575 {
576 in_attr = &in_list->attr;
577 if (in_attr->i == 0)
578 continue;
579 if (in_attr->i == 1 && strcmp (in_attr->s, "gnu") != 0)
580 {
581 _bfd_error_handler
582 (_("ERROR: %B: Must be processed by '%s' toolchain"),
583 ibfd, in_attr->s);
584 return FALSE;
585 }
586 if (!out_list || out_list->tag != Tag_compatibility
587 || strcmp (in_attr->s, out_list->attr.s) != 0)
588 {
589 /* Add this compatibility tag to the output. */
590 bfd_elf_add_proc_attr_compat (obfd, in_attr->i, in_attr->s);
591 continue;
592 }
593 out_attr = &out_list->attr;
594 /* Check all the input tags with the same identifier. */
595 for (;;)
596 {
597 if (out_list->tag != Tag_compatibility
598 || in_attr->i != out_attr->i
599 || strcmp (in_attr->s, out_attr->s) != 0)
600 {
601 _bfd_error_handler
602 (_("ERROR: %B: Incompatible object tag '%s':%d"),
603 ibfd, in_attr->s, in_attr->i);
604 return FALSE;
605 }
606 in_list = in_list->next;
607 if (in_list->tag != Tag_compatibility
608 || strcmp (in_attr->s, in_list->attr.s) != 0)
609 break;
610 in_attr = &in_list->attr;
611 out_list = out_list->next;
612 if (out_list)
613 out_attr = &out_list->attr;
614 }
615
616 /* Check the output doesn't have extra tags with this identifier. */
617 if (out_list && out_list->tag == Tag_compatibility
618 && strcmp (in_attr->s, out_list->attr.s) == 0)
619 {
620 _bfd_error_handler
621 (_("ERROR: %B: Incompatible object tag '%s':%d"),
622 ibfd, in_attr->s, out_list->attr.i);
623 return FALSE;
624 }
625 }
626 }
627
628 return TRUE;
629}
This page took 0.138939 seconds and 4 git commands to generate.