return count;
}
+typedef struct objcopy_internal_note
+{
+ Elf_Internal_Note note;
+ bfd_vma start;
+ bfd_vma end;
+ bfd_boolean modified;
+} objcopy_internal_note;
+
+/* Returns TRUE if a gap does, or could, exist between the address range
+ covered by PNOTE1 and PNOTE2. */
+
+static bfd_boolean
+gap_exists (objcopy_internal_note * pnote1,
+ objcopy_internal_note * pnote2)
+{
+ /* Without range end notes, we assume that a gap might exist. */
+ if (pnote1->end == 0 || pnote2->end == 0)
+ return TRUE;
+
+ /* FIXME: Alignment of 16 bytes taken from x86_64 binaries.
+ Really we should extract the alignment of the section covered by the notes. */
+ return BFD_ALIGN (pnote1->end, 16) < pnote2->start;
+}
+
+static bfd_boolean
+is_open_note (objcopy_internal_note * pnote)
+{
+ return (pnote->note.type == NT_GNU_BUILD_ATTRIBUTE_OPEN);
+}
+
+static bfd_boolean
+is_func_note (objcopy_internal_note * pnote)
+{
+ return (pnote->note.type == NT_GNU_BUILD_ATTRIBUTE_FUNC);
+}
+
+static bfd_boolean
+is_64bit (bfd * abfd)
+{
+ /* Should never happen, but let's be paranoid. */
+ if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+ return FALSE;
+
+ return elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64;
+}
+
/* Merge the notes on SEC, removing redundant entries.
Returns the new, smaller size of the section upon success. */
static bfd_size_type
merge_gnu_build_notes (bfd * abfd, asection * sec, bfd_size_type size, bfd_byte * contents)
{
- Elf_Internal_Note * pnotes_end;
- Elf_Internal_Note * pnotes;
- Elf_Internal_Note * pnote;
+ objcopy_internal_note * pnotes_end;
+ objcopy_internal_note * pnotes = NULL;
+ objcopy_internal_note * pnote;
bfd_size_type remain = size;
unsigned version_1_seen = 0;
unsigned version_2_seen = 0;
+ unsigned version_3_seen = 0;
bfd_boolean duplicate_found = FALSE;
const char * err = NULL;
bfd_byte * in = contents;
int attribute_type_byte;
int val_start;
+ unsigned long previous_func_start = 0;
+ unsigned long previous_open_start = 0;
+ unsigned long previous_func_end = 0;
+ unsigned long previous_open_end = 0;
+ long relsize;
- /* Make a copy of the notes.
+
+ relsize = bfd_get_reloc_upper_bound (abfd, sec);
+ if (relsize > 0)
+ {
+ arelent ** relpp;
+ long relcount;
+
+ /* If there are relocs associated with this section then we
+ cannot safely merge it. */
+ relpp = (arelent **) xmalloc (relsize);
+ relcount = bfd_canonicalize_reloc (abfd, sec, relpp, isympp);
+ free (relpp);
+ if (relcount != 0)
+ goto done;
+ }
+
+ /* Make a copy of the notes and convert to our internal format.
Minimum size of a note is 12 bytes. */
- pnote = pnotes = (Elf_Internal_Note *) xcalloc ((size / 12), sizeof (Elf_Internal_Note));
+ pnote = pnotes = (objcopy_internal_note *) xcalloc ((size / 12), sizeof (* pnote));
while (remain >= 12)
{
- pnote->namesz = (bfd_get_32 (abfd, in ) + 3) & ~3;
- pnote->descsz = (bfd_get_32 (abfd, in + 4) + 3) & ~3;
- pnote->type = bfd_get_32 (abfd, in + 8);
+ bfd_vma start, end;
+
+ pnote->note.namesz = (bfd_get_32 (abfd, in ) + 3) & ~3;
+ pnote->note.descsz = (bfd_get_32 (abfd, in + 4) + 3) & ~3;
+ pnote->note.type = bfd_get_32 (abfd, in + 8);
- if (pnote->type != NT_GNU_BUILD_ATTRIBUTE_OPEN
- && pnote->type != NT_GNU_BUILD_ATTRIBUTE_FUNC)
+ if (pnote->note.type != NT_GNU_BUILD_ATTRIBUTE_OPEN
+ && pnote->note.type != NT_GNU_BUILD_ATTRIBUTE_FUNC)
{
err = _("corrupt GNU build attribute note: wrong note type");
goto done;
}
- if (pnote->namesz + pnote->descsz + 12 > remain)
+ if (pnote->note.namesz + pnote->note.descsz + 12 > remain)
{
err = _("corrupt GNU build attribute note: note too big");
goto done;
}
- if (pnote->namesz < 2)
+ if (pnote->note.namesz < 2)
{
err = _("corrupt GNU build attribute note: name too small");
goto done;
}
- if (pnote->descsz != 0
- && pnote->descsz != 4
- && pnote->descsz != 8)
+ pnote->note.namedata = (char *)(in + 12);
+ pnote->note.descdata = (char *)(in + 12 + pnote->note.namesz);
+
+ remain -= 12 + pnote->note.namesz + pnote->note.descsz;
+ in += 12 + pnote->note.namesz + pnote->note.descsz;
+
+ if (pnote->note.namesz > 2
+ && pnote->note.namedata[0] == '$'
+ && pnote->note.namedata[1] == GNU_BUILD_ATTRIBUTE_VERSION
+ && pnote->note.namedata[2] == '1')
+ ++ version_1_seen;
+ else if (pnote->note.namesz > 4
+ && pnote->note.namedata[0] == 'G'
+ && pnote->note.namedata[1] == 'A'
+ && pnote->note.namedata[2] == '$'
+ && pnote->note.namedata[3] == GNU_BUILD_ATTRIBUTE_VERSION)
{
+ if (pnote->note.namedata[4] == '2')
+ ++ version_2_seen;
+ else if (pnote->note.namedata[4] == '3')
+ ++ version_3_seen;
+ else
+ {
+ err = _("corrupt GNU build attribute note: unsupported version");
+ goto done;
+ }
+ }
+
+ switch (pnote->note.descsz)
+ {
+ case 0:
+ start = end = 0;
+ break;
+
+ case 4:
+ start = bfd_get_32 (abfd, pnote->note.descdata);
+ /* FIXME: For version 1 and 2 notes we should try to
+ calculate the end address by finding a symbol whose
+ value is START, and then adding in its size.
+
+ For now though, since v1 and v2 was not intended to
+ handle gaps, we chose an artificially large end
+ address. */
+ end = 0x7ffffffffffffffUL;
+ break;
+
+ case 8:
+ if (! is_64bit (abfd))
+ {
+ start = bfd_get_32 (abfd, pnote->note.descdata);
+ end = bfd_get_32 (abfd, pnote->note.descdata + 4);
+ }
+ else
+ {
+ start = bfd_get_64 (abfd, pnote->note.descdata);
+ /* FIXME: For version 1 and 2 notes we should try to
+ calculate the end address by finding a symbol whose
+ value is START, and then adding in its size.
+
+ For now though, since v1 and v2 was not intended to
+ handle gaps, we chose an artificially large end
+ address. */
+ end = 0x7ffffffffffffffUL;
+ }
+ break;
+
+ case 16:
+ start = bfd_get_64 (abfd, pnote->note.descdata);
+ end = bfd_get_64 (abfd, pnote->note.descdata + 8);
+ break;
+
+ default:
err = _("corrupt GNU build attribute note: bad description size");
goto done;
}
- pnote->namedata = (char *)(in + 12);
- pnote->descdata = (char *)(in + 12 + pnote->namesz);
+ if (is_open_note (pnote))
+ {
+ if (start)
+ previous_open_start = start;
+
+ pnote->start = previous_open_start;
+
+ if (end)
+ previous_open_end = end;
- remain -= 12 + pnote->namesz + pnote->descsz;
- in += 12 + pnote->namesz + pnote->descsz;
+ pnote->end = previous_open_end;
+ }
+ else
+ {
+ if (start)
+ previous_func_start = start;
+
+ pnote->start = previous_func_start;
+
+ if (end)
+ previous_func_end = end;
+
+ pnote->end = previous_func_end;
+ }
- if (pnote->namedata[pnote->namesz - 1] != 0)
+ if (pnote->note.namedata[pnote->note.namesz - 1] != 0)
{
err = _("corrupt GNU build attribute note: name not NUL terminated");
goto done;
}
-
- if (pnote->namesz > 2
- && pnote->namedata[0] == '$'
- && pnote->namedata[1] == GNU_BUILD_ATTRIBUTE_VERSION
- && pnote->namedata[2] == '1')
- ++ version_1_seen;
- else if (pnote->namesz > 4
- && pnote->namedata[0] == 'G'
- && pnote->namedata[1] == 'A'
- && pnote->namedata[2] == '$'
- && pnote->namedata[3] == GNU_BUILD_ATTRIBUTE_VERSION
- && pnote->namedata[4] == '2')
- ++ version_2_seen;
+
pnote ++;
}
goto done;
}
- if (version_1_seen == 0 && version_2_seen == 0)
+ if (version_1_seen == 0 && version_2_seen == 0 && version_3_seen == 0)
{
err = _("bad GNU build attribute notes: no known versions detected");
goto done;
}
- if (version_1_seen > 0 && version_2_seen > 0)
+ if ((version_1_seen > 0 && version_2_seen > 0)
+ || (version_1_seen > 0 && version_3_seen > 0)
+ || (version_2_seen > 0 && version_3_seen > 0))
{
err = _("bad GNU build attribute notes: multiple different versions");
goto done;
}
/* Merging is only needed if there is more than one version note... */
- if (version_1_seen == 1 || version_2_seen == 1)
+ if (version_1_seen == 1 || version_2_seen == 1 || version_3_seen == 1)
goto done;
attribute_type_byte = version_1_seen ? 1 : 3;
val_start = attribute_type_byte + 1;
/* The first note should be the first version note. */
- if (pnotes[0].namedata[attribute_type_byte] != GNU_BUILD_ATTRIBUTE_VERSION)
+ if (pnotes[0].note.namedata[attribute_type_byte] != GNU_BUILD_ATTRIBUTE_VERSION)
{
err = _("bad GNU build attribute notes: first note not version note");
goto done;
2. Preserve any NT_GNU_BUILD_ATTRIBUTE_FUNC notes.
3. Eliminate any NT_GNU_BUILD_ATTRIBUTE_OPEN notes that have the same
full name field as the immediately preceeding note with the same type
- of name.
+ of name and whose address ranges coincide.
+ IE - it there are gaps in the coverage of the notes, then these gaps
+ must be preserved.
4. Combine the numeric value of any NT_GNU_BUILD_ATTRIBUTE_OPEN notes
of type GNU_BUILD_ATTRIBUTE_STACK_SIZE.
5. If an NT_GNU_BUILD_ATTRIBUTE_OPEN note is going to be preserved and
address to which it refers. */
for (pnote = pnotes + 1; pnote < pnotes_end; pnote ++)
{
- Elf_Internal_Note * back;
- Elf_Internal_Note * prev_open = NULL;
+ int note_type;
+ objcopy_internal_note * back;
+ objcopy_internal_note * prev_open_with_range = NULL;
- if (pnote->type == NT_GNU_BUILD_ATTRIBUTE_FUNC)
+ /* Rule 2 - preserve function notes. */
+ if (! is_open_note (pnote))
continue;
- /* Scan for duplicates. Clear the type field of any found - but do not
- delete them just yet. */
+ note_type = pnote->note.namedata[attribute_type_byte];
+
+ /* Scan backwards from pnote, looking for duplicates.
+ Clear the type field of any found - but do not delete them just yet. */
for (back = pnote - 1; back >= pnotes; back --)
{
- if (back->descsz > 0
- && back->type != NT_GNU_BUILD_ATTRIBUTE_FUNC
- && prev_open == NULL)
- prev_open = back;
+ int back_type = back->note.namedata[attribute_type_byte];
- if (back->type == pnote->type
- && back->namedata[attribute_type_byte] == pnote->namedata[attribute_type_byte])
- {
- if (back->namedata[attribute_type_byte] == GNU_BUILD_ATTRIBUTE_STACK_SIZE)
- {
- unsigned char * name;
- unsigned long note_val;
- unsigned long back_val;
- unsigned int shift;
- unsigned int bytes;
- unsigned long byte;
-
- for (shift = 0, note_val = 0,
- bytes = pnote->namesz - val_start,
- name = (unsigned char *) pnote->namedata + val_start;
- bytes--;)
- {
- byte = (* name ++) & 0xff;
- note_val |= byte << shift;
- shift += 8;
- }
+ /* If this is the first open note with an address
+ range that we have encountered then record it. */
+ if (prev_open_with_range == NULL
+ && back->note.descsz > 0
+ && ! is_func_note (back))
+ prev_open_with_range = back;
- for (shift = 0, back_val = 0,
- bytes = back->namesz - val_start,
- name = (unsigned char *) back->namedata + val_start;
- bytes--;)
- {
- byte = (* name ++) & 0xff;
- back_val |= byte << shift;
- shift += 8;
- }
+ if (! is_open_note (back))
+ continue;
- back_val += note_val;
- if (num_bytes (back_val) >= back->namesz - val_start)
- {
- /* We have a problem - the new value requires more bytes of
- storage in the name field than are available. Currently
- we have no way of fixing this, so we just preserve both
- notes. */
- continue;
- }
+ /* If the two notes are different then keep on searching. */
+ if (back_type != note_type)
+ continue;
- /* Write the new val into back. */
- name = (unsigned char *) back->namedata + val_start;
- while (name < (unsigned char *) back->namedata + back->namesz)
- {
- byte = back_val & 0xff;
- * name ++ = byte;
- if (back_val == 0)
- break;
- back_val >>= 8;
- }
-
- duplicate_found = TRUE;
- pnote->type = 0;
- break;
+ /* Rule 4 - combine stack size notes. */
+ if (back_type == GNU_BUILD_ATTRIBUTE_STACK_SIZE)
+ {
+ unsigned char * name;
+ unsigned long note_val;
+ unsigned long back_val;
+ unsigned int shift;
+ unsigned int bytes;
+ unsigned long byte;
+
+ for (shift = 0, note_val = 0,
+ bytes = pnote->note.namesz - val_start,
+ name = (unsigned char *) pnote->note.namedata + val_start;
+ bytes--;)
+ {
+ byte = (* name ++) & 0xff;
+ note_val |= byte << shift;
+ shift += 8;
}
-
- if (back->namesz == pnote->namesz
- && memcmp (back->namedata, pnote->namedata, back->namesz) == 0)
+
+ for (shift = 0, back_val = 0,
+ bytes = back->note.namesz - val_start,
+ name = (unsigned char *) back->note.namedata + val_start;
+ bytes--;)
{
- duplicate_found = TRUE;
- pnote->type = 0;
- break;
+ byte = (* name ++) & 0xff;
+ back_val |= byte << shift;
+ shift += 8;
}
- /* If we have found an attribute match then stop searching backwards. */
- if (! ISPRINT (back->namedata[attribute_type_byte])
- /* Names are NUL terminated, so this is safe. */
- || strcmp (back->namedata + val_start, pnote->namedata + val_start) == 0)
+ back_val += note_val;
+ if (num_bytes (back_val) >= back->note.namesz - val_start)
{
- /* Since we are keeping this note we must check to see if its
- description refers back to an earlier OPEN version note. If so
- then we must make sure that version note is also preserved. */
- if (pnote->descsz == 0
- && prev_open != NULL
- && prev_open->type == 0)
- prev_open->type = NT_GNU_BUILD_ATTRIBUTE_FUNC;
+ /* We have a problem - the new value requires more bytes of
+ storage in the name field than are available. Currently
+ we have no way of fixing this, so we just preserve both
+ notes. */
+ continue;
+ }
- break;
+ /* Write the new val into back. */
+ name = (unsigned char *) back->note.namedata + val_start;
+ while (name < (unsigned char *) back->note.namedata
+ + back->note.namesz)
+ {
+ byte = back_val & 0xff;
+ * name ++ = byte;
+ if (back_val == 0)
+ break;
+ back_val >>= 8;
}
+
+ duplicate_found = TRUE;
+ pnote->note.type = 0;
+ break;
+ }
+
+ /* Rule 3 - combine identical open notes. */
+ if (back->note.namesz == pnote->note.namesz
+ && memcmp (back->note.namedata,
+ pnote->note.namedata, back->note.namesz) == 0
+ && ! gap_exists (back, pnote))
+ {
+ duplicate_found = TRUE;
+ pnote->note.type = 0;
+
+ if (pnote->end > back->end)
+ back->end = pnote->end;
+
+ if (version_3_seen)
+ back->modified = TRUE;
+ break;
+ }
+
+ /* Rule 5 - Since we are keeping this note we must check to see
+ if its description refers back to an earlier OPEN version
+ note that has been scheduled for deletion. If so then we
+ must make sure that version note is also preserved. */
+ if (version_3_seen)
+ {
+ /* As of version 3 we can just
+ move the range into the note. */
+ pnote->modified = TRUE;
+ pnote->note.type = NT_GNU_BUILD_ATTRIBUTE_FUNC;
+ back->modified = TRUE;
+ back->note.type = NT_GNU_BUILD_ATTRIBUTE_FUNC;
}
+ else
+ {
+ if (pnote->note.descsz == 0
+ && prev_open_with_range != NULL
+ && prev_open_with_range->note.type == 0)
+ prev_open_with_range->note.type = NT_GNU_BUILD_ATTRIBUTE_OPEN;
+ }
+
+ /* We have found a similar attribute but the details do not match.
+ Stop searching backwards. */
+ break;
}
}
bfd_byte * old;
bfd_byte * new;
bfd_size_type new_size;
- arelent ** relpp = NULL;
- long relsize;
- long relcount = 0;
-
- relsize = bfd_get_reloc_upper_bound (abfd, sec);
- if (relsize > 0)
- {
- /* If there are relocs associated with this section then we may
- have to adjust them as well, as we remove notes. */
- relpp = (arelent **) xmalloc (relsize);
- relcount = bfd_canonicalize_reloc (abfd, sec, relpp, isympp);
- if (relcount < 0)
- /* Do not bother complaining here - copy_relocations_in_section
- will do that for us. */
- relcount = 0;
- }
+ bfd_vma prev_start = 0;
+ bfd_vma prev_end = 0;
/* Eliminate the duplicates. */
new = new_contents = xmalloc (size);
pnote < pnotes_end;
pnote ++)
{
- bfd_size_type note_size = 12 + pnote->namesz + pnote->descsz;
+ bfd_size_type note_size = 12 + pnote->note.namesz + pnote->note.descsz;
- if (pnote->type == 0)
+ if (pnote->note.type != 0)
{
- if (relcount > 0)
+ if (pnote->modified)
{
- arelent ** rel;
-
- /* If there is a reloc at the current offset, delete it.
- Adjust the location of any relocs above the current
- location downwards by the size of the note being deleted.
- FIXME: We could optimize this loop by retaining a pointer to
- the last reloc below the current note. */
- for (rel = relpp; rel < relpp + relcount; rel ++)
+ /* If the note has been modified then we must copy it by
+ hand, potentially adding in a new description field. */
+ if (pnote->start == prev_start && pnote->end == prev_end)
+ {
+ bfd_put_32 (abfd, pnote->note.namesz, new);
+ bfd_put_32 (abfd, 0, new + 4);
+ bfd_put_32 (abfd, pnote->note.type, new + 8);
+ new += 12;
+ memcpy (new, pnote->note.namedata, pnote->note.namesz);
+ new += pnote->note.namesz;
+ }
+ else
{
- if ((* rel)->howto == NULL)
- continue;
- if ((* rel)->address < (bfd_vma) (new - new_contents))
- continue;
- if ((* rel)->address >= (bfd_vma) ((new + note_size) - new_contents))
- (* rel)->address -= note_size;
+ bfd_put_32 (abfd, pnote->note.namesz, new);
+ bfd_put_32 (abfd, is_64bit (abfd) ? 16 : 8, new + 4);
+ bfd_put_32 (abfd, pnote->note.type, new + 8);
+ new += 12;
+ memcpy (new, pnote->note.namedata, pnote->note.namesz);
+ new += pnote->note.namesz;
+ if (is_64bit (abfd))
+ {
+ bfd_put_64 (abfd, pnote->start, new);
+ bfd_put_64 (abfd, pnote->end, new + 8);
+ new += 16;
+ }
else
- (* rel)->howto = NULL;
+ {
+ bfd_put_32 (abfd, pnote->start, new);
+ bfd_put_32 (abfd, pnote->end, new + 4);
+ new += 8;
+ }
}
}
- }
- else
- {
- memcpy (new, old, note_size);
- new += note_size;
+ else
+ {
+ memcpy (new, old, note_size);
+ new += note_size;
+ }
+ prev_start = pnote->start;
+ prev_end = pnote->end;
}
old += note_size;
memcpy (contents, new_contents, new_size);
size = new_size;
free (new_contents);
-
- if (relcount > 0)
- {
- arelent **rel = relpp;
-
- while (rel < relpp + relcount)
- if ((*rel)->howto != NULL)
- rel++;
- else
- {
- /* Delete eliminated relocs.
- FIXME: There are better ways to do this. */
- memmove (rel, rel + 1,
- ((relcount - (rel - relpp)) - 1) * sizeof (*rel));
- relcount--;
- }
- bfd_set_reloc (abfd, sec, relpp, relcount);
- }
}
done:
case NT_ARCH:
return _("NT_ARCH (architecture)");
case NT_GNU_BUILD_ATTRIBUTE_OPEN:
- return _("NT_GNU_BUILD_ATTRIBUTE_OPEN");
+ return _("OPEN");
case NT_GNU_BUILD_ATTRIBUTE_FUNC:
- return _("NT_GNU_BUILD_ATTRIBUTE_FUNC");
+ return _("func");
default:
break;
}
return TRUE;
}
-/* Print the name of the symbol associated with a build attribute
- that is attached to address OFFSET. */
+/* Find the symbol associated with a build attribute that is attached
+ to address OFFSET. If PNAME is non-NULL then store the name of
+ the symbol (if found) in the provided pointer, Returns NULL if a
+ symbol could not be found. */
-static bfd_boolean
-print_symbol_for_build_attribute (Filedata * filedata,
- unsigned long offset,
- bfd_boolean is_open_attr)
+static Elf_Internal_Sym *
+get_symbol_for_build_attribute (Filedata * filedata,
+ unsigned long offset,
+ bfd_boolean is_open_attr,
+ const char ** pname)
{
static Filedata * saved_filedata = NULL;
static char * strtab;
}
if (symtab == NULL || strtab == NULL)
- {
- printf ("\n");
- return FALSE;
- }
+ return NULL;
/* Find a symbol whose value matches offset. */
for (sym = symtab; sym < symtab + nsyms; sym ++)
FUNC symbols entirely. */
switch (ELF_ST_TYPE (sym->st_info))
{
- case STT_FILE:
- saved_sym = sym;
- /* We can stop searching now. */
- sym = symtab + nsyms;
- continue;
-
case STT_OBJECT:
+ case STT_FILE:
saved_sym = sym;
+ if (sym->st_size)
+ {
+ /* If the symbol has a size associated
+ with it then we can stop searching. */
+ sym = symtab + nsyms;
+ }
continue;
case STT_FUNC:
}
}
- printf (" (%s: %s)\n",
- is_open_attr ? _("file") : _("func"),
- saved_sym ? strtab + saved_sym->st_name : _("<no symbol found>)"));
- return TRUE;
+ if (saved_sym && pname)
+ * pname = strtab + saved_sym->st_name;
+
+ return saved_sym;
}
static bfd_boolean
print_gnu_build_attribute_description (Elf_Internal_Note * pnote,
Filedata * filedata)
{
- static unsigned long global_offset = 0;
- unsigned long offset;
- unsigned int desc_size = is_32bit_elf ? 4 : 8;
- bfd_boolean is_open_attr = pnote->type == NT_GNU_BUILD_ATTRIBUTE_OPEN;
+ static unsigned long global_offset = 0;
+ static unsigned long global_end = 0;
+ static unsigned long func_offset = 0;
+ static unsigned long func_end = 0;
- if (pnote->descsz == 0)
+ Elf_Internal_Sym * sym;
+ const char * name;
+ unsigned long start;
+ unsigned long end;
+ bfd_boolean is_open_attr = pnote->type == NT_GNU_BUILD_ATTRIBUTE_OPEN;
+
+ switch (pnote->descsz)
{
+ case 0:
+ /* A zero-length description means that the range of
+ the previous note of the same type should be used. */
if (is_open_attr)
{
- printf (_(" Applies from offset %#lx\n"), global_offset);
- return TRUE;
+ if (global_end > global_offset)
+ printf (_(" Applies to region from %#lx to %#lx\n"),
+ global_offset, global_end);
+ else
+ printf (_(" Applies to region from %#lx\n"), global_offset);
}
else
{
- printf (_(" Applies to func at %#lx"), global_offset);
- return print_symbol_for_build_attribute (filedata, global_offset, is_open_attr);
+ if (func_end > func_offset)
+ printf (_(" Applies to region from %#lx to %#lx\n"), func_offset, func_end);
+ else
+ printf (_(" Applies to region from %#lx\n"), func_offset);
}
- }
+ return TRUE;
- if (pnote->descsz != desc_size)
- {
+ case 4:
+ start = byte_get ((unsigned char *) pnote->descdata, 4);
+ end = 0;
+ break;
+
+ case 8:
+ if (is_32bit_elf)
+ {
+ /* FIXME: We should check that version 3+ notes are being used here... */
+ start = byte_get ((unsigned char *) pnote->descdata, 4);
+ end = byte_get ((unsigned char *) pnote->descdata + 4, 4);
+ }
+ else
+ {
+ start = byte_get ((unsigned char *) pnote->descdata, 8);
+ end = 0;
+ }
+ break;
+
+ case 16:
+ start = byte_get ((unsigned char *) pnote->descdata, 8);
+ end = byte_get ((unsigned char *) pnote->descdata + 8, 8);
+ break;
+
+ default:
error (_(" <invalid description size: %lx>\n"), pnote->descsz);
printf (_(" <invalid descsz>"));
return FALSE;
}
- offset = byte_get ((unsigned char *) pnote->descdata, desc_size);
+ name = NULL;
+ sym = get_symbol_for_build_attribute (filedata, start, is_open_attr, & name);
+
+ if (end == 0 && sym != NULL && sym->st_size > 0)
+ end = start + sym->st_size;
if (is_open_attr)
{
- printf (_(" Applies from offset %#lx"), offset);
- global_offset = offset;
+ /* FIXME: Need to properly allow for section alignment. 16 is just the alignment used on x86_64. */
+ if (global_end > 0 && start > BFD_ALIGN (global_end, 16))
+ warn (_("Gap in build notes detected from %#lx to %#lx\n"),
+ global_end + 1, start - 1);
+
+ printf (_(" Applies to region from %#lx"), start);
+ global_offset = start;
+
+ if (end)
+ {
+ printf (_(" to %#lx"), end);
+ global_end = end;
+ }
}
else
{
- printf (_(" Applies to func at %#lx"), offset);
+ printf (_(" Applies to region from %#lx"), start);
+ func_offset = start;
+
+ if (end)
+ {
+ printf (_(" to %#lx"), end);
+ func_end = end;
+ }
}
- return print_symbol_for_build_attribute (filedata, offset, is_open_attr);
+ if (sym && name)
+ printf (_(" (%s)"), name);
+
+ printf ("\n");
+ return TRUE;
}
static bfd_boolean
return FALSE;
}
- left = 20;
+ if (do_wide)
+ left = 28;
+ else
+ left = 20;
/* Version 2 of the spec adds a "GA" prefix to the name field. */
if (name[0] == 'G' && name[1] == 'A')
{
+ if (pnote->namesz < 4)
+ {
+ error (_("corrupt name field in GNU build attribute note: size = %ld\n"), pnote->namesz);
+ print_symbol (-20, _(" <corrupt name>"));
+ return FALSE;
+ }
+
printf ("GA");
name += 2;
left -= 2;