/* Support for the generic parts of COFF, for BFD.
- Copyright (C) 1990-2017 Free Software Foundation, Inc.
+ Copyright (C) 1990-2019 Free Software Foundation, Inc.
Written by Cygnus Support.
This file is part of BFD, the Binary File Descriptor library.
coff_data (abfd). */
#include "sysdep.h"
+#include <limits.h>
#include "bfd.h"
#include "libbfd.h"
#include "coff/internal.h"
const char *strings;
/* Flag that this BFD uses long names, even though the format might
- expect them to be off by default. This won't directly affect the
- format of any output BFD created from this one, but the information
- can be used to decide what to do. */
+ expect them to be off by default. This won't directly affect the
+ format of any output BFD created from this one, but the information
+ can be used to decide what to do. */
bfd_coff_set_long_section_names (abfd, TRUE);
memcpy (buf, hdr->s_name + 1, SCNNMLEN - 1);
buf[SCNNMLEN - 1] = '\0';
return FALSE;
strings += strindex;
name = (char *) bfd_alloc (abfd,
- (bfd_size_type) strlen (strings) + 1 + 1);
+ (bfd_size_type) strlen (strings) + 1 + 1);
if (name == NULL)
return FALSE;
strcpy (name, strings);
{
/* Assorted wastage to null-terminate the name, thanks AT&T! */
name = (char *) bfd_alloc (abfd,
- (bfd_size_type) sizeof (hdr->s_name) + 1 + 1);
+ (bfd_size_type) sizeof (hdr->s_name) + 1 + 1);
if (name == NULL)
return FALSE;
strncpy (name, (char *) &hdr->s_name[0], sizeof (hdr->s_name));
{
_bfd_error_handler
/* xgettext: c-format */
- (_("%B: unable to initialize compress status for section %s"),
+ (_("%pB: unable to initialize compress status for section %s"),
abfd, name);
return FALSE;
}
memcpy (new_name + 2, name + 1, len);
}
}
- break;
+ break;
case decompress:
if (!bfd_init_section_decompress_status (abfd, return_section))
{
_bfd_error_handler
/* xgettext: c-format */
- (_("%B: unable to initialize decompress status for section %s"),
+ (_("%pB: unable to initialize decompress status for section %s"),
abfd, name);
return FALSE;
}
ECOFF as well. */
const bfd_target *
coff_real_object_p (bfd *,
- unsigned,
- struct internal_filehdr *,
- struct internal_aouthdr *);
+ unsigned,
+ struct internal_filehdr *,
+ struct internal_aouthdr *);
const bfd_target *
coff_real_object_p (bfd *abfd,
unsigned nscns,
if (limit == 0)
{
/* This may be from the backend linker, in which case the
- lineno_count in the sections is correct. */
+ lineno_count in the sections is correct. */
for (s = abfd->sections; s != NULL; s = s->next)
total += s->lineno_count;
return total;
coff_symbol_type *q = coffsymbol (q_maybe);
/* The AIX 4.1 compiler can sometimes generate line numbers
- attached to debugging symbols. We try to simply ignore
- those here. */
+ attached to debugging symbols. We try to simply ignore
+ those here. */
if (q->lineno != NULL
&& q->symbol.section->owner != NULL)
{
/* This symbol has line numbers. Increment the owning
- section's linenumber count. */
+ section's linenumber count. */
alent *l = q->lineno;
do
syment->n_value = (coff_symbol_ptr->symbol.value
+ coff_symbol_ptr->symbol.section->output_offset);
if (! obj_pe (abfd))
- {
- syment->n_value += (syment->n_sclass == C_STATLAB)
- ? coff_symbol_ptr->symbol.section->output_section->lma
- : coff_symbol_ptr->symbol.section->output_section->vma;
- }
+ {
+ syment->n_value += (syment->n_sclass == C_STATLAB)
+ ? coff_symbol_ptr->symbol.section->output_section->lma
+ : coff_symbol_ptr->symbol.section->output_section->vma;
+ }
}
else
{
if (s->fix_line)
{
/* The value is the offset into the line number entries
- for the symbol's section. On output, the symbol's
- section should be N_DEBUG. */
+ for the symbol's section. On output, the symbol's
+ section should be N_DEBUG. */
s->u.syment.n_value =
(coff_symbol_ptr->symbol.section->output_section->line_filepos
+ s->u.syment.n_value * bfd_coff_linesz (bfd_ptr));
if (bfd_coff_force_symnames_in_strings (abfd))
{
- native->u.syment._n._n_n._n_offset =
+ native->u.syment._n._n_n._n_offset =
(*string_size_p + STRING_SIZE_SIZE);
native->u.syment._n._n_n._n_zeroes = 0;
*string_size_p += 6; /* strlen(".file") + 1 */
}
else
- strncpy (native->u.syment._n._n_name, ".file", SYMNMLEN);
+ strncpy (native->u.syment._n._n_name, ".file", SYMNMLEN);
BFD_ASSERT (! (native + 1)->is_sym);
auxent = &(native + 1)->u.auxent;
{
symbol->name = "";
if (isym != NULL)
- memset (isym, 0, sizeof (*isym));
+ memset (isym, 0, sizeof (*isym));
return TRUE;
}
native = dummy;
else if (symbol->flags & BSF_DEBUGGING)
{
/* There isn't much point to writing out a debugging symbol
- unless we are prepared to convert it into COFF debugging
- format. So, we just ignore them. We must clobber the symbol
- name to keep it from being put in the string table. */
+ unless we are prepared to convert it into COFF debugging
+ format. So, we just ignore them. We must clobber the symbol
+ name to keep it from being put in the string table. */
symbol->name = "";
if (isym != NULL)
- memset (isym, 0, sizeof (*isym));
+ memset (isym, 0, sizeof (*isym));
return TRUE;
}
else
native->u.syment.n_value += output_section->vma;
/* Copy the any flags from the file header into the symbol.
- FIXME: Why? */
+ FIXME: Why? */
{
coff_symbol_type *c = coff_symbol_from (symbol);
if (c != (coff_symbol_type *) NULL)
else
{
/* We would normally not write anything here, but we'll write
- out 4 so that any stupid coff reader which tries to read the
- string table even when there isn't one won't croak. */
+ out 4 so that any stupid coff reader which tries to read the
+ string table even when there isn't one won't croak. */
unsigned int size = STRING_SIZE_SIZE;
bfd_byte buffer[STRING_SIZE_SIZE];
combined_entry_type *table_base,
combined_entry_type *symbol,
unsigned int indaux,
- combined_entry_type *auxent)
+ combined_entry_type *auxent,
+ combined_entry_type *table_end)
{
unsigned int type = symbol->u.syment.n_type;
unsigned int n_sclass = symbol->u.syment.n_sclass;
if ((ISFCN (type) || ISTAG (n_sclass) || n_sclass == C_BLOCK
|| n_sclass == C_FCN)
- && auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l > 0)
+ && auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l > 0
+ && auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l
+ < (long) obj_raw_syment_count (abfd)
+ && table_base + auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l
+ < table_end)
{
auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p =
table_base + auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l;
auxent->fix_end = 1;
}
+
/* A negative tagndx is meaningless, but the SCO 3.2v4 cc can
generate one, so we must be careful to ignore it. */
- if (auxent->u.auxent.x_sym.x_tagndx.l > 0)
+ if ((unsigned long) auxent->u.auxent.x_sym.x_tagndx.l
+ < obj_raw_syment_count (abfd)
+ && table_base + auxent->u.auxent.x_sym.x_tagndx.l < table_end)
{
auxent->u.auxent.x_sym.x_tagndx.p =
table_base + auxent->u.auxent.x_sym.x_tagndx.l;
size = obj_raw_syment_count (abfd) * symesz;
if (size == 0)
return TRUE;
+ /* Check for integer overflow and for unreasonable symbol counts. */
+ if (size < obj_raw_syment_count (abfd)
+ || (bfd_get_file_size (abfd) > 0
+ && size > bfd_get_file_size (abfd)))
+
+ {
+ _bfd_error_handler (_("%pB: corrupt symbol count: %#" PRIx64 ""),
+ abfd, (uint64_t) obj_raw_syment_count (abfd));
+ return FALSE;
+ }
syms = bfd_malloc (size);
if (syms == NULL)
{
/* PR 21013: Provide an error message when the alloc fails. */
- _bfd_error_handler (_("%B: Not enough memory to allocate space for %lu symbols"),
- abfd, size);
+ _bfd_error_handler (_("%pB: not enough memory to allocate space "
+ "for %#" PRIx64 " symbols of size %#" PRIx64),
+ abfd, (uint64_t) obj_raw_syment_count (abfd),
+ (uint64_t) symesz);
return FALSE;
}
}
obj_coff_external_syms (abfd) = syms;
-
return TRUE;
}
#endif
}
- if (strsize < STRING_SIZE_SIZE)
+ if (strsize < STRING_SIZE_SIZE || strsize > bfd_get_file_size (abfd))
{
_bfd_error_handler
/* xgettext: c-format */
- (_("%B: bad string table size %lu"), abfd, (unsigned long) strsize);
+ (_("%pB: bad string table size %" PRIu64), abfd, (uint64_t) strsize);
bfd_set_error (bfd_error_bad_value);
return NULL;
}
bfd_boolean
_bfd_coff_free_symbols (bfd *abfd)
{
+ if (! bfd_family_coff (abfd))
+ return FALSE;
+
if (obj_coff_external_syms (abfd) != NULL
&& ! obj_coff_keep_syms (abfd))
{
free (obj_coff_external_syms (abfd));
obj_coff_external_syms (abfd) = NULL;
}
+
if (obj_coff_strings (abfd) != NULL
&& ! obj_coff_keep_strings (abfd))
{
obj_coff_strings (abfd) = NULL;
obj_coff_strings_len (abfd) = 0;
}
+
return TRUE;
}
return NULL;
size = obj_raw_syment_count (abfd) * sizeof (combined_entry_type);
+ /* Check for integer overflow. */
+ if (size < obj_raw_syment_count (abfd))
+ return NULL;
internal = (combined_entry_type *) bfd_zalloc (abfd, size);
if (internal == NULL && size != 0)
return NULL;
internal_ptr->is_sym = FALSE;
coff_pointerize_aux (abfd, internal, symbol_ptr, i,
- internal_ptr);
+ internal_ptr, internal_end);
}
}
else
{
/* Ordinary short filename, put into memory anyway. The
- Microsoft PE tools sometimes store a filename in
- multiple AUX entries. */
+ Microsoft PE tools sometimes store a filename in
+ multiple AUX entries. */
if (internal_ptr->u.syment.n_numaux > 1
&& coff_data (abfd)->pe)
internal_ptr->u.syment._n._n_n._n_offset =
char *newstring;
/* Find the length of this string without walking into memory
- that isn't ours. */
+ that isn't ours. */
for (i = 0; i < 8; ++i)
if (internal_ptr->u.syment._n._n_name[i] == '\0')
break;
else if (!bfd_coff_symname_in_debug (abfd, &internal_ptr->u.syment))
{
/* Long name already. Point symbol at the string in the
- table. */
+ table. */
if (string_table == NULL)
{
string_table = _bfd_coff_read_string_table (abfd);
bfd_set_error (bfd_error_invalid_operation);
return -1;
}
+#if SIZEOF_LONG == SIZEOF_INT
+ if (asect->reloc_count >= LONG_MAX / sizeof (arelent *))
+ {
+ bfd_set_error (bfd_error_file_too_big);
+ return -1;
+ }
+#endif
return (asect->reloc_count + 1) * sizeof (arelent *);
}
bfd_boolean
coff_find_nearest_line_with_names (bfd *abfd,
- asymbol **symbols,
- asection *section,
- bfd_vma offset,
- const char **filename_ptr,
- const char **functionname_ptr,
- unsigned int *line_ptr,
- const struct dwarf_debug_section *debug_sections)
+ asymbol **symbols,
+ asection *section,
+ bfd_vma offset,
+ const char **filename_ptr,
+ const char **functionname_ptr,
+ unsigned int *line_ptr,
+ const struct dwarf_debug_section *debug_sections)
{
bfd_boolean found;
unsigned int i;
/* Also try examining DWARF2 debugging information. */
if (_bfd_dwarf2_find_nearest_line (abfd, symbols, NULL, section, offset,
filename_ptr, functionname_ptr,
- line_ptr, NULL, debug_sections, 0,
+ line_ptr, NULL, debug_sections,
&coff_data(abfd)->dwarf2_find_line_info))
return TRUE;
+ sec_data = coff_section_data (abfd, section);
+
/* If the DWARF lookup failed, but there is DWARF information available
then the problem might be that the file has been rebased. This tool
changes the VMAs of all the sections, but it does not update the DWARF
information. So try again, using a bias against the address sought. */
if (coff_data (abfd)->dwarf2_find_line_info != NULL)
{
- bfd_signed_vma bias;
+ bfd_signed_vma bias = 0;
- bias = _bfd_dwarf2_find_symbol_bias (symbols,
- & coff_data (abfd)->dwarf2_find_line_info);
+ /* Create a cache of the result for the next call. */
+ if (sec_data == NULL && section->owner == abfd)
+ {
+ amt = sizeof (struct coff_section_tdata);
+ section->used_by_bfd = bfd_zalloc (abfd, amt);
+ sec_data = (struct coff_section_tdata *) section->used_by_bfd;
+ }
+
+ if (sec_data != NULL && sec_data->saved_bias)
+ bias = sec_data->saved_bias;
+ else if (symbols)
+ {
+ bias = _bfd_dwarf2_find_symbol_bias (symbols,
+ & coff_data (abfd)->dwarf2_find_line_info);
+
+ if (sec_data)
+ {
+ sec_data->saved_bias = TRUE;
+ sec_data->bias = bias;
+ }
+ }
if (bias
&& _bfd_dwarf2_find_nearest_line (abfd, symbols, NULL, section,
offset + bias,
filename_ptr, functionname_ptr,
- line_ptr, NULL, debug_sections, 0,
+ line_ptr, NULL, debug_sections,
&coff_data(abfd)->dwarf2_find_line_info))
return TRUE;
}
file_addr += coff_section_from_bfd_index (abfd,
p2->u.syment.n_scnum)->vma;
/* We use <= MAXDIFF here so that if we get a zero length
- file, we actually use the next file entry. */
+ file, we actually use the next file entry. */
if (p2 < pend
&& offset + sec_vma >= file_addr
&& offset + sec_vma - file_addr <= maxdiff)
}
}
- /* Now wander though the raw linenumbers of the section. */
- /* If we have been called on this section before, and the offset we
- want is further down then we can prime the lookup loop. */
- sec_data = coff_section_data (abfd, section);
+ if (section->lineno_count == 0)
+ {
+ *functionname_ptr = NULL;
+ *line_ptr = 0;
+ return TRUE;
+ }
+
+ /* Now wander though the raw linenumbers of the section.
+ If we have been called on this section before, and the offset
+ we want is further down then we can prime the lookup loop. */
if (sec_data != NULL
&& sec_data->i > 0
&& offset >= sec_data->offset)
coff_symbol_type *coff = (coff_symbol_type *) (l->u.sym);
if (coff->symbol.value > offset)
break;
+
*functionname_ptr = coff->symbol.name;
last_value = coff->symbol.value;
if (coff->native)
section->used_by_bfd = bfd_zalloc (abfd, amt);
sec_data = (struct coff_section_tdata *) section->used_by_bfd;
}
+
if (sec_data != NULL)
{
sec_data->offset = offset;
if (discriminator_ptr)
*discriminator_ptr = 0;
return coff_find_nearest_line_with_names (abfd, symbols, section, offset,
- filename_ptr, functionname_ptr,
- line_ptr, dwarf_debug_sections);
+ filename_ptr, functionname_ptr,
+ line_ptr, dwarf_debug_sections);
}
bfd_boolean
/* Change the class of a coff symbol held by BFD. */
bfd_boolean
-bfd_coff_set_symbol_class (bfd * abfd,
- asymbol * symbol,
- unsigned int symbol_class)
+bfd_coff_set_symbol_class (bfd * abfd,
+ asymbol * symbol,
+ unsigned int symbol_class)
{
coff_symbol_type * csym;
struct bfd_section_already_linked_hash_entry *already_linked_list;
struct coff_comdat_info *s_comdat;
+ if (sec->output_section == bfd_abs_section_ptr)
+ return FALSE;
+
flags = sec->flags;
if ((flags & SEC_LINK_ONCE) == 0)
return FALSE;
if (h != NULL)
{
switch (h->root.type)
- {
- case bfd_link_hash_defined:
- case bfd_link_hash_defweak:
- return h->root.u.def.section;
+ {
+ case bfd_link_hash_defined:
+ case bfd_link_hash_defweak:
+ return h->root.u.def.section;
- case bfd_link_hash_common:
- return h->root.u.c.p->section;
+ case bfd_link_hash_common:
+ return h->root.u.c.p->section;
- case bfd_link_hash_undefined:
case bfd_link_hash_undefweak:
- default:
- break;
- }
+ if (h->symbol_class == C_NT_WEAK && h->numaux == 1)
+ {
+ /* PE weak externals. A weak symbol may include an auxiliary
+ record indicating that if the weak symbol is not resolved,
+ another external symbol is used instead. */
+ struct coff_link_hash_entry *h2 =
+ h->auxbfd->tdata.coff_obj_data->sym_hashes[
+ h->aux->x_sym.x_tagndx.l];
+
+ if (h2 && h2->root.type != bfd_link_hash_undefined)
+ return h2->root.u.def.section;
+ }
+ break;
+
+ case bfd_link_hash_undefined:
+ default:
+ break;
+ }
return NULL;
}
struct coff_reloc_cookie cookie;
if (!init_reloc_cookie_for_section (&cookie, info, sec))
- ret = FALSE;
+ ret = FALSE;
else
- {
- for (; cookie.rel < cookie.relend; cookie.rel++)
- {
+ {
+ for (; cookie.rel < cookie.relend; cookie.rel++)
+ {
if (!_bfd_coff_gc_mark_reloc (info, sec, gc_mark_hook, &cookie))
{
ret = FALSE;
break;
}
}
- fini_reloc_cookie_for_section (&cookie, sec);
- }
+ fini_reloc_cookie_for_section (&cookie, sec);
+ }
}
return ret;
asection *isec;
bfd_boolean some_kept;
- if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
+ if (bfd_get_flavour (ibfd) != bfd_target_coff_flavour)
continue;
/* Ensure all linker created sections are kept, and see whether
for (o = sub->sections; o != NULL; o = o->next)
{
/* Keep debug and special sections. */
- if ((o->flags & (SEC_DEBUGGING | SEC_LINKER_CREATED)) != 0
+ if ((o->flags & (SEC_DEBUGGING | SEC_LINKER_CREATED)) != 0
|| (o->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0)
o->gc_mark = 1;
- else if (CONST_STRNEQ (o->name, ".idata")
+ else if (CONST_STRNEQ (o->name, ".idata")
|| CONST_STRNEQ (o->name, ".pdata")
|| CONST_STRNEQ (o->name, ".xdata")
|| CONST_STRNEQ (o->name, ".rsrc"))
if (info->print_gc_sections && o->size != 0)
/* xgettext: c-format */
- _bfd_error_handler (_("Removing unused section '%s' in file '%B'"), sub, o->name);
+ _bfd_error_handler (_("removing unused section '%pA' in file '%pB'"),
+ o, sub);
#if 0
/* But we also have to update some of the relocation
if (!bed->can_gc_sections
|| !is_coff_hash_table (info->hash))
{
- _bfd_error_handler(_("Warning: gc-sections option ignored"));
+ _bfd_error_handler(_("warning: gc-sections option ignored"));
return TRUE;
}
#endif
asection *o;
if (bfd_get_flavour (sub) != bfd_target_coff_flavour)
- continue;
+ continue;
for (o = sub->sections; o != NULL; o = o->next)
- {
+ {
if (((o->flags & (SEC_EXCLUDE | SEC_KEEP)) == SEC_KEEP
|| CONST_STRNEQ (o->name, ".vectors")
|| CONST_STRNEQ (o->name, ".ctors")
if (!_bfd_coff_gc_mark (info, o, _bfd_coff_gc_mark_hook))
return FALSE;
}
- }
+ }
}
/* Allow the backend to mark additional target specific sections. */