1,7 → 1,5 |
/* Support for the generic parts of COFF, for BFD. |
Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, |
2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 |
Free Software Foundation, Inc. |
Copyright (C) 1990-2015 Free Software Foundation, Inc. |
Written by Cygnus Support. |
|
This file is part of BFD, the Binary File Descriptor library. |
86,9 → 84,8 |
strings = _bfd_coff_read_string_table (abfd); |
if (strings == NULL) |
return FALSE; |
/* FIXME: For extra safety, we should make sure that |
strindex does not run us past the end, but right now we |
don't know the length of the string table. */ |
if ((bfd_size_type)(strindex + 2) >= obj_coff_strings_len (abfd)) |
return FALSE; |
strings += strindex; |
name = (char *) bfd_alloc (abfd, |
(bfd_size_type) strlen (strings) + 1 + 1); |
149,8 → 146,9 |
/* Compress/decompress DWARF debug sections with names: .debug_* and |
.zdebug_*, after the section flags is set. */ |
if ((flags & SEC_DEBUGGING) |
&& strlen (name) > 7 |
&& ((name[1] == 'd' && name[6] == '_') |
|| (name[1] == 'z' && name[7] == '_'))) |
|| (strlen (name) > 8 && name[1] == 'z' && name[7] == '_'))) |
{ |
enum { nothing, compress, decompress } action = nothing; |
char *new_name = NULL; |
180,6 → 178,8 |
abfd, name); |
return FALSE; |
} |
if (return_section->compress_status == COMPRESS_SECTION_DONE) |
{ |
if (name[1] != 'z') |
{ |
unsigned int len = strlen (name); |
191,6 → 191,7 |
new_name[1] = 'z'; |
memcpy (new_name + 2, name + 1, len); |
} |
} |
break; |
case decompress: |
if (!bfd_init_section_decompress_status (abfd, return_section)) |
368,6 → 369,10 |
bfd_release (abfd, opthdr); |
return NULL; |
} |
/* PR 17512: file: 11056-1136-0.004. */ |
if (internal_f.f_opthdr < aoutsz) |
memset (((char *) opthdr) + internal_f.f_opthdr, 0, aoutsz - internal_f.f_opthdr); |
|
bfd_coff_swap_aouthdr_in (abfd, opthdr, (void *) &internal_a); |
bfd_release (abfd, opthdr); |
} |
466,6 → 471,11 |
if (strings == NULL) |
return NULL; |
} |
/* PR 17910: Only check for string overflow if the length has been set. |
Some DLLs, eg those produced by Visual Studio, may not set the length field. */ |
if (obj_coff_strings_len (abfd) > 0 |
&& sym->_n._n_n._n_offset >= obj_coff_strings_len (abfd)) |
return NULL; |
return strings + sym->_n._n_n._n_offset; |
} |
} |
629,22 → 639,6 |
return total; |
} |
|
/* Takes a bfd and a symbol, returns a pointer to the coff specific |
area of the symbol if there is one. */ |
|
coff_symbol_type * |
coff_symbol_from (bfd *ignore_abfd ATTRIBUTE_UNUSED, |
asymbol *symbol) |
{ |
if (!bfd_family_coff (bfd_asymbol_bfd (symbol))) |
return (coff_symbol_type *) NULL; |
|
if (bfd_asymbol_bfd (symbol)->tdata.coff_obj_data == (coff_data_type *) NULL) |
return (coff_symbol_type *) NULL; |
|
return (coff_symbol_type *) symbol; |
} |
|
static void |
fixup_symbol_value (bfd *abfd, |
coff_symbol_type *coff_symbol_ptr, |
761,7 → 755,9 |
|
for (symbol_index = 0; symbol_index < symbol_count; symbol_index++) |
{ |
coff_symbol_type *coff_symbol_ptr = coff_symbol_from (bfd_ptr, symbol_ptr_ptr[symbol_index]); |
coff_symbol_type *coff_symbol_ptr; |
|
coff_symbol_ptr = coff_symbol_from (symbol_ptr_ptr[symbol_index]); |
symbol_ptr_ptr[symbol_index]->udata.i = symbol_index; |
if (coff_symbol_ptr && coff_symbol_ptr->native) |
{ |
768,6 → 764,7 |
combined_entry_type *s = coff_symbol_ptr->native; |
int i; |
|
BFD_ASSERT (s->is_sym); |
if (s->u.syment.n_sclass == C_FILE) |
{ |
if (last_file != NULL) |
804,14 → 801,15 |
|
for (symbol_index = 0; symbol_index < symbol_count; symbol_index++) |
{ |
coff_symbol_type *coff_symbol_ptr = |
coff_symbol_from (bfd_ptr, symbol_ptr_ptr[symbol_index]); |
coff_symbol_type *coff_symbol_ptr; |
|
coff_symbol_ptr = coff_symbol_from (symbol_ptr_ptr[symbol_index]); |
if (coff_symbol_ptr && coff_symbol_ptr->native) |
{ |
int i; |
combined_entry_type *s = coff_symbol_ptr->native; |
|
BFD_ASSERT (s->is_sym); |
if (s->fix_value) |
{ |
/* FIXME: We should use a union here. */ |
835,6 → 833,8 |
for (i = 0; i < s->u.syment.n_numaux; i++) |
{ |
combined_entry_type *a = s + i + 1; |
|
BFD_ASSERT (! a->is_sym); |
if (a->fix_tag) |
{ |
a->u.auxent.x_sym.x_tagndx.l = |
878,6 → 878,7 |
} |
name_length = strlen (name); |
|
BFD_ASSERT (native->is_sym); |
if (native->u.syment.n_sclass == C_FILE |
&& native->u.syment.n_numaux > 0) |
{ |
893,6 → 894,7 |
else |
strncpy (native->u.syment._n._n_name, ".file", SYMNMLEN); |
|
BFD_ASSERT (! (native + 1)->is_sym); |
auxent = &(native + 1)->u.auxent; |
|
filnmlen = bfd_coff_filnmlen (abfd); |
995,6 → 997,8 |
void * buf; |
bfd_size_type symesz; |
|
BFD_ASSERT (native->is_sym); |
|
if (native->u.syment.n_sclass == C_FILE) |
symbol->flags |= BSF_DEBUGGING; |
|
1035,6 → 1039,7 |
return FALSE; |
for (j = 0; j < native->u.syment.n_numaux; j++) |
{ |
BFD_ASSERT (! (native + j + 1)->is_sym); |
bfd_coff_swap_aux_out (abfd, |
&((native + j + 1)->u.auxent), |
type, n_sclass, (int) j, |
1084,6 → 1089,8 |
return TRUE; |
} |
native = dummy; |
native->is_sym = TRUE; |
native[1].is_sym = FALSE; |
native->u.syment.n_type = T_NULL; |
native->u.syment.n_flags = 0; |
native->u.syment.n_numaux = 0; |
1124,7 → 1131,7 |
/* Copy the any flags from the file header into the symbol. |
FIXME: Why? */ |
{ |
coff_symbol_type *c = coff_symbol_from (abfd, symbol); |
coff_symbol_type *c = coff_symbol_from (symbol); |
if (c != (coff_symbol_type *) NULL) |
native->u.syment.n_flags = bfd_asymbol_bfd (&c->symbol)->flags; |
} |
1169,6 → 1176,7 |
return TRUE; |
} |
|
BFD_ASSERT (native->is_sym); |
/* If this symbol has an associated line number, we must store the |
symbol index in the line number field. We also tag the auxent to |
point to the right place in the lineno table. */ |
1255,7 → 1263,7 |
for (p = abfd->outsymbols, i = 0; i < limit; i++, p++) |
{ |
asymbol *symbol = *p; |
coff_symbol_type *c_symbol = coff_symbol_from (abfd, symbol); |
coff_symbol_type *c_symbol = coff_symbol_from (symbol); |
|
if (c_symbol == (coff_symbol_type *) NULL |
|| c_symbol->native == (combined_entry_type *) NULL) |
1278,6 → 1286,7 |
symbol which has no associated section and we do not have to |
worry about this, all we need to know is that it is local. */ |
current_error_handler = bfd_set_error_handler (null_error_handler); |
BFD_ASSERT (c_symbol->native->is_sym); |
sym_class = bfd_coff_classify_symbol (abfd, |
&c_symbol->native->u.syment); |
(void) bfd_set_error_handler (current_error_handler); |
1354,7 → 1363,7 |
{ |
asymbol *q = *p; |
size_t name_length = strlen (q->name); |
coff_symbol_type *c_symbol = coff_symbol_from (abfd, q); |
coff_symbol_type *c_symbol = coff_symbol_from (q); |
size_t maxlen; |
|
/* Figure out whether the symbol name should go in the string |
1370,6 → 1379,9 |
file name, nor does it go in the .debug section. */ |
maxlen = bfd_coff_force_symnames_in_strings (abfd) ? 0 : SYMNMLEN; |
|
else if (! c_symbol->native->is_sym) |
maxlen = bfd_coff_force_symnames_in_strings (abfd) ? 0 : SYMNMLEN; |
|
else if (bfd_coff_symname_in_debug (abfd, |
&c_symbol->native->u.syment)) |
/* This symbol name is in the XCOFF .debug section. |
1460,6 → 1472,7 |
{ |
/* Found a linenumber entry, output. */ |
struct internal_lineno out; |
|
memset ((void *) & out, 0, sizeof (out)); |
out.l_lnno = 0; |
out.l_addr.l_symndx = l->u.offset; |
1507,6 → 1520,7 |
unsigned int type = symbol->u.syment.n_type; |
unsigned int n_sclass = symbol->u.syment.n_sclass; |
|
BFD_ASSERT (symbol->is_sym); |
if (coff_backend_info (abfd)->_bfd_coff_pointerize_aux_hook) |
{ |
if ((*coff_backend_info (abfd)->_bfd_coff_pointerize_aux_hook) |
1520,6 → 1534,7 |
if (n_sclass == C_FILE) |
return; |
|
BFD_ASSERT (! auxent->is_sym); |
/* Otherwise patch up. */ |
#define N_TMASK coff_data (abfd)->local_n_tmask |
#define N_BTSHFT coff_data (abfd)->local_n_btshft |
1547,7 → 1562,7 |
we didn't want to go to the trouble until someone needed it. */ |
|
static char * |
build_debug_section (bfd *abfd) |
build_debug_section (bfd *abfd, asection ** sect_return) |
{ |
char *debug_section; |
file_ptr position; |
1575,6 → 1590,8 |
|| bfd_bread (debug_section, sec_size, abfd) != sec_size |
|| bfd_seek (abfd, position, SEEK_SET) != 0) |
return NULL; |
|
* sect_return = sect; |
return debug_section; |
} |
|
1637,7 → 1654,9 |
|
/* Read in the external strings. The strings are not loaded until |
they are needed. This is because we have no simple way of |
detecting a missing string table in an archive. */ |
detecting a missing string table in an archive. If the strings |
are loaded then the STRINGS and STRINGS_LEN fields in the |
coff_tdata structure will be set. */ |
|
const char * |
_bfd_coff_read_string_table (bfd *abfd) |
1687,10 → 1706,16 |
return NULL; |
} |
|
strings = (char *) bfd_malloc (strsize); |
strings = (char *) bfd_malloc (strsize + 1); |
if (strings == NULL) |
return NULL; |
|
/* PR 17521 file: 079-54929-0.004. |
A corrupt file could contain an index that points into the first |
STRING_SIZE_SIZE bytes of the string table, so make sure that |
they are zero. */ |
memset (strings, 0, STRING_SIZE_SIZE); |
|
if (bfd_bread (strings + STRING_SIZE_SIZE, strsize - STRING_SIZE_SIZE, abfd) |
!= strsize - STRING_SIZE_SIZE) |
{ |
1699,7 → 1724,9 |
} |
|
obj_coff_strings (abfd) = strings; |
|
obj_coff_strings_len (abfd) = strsize; |
/* Terminate the string table, just in case. */ |
strings[strsize] = 0; |
return strings; |
} |
|
1719,6 → 1746,7 |
{ |
free (obj_coff_strings (abfd)); |
obj_coff_strings (abfd) = NULL; |
obj_coff_strings_len (abfd) = 0; |
} |
return TRUE; |
} |
1739,12 → 1767,16 |
char *raw_src; |
char *raw_end; |
const char *string_table = NULL; |
char *debug_section = NULL; |
asection * debug_sec = NULL; |
char *debug_sec_data = NULL; |
bfd_size_type size; |
|
if (obj_raw_syments (abfd) != NULL) |
return obj_raw_syments (abfd); |
|
if (! _bfd_coff_get_external_symbols (abfd)) |
return NULL; |
|
size = obj_raw_syment_count (abfd) * sizeof (combined_entry_type); |
internal = (combined_entry_type *) bfd_zalloc (abfd, size); |
if (internal == NULL && size != 0) |
1751,9 → 1783,6 |
return NULL; |
internal_end = internal + obj_raw_syment_count (abfd); |
|
if (! _bfd_coff_get_external_symbols (abfd)) |
return NULL; |
|
raw_src = (char *) obj_coff_external_syms (abfd); |
|
/* Mark the end of the symbols. */ |
1768,17 → 1797,35 |
raw_src < raw_end; |
raw_src += symesz, internal_ptr++) |
{ |
unsigned int i; |
|
unsigned int i; |
bfd_coff_swap_sym_in (abfd, (void *) raw_src, |
(void *) & internal_ptr->u.syment); |
symbol_ptr = internal_ptr; |
internal_ptr->is_sym = TRUE; |
|
/* PR 17512: file: 1353-1166-0.004. */ |
if (symbol_ptr->u.syment.n_sclass == C_FILE |
&& symbol_ptr->u.syment.n_numaux > 0 |
&& raw_src + symesz + symbol_ptr->u.syment.n_numaux |
* symesz > raw_end) |
{ |
bfd_release (abfd, internal); |
return NULL; |
} |
|
for (i = 0; |
i < symbol_ptr->u.syment.n_numaux; |
i++) |
{ |
internal_ptr++; |
/* PR 17512: Prevent buffer overrun. */ |
if (internal_ptr >= internal_end) |
{ |
bfd_release (abfd, internal); |
return NULL; |
} |
|
raw_src += symesz; |
bfd_coff_swap_aux_in (abfd, (void *) raw_src, |
symbol_ptr->u.syment.n_type, |
1785,6 → 1832,8 |
symbol_ptr->u.syment.n_sclass, |
(int) i, symbol_ptr->u.syment.n_numaux, |
&(internal_ptr->u.auxent)); |
|
internal_ptr->is_sym = FALSE; |
coff_pointerize_aux (abfd, internal, symbol_ptr, i, |
internal_ptr); |
} |
1798,12 → 1847,18 |
for (internal_ptr = internal; internal_ptr < internal_end; |
internal_ptr++) |
{ |
BFD_ASSERT (internal_ptr->is_sym); |
|
if (internal_ptr->u.syment.n_sclass == C_FILE |
&& internal_ptr->u.syment.n_numaux > 0) |
{ |
combined_entry_type * aux = internal_ptr + 1; |
|
/* Make a file symbol point to the name in the auxent, since |
the text ".file" is redundant. */ |
if ((internal_ptr + 1)->u.auxent.x_file.x_n.x_zeroes == 0) |
BFD_ASSERT (! aux->is_sym); |
|
if (aux->u.auxent.x_file.x_n.x_zeroes == 0) |
{ |
/* The filename is a long one, point into the string table. */ |
if (string_table == NULL) |
1813,10 → 1868,12 |
return NULL; |
} |
|
if ((bfd_size_type)(aux->u.auxent.x_file.x_n.x_offset) |
>= obj_coff_strings_len (abfd)) |
internal_ptr->u.syment._n._n_n._n_offset = (bfd_hostptr_t) _("<corrupt>"); |
else |
internal_ptr->u.syment._n._n_n._n_offset = |
((bfd_hostptr_t) |
(string_table |
+ (internal_ptr + 1)->u.auxent.x_file.x_n.x_offset)); |
(bfd_hostptr_t) (string_table + (aux->u.auxent.x_file.x_n.x_offset)); |
} |
else |
{ |
1826,15 → 1883,15 |
if (internal_ptr->u.syment.n_numaux > 1 |
&& coff_data (abfd)->pe) |
internal_ptr->u.syment._n._n_n._n_offset = |
((bfd_hostptr_t) |
(bfd_hostptr_t) |
copy_name (abfd, |
(internal_ptr + 1)->u.auxent.x_file.x_fname, |
internal_ptr->u.syment.n_numaux * symesz)); |
aux->u.auxent.x_file.x_fname, |
internal_ptr->u.syment.n_numaux * symesz); |
else |
internal_ptr->u.syment._n._n_n._n_offset = |
((bfd_hostptr_t) |
copy_name (abfd, |
(internal_ptr + 1)->u.auxent.x_file.x_fname, |
aux->u.auxent.x_file.x_fname, |
(size_t) bfd_coff_filnmlen (abfd))); |
} |
} |
1871,6 → 1928,10 |
if (string_table == NULL) |
return NULL; |
} |
if (internal_ptr->u.syment._n._n_n._n_offset >= obj_coff_strings_len (abfd) |
|| string_table + internal_ptr->u.syment._n._n_n._n_offset < string_table) |
internal_ptr->u.syment._n._n_n._n_offset = (bfd_hostptr_t) _("<corrupt>"); |
else |
internal_ptr->u.syment._n._n_n._n_offset = |
((bfd_hostptr_t) |
(string_table |
1879,12 → 1940,23 |
else |
{ |
/* Long name in debug section. Very similar. */ |
if (debug_section == NULL) |
debug_section = build_debug_section (abfd); |
if (debug_sec_data == NULL) |
debug_sec_data = build_debug_section (abfd, & debug_sec); |
if (debug_sec_data != NULL) |
{ |
BFD_ASSERT (debug_sec != NULL); |
/* PR binutils/17512: Catch out of range offsets into the debug data. */ |
if (internal_ptr->u.syment._n._n_n._n_offset > debug_sec->size |
|| debug_sec_data + internal_ptr->u.syment._n._n_n._n_offset < debug_sec_data) |
internal_ptr->u.syment._n._n_n._n_offset = (bfd_hostptr_t) _("<corrupt>"); |
else |
internal_ptr->u.syment._n._n_n._n_offset = (bfd_hostptr_t) |
(debug_section + internal_ptr->u.syment._n._n_n._n_offset); |
(debug_sec_data + internal_ptr->u.syment._n._n_n._n_offset); |
} |
else |
internal_ptr->u.syment._n._n_n._n_offset = (bfd_hostptr_t) ""; |
} |
} |
internal_ptr += internal_ptr->u.syment.n_numaux; |
} |
|
1915,7 → 1987,7 |
if (new_symbol == NULL) |
return NULL; |
new_symbol->symbol.section = 0; |
new_symbol->native = 0; |
new_symbol->native = NULL; |
new_symbol->lineno = NULL; |
new_symbol->done_lineno = FALSE; |
new_symbol->symbol.the_bfd = abfd; |
1941,6 → 2013,7 |
new_symbol->native = (combined_entry_type *) bfd_zalloc (abfd, amt); |
if (!new_symbol->native) |
return NULL; |
new_symbol->native->is_sym = TRUE; |
new_symbol->symbol.section = bfd_abs_section_ptr; |
new_symbol->symbol.flags = BSF_DEBUGGING; |
new_symbol->lineno = NULL; |
1956,81 → 2029,12 |
bfd_symbol_info (symbol, ret); |
|
if (coffsymbol (symbol)->native != NULL |
&& coffsymbol (symbol)->native->fix_value) |
&& coffsymbol (symbol)->native->fix_value |
&& coffsymbol (symbol)->native->is_sym) |
ret->value = coffsymbol (symbol)->native->u.syment.n_value - |
(bfd_hostptr_t) obj_raw_syments (abfd); |
} |
|
/* Return the COFF syment for a symbol. */ |
|
bfd_boolean |
bfd_coff_get_syment (bfd *abfd, |
asymbol *symbol, |
struct internal_syment *psyment) |
{ |
coff_symbol_type *csym; |
|
csym = coff_symbol_from (abfd, symbol); |
if (csym == NULL || csym->native == NULL) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return FALSE; |
} |
|
*psyment = csym->native->u.syment; |
|
if (csym->native->fix_value) |
psyment->n_value = psyment->n_value - |
(bfd_hostptr_t) obj_raw_syments (abfd); |
|
/* FIXME: We should handle fix_line here. */ |
|
return TRUE; |
} |
|
/* Return the COFF auxent for a symbol. */ |
|
bfd_boolean |
bfd_coff_get_auxent (bfd *abfd, |
asymbol *symbol, |
int indx, |
union internal_auxent *pauxent) |
{ |
coff_symbol_type *csym; |
combined_entry_type *ent; |
|
csym = coff_symbol_from (abfd, symbol); |
|
if (csym == NULL |
|| csym->native == NULL |
|| indx >= csym->native->u.syment.n_numaux) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
return FALSE; |
} |
|
ent = csym->native + indx + 1; |
|
*pauxent = ent->u.auxent; |
|
if (ent->fix_tag) |
pauxent->x_sym.x_tagndx.l = |
((combined_entry_type *) pauxent->x_sym.x_tagndx.p |
- obj_raw_syments (abfd)); |
|
if (ent->fix_end) |
pauxent->x_sym.x_fcnary.x_fcn.x_endndx.l = |
((combined_entry_type *) pauxent->x_sym.x_fcnary.x_fcn.x_endndx.p |
- obj_raw_syments (abfd)); |
|
if (ent->fix_scnlen) |
pauxent->x_csect.x_scnlen.l = |
((combined_entry_type *) pauxent->x_csect.x_scnlen.p |
- obj_raw_syments (abfd)); |
|
return TRUE; |
} |
|
/* Print out information about COFF symbol. */ |
|
void |
2064,6 → 2068,15 |
|
fprintf (file, "[%3ld]", (long) (combined - root)); |
|
/* PR 17512: file: 079-33786-0.001:0.1. */ |
if (combined < obj_raw_syments (abfd) |
|| combined >= obj_raw_syments (abfd) + obj_raw_syment_count (abfd)) |
{ |
fprintf (file, _("<corrupt info> %s"), symbol->name); |
break; |
} |
|
BFD_ASSERT (combined->is_sym); |
if (! combined->fix_value) |
val = (bfd_vma) combined->u.syment.n_value; |
else |
2083,6 → 2096,7 |
combined_entry_type *auxp = combined + aux + 1; |
long tagndx; |
|
BFD_ASSERT (! auxp->is_sym); |
if (auxp->fix_tag) |
tagndx = auxp->u.auxent.x_sym.x_tagndx.p - root; |
else |
2157,8 → 2171,11 |
l++; |
while (l->line_number) |
{ |
if (l->line_number > 0) |
{ |
fprintf (file, "\n%4d : ", l->line_number); |
bfd_fprintf_vma (abfd, file, l->u.offset + symbol->section->vma); |
} |
l++; |
} |
} |
2193,13 → 2210,13 |
|
bfd_boolean |
coff_find_nearest_line_with_names (bfd *abfd, |
const struct dwarf_debug_section *debug_sections, |
asymbol **symbols, |
asection *section, |
asymbol **symbols, |
bfd_vma offset, |
const char **filename_ptr, |
const char **functionname_ptr, |
unsigned int *line_ptr) |
unsigned int *line_ptr, |
const struct dwarf_debug_section *debug_sections) |
{ |
bfd_boolean found; |
unsigned int i; |
2224,13 → 2241,32 |
return TRUE; |
|
/* Also try examining DWARF2 debugging information. */ |
if (_bfd_dwarf2_find_nearest_line (abfd, debug_sections, |
section, symbols, offset, |
if (_bfd_dwarf2_find_nearest_line (abfd, symbols, NULL, section, offset, |
filename_ptr, functionname_ptr, |
line_ptr, NULL, 0, |
line_ptr, NULL, debug_sections, 0, |
&coff_data(abfd)->dwarf2_find_line_info)) |
return TRUE; |
|
/* 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; |
|
bias = _bfd_dwarf2_find_symbol_bias (symbols, |
& coff_data (abfd)->dwarf2_find_line_info); |
|
if (bias |
&& _bfd_dwarf2_find_nearest_line (abfd, symbols, NULL, section, |
offset + bias, |
filename_ptr, functionname_ptr, |
line_ptr, NULL, debug_sections, 0, |
&coff_data(abfd)->dwarf2_find_line_info)) |
return TRUE; |
} |
|
*filename_ptr = 0; |
*functionname_ptr = 0; |
*line_ptr = 0; |
2250,6 → 2286,7 |
pend = p + cof->raw_syment_count; |
while (p < pend) |
{ |
BFD_ASSERT (p->is_sym); |
if (p->u.syment.n_sclass == C_FILE) |
break; |
p += 1 + p->u.syment.n_numaux; |
2273,6 → 2310,7 |
p2 < pend; |
p2 += 1 + p2->u.syment.n_numaux) |
{ |
BFD_ASSERT (p2->is_sym); |
if (p2->u.syment.n_scnum > 0 |
&& (section |
== coff_section_from_bfd_index (abfd, |
2284,6 → 2322,8 |
break; |
} |
} |
if (p2 >= pend) |
break; |
|
file_addr = (bfd_vma) p2->u.syment.n_value; |
/* PR 11512: Include the section address of the function name symbol. */ |
2348,6 → 2388,8 |
if (coff->native) |
{ |
combined_entry_type *s = coff->native; |
|
BFD_ASSERT (s->is_sym); |
s = s + 1 + s->u.syment.n_numaux; |
|
/* In XCOFF a debugging symbol can follow the |
2360,6 → 2402,7 |
{ |
/* The linenumber is stored in the auxent. */ |
union internal_auxent *a = &((s + 1)->u.auxent); |
|
line_base = a->x_sym.x_misc.x_lnsz.x_lnno; |
*line_ptr = line_base; |
} |
2409,37 → 2452,21 |
|
bfd_boolean |
coff_find_nearest_line (bfd *abfd, |
asection *section, |
asymbol **symbols, |
bfd_vma offset, |
const char **filename_ptr, |
const char **functionname_ptr, |
unsigned int *line_ptr) |
{ |
return coff_find_nearest_line_with_names (abfd, dwarf_debug_sections, |
section, symbols, offset, |
filename_ptr, functionname_ptr, |
line_ptr); |
} |
|
bfd_boolean |
coff_find_nearest_line_discriminator (bfd *abfd, |
asection *section, |
asymbol **symbols, |
bfd_vma offset, |
const char **filename_ptr, |
const char **functionname_ptr, |
unsigned int *line_ptr, |
unsigned int *discriminator) |
unsigned int *discriminator_ptr) |
{ |
*discriminator = 0; |
return coff_find_nearest_line_with_names (abfd, dwarf_debug_sections, |
section, symbols, offset, |
if (discriminator_ptr) |
*discriminator_ptr = 0; |
return coff_find_nearest_line_with_names (abfd, symbols, section, offset, |
filename_ptr, functionname_ptr, |
line_ptr); |
line_ptr, dwarf_debug_sections); |
} |
|
|
bfd_boolean |
coff_find_inliner_info (bfd *abfd, |
const char **filename_ptr, |
2459,7 → 2486,7 |
{ |
size_t size; |
|
if (!info->relocatable) |
if (!bfd_link_relocatable (info)) |
size = bfd_coff_filhsz (abfd) + bfd_coff_aoutsz (abfd); |
else |
size = bfd_coff_filhsz (abfd); |
2477,7 → 2504,7 |
{ |
coff_symbol_type * csym; |
|
csym = coff_symbol_from (abfd, symbol); |
csym = coff_symbol_from (symbol); |
if (csym == NULL) |
{ |
bfd_set_error (bfd_error_invalid_operation); |
2497,6 → 2524,7 |
if (native == NULL) |
return FALSE; |
|
native->is_sym = TRUE; |
native->u.syment.n_type = T_NULL; |
native->u.syment.n_sclass = symbol_class; |
|
2532,16 → 2560,6 |
return TRUE; |
} |
|
struct coff_comdat_info * |
bfd_coff_get_comdat_section (bfd *abfd, struct bfd_section *sec) |
{ |
if (bfd_get_flavour (abfd) == bfd_target_coff_flavour |
&& coff_section_data (abfd, sec) != NULL) |
return coff_section_data (abfd, sec)->comdat; |
else |
return NULL; |
} |
|
bfd_boolean |
_bfd_coff_section_already_linked (bfd *abfd, |
asection *sec, |
2608,3 → 2626,431 |
info->callbacks->einfo (_("%F%P: already_linked_table: %E\n")); |
return FALSE; |
} |
|
/* Initialize COOKIE for input bfd ABFD. */ |
|
static bfd_boolean |
init_reloc_cookie (struct coff_reloc_cookie *cookie, |
struct bfd_link_info *info ATTRIBUTE_UNUSED, |
bfd *abfd) |
{ |
/* Sometimes the symbol table does not yet have been loaded here. */ |
bfd_coff_slurp_symbol_table (abfd); |
|
cookie->abfd = abfd; |
cookie->sym_hashes = obj_coff_sym_hashes (abfd); |
|
cookie->symbols = obj_symbols (abfd); |
|
return TRUE; |
} |
|
/* Free the memory allocated by init_reloc_cookie, if appropriate. */ |
|
static void |
fini_reloc_cookie (struct coff_reloc_cookie *cookie ATTRIBUTE_UNUSED, |
bfd *abfd ATTRIBUTE_UNUSED) |
{ |
/* Nothing to do. */ |
} |
|
/* Initialize the relocation information in COOKIE for input section SEC |
of input bfd ABFD. */ |
|
static bfd_boolean |
init_reloc_cookie_rels (struct coff_reloc_cookie *cookie, |
struct bfd_link_info *info ATTRIBUTE_UNUSED, |
bfd *abfd, |
asection *sec) |
{ |
if (sec->reloc_count == 0) |
{ |
cookie->rels = NULL; |
cookie->relend = NULL; |
cookie->rel = NULL; |
return TRUE; |
} |
|
cookie->rels = _bfd_coff_read_internal_relocs (abfd, sec, FALSE, NULL, 0, NULL); |
|
if (cookie->rels == NULL) |
return FALSE; |
|
cookie->rel = cookie->rels; |
cookie->relend = (cookie->rels + sec->reloc_count); |
return TRUE; |
} |
|
/* Free the memory allocated by init_reloc_cookie_rels, |
if appropriate. */ |
|
static void |
fini_reloc_cookie_rels (struct coff_reloc_cookie *cookie, |
asection *sec) |
{ |
if (cookie->rels && coff_section_data (NULL, sec)->relocs != cookie->rels) |
free (cookie->rels); |
} |
|
/* Initialize the whole of COOKIE for input section SEC. */ |
|
static bfd_boolean |
init_reloc_cookie_for_section (struct coff_reloc_cookie *cookie, |
struct bfd_link_info *info, |
asection *sec) |
{ |
if (!init_reloc_cookie (cookie, info, sec->owner)) |
return FALSE; |
|
if (!init_reloc_cookie_rels (cookie, info, sec->owner, sec)) |
{ |
fini_reloc_cookie (cookie, sec->owner); |
return FALSE; |
} |
return TRUE; |
} |
|
/* Free the memory allocated by init_reloc_cookie_for_section, |
if appropriate. */ |
|
static void |
fini_reloc_cookie_for_section (struct coff_reloc_cookie *cookie, |
asection *sec) |
{ |
fini_reloc_cookie_rels (cookie, sec); |
fini_reloc_cookie (cookie, sec->owner); |
} |
|
static asection * |
_bfd_coff_gc_mark_hook (asection *sec, |
struct bfd_link_info *info ATTRIBUTE_UNUSED, |
struct internal_reloc *rel ATTRIBUTE_UNUSED, |
struct coff_link_hash_entry *h, |
struct internal_syment *sym) |
{ |
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_common: |
return h->root.u.c.p->section; |
|
case bfd_link_hash_undefined: |
case bfd_link_hash_undefweak: |
default: |
break; |
} |
return NULL; |
} |
|
return coff_section_from_bfd_index (sec->owner, sym->n_scnum); |
} |
|
/* COOKIE->rel describes a relocation against section SEC, which is |
a section we've decided to keep. Return the section that contains |
the relocation symbol, or NULL if no section contains it. */ |
|
static asection * |
_bfd_coff_gc_mark_rsec (struct bfd_link_info *info, asection *sec, |
coff_gc_mark_hook_fn gc_mark_hook, |
struct coff_reloc_cookie *cookie) |
{ |
struct coff_link_hash_entry *h; |
|
h = cookie->sym_hashes[cookie->rel->r_symndx]; |
if (h != NULL) |
{ |
while (h->root.type == bfd_link_hash_indirect |
|| h->root.type == bfd_link_hash_warning) |
h = (struct coff_link_hash_entry *) h->root.u.i.link; |
|
return (*gc_mark_hook) (sec, info, cookie->rel, h, NULL); |
} |
|
return (*gc_mark_hook) (sec, info, cookie->rel, NULL, |
&(cookie->symbols |
+ obj_convert (sec->owner)[cookie->rel->r_symndx])->native->u.syment); |
} |
|
static bfd_boolean _bfd_coff_gc_mark |
(struct bfd_link_info *, asection *, coff_gc_mark_hook_fn); |
|
/* COOKIE->rel describes a relocation against section SEC, which is |
a section we've decided to keep. Mark the section that contains |
the relocation symbol. */ |
|
static bfd_boolean |
_bfd_coff_gc_mark_reloc (struct bfd_link_info *info, |
asection *sec, |
coff_gc_mark_hook_fn gc_mark_hook, |
struct coff_reloc_cookie *cookie) |
{ |
asection *rsec; |
|
rsec = _bfd_coff_gc_mark_rsec (info, sec, gc_mark_hook, cookie); |
if (rsec && !rsec->gc_mark) |
{ |
if (bfd_get_flavour (rsec->owner) != bfd_target_coff_flavour) |
rsec->gc_mark = 1; |
else if (!_bfd_coff_gc_mark (info, rsec, gc_mark_hook)) |
return FALSE; |
} |
return TRUE; |
} |
|
/* The mark phase of garbage collection. For a given section, mark |
it and any sections in this section's group, and all the sections |
which define symbols to which it refers. */ |
|
static bfd_boolean |
_bfd_coff_gc_mark (struct bfd_link_info *info, |
asection *sec, |
coff_gc_mark_hook_fn gc_mark_hook) |
{ |
bfd_boolean ret = TRUE; |
|
sec->gc_mark = 1; |
|
/* Look through the section relocs. */ |
if ((sec->flags & SEC_RELOC) != 0 |
&& sec->reloc_count > 0) |
{ |
struct coff_reloc_cookie cookie; |
|
if (!init_reloc_cookie_for_section (&cookie, info, sec)) |
ret = FALSE; |
else |
{ |
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); |
} |
} |
|
return ret; |
} |
|
static bfd_boolean |
_bfd_coff_gc_mark_extra_sections (struct bfd_link_info *info, |
coff_gc_mark_hook_fn mark_hook ATTRIBUTE_UNUSED) |
{ |
bfd *ibfd; |
|
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) |
{ |
asection *isec; |
bfd_boolean some_kept; |
|
if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) |
continue; |
|
/* Ensure all linker created sections are kept, and see whether |
any other section is already marked. */ |
some_kept = FALSE; |
for (isec = ibfd->sections; isec != NULL; isec = isec->next) |
{ |
if ((isec->flags & SEC_LINKER_CREATED) != 0) |
isec->gc_mark = 1; |
else if (isec->gc_mark) |
some_kept = TRUE; |
} |
|
/* If no section in this file will be kept, then we can |
toss out debug sections. */ |
if (!some_kept) |
continue; |
|
/* Keep debug and special sections like .comment when they are |
not part of a group, or when we have single-member groups. */ |
for (isec = ibfd->sections; isec != NULL; isec = isec->next) |
if ((isec->flags & SEC_DEBUGGING) != 0 |
|| (isec->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0) |
isec->gc_mark = 1; |
} |
return TRUE; |
} |
|
/* Sweep symbols in swept sections. Called via coff_link_hash_traverse. */ |
|
static bfd_boolean |
coff_gc_sweep_symbol (struct coff_link_hash_entry *h, |
void *data ATTRIBUTE_UNUSED) |
{ |
if (h->root.type == bfd_link_hash_warning) |
h = (struct coff_link_hash_entry *) h->root.u.i.link; |
|
if ((h->root.type == bfd_link_hash_defined |
|| h->root.type == bfd_link_hash_defweak) |
&& !h->root.u.def.section->gc_mark |
&& !(h->root.u.def.section->owner->flags & DYNAMIC)) |
{ |
/* Do our best to hide the symbol. */ |
h->root.u.def.section = bfd_und_section_ptr; |
h->symbol_class = C_HIDDEN; |
} |
|
return TRUE; |
} |
|
/* The sweep phase of garbage collection. Remove all garbage sections. */ |
|
typedef bfd_boolean (*gc_sweep_hook_fn) |
(bfd *, struct bfd_link_info *, asection *, const struct internal_reloc *); |
|
static bfd_boolean |
coff_gc_sweep (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) |
{ |
bfd *sub; |
|
for (sub = info->input_bfds; sub != NULL; sub = sub->link.next) |
{ |
asection *o; |
|
if (bfd_get_flavour (sub) != bfd_target_coff_flavour) |
continue; |
|
for (o = sub->sections; o != NULL; o = o->next) |
{ |
/* Keep debug and special sections. */ |
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") |
|| CONST_STRNEQ (o->name, ".pdata") |
|| CONST_STRNEQ (o->name, ".xdata") |
|| CONST_STRNEQ (o->name, ".rsrc")) |
o->gc_mark = 1; |
|
if (o->gc_mark) |
continue; |
|
/* Skip sweeping sections already excluded. */ |
if (o->flags & SEC_EXCLUDE) |
continue; |
|
/* Since this is early in the link process, it is simple |
to remove a section from the output. */ |
o->flags |= SEC_EXCLUDE; |
|
if (info->print_gc_sections && o->size != 0) |
_bfd_error_handler (_("Removing unused section '%s' in file '%B'"), sub, o->name); |
|
#if 0 |
/* But we also have to update some of the relocation |
info we collected before. */ |
if (gc_sweep_hook |
&& (o->flags & SEC_RELOC) != 0 |
&& o->reloc_count > 0 |
&& !bfd_is_abs_section (o->output_section)) |
{ |
struct internal_reloc *internal_relocs; |
bfd_boolean r; |
|
internal_relocs |
= _bfd_coff_link_read_relocs (o->owner, o, NULL, NULL, |
info->keep_memory); |
if (internal_relocs == NULL) |
return FALSE; |
|
r = (*gc_sweep_hook) (o->owner, info, o, internal_relocs); |
|
if (coff_section_data (o)->relocs != internal_relocs) |
free (internal_relocs); |
|
if (!r) |
return FALSE; |
} |
#endif |
} |
} |
|
/* Remove the symbols that were in the swept sections from the dynamic |
symbol table. */ |
coff_link_hash_traverse (coff_hash_table (info), coff_gc_sweep_symbol, |
NULL); |
|
return TRUE; |
} |
|
/* Keep all sections containing symbols undefined on the command-line, |
and the section containing the entry symbol. */ |
|
static void |
_bfd_coff_gc_keep (struct bfd_link_info *info) |
{ |
struct bfd_sym_chain *sym; |
|
for (sym = info->gc_sym_list; sym != NULL; sym = sym->next) |
{ |
struct coff_link_hash_entry *h; |
|
h = coff_link_hash_lookup (coff_hash_table (info), sym->name, |
FALSE, FALSE, FALSE); |
|
if (h != NULL |
&& (h->root.type == bfd_link_hash_defined |
|| h->root.type == bfd_link_hash_defweak) |
&& !bfd_is_abs_section (h->root.u.def.section)) |
h->root.u.def.section->flags |= SEC_KEEP; |
} |
} |
|
/* Do mark and sweep of unused sections. */ |
|
bfd_boolean |
bfd_coff_gc_sections (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) |
{ |
bfd *sub; |
|
/* FIXME: Should we implement this? */ |
#if 0 |
const bfd_coff_backend_data *bed = coff_backend_info (abfd); |
|
if (!bed->can_gc_sections |
|| !is_coff_hash_table (info->hash)) |
{ |
(*_bfd_error_handler)(_("Warning: gc-sections option ignored")); |
return TRUE; |
} |
#endif |
|
_bfd_coff_gc_keep (info); |
|
/* Grovel through relocs to find out who stays ... */ |
for (sub = info->input_bfds; sub != NULL; sub = sub->link.next) |
{ |
asection *o; |
|
if (bfd_get_flavour (sub) != bfd_target_coff_flavour) |
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") |
|| CONST_STRNEQ (o->name, ".dtors")) |
&& !o->gc_mark) |
{ |
if (!_bfd_coff_gc_mark (info, o, _bfd_coff_gc_mark_hook)) |
return FALSE; |
} |
} |
} |
|
/* Allow the backend to mark additional target specific sections. */ |
_bfd_coff_gc_mark_extra_sections (info, _bfd_coff_gc_mark_hook); |
|
/* ... and mark SEC_EXCLUDE for those that go. */ |
return coff_gc_sweep (abfd, info); |
} |