static bfd_boolean _bfd_get_file_window_malloc(bfd *abfd, ufile_ptr offset, bfd_size_type size, bfd_window *windowp, bfd_window_internal *i, bfd_boolean writable ATTRIBUTE_UNUSED) { static size_t pagesize; size_t size_to_alloc = size; /* Make sure we know the page size, so we can be friendly to mmap: */ if (pagesize == 0) pagesize = getpagesize(); if (pagesize == 0) abort(); # if HAVE_MPROTECT if (!writable) { size_to_alloc += (pagesize - 1); size_to_alloc -= (size_to_alloc % pagesize); } # endif /* HAVE_MPROTECT */ if (debug_windows) fprintf(stderr, "\n\t%s(%6ld)", (i->data ? "realloc" : " malloc"), (long)size_to_alloc); i->data = (PTR)bfd_realloc(i->data, size_to_alloc); if (debug_windows) fprintf(stderr, "\t-> %p\n", i->data); i->refcount = 1; if (i->data == NULL) { if (size_to_alloc == 0) return TRUE; bfd_set_error(bfd_error_no_memory); return FALSE; } if (bfd_seek(abfd, offset, SEEK_SET) != 0) return FALSE; i->size = bfd_bread(i->data, size, abfd); if (i->size != size) return FALSE; i->mapped = 0; # if HAVE_MPROTECT if (!writable) { if (debug_windows) fprintf(stderr, "\tmprotect (%p, %ld, PROT_READ)\n", i->data, (long)i->size); mprotect(i->data, i->size, PROT_READ); } # endif /* HAVE_MPROTECT */ windowp->data = i->data; windowp->size = i->size; return TRUE; }
bfd_size_type bfd_bwrite (const void *ptr, bfd_size_type size, bfd *abfd) { size_t nwrote; if ((abfd->flags & BFD_IN_MEMORY) != 0) { struct bfd_in_memory *bim = abfd->iostream; size = (size_t) size; if (abfd->where + size > bim->size) { bfd_size_type newsize, oldsize; oldsize = (bim->size + 127) & ~(bfd_size_type) 127; bim->size = abfd->where + size; /* Round up to cut down on memory fragmentation */ newsize = (bim->size + 127) & ~(bfd_size_type) 127; if (newsize > oldsize) { bim->buffer = bfd_realloc (bim->buffer, newsize); if (bim->buffer == 0) { bim->size = 0; return 0; } } } memcpy (bim->buffer + abfd->where, ptr, (size_t) size); abfd->where += size; return size; } if (abfd->iovec) nwrote = abfd->iovec->bwrite (abfd, ptr, size); else nwrote = 0; if (nwrote != (size_t) -1) abfd->where += nwrote; if (nwrote != size) { #ifdef ENOSPC errno = ENOSPC; #endif bfd_set_error (bfd_error_system_call); } return nwrote; }
bfd_size_type _bfd_elf_strtab_add (struct elf_strtab_hash *tab, const char *str, bfd_boolean copy) { register struct elf_strtab_hash_entry *entry; /* We handle this specially, since we don't want to do refcounting on it. */ if (*str == '\0') return 0; BFD_ASSERT (tab->sec_size == 0); entry = (struct elf_strtab_hash_entry *) bfd_hash_lookup (&tab->table, str, TRUE, copy); if (entry == NULL) return (bfd_size_type) -1; entry->refcount++; if (entry->len == 0) { entry->len = strlen (str) + 1; /* 2G strings lose. */ BFD_ASSERT (entry->len > 0); if (tab->size == tab->alloced) { bfd_size_type amt = sizeof (struct elf_strtab_hash_entry *); tab->alloced *= 2; tab->array = bfd_realloc (tab->array, tab->alloced * amt); if (tab->array == NULL) return (bfd_size_type) -1; } entry->u.index = tab->size++; tab->array[entry->u.index] = entry; } return entry->u.index; }
bfd_boolean _bfd_elf_discard_section_eh_frame (bfd *abfd, struct bfd_link_info *info, asection *sec, bfd_boolean (*reloc_symbol_deleted_p) (bfd_vma, void *), struct elf_reloc_cookie *cookie) { #define REQUIRE(COND) \ do \ if (!(COND)) \ goto free_no_table; \ while (0) bfd_byte *ehbuf = NULL, *buf; bfd_byte *last_fde; struct eh_cie_fde *ent, *this_inf; unsigned int hdr_length, hdr_id; struct extended_cie { struct cie cie; unsigned int offset; unsigned int usage_count; unsigned int entry; } *ecies = NULL, *ecie; unsigned int ecie_count = 0, ecie_alloced = 0; struct cie *cie; struct elf_link_hash_table *htab; struct eh_frame_hdr_info *hdr_info; struct eh_frame_sec_info *sec_info = NULL; unsigned int offset; unsigned int ptr_size; unsigned int entry_alloced; if (sec->size == 0) { /* This file does not contain .eh_frame information. */ return FALSE; } if (bfd_is_abs_section (sec->output_section)) { /* At least one of the sections is being discarded from the link, so we should just ignore them. */ return FALSE; } htab = elf_hash_table (info); hdr_info = &htab->eh_info; if (hdr_info->cies == NULL && !info->relocatable) hdr_info->cies = htab_try_create (1, cie_hash, cie_eq, free); /* Read the frame unwind information from abfd. */ REQUIRE (bfd_malloc_and_get_section (abfd, sec, &ehbuf)); if (sec->size >= 4 && bfd_get_32 (abfd, ehbuf) == 0 && cookie->rel == cookie->relend) { /* Empty .eh_frame section. */ free (ehbuf); return FALSE; } /* If .eh_frame section size doesn't fit into int, we cannot handle it (it would need to use 64-bit .eh_frame format anyway). */ REQUIRE (sec->size == (unsigned int) sec->size); ptr_size = (get_elf_backend_data (abfd) ->elf_backend_eh_frame_address_size (abfd, sec)); REQUIRE (ptr_size != 0); buf = ehbuf; sec_info = bfd_zmalloc (sizeof (struct eh_frame_sec_info) + 99 * sizeof (struct eh_cie_fde)); REQUIRE (sec_info); entry_alloced = 100; #define ENSURE_NO_RELOCS(buf) \ REQUIRE (!(cookie->rel < cookie->relend \ && (cookie->rel->r_offset \ < (bfd_size_type) ((buf) - ehbuf)) \ && cookie->rel->r_info != 0)) #define SKIP_RELOCS(buf) \ while (cookie->rel < cookie->relend \ && (cookie->rel->r_offset \ < (bfd_size_type) ((buf) - ehbuf))) \ cookie->rel++ #define GET_RELOC(buf) \ ((cookie->rel < cookie->relend \ && (cookie->rel->r_offset \ == (bfd_size_type) ((buf) - ehbuf))) \ ? cookie->rel : NULL) for (;;) { char *aug; bfd_byte *start, *end, *insns, *insns_end; bfd_size_type length; unsigned int set_loc_count; if (sec_info->count == entry_alloced) { sec_info = bfd_realloc (sec_info, sizeof (struct eh_frame_sec_info) + ((entry_alloced + 99) * sizeof (struct eh_cie_fde))); REQUIRE (sec_info); memset (&sec_info->entry[entry_alloced], 0, 100 * sizeof (struct eh_cie_fde)); entry_alloced += 100; } this_inf = sec_info->entry + sec_info->count; last_fde = buf; if ((bfd_size_type) (buf - ehbuf) == sec->size) break; /* Read the length of the entry. */ REQUIRE (skip_bytes (&buf, ehbuf + sec->size, 4)); hdr_length = bfd_get_32 (abfd, buf - 4); /* 64-bit .eh_frame is not supported. */ REQUIRE (hdr_length != 0xffffffff); /* The CIE/FDE must be fully contained in this input section. */ REQUIRE ((bfd_size_type) (buf - ehbuf) + hdr_length <= sec->size); end = buf + hdr_length; this_inf->offset = last_fde - ehbuf; this_inf->size = 4 + hdr_length; if (hdr_length == 0) { /* A zero-length CIE should only be found at the end of the section. */ REQUIRE ((bfd_size_type) (buf - ehbuf) == sec->size); ENSURE_NO_RELOCS (buf); sec_info->count++; break; } REQUIRE (skip_bytes (&buf, end, 4)); hdr_id = bfd_get_32 (abfd, buf - 4); if (hdr_id == 0) { unsigned int initial_insn_length; /* CIE */ this_inf->cie = 1; if (ecie_count == ecie_alloced) { ecies = bfd_realloc (ecies, (ecie_alloced + 20) * sizeof (*ecies)); REQUIRE (ecies); memset (&ecies[ecie_alloced], 0, 20 * sizeof (*ecies)); ecie_alloced += 20; } cie = &ecies[ecie_count].cie; ecies[ecie_count].offset = this_inf->offset; ecies[ecie_count++].entry = sec_info->count; cie->length = hdr_length; start = buf; REQUIRE (read_byte (&buf, end, &cie->version)); /* Cannot handle unknown versions. */ REQUIRE (cie->version == 1 || cie->version == 3); REQUIRE (strlen ((char *) buf) < sizeof (cie->augmentation)); strcpy (cie->augmentation, (char *) buf); buf = (bfd_byte *) strchr ((char *) buf, '\0') + 1; ENSURE_NO_RELOCS (buf); if (buf[0] == 'e' && buf[1] == 'h') { /* GCC < 3.0 .eh_frame CIE */ /* We cannot merge "eh" CIEs because __EXCEPTION_TABLE__ is private to each CIE, so we don't need it for anything. Just skip it. */ REQUIRE (skip_bytes (&buf, end, ptr_size)); SKIP_RELOCS (buf); } REQUIRE (read_uleb128 (&buf, end, &cie->code_align)); REQUIRE (read_sleb128 (&buf, end, &cie->data_align)); if (cie->version == 1) { REQUIRE (buf < end); cie->ra_column = *buf++; } else REQUIRE (read_uleb128 (&buf, end, &cie->ra_column)); ENSURE_NO_RELOCS (buf); cie->lsda_encoding = DW_EH_PE_omit; cie->fde_encoding = DW_EH_PE_omit; cie->per_encoding = DW_EH_PE_omit; aug = cie->augmentation; if (aug[0] != 'e' || aug[1] != 'h') { if (*aug == 'z') { aug++; REQUIRE (read_uleb128 (&buf, end, &cie->augmentation_size)); ENSURE_NO_RELOCS (buf); } while (*aug != '\0') switch (*aug++) { case 'L': REQUIRE (read_byte (&buf, end, &cie->lsda_encoding)); ENSURE_NO_RELOCS (buf); REQUIRE (get_DW_EH_PE_width (cie->lsda_encoding, ptr_size)); break; case 'R': REQUIRE (read_byte (&buf, end, &cie->fde_encoding)); ENSURE_NO_RELOCS (buf); REQUIRE (get_DW_EH_PE_width (cie->fde_encoding, ptr_size)); break; case 'S': break; case 'P': { int per_width; REQUIRE (read_byte (&buf, end, &cie->per_encoding)); per_width = get_DW_EH_PE_width (cie->per_encoding, ptr_size); REQUIRE (per_width); if ((cie->per_encoding & 0xf0) == DW_EH_PE_aligned) { length = -(buf - ehbuf) & (per_width - 1); REQUIRE (skip_bytes (&buf, end, length)); } ENSURE_NO_RELOCS (buf); /* Ensure we have a reloc here. */ if (GET_RELOC (buf) != NULL) { unsigned long r_symndx; #ifdef BFD64 if (ptr_size == 8) r_symndx = ELF64_R_SYM (cookie->rel->r_info); else #endif r_symndx = ELF32_R_SYM (cookie->rel->r_info); if (r_symndx >= cookie->locsymcount || ELF_ST_BIND (cookie->locsyms[r_symndx] .st_info) != STB_LOCAL) { struct elf_link_hash_entry *h; r_symndx -= cookie->extsymoff; h = cookie->sym_hashes[r_symndx]; while (h->root.type == bfd_link_hash_indirect || h->root.type == bfd_link_hash_warning) h = (struct elf_link_hash_entry *) h->root.u.i.link; cie->personality.h = h; } else { Elf_Internal_Sym *sym; asection *sym_sec; bfd_vma val; sym = &cookie->locsyms[r_symndx]; sym_sec = (bfd_section_from_elf_index (abfd, sym->st_shndx)); if (sym_sec != NULL) { if (sym_sec->kept_section != NULL) sym_sec = sym_sec->kept_section; if (sym_sec->output_section != NULL) { val = (sym->st_value + sym_sec->output_offset + sym_sec->output_section->vma); cie->personality.val = val; cie->local_personality = 1; } } } /* Cope with MIPS-style composite relocations. */ do cookie->rel++; while (GET_RELOC (buf) != NULL); } REQUIRE (skip_bytes (&buf, end, per_width)); REQUIRE (cie->local_personality || cie->personality.h); } break; default: /* Unrecognized augmentation. Better bail out. */ goto free_no_table; } } /* For shared libraries, try to get rid of as many RELATIVE relocs as possible. */ if (info->shared && (get_elf_backend_data (abfd) ->elf_backend_can_make_relative_eh_frame (abfd, info, sec))) { if ((cie->fde_encoding & 0xf0) == DW_EH_PE_absptr) cie->make_relative = 1; /* If the CIE doesn't already have an 'R' entry, it's fairly easy to add one, provided that there's no aligned data after the augmentation string. */ else if (cie->fde_encoding == DW_EH_PE_omit && (cie->per_encoding & 0xf0) != DW_EH_PE_aligned) { if (*cie->augmentation == 0) this_inf->add_augmentation_size = 1; this_inf->add_fde_encoding = 1; cie->make_relative = 1; } } if (info->shared && (get_elf_backend_data (abfd) ->elf_backend_can_make_lsda_relative_eh_frame (abfd, info, sec)) && (cie->lsda_encoding & 0xf0) == DW_EH_PE_absptr) cie->make_lsda_relative = 1; /* If FDE encoding was not specified, it defaults to DW_EH_absptr. */ if (cie->fde_encoding == DW_EH_PE_omit) cie->fde_encoding = DW_EH_PE_absptr; initial_insn_length = end - buf; if (initial_insn_length <= sizeof (cie->initial_instructions)) { cie->initial_insn_length = initial_insn_length; memcpy (cie->initial_instructions, buf, initial_insn_length); } insns = buf; buf += initial_insn_length; ENSURE_NO_RELOCS (buf); } else { /* Find the corresponding CIE. */ unsigned int cie_offset = this_inf->offset + 4 - hdr_id; for (ecie = ecies; ecie < ecies + ecie_count; ++ecie) if (cie_offset == ecie->offset) break; /* Ensure this FDE references one of the CIEs in this input section. */ REQUIRE (ecie != ecies + ecie_count); cie = &ecie->cie; ENSURE_NO_RELOCS (buf); REQUIRE (GET_RELOC (buf)); if ((*reloc_symbol_deleted_p) (buf - ehbuf, cookie)) /* This is a FDE against a discarded section. It should be deleted. */ this_inf->removed = 1; else { if (info->shared && (((cie->fde_encoding & 0xf0) == DW_EH_PE_absptr && cie->make_relative == 0) || (cie->fde_encoding & 0xf0) == DW_EH_PE_aligned)) { /* If a shared library uses absolute pointers which we cannot turn into PC relative, don't create the binary search table, since it is affected by runtime relocations. */ hdr_info->table = FALSE; (*info->callbacks->einfo) (_("%P: fde encoding in %B(%A) prevents .eh_frame_hdr" " table being created.\n"), abfd, sec); } ecie->usage_count++; hdr_info->fde_count++; this_inf->cie_inf = (void *) (ecie - ecies); } /* Skip the initial location and address range. */ start = buf; length = get_DW_EH_PE_width (cie->fde_encoding, ptr_size); REQUIRE (skip_bytes (&buf, end, 2 * length)); /* Skip the augmentation size, if present. */ if (cie->augmentation[0] == 'z') REQUIRE (read_uleb128 (&buf, end, &length)); else length = 0; /* Of the supported augmentation characters above, only 'L' adds augmentation data to the FDE. This code would need to be adjusted if any future augmentations do the same thing. */ if (cie->lsda_encoding != DW_EH_PE_omit) { this_inf->lsda_offset = buf - start; /* If there's no 'z' augmentation, we don't know where the CFA insns begin. Assume no padding. */ if (cie->augmentation[0] != 'z') length = end - buf; } /* Skip over the augmentation data. */ REQUIRE (skip_bytes (&buf, end, length)); insns = buf; buf = last_fde + 4 + hdr_length; SKIP_RELOCS (buf); } /* Try to interpret the CFA instructions and find the first padding nop. Shrink this_inf's size so that it doesn't include the padding. */ length = get_DW_EH_PE_width (cie->fde_encoding, ptr_size); set_loc_count = 0; insns_end = skip_non_nops (insns, end, length, &set_loc_count); /* If we don't understand the CFA instructions, we can't know what needs to be adjusted there. */ if (insns_end == NULL /* For the time being we don't support DW_CFA_set_loc in CIE instructions. */ || (set_loc_count && this_inf->cie)) goto free_no_table; this_inf->size -= end - insns_end; if (insns_end != end && this_inf->cie) { cie->initial_insn_length -= end - insns_end; cie->length -= end - insns_end; } if (set_loc_count && ((cie->fde_encoding & 0xf0) == DW_EH_PE_pcrel || cie->make_relative)) { unsigned int cnt; bfd_byte *p; this_inf->set_loc = bfd_malloc ((set_loc_count + 1) * sizeof (unsigned int)); REQUIRE (this_inf->set_loc); this_inf->set_loc[0] = set_loc_count; p = insns; cnt = 0; while (p < end) { if (*p == DW_CFA_set_loc) this_inf->set_loc[++cnt] = p + 1 - start; REQUIRE (skip_cfa_op (&p, end, length)); } } this_inf->fde_encoding = cie->fde_encoding; this_inf->lsda_encoding = cie->lsda_encoding; sec_info->count++; } elf_section_data (sec)->sec_info = sec_info; sec->sec_info_type = ELF_INFO_TYPE_EH_FRAME; /* Look at all CIEs in this section and determine which can be removed as unused, which can be merged with previous duplicate CIEs and which need to be kept. */ for (ecie = ecies; ecie < ecies + ecie_count; ++ecie) { if (ecie->usage_count == 0) { sec_info->entry[ecie->entry].removed = 1; continue; } ecie->cie.output_sec = sec->output_section; ecie->cie.cie_inf = sec_info->entry + ecie->entry; cie_compute_hash (&ecie->cie); if (hdr_info->cies != NULL) { void **loc = htab_find_slot_with_hash (hdr_info->cies, &ecie->cie, ecie->cie.hash, INSERT); if (loc != NULL) { if (*loc != HTAB_EMPTY_ENTRY) { sec_info->entry[ecie->entry].removed = 1; ecie->cie.cie_inf = ((struct cie *) *loc)->cie_inf; continue; } *loc = malloc (sizeof (struct cie)); if (*loc == NULL) *loc = HTAB_DELETED_ENTRY; else memcpy (*loc, &ecie->cie, sizeof (struct cie)); } } ecie->cie.cie_inf->make_relative = ecie->cie.make_relative; ecie->cie.cie_inf->make_lsda_relative = ecie->cie.make_lsda_relative; ecie->cie.cie_inf->per_encoding_relative = (ecie->cie.per_encoding & 0x70) == DW_EH_PE_pcrel; } /* Ok, now we can assign new offsets. */ offset = 0; for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent) if (!ent->removed) { if (!ent->cie) { ecie = ecies + (bfd_hostptr_t) ent->cie_inf; ent->cie_inf = ecie->cie.cie_inf; } ent->new_offset = offset; offset += size_of_output_cie_fde (ent, ptr_size); } /* Resize the sec as needed. */ sec->rawsize = sec->size; sec->size = offset; free (ehbuf); if (ecies) free (ecies); return offset != sec->rawsize; free_no_table: (*info->callbacks->einfo) (_("%P: error in %B(%A); no .eh_frame_hdr table will be created.\n"), abfd, sec); if (ehbuf) free (ehbuf); if (sec_info) free (sec_info); if (ecies) free (ecies); hdr_info->table = FALSE; return FALSE; #undef REQUIRE }
bfd_boolean xcoff64_core_file_matches_executable_p (bfd *core_bfd, bfd *exec_bfd) { struct core_dumpxx core; char *path, *s; size_t alloc; const char *str1, *str2; bfd_boolean return_value = FALSE; /* Get the header. */ if (bfd_seek (core_bfd, 0, SEEK_SET) != 0) return return_value; if (sizeof (struct core_dumpxx) != bfd_bread (&core, sizeof (struct core_dumpxx), core_bfd)) return return_value; if (bfd_seek (core_bfd, core.c_loader, SEEK_SET) != 0) return return_value; alloc = 100; path = bfd_malloc (alloc); if (path == NULL) return return_value; s = path; while (1) { if (bfd_bread (s, 1, core_bfd) != 1) goto xcoff64_core_file_matches_executable_p_end_1; if (*s == '\0') break; ++s; if (s == path + alloc) { char *n; alloc *= 2; n = bfd_realloc (path, alloc); if (n == NULL) goto xcoff64_core_file_matches_executable_p_end_1; s = n + (path - s); path = n; } } str1 = strrchr (path, '/'); str2 = strrchr (exec_bfd->filename, '/'); /* Step over character '/'. */ str1 = str1 != NULL ? str1 + 1 : path; str2 = str2 != NULL ? str2 + 1 : exec_bfd->filename; if (strcmp (str1, str2) == 0) return_value = TRUE; xcoff64_core_file_matches_executable_p_end_1: free (path); return return_value; }
bfd_boolean _bfd_elf_discard_section_eh_frame (bfd *abfd, struct bfd_link_info *info, asection *sec, bfd_boolean (*reloc_symbol_deleted_p) (bfd_vma, void *), struct elf_reloc_cookie *cookie) { #define REQUIRE(COND) \ do \ if (!(COND)) \ goto free_no_table; \ while (0) bfd_byte *ehbuf = NULL, *buf; bfd_byte *last_cie, *last_fde; struct eh_cie_fde *ent, *last_cie_inf, *this_inf; struct cie_header hdr; struct cie cie; struct elf_link_hash_table *htab; struct eh_frame_hdr_info *hdr_info; struct eh_frame_sec_info *sec_info = NULL; unsigned int cie_usage_count, offset; unsigned int ptr_size; if (sec->size == 0) { /* This file does not contain .eh_frame information. */ return FALSE; } if ((sec->output_section != NULL && bfd_is_abs_section (sec->output_section))) { /* At least one of the sections is being discarded from the link, so we should just ignore them. */ return FALSE; } htab = elf_hash_table (info); hdr_info = &htab->eh_info; /* Read the frame unwind information from abfd. */ REQUIRE (bfd_malloc_and_get_section (abfd, sec, &ehbuf)); if (sec->size >= 4 && bfd_get_32 (abfd, ehbuf) == 0 && cookie->rel == cookie->relend) { /* Empty .eh_frame section. */ free (ehbuf); return FALSE; } /* If .eh_frame section size doesn't fit into int, we cannot handle it (it would need to use 64-bit .eh_frame format anyway). */ REQUIRE (sec->size == (unsigned int) sec->size); ptr_size = (get_elf_backend_data (abfd) ->elf_backend_eh_frame_address_size (abfd, sec)); REQUIRE (ptr_size != 0); buf = ehbuf; last_cie = NULL; last_cie_inf = NULL; memset (&cie, 0, sizeof (cie)); cie_usage_count = 0; sec_info = bfd_zmalloc (sizeof (struct eh_frame_sec_info) + 99 * sizeof (struct eh_cie_fde)); REQUIRE (sec_info); sec_info->alloced = 100; #define ENSURE_NO_RELOCS(buf) \ REQUIRE (!(cookie->rel < cookie->relend \ && (cookie->rel->r_offset \ < (bfd_size_type) ((buf) - ehbuf)) \ && cookie->rel->r_info != 0)) #define SKIP_RELOCS(buf) \ while (cookie->rel < cookie->relend \ && (cookie->rel->r_offset \ < (bfd_size_type) ((buf) - ehbuf))) \ cookie->rel++ #define GET_RELOC(buf) \ ((cookie->rel < cookie->relend \ && (cookie->rel->r_offset \ == (bfd_size_type) ((buf) - ehbuf))) \ ? cookie->rel : NULL) for (;;) { char *aug; bfd_byte *start, *end, *insns; bfd_size_type length; if (sec_info->count == sec_info->alloced) { struct eh_cie_fde *old_entry = sec_info->entry; sec_info = bfd_realloc (sec_info, sizeof (struct eh_frame_sec_info) + ((sec_info->alloced + 99) * sizeof (struct eh_cie_fde))); REQUIRE (sec_info); memset (&sec_info->entry[sec_info->alloced], 0, 100 * sizeof (struct eh_cie_fde)); sec_info->alloced += 100; /* Now fix any pointers into the array. */ if (last_cie_inf >= old_entry && last_cie_inf < old_entry + sec_info->count) last_cie_inf = sec_info->entry + (last_cie_inf - old_entry); } this_inf = sec_info->entry + sec_info->count; last_fde = buf; /* If we are at the end of the section, we still need to decide on whether to output or discard last encountered CIE (if any). */ if ((bfd_size_type) (buf - ehbuf) == sec->size) { hdr.length = 0; hdr.id = (unsigned int) -1; end = buf; } else { /* Read the length of the entry. */ REQUIRE (skip_bytes (&buf, ehbuf + sec->size, 4)); hdr.length = bfd_get_32 (abfd, buf - 4); /* 64-bit .eh_frame is not supported. */ REQUIRE (hdr.length != 0xffffffff); /* The CIE/FDE must be fully contained in this input section. */ REQUIRE ((bfd_size_type) (buf - ehbuf) + hdr.length <= sec->size); end = buf + hdr.length; this_inf->offset = last_fde - ehbuf; this_inf->size = 4 + hdr.length; if (hdr.length == 0) { /* A zero-length CIE should only be found at the end of the section. */ REQUIRE ((bfd_size_type) (buf - ehbuf) == sec->size); ENSURE_NO_RELOCS (buf); sec_info->count++; /* Now just finish last encountered CIE processing and break the loop. */ hdr.id = (unsigned int) -1; } else { REQUIRE (skip_bytes (&buf, end, 4)); hdr.id = bfd_get_32 (abfd, buf - 4); REQUIRE (hdr.id != (unsigned int) -1); } } if (hdr.id == 0 || hdr.id == (unsigned int) -1) { unsigned int initial_insn_length; /* CIE */ if (last_cie != NULL) { /* Now check if this CIE is identical to the last CIE, in which case we can remove it provided we adjust all FDEs. Also, it can be removed if we have removed all FDEs using it. */ if ((!info->relocatable && hdr_info->last_cie_sec && (sec->output_section == hdr_info->last_cie_sec->output_section) && cie_compare (&cie, &hdr_info->last_cie) == 0) || cie_usage_count == 0) last_cie_inf->removed = 1; else { hdr_info->last_cie = cie; hdr_info->last_cie_sec = sec; last_cie_inf->make_relative = cie.make_relative; last_cie_inf->make_lsda_relative = cie.make_lsda_relative; last_cie_inf->per_encoding_relative = (cie.per_encoding & 0x70) == DW_EH_PE_pcrel; } } if (hdr.id == (unsigned int) -1) break; last_cie_inf = this_inf; this_inf->cie = 1; cie_usage_count = 0; memset (&cie, 0, sizeof (cie)); cie.hdr = hdr; REQUIRE (read_byte (&buf, end, &cie.version)); /* Cannot handle unknown versions. */ REQUIRE (cie.version == 1 || cie.version == 3); REQUIRE (strlen ((char *) buf) < sizeof (cie.augmentation)); strcpy (cie.augmentation, (char *) buf); buf = (bfd_byte *) strchr ((char *) buf, '\0') + 1; ENSURE_NO_RELOCS (buf); if (buf[0] == 'e' && buf[1] == 'h') { /* GCC < 3.0 .eh_frame CIE */ /* We cannot merge "eh" CIEs because __EXCEPTION_TABLE__ is private to each CIE, so we don't need it for anything. Just skip it. */ REQUIRE (skip_bytes (&buf, end, ptr_size)); SKIP_RELOCS (buf); } REQUIRE (read_uleb128 (&buf, end, &cie.code_align)); REQUIRE (read_sleb128 (&buf, end, &cie.data_align)); if (cie.version == 1) { REQUIRE (buf < end); cie.ra_column = *buf++; } else REQUIRE (read_uleb128 (&buf, end, &cie.ra_column)); ENSURE_NO_RELOCS (buf); cie.lsda_encoding = DW_EH_PE_omit; cie.fde_encoding = DW_EH_PE_omit; cie.per_encoding = DW_EH_PE_omit; aug = cie.augmentation; if (aug[0] != 'e' || aug[1] != 'h') { if (*aug == 'z') { aug++; REQUIRE (read_uleb128 (&buf, end, &cie.augmentation_size)); ENSURE_NO_RELOCS (buf); } while (*aug != '\0') switch (*aug++) { case 'L': REQUIRE (read_byte (&buf, end, &cie.lsda_encoding)); ENSURE_NO_RELOCS (buf); REQUIRE (get_DW_EH_PE_width (cie.lsda_encoding, ptr_size)); break; case 'R': REQUIRE (read_byte (&buf, end, &cie.fde_encoding)); ENSURE_NO_RELOCS (buf); REQUIRE (get_DW_EH_PE_width (cie.fde_encoding, ptr_size)); break; case 'P': { int per_width; REQUIRE (read_byte (&buf, end, &cie.per_encoding)); per_width = get_DW_EH_PE_width (cie.per_encoding, ptr_size); REQUIRE (per_width); if ((cie.per_encoding & 0xf0) == DW_EH_PE_aligned) { length = -(buf - ehbuf) & (per_width - 1); REQUIRE (skip_bytes (&buf, end, length)); } ENSURE_NO_RELOCS (buf); /* Ensure we have a reloc here, against a global symbol. */ if (GET_RELOC (buf) != NULL) { unsigned long r_symndx; #ifdef BFD64 if (ptr_size == 8) r_symndx = ELF64_R_SYM (cookie->rel->r_info); else #endif r_symndx = ELF32_R_SYM (cookie->rel->r_info); if (r_symndx >= cookie->locsymcount) { struct elf_link_hash_entry *h; r_symndx -= cookie->extsymoff; h = cookie->sym_hashes[r_symndx]; while (h->root.type == bfd_link_hash_indirect || h->root.type == bfd_link_hash_warning) h = (struct elf_link_hash_entry *) h->root.u.i.link; cie.personality = h; } /* Cope with MIPS-style composite relocations. */ do cookie->rel++; while (GET_RELOC (buf) != NULL); } REQUIRE (skip_bytes (&buf, end, per_width)); } break; default: /* Unrecognized augmentation. Better bail out. */ goto free_no_table; } } /* For shared libraries, try to get rid of as many RELATIVE relocs as possible. */ if (info->shared && (get_elf_backend_data (abfd) ->elf_backend_can_make_relative_eh_frame (abfd, info, sec))) { if ((cie.fde_encoding & 0xf0) == DW_EH_PE_absptr) cie.make_relative = 1; /* If the CIE doesn't already have an 'R' entry, it's fairly easy to add one, provided that there's no aligned data after the augmentation string. */ else if (cie.fde_encoding == DW_EH_PE_omit && (cie.per_encoding & 0xf0) != DW_EH_PE_aligned) { if (*cie.augmentation == 0) this_inf->add_augmentation_size = 1; this_inf->add_fde_encoding = 1; cie.make_relative = 1; } } if (info->shared && (get_elf_backend_data (abfd) ->elf_backend_can_make_lsda_relative_eh_frame (abfd, info, sec)) && (cie.lsda_encoding & 0xf0) == DW_EH_PE_absptr) cie.make_lsda_relative = 1; /* If FDE encoding was not specified, it defaults to DW_EH_absptr. */ if (cie.fde_encoding == DW_EH_PE_omit) cie.fde_encoding = DW_EH_PE_absptr; initial_insn_length = end - buf; if (initial_insn_length <= 50) { cie.initial_insn_length = initial_insn_length; memcpy (cie.initial_instructions, buf, initial_insn_length); } insns = buf; buf += initial_insn_length; ENSURE_NO_RELOCS (buf); last_cie = last_fde; } else { /* Ensure this FDE uses the last CIE encountered. */ REQUIRE (last_cie); REQUIRE (hdr.id == (unsigned int) (buf - 4 - last_cie)); ENSURE_NO_RELOCS (buf); REQUIRE (GET_RELOC (buf)); if ((*reloc_symbol_deleted_p) (buf - ehbuf, cookie)) /* This is a FDE against a discarded section. It should be deleted. */ this_inf->removed = 1; else { if (info->shared && (((cie.fde_encoding & 0xf0) == DW_EH_PE_absptr && cie.make_relative == 0) || (cie.fde_encoding & 0xf0) == DW_EH_PE_aligned)) { /* If a shared library uses absolute pointers which we cannot turn into PC relative, don't create the binary search table, since it is affected by runtime relocations. */ hdr_info->table = FALSE; } cie_usage_count++; hdr_info->fde_count++; } /* Skip the initial location and address range. */ start = buf; length = get_DW_EH_PE_width (cie.fde_encoding, ptr_size); REQUIRE (skip_bytes (&buf, end, 2 * length)); /* Skip the augmentation size, if present. */ if (cie.augmentation[0] == 'z') REQUIRE (read_uleb128 (&buf, end, &length)); else length = 0; /* Of the supported augmentation characters above, only 'L' adds augmentation data to the FDE. This code would need to be adjusted if any future augmentations do the same thing. */ if (cie.lsda_encoding != DW_EH_PE_omit) { this_inf->lsda_offset = buf - start; /* If there's no 'z' augmentation, we don't know where the CFA insns begin. Assume no padding. */ if (cie.augmentation[0] != 'z') length = end - buf; } /* Skip over the augmentation data. */ REQUIRE (skip_bytes (&buf, end, length)); insns = buf; buf = last_fde + 4 + hdr.length; SKIP_RELOCS (buf); } /* Try to interpret the CFA instructions and find the first padding nop. Shrink this_inf's size so that it doesn't including the padding. */ length = get_DW_EH_PE_width (cie.fde_encoding, ptr_size); insns = skip_non_nops (insns, end, length); if (insns != 0) this_inf->size -= end - insns; this_inf->fde_encoding = cie.fde_encoding; this_inf->lsda_encoding = cie.lsda_encoding; sec_info->count++; } elf_section_data (sec)->sec_info = sec_info; sec->sec_info_type = ELF_INFO_TYPE_EH_FRAME; /* Ok, now we can assign new offsets. */ offset = 0; last_cie_inf = hdr_info->last_cie_inf; for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent) if (!ent->removed) { if (ent->cie) last_cie_inf = ent; else ent->cie_inf = last_cie_inf; ent->new_offset = offset; offset += size_of_output_cie_fde (ent, ptr_size); } hdr_info->last_cie_inf = last_cie_inf; /* Resize the sec as needed. */ sec->rawsize = sec->size; sec->size = offset; if (sec->size == 0) sec->flags |= SEC_EXCLUDE; free (ehbuf); return offset != sec->rawsize; free_no_table: if (ehbuf) free (ehbuf); if (sec_info) free (sec_info); hdr_info->table = FALSE; hdr_info->last_cie.hdr.length = 0; return FALSE; #undef REQUIRE }
int bfd_seek (bfd *abfd, file_ptr position, int direction) { int result; file_ptr file_position; /* For the time being, a BFD may not seek to it's end. The problem is that we don't easily have a way to recognize the end of an element in an archive. */ BFD_ASSERT (direction == SEEK_SET || direction == SEEK_CUR); if (direction == SEEK_CUR && position == 0) return 0; if ((abfd->flags & BFD_IN_MEMORY) != 0) { struct bfd_in_memory *bim; bim = abfd->iostream; if (direction == SEEK_SET) abfd->where = position; else abfd->where += position; if (abfd->where > bim->size) { if ((abfd->direction == write_direction) || (abfd->direction == both_direction)) { bfd_size_type newsize, oldsize; oldsize = (bim->size + 127) & ~(bfd_size_type) 127; bim->size = abfd->where; /* Round up to cut down on memory fragmentation */ newsize = (bim->size + 127) & ~(bfd_size_type) 127; if (newsize > oldsize) { bim->buffer = bfd_realloc (bim->buffer, newsize); if (bim->buffer == 0) { bim->size = 0; return -1; } } } else { abfd->where = bim->size; bfd_set_error (bfd_error_file_truncated); return -1; } } return 0; } if (abfd->format != bfd_archive && abfd->my_archive == 0) { if (direction == SEEK_SET && (bfd_vma) position == abfd->where) return 0; } else { /* We need something smarter to optimize access to archives. Currently, anything inside an archive is read via the file handle for the archive. Which means that a bfd_seek on one component affects the `current position' in the archive, as well as in any other component. It might be sufficient to put a spike through the cache abstraction, and look to the archive for the file position, but I think we should try for something cleaner. In the meantime, no optimization for archives. */ } file_position = position; if (direction == SEEK_SET && abfd->my_archive != NULL) file_position += abfd->origin; if (abfd->iovec) result = abfd->iovec->bseek (abfd, file_position, direction); else result = -1; if (result != 0) { int hold_errno = errno; /* Force redetermination of `where' field. */ bfd_tell (abfd); /* An EINVAL error probably means that the file offset was absurd. */ if (hold_errno == EINVAL) bfd_set_error (bfd_error_file_truncated); else { bfd_set_error (bfd_error_system_call); errno = hold_errno; } } else { /* Adjust `where' field. */ if (direction == SEEK_SET) abfd->where = position; else abfd->where += position; } return result; }
bfd_boolean _bfd_link_section_stabs (bfd *abfd, struct stab_info *sinfo, asection *stabsec, asection *stabstrsec, void * *psecinfo, bfd_size_type *pstring_offset) { bfd_boolean first; bfd_size_type count, amt; struct stab_section_info *secinfo; bfd_byte *stabbuf = NULL; bfd_byte *stabstrbuf = NULL; bfd_byte *sym, *symend; bfd_size_type stroff, next_stroff, skip; bfd_size_type *pstridx; if (stabsec->size == 0 || stabstrsec->size == 0) /* This file does not contain stabs debugging information. */ return TRUE; if (stabsec->size % STABSIZE != 0) /* Something is wrong with the format of these stab symbols. Don't try to optimize them. */ return TRUE; if ((stabstrsec->flags & SEC_RELOC) != 0) /* We shouldn't see relocations in the strings, and we aren't prepared to handle them. */ return TRUE; if (bfd_is_abs_section (stabsec->output_section) || bfd_is_abs_section (stabstrsec->output_section)) /* At least one of the sections is being discarded from the link, so we should just ignore them. */ return TRUE; first = FALSE; if (sinfo->stabstr == NULL) { flagword flags; /* Initialize the stabs information we need to keep track of. */ first = TRUE; sinfo->strings = _bfd_stringtab_init (); if (sinfo->strings == NULL) goto error_return; /* Make sure the first byte is zero. */ (void) _bfd_stringtab_add (sinfo->strings, "", TRUE, TRUE); if (! bfd_hash_table_init (&sinfo->includes, stab_link_includes_newfunc, sizeof (struct stab_link_includes_entry))) goto error_return; flags = (SEC_HAS_CONTENTS | SEC_READONLY | SEC_DEBUGGING | SEC_LINKER_CREATED); sinfo->stabstr = bfd_make_section_anyway_with_flags (abfd, ".stabstr", flags); if (sinfo->stabstr == NULL) goto error_return; } /* Initialize the information we are going to store for this .stab section. */ count = stabsec->size / STABSIZE; amt = sizeof (struct stab_section_info); amt += (count - 1) * sizeof (bfd_size_type); *psecinfo = bfd_alloc (abfd, amt); if (*psecinfo == NULL) goto error_return; secinfo = (struct stab_section_info *) *psecinfo; secinfo->excls = NULL; stabsec->rawsize = stabsec->size; secinfo->cumulative_skips = NULL; memset (secinfo->stridxs, 0, (size_t) count * sizeof (bfd_size_type)); /* Read the stabs information from abfd. */ if (!bfd_malloc_and_get_section (abfd, stabsec, &stabbuf) || !bfd_malloc_and_get_section (abfd, stabstrsec, &stabstrbuf)) goto error_return; /* Look through the stabs symbols, work out the new string indices, and identify N_BINCL symbols which can be eliminated. */ stroff = 0; /* The stabs sections can be split when -split-by-reloc/-split-by-file is used. We must keep track of each stab section's place in the single concatenated string table. */ next_stroff = pstring_offset ? *pstring_offset : 0; skip = 0; symend = stabbuf + stabsec->size; for (sym = stabbuf, pstridx = secinfo->stridxs; sym < symend; sym += STABSIZE, ++pstridx) { bfd_size_type symstroff; int type; const char *string; if (*pstridx != 0) /* This symbol has already been handled by an N_BINCL pass. */ continue; type = sym[TYPEOFF]; if (type == 0) { /* Special type 0 stabs indicate the offset to the next string table. We only copy the very first one. */ stroff = next_stroff; next_stroff += bfd_get_32 (abfd, sym + 8); if (pstring_offset) *pstring_offset = next_stroff; if (! first) { *pstridx = (bfd_size_type) -1; ++skip; continue; } first = FALSE; } /* Store the string in the hash table, and record the index. */ symstroff = stroff + bfd_get_32 (abfd, sym + STRDXOFF); if (symstroff >= stabstrsec->size) { (*_bfd_error_handler) (_("%B(%A+0x%lx): Stabs entry has invalid string index."), abfd, stabsec, (long) (sym - stabbuf)); bfd_set_error (bfd_error_bad_value); goto error_return; } string = (char *) stabstrbuf + symstroff; *pstridx = _bfd_stringtab_add (sinfo->strings, string, TRUE, TRUE); /* An N_BINCL symbol indicates the start of the stabs entries for a header file. We need to scan ahead to the next N_EINCL symbol, ignoring nesting, adding up all the characters in the symbol names, not including the file numbers in types (the first number after an open parenthesis). */ if (type == (int) N_BINCL) { bfd_vma sum_chars; bfd_vma num_chars; bfd_vma buf_len = 0; char * symb; char * symb_rover; int nest; bfd_byte * incl_sym; struct stab_link_includes_entry * incl_entry; struct stab_link_includes_totals * t; struct stab_excl_list * ne; symb = symb_rover = NULL; sum_chars = num_chars = 0; nest = 0; for (incl_sym = sym + STABSIZE; incl_sym < symend; incl_sym += STABSIZE) { int incl_type; incl_type = incl_sym[TYPEOFF]; if (incl_type == 0) break; else if (incl_type == (int) N_EXCL) continue; else if (incl_type == (int) N_EINCL) { if (nest == 0) break; --nest; } else if (incl_type == (int) N_BINCL) ++nest; else if (nest == 0) { const char *str; str = ((char *) stabstrbuf + stroff + bfd_get_32 (abfd, incl_sym + STRDXOFF)); for (; *str != '\0'; str++) { if (num_chars >= buf_len) { buf_len += 32 * 1024; symb = bfd_realloc (symb, buf_len); if (symb == NULL) goto error_return; symb_rover = symb + num_chars; } * symb_rover ++ = * str; sum_chars += *str; num_chars ++; if (*str == '(') { /* Skip the file number. */ ++str; while (ISDIGIT (*str)) ++str; --str; } } } } BFD_ASSERT (num_chars == (bfd_vma) (symb_rover - symb)); /* If we have already included a header file with the same value, then replaced this one with an N_EXCL symbol. */ incl_entry = (struct stab_link_includes_entry * ) bfd_hash_lookup (&sinfo->includes, string, TRUE, TRUE); if (incl_entry == NULL) goto error_return; for (t = incl_entry->totals; t != NULL; t = t->next) if (t->sum_chars == sum_chars && t->num_chars == num_chars && memcmp (t->symb, symb, num_chars) == 0) break; /* Record this symbol, so that we can set the value correctly. */ amt = sizeof *ne; ne = bfd_alloc (abfd, amt); if (ne == NULL) goto error_return; ne->offset = sym - stabbuf; ne->val = sum_chars; ne->type = (int) N_BINCL; ne->next = secinfo->excls; secinfo->excls = ne; if (t == NULL) { /* This is the first time we have seen this header file with this set of stabs strings. */ t = bfd_hash_allocate (&sinfo->includes, sizeof *t); if (t == NULL) goto error_return; t->sum_chars = sum_chars; t->num_chars = num_chars; t->symb = bfd_realloc (symb, num_chars); /* Trim data down. */ t->next = incl_entry->totals; incl_entry->totals = t; } else { bfd_size_type *incl_pstridx; /* We have seen this header file before. Tell the final pass to change the type to N_EXCL. */ ne->type = (int) N_EXCL; /* Free off superfluous symbols. */ free (symb); /* Mark the skipped symbols. */ nest = 0; for (incl_sym = sym + STABSIZE, incl_pstridx = pstridx + 1; incl_sym < symend; incl_sym += STABSIZE, ++incl_pstridx) { int incl_type; incl_type = incl_sym[TYPEOFF]; if (incl_type == (int) N_EINCL) { if (nest == 0) { *incl_pstridx = (bfd_size_type) -1; ++skip; break; } --nest; } else if (incl_type == (int) N_BINCL) ++nest; else if (incl_type == (int) N_EXCL) /* Keep existing exclusion marks. */ continue; else if (nest == 0) { *incl_pstridx = (bfd_size_type) -1; ++skip; } } } } } free (stabbuf); stabbuf = NULL; free (stabstrbuf); stabstrbuf = NULL; /* We need to set the section sizes such that the linker will compute the output section sizes correctly. We set the .stab size to not include the entries we don't want. We set SEC_EXCLUDE for the .stabstr section, so that it will be dropped from the link. We record the size of the strtab in the first .stabstr section we saw, and make sure we don't set SEC_EXCLUDE for that section. */ stabsec->size = (count - skip) * STABSIZE; if (stabsec->size == 0) stabsec->flags |= SEC_EXCLUDE | SEC_KEEP; stabstrsec->flags |= SEC_EXCLUDE | SEC_KEEP; sinfo->stabstr->size = _bfd_stringtab_size (sinfo->strings); /* Calculate the `cumulative_skips' array now that stabs have been deleted for this section. */ if (skip != 0) { bfd_size_type i, offset; bfd_size_type *pskips; amt = count * sizeof (bfd_size_type); secinfo->cumulative_skips = bfd_alloc (abfd, amt); if (secinfo->cumulative_skips == NULL) goto error_return; pskips = secinfo->cumulative_skips; pstridx = secinfo->stridxs; offset = 0; for (i = 0; i < count; i++, pskips++, pstridx++) { *pskips = offset; if (*pstridx == (bfd_size_type) -1) offset += STABSIZE; } BFD_ASSERT (offset != 0); } return TRUE; error_return: if (stabbuf != NULL) free (stabbuf); if (stabstrbuf != NULL) free (stabstrbuf); return FALSE; }
static bfd_boolean _bfd_get_file_window_mmap(bfd *abfd, ufile_ptr offset, bfd_size_type size, bfd_window *windowp, bfd_window_internal *i, bfd_boolean writable) { static size_t pagesize; bfd_size_type size_to_alloc = size; if (debug_windows) fprintf(stderr, "bfd_get_file_window (%p, %6ld, %6ld, %p<%p,%lx,%p>, %d)", (void *)abfd, (long)offset, (long)size, (void *)windowp, windowp->data, (unsigned long)windowp->size, (void *)windowp->i, writable); /* Make sure we know the page size, so we can be friendly to mmap: */ if (pagesize == 0) pagesize = (size_t)getpagesize(); if (pagesize == 0) abort(); # ifdef HAVE_MMAP if (ok_to_map && ((i->data == 0) || (i->mapped == 1)) && ((abfd->flags & BFD_IN_MEMORY) == 0)) { file_ptr file_offset, offset2; size_t real_size; int fd; FILE *f; /* Find the real file and the real offset into it: */ while (abfd->my_archive != NULL) { offset += abfd->origin; abfd = abfd->my_archive; } f = bfd_cache_lookup(abfd); fd = fileno(f); /* Compute offsets and size for mmap and for the user's data: */ offset2 = (file_ptr)(offset % pagesize); if (offset2 < 0) abort(); file_offset = ((file_ptr)offset - offset2); real_size = (size_t)(offset + size - (unsigned long)file_offset); real_size = (real_size + pagesize - 1UL); real_size -= (real_size % pagesize); /* If we are re-using a memory region, make sure it is big enough: */ if (i->data && (i->size < size)) { munmap(i->data, (size_t)i->size); i->data = 0; } i->data = mmap(i->data, real_size, (writable ? (PROT_WRITE | PROT_READ) : PROT_READ), (writable ? (MAP_FILE | MAP_PRIVATE) : (MAP_FILE | MAP_SHARED)), fd, (off_t)file_offset); if (i->data == (void *)-1) { /* An error happened. Report it, or try using malloc, or * something: */ bfd_set_error(bfd_error_system_call); i->data = 0; windowp->data = 0; if (debug_windows) fprintf(stderr, "\t\tmmap failed!\n"); return FALSE; } if (debug_windows) fprintf(stderr, "\n\tmapped %ld at %p, offset is %ld\n", (long)real_size, i->data, (long)offset2); i->size = real_size; windowp->data = ((bfd_byte *)i->data + offset2); windowp->size = size; i->mapped = 1; return TRUE; } else if (debug_windows) { if (ok_to_map) fprintf(stderr, _("not mapping: data=%lx mapped=%d\n"), (unsigned long)i->data, (int)i->mapped); else fprintf(stderr, _("not mapping: env var not set\n")); } # else ok_to_map = 0; # endif /* HAVE_MMAP */ # ifdef HAVE_MPROTECT if (!writable) { size_to_alloc += (pagesize - 1); size_to_alloc -= (size_to_alloc % pagesize); } # endif /* HAVE_MPROTECT */ if (debug_windows) fprintf(stderr, "\n\t%s(%6ld)", (i->data ? "realloc" : " malloc"), (long)size_to_alloc); i->data = bfd_realloc(i->data, size_to_alloc); if (debug_windows) fprintf(stderr, "\t-> %p\n", i->data); i->refcount = 1; if (i->data == NULL) { if (size_to_alloc == 0) return TRUE; return FALSE; } if (bfd_seek(abfd, (file_ptr)offset, SEEK_SET) != 0) return FALSE; i->size = bfd_bread(i->data, size, abfd); if (i->size != size) return FALSE; i->mapped = 0; # ifdef HAVE_MPROTECT if (!writable) { if (debug_windows) fprintf(stderr, "\tmprotect (%p, %ld, PROT_READ)\n", i->data, (long)i->size); mprotect(i->data, i->size, PROT_READ); } # endif /* HAVE_MPROTECT */ windowp->data = i->data; windowp->size = i->size; return TRUE; }
int _bfd_vms_slurp_gsd (bfd * abfd, int objtype) { int gsd_type, gsd_size; asection *section; unsigned char *vms_rec; flagword new_flags, old_flags; char *name; asymbol *symbol; vms_symbol_entry *entry; unsigned long base_addr; unsigned long align_addr; static unsigned int psect_idx = 0; #if VMS_DEBUG vms_debug (2, "GSD/EGSD (%d/%x)\n", objtype, objtype); #endif switch (objtype) { case EOBJ_S_C_EGSD: PRIV (vms_rec) += 8; /* Skip type, size, l_temp. */ PRIV (rec_size) -= 8; break; case OBJ_S_C_GSD: PRIV (vms_rec) += 1; PRIV (rec_size) -= 1; break; default: return -1; } /* Calculate base address for each section. */ base_addr = 0L; abfd->symcount = 0; while (PRIV (rec_size) > 0) { vms_rec = PRIV (vms_rec); if (objtype == OBJ_S_C_GSD) gsd_type = vms_rec[0]; else { _bfd_vms_get_header_values (abfd, vms_rec, &gsd_type, &gsd_size); gsd_type += EVAX_OFFSET; } #if VMS_DEBUG vms_debug (3, "gsd_type %d\n", gsd_type); #endif switch (gsd_type) { case GSD_S_C_PSC: { /* Program section definition. */ asection *old_section = 0; #if VMS_DEBUG vms_debug (4, "GSD_S_C_PSC\n"); #endif /* If this section isn't a bfd section. */ if (PRIV (is_vax) && (psect_idx < (abfd->section_count - 1))) { /* Check for temporary section from TIR record. */ if (psect_idx < PRIV (section_count)) old_section = PRIV (sections)[psect_idx]; else old_section = 0; } name = _bfd_vms_save_counted_string (vms_rec + 8); section = bfd_make_section (abfd, name); if (!section) { (*_bfd_error_handler) (_("bfd_make_section (%s) failed"), name); return -1; } old_flags = bfd_getl16 (vms_rec + 2); section->size = bfd_getl32 (vms_rec + 4); /* allocation */ new_flags = vms_secflag_by_name (abfd, vax_section_flags, name, section->size > 0); if (old_flags & EGPS_S_V_REL) new_flags |= SEC_RELOC; if (old_flags & GPS_S_M_OVR) new_flags |= SEC_IS_COMMON; if (!bfd_set_section_flags (abfd, section, new_flags)) { (*_bfd_error_handler) (_("bfd_set_section_flags (%s, %x) failed"), name, new_flags); return -1; } section->alignment_power = vms_rec[1]; align_addr = (1 << section->alignment_power); if ((base_addr % align_addr) != 0) base_addr += (align_addr - (base_addr % align_addr)); section->vma = (bfd_vma)base_addr; base_addr += section->size; /* Global section is common symbol. */ if (old_flags & GPS_S_M_GBL) { entry = _bfd_vms_enter_symbol (abfd, name); if (entry == NULL) { bfd_set_error (bfd_error_no_memory); return -1; } symbol = entry->symbol; symbol->value = 0; symbol->section = section; symbol->flags = (BSF_GLOBAL | BSF_SECTION_SYM | BSF_OLD_COMMON); } /* Copy saved contents if old_section set. */ if (old_section != 0) { section->contents = old_section->contents; if (section->size < old_section->size) { (*_bfd_error_handler) (_("Size mismatch section %s=%lx, %s=%lx"), old_section->name, (unsigned long) old_section->size, section->name, (unsigned long) section->size); return -1; } else if (section->size > old_section->size) { section->contents = bfd_realloc (old_section->contents, section->size); if (section->contents == NULL) { bfd_set_error (bfd_error_no_memory); return -1; } } } else { section->contents = bfd_zmalloc (section->size); if (section->contents == NULL) { bfd_set_error (bfd_error_no_memory); return -1; } } #if VMS_DEBUG vms_debug (4, "gsd psc %d (%s, flags %04x=%s) ", section->index, name, old_flags, flag2str (gpsflagdesc, old_flags)); vms_debug (4, "%d bytes at 0x%08lx (mem %p)\n", section->size, section->vma, section->contents); #endif gsd_size = vms_rec[8] + 9; psect_idx++; } break; case GSD_S_C_EPM: case GSD_S_C_EPMW: #if VMS_DEBUG vms_debug (4, "gsd epm\n"); #endif /* Fall through. */ case GSD_S_C_SYM: case GSD_S_C_SYMW: { int name_offset = 0, value_offset = 0; /* Symbol specification (definition or reference). */ #if VMS_DEBUG vms_debug (4, "GSD_S_C_SYM(W)\n"); #endif old_flags = bfd_getl16 (vms_rec + 2); new_flags = BSF_NO_FLAGS; if (old_flags & GSY_S_M_WEAK) new_flags |= BSF_WEAK; switch (gsd_type) { case GSD_S_C_EPM: name_offset = 11; value_offset = 5; new_flags |= BSF_FUNCTION; break; case GSD_S_C_EPMW: name_offset = 12; value_offset = 6; new_flags |= BSF_FUNCTION; break; case GSD_S_C_SYM: if (old_flags & GSY_S_M_DEF) /* Symbol definition. */ name_offset = 9; else name_offset = 4; value_offset = 5; break; case GSD_S_C_SYMW: if (old_flags & GSY_S_M_DEF) /* Symbol definition. */ name_offset = 10; else name_offset = 5; value_offset = 6; break; } /* Save symbol in vms_symbol_table. */ entry = _bfd_vms_enter_symbol (abfd, _bfd_vms_save_counted_string (vms_rec + name_offset)); if (entry == NULL) { bfd_set_error (bfd_error_no_memory); return -1; } symbol = entry->symbol; if (old_flags & GSY_S_M_DEF) { /* Symbol definition. */ int psect; symbol->value = bfd_getl32 (vms_rec + value_offset); if ((gsd_type == GSD_S_C_SYMW) || (gsd_type == GSD_S_C_EPMW)) psect = bfd_getl16 (vms_rec + value_offset - 2); else psect = vms_rec[value_offset-1]; symbol->section = (asection *)(unsigned long)psect; #if VMS_DEBUG vms_debug (4, "gsd sym def #%d (%s, %ld, %04x=%s)\n", abfd->symcount, symbol->name, (long)symbol->section, old_flags, flag2str(gsyflagdesc, old_flags)); #endif } else { /* Symbol reference. */ #if VMS_DEBUG vms_debug (4, "gsd sym ref #%d (%s, %04x=%s)\n", abfd->symcount, symbol->name, old_flags, flag2str (gsyflagdesc, old_flags)); #endif symbol->section = (asection *)(unsigned long)-1; } gsd_size = vms_rec[name_offset] + name_offset + 1; symbol->flags = new_flags; } break; case GSD_S_C_PRO: case GSD_S_C_PROW: #if VMS_DEBUG vms_debug (4, "gsd pro\n"); #endif break; case GSD_S_C_IDC: #if VMS_DEBUG vms_debug (4, "gsd idc\n"); #endif break; case GSD_S_C_ENV: #if VMS_DEBUG vms_debug (4, "gsd env\n"); #endif break; case GSD_S_C_LSY: #if VMS_DEBUG vms_debug (4, "gsd lsy\n"); #endif break; case GSD_S_C_LEPM: #if VMS_DEBUG vms_debug (4, "gsd lepm\n"); #endif break; case GSD_S_C_LPRO: #if VMS_DEBUG vms_debug (4, "gsd lpro\n"); #endif break; case GSD_S_C_SPSC: #if VMS_DEBUG vms_debug (4, "gsd spsc\n"); #endif break; case GSD_S_C_SYMV: #if VMS_DEBUG vms_debug (4, "gsd symv\n"); #endif break; case GSD_S_C_EPMV: #if VMS_DEBUG vms_debug (4, "gsd epmv\n"); #endif break; case GSD_S_C_PROV: #if VMS_DEBUG vms_debug (4, "gsd prov\n"); #endif break; case EGSD_S_C_PSC + EVAX_OFFSET: { /* Program section definition. */ name = _bfd_vms_save_counted_string (vms_rec + EGPS_S_B_NAMLNG); section = bfd_make_section (abfd, name); if (!section) return -1; old_flags = bfd_getl16 (vms_rec + EGPS_S_W_FLAGS); section->size = bfd_getl32 (vms_rec + EGPS_S_L_ALLOC); new_flags = vms_secflag_by_name (abfd, evax_section_flags, name, section->size > 0); if (old_flags & EGPS_S_V_REL) new_flags |= SEC_RELOC; if (!bfd_set_section_flags (abfd, section, new_flags)) return -1; section->alignment_power = vms_rec[EGPS_S_B_ALIGN]; align_addr = (1 << section->alignment_power); if ((base_addr % align_addr) != 0) base_addr += (align_addr - (base_addr % align_addr)); section->vma = (bfd_vma)base_addr; base_addr += section->size; section->contents = bfd_zmalloc (section->size); if (section->contents == NULL) return -1; section->filepos = (unsigned int)-1; #if VMS_DEBUG vms_debug (4, "EGSD P-section %d (%s, flags %04x=%s) ", section->index, name, old_flags, flag2str(gpsflagdesc, old_flags)); vms_debug (4, "%d bytes at 0x%08lx (mem %p)\n", section->size, section->vma, section->contents); #endif } break; case EGSD_S_C_SYM + EVAX_OFFSET: { /* Global symbol specification (definition or reference). */ symbol = bfd_make_empty_symbol (abfd); if (symbol == 0) return -1; old_flags = bfd_getl16 (vms_rec + EGSY_S_W_FLAGS); new_flags = BSF_NO_FLAGS; if (old_flags & EGSY_S_V_WEAK) new_flags |= BSF_WEAK; if (old_flags & EGSY_S_V_DEF) { /* Symbol definition. */ if (old_flags & EGSY_S_V_NORM) new_flags |= BSF_FUNCTION; symbol->name = _bfd_vms_save_counted_string (vms_rec + ESDF_S_B_NAMLNG); symbol->value = bfd_getl64 (vms_rec + ESDF_S_L_VALUE); symbol->section = (asection *)(unsigned long) bfd_getl32 (vms_rec + ESDF_S_L_PSINDX); #if VMS_DEBUG vms_debug (4, "EGSD sym def #%d (%s, %ld, %04x=%s)\n", abfd->symcount, symbol->name, (long)symbol->section, old_flags, flag2str (gsyflagdesc, old_flags)); #endif } else { /* Symbol reference. */ symbol->name = _bfd_vms_save_counted_string (vms_rec + ESRF_S_B_NAMLNG); #if VMS_DEBUG vms_debug (4, "EGSD sym ref #%d (%s, %04x=%s)\n", abfd->symcount, symbol->name, old_flags, flag2str (gsyflagdesc, old_flags)); #endif symbol->section = (asection *)(unsigned long)-1; } symbol->flags = new_flags; /* Register symbol in VMS symbol table. */ entry = (vms_symbol_entry *) bfd_hash_lookup (PRIV (vms_symbol_table), symbol->name, TRUE, FALSE); if (entry == NULL) { bfd_set_error (bfd_error_no_memory); return -1; } if (entry->symbol != NULL) { /* FIXME ?, DEC C generates this. */ #if VMS_DEBUG vms_debug (4, "EGSD_S_C_SYM: duplicate \"%s\"\n", symbol->name); #endif } else { entry->symbol = symbol; PRIV (gsd_sym_count)++; abfd->symcount++; } } break; case EGSD_S_C_SYMG + EVAX_OFFSET: { /* Universal symbol specification (definition). */ symbol = bfd_make_empty_symbol (abfd); if (symbol == 0) return -1; old_flags = bfd_getl16 (vms_rec + EGST_S_W_FLAGS); new_flags = BSF_NO_FLAGS; if (old_flags & EGSY_S_V_WEAK) new_flags |= BSF_WEAK; if (old_flags & EGSY_S_V_DEF) /* symbol definition */ { if (old_flags & EGSY_S_V_NORM) new_flags |= BSF_FUNCTION; symbol->name = _bfd_vms_save_counted_string (vms_rec + EGST_S_B_NAMLNG); /* For BSF_FUNCTION symbols, the entry point is in LP_1 and the descriptor in LP_2. For other symbols, the unique value is in LP_2. */ symbol->value = bfd_getl64 (vms_rec + EGST_S_Q_LP_2); /* Adding this offset is necessary in order for GDB to read the DWARF-2 debug info from shared libraries. */ if (abfd->flags & DYNAMIC && strstr (symbol->name, "$DWARF2.DEBUG") != 0) symbol->value += PRIV (symvva); } else /* symbol reference */ (*_bfd_error_handler) ("Invalid EGST reference"); symbol->flags = new_flags; if (register_universal_symbol (abfd, symbol, old_flags) < 0) return -1; /* Make a second symbol for the entry point. */ if (symbol->flags & BSF_FUNCTION) { asymbol *en_sym; char *name = bfd_alloc (abfd, strlen (symbol->name) + 5); en_sym = bfd_make_empty_symbol (abfd); if (en_sym == 0) return -1; strcpy (name, symbol->name); strcat (name, "..en"); en_sym->name = name; en_sym->value = bfd_getl64 (vms_rec + EGST_S_Q_LP_1); if (register_universal_symbol (abfd, en_sym, old_flags) < 0) return -1; } } break; case EGSD_S_C_IDC + EVAX_OFFSET: break; default: (*_bfd_error_handler) (_("Unknown GSD/EGSD subtype %d"), gsd_type); bfd_set_error (bfd_error_bad_value); return -1; } PRIV (rec_size) -= gsd_size; PRIV (vms_rec) += gsd_size; } if (abfd->symcount > 0) abfd->flags |= HAS_SYMS; return 0; }
bfd_boolean rs6000coff_core_file_matches_executable_p (bfd *core_bfd, bfd *exec_bfd) { CoreHdr core; bfd_size_type size; char *path, *s; size_t alloc; const char *str1, *str2; bfd_boolean ret; file_ptr c_loader; if (!read_hdr (core_bfd, &core)) return FALSE; if (CORE_NEW (core)) c_loader = CNEW_LOADER (core.new_dump); #ifndef BFD64 else c_loader = (file_ptr) (ptr_to_uint) COLD_LOADER (core.old); #endif if (CORE_NEW (core) && CNEW_PROC64 (core.new_dump)) size = (int) ((LdInfo *) 0)->l64.ldinfo_filename; else size = (int) ((LdInfo *) 0)->l32.ldinfo_filename; if (bfd_seek (core_bfd, c_loader + size, SEEK_SET) != 0) return FALSE; alloc = 100; path = bfd_malloc ((bfd_size_type) alloc); if (path == NULL) return FALSE; s = path; while (1) { if (bfd_bread (s, (bfd_size_type) 1, core_bfd) != 1) { free (path); return FALSE; } if (*s == '\0') break; ++s; if (s == path + alloc) { char *n; alloc *= 2; n = bfd_realloc (path, (bfd_size_type) alloc); if (n == NULL) { free (path); return FALSE; } s = n + (path - s); path = n; } } str1 = strrchr (path, '/'); str2 = strrchr (exec_bfd->filename, '/'); /* step over character '/' */ str1 = str1 != NULL ? str1 + 1 : path; str2 = str2 != NULL ? str2 + 1 : exec_bfd->filename; if (strcmp (str1, str2) == 0) ret = TRUE; else ret = FALSE; free (path); return ret; }
bfd_boolean _bfd_elf_discard_section_eh_frame (bfd *abfd, struct bfd_link_info *info, asection *sec, bfd_boolean (*reloc_symbol_deleted_p) (bfd_vma, void *), struct elf_reloc_cookie *cookie) { bfd_byte *ehbuf = NULL, *buf; bfd_byte *last_cie, *last_fde; struct cie_header hdr; struct cie cie; struct elf_link_hash_table *htab; struct eh_frame_hdr_info *hdr_info; struct eh_frame_sec_info *sec_info = NULL; unsigned int leb128_tmp; unsigned int cie_usage_count, last_cie_ndx, i, offset; unsigned int make_relative, make_lsda_relative; bfd_size_type new_size; unsigned int ptr_size; if (sec->_raw_size == 0) { /* This file does not contain .eh_frame information. */ return FALSE; } if ((sec->output_section != NULL && bfd_is_abs_section (sec->output_section))) { /* At least one of the sections is being discarded from the link, so we should just ignore them. */ return FALSE; } htab = elf_hash_table (info); hdr_info = &htab->eh_info; /* Read the frame unwind information from abfd. */ ehbuf = bfd_malloc (sec->_raw_size); if (ehbuf == NULL) goto free_no_table; if (! bfd_get_section_contents (abfd, sec, ehbuf, 0, sec->_raw_size)) goto free_no_table; if (sec->_raw_size >= 4 && bfd_get_32 (abfd, ehbuf) == 0 && cookie->rel == cookie->relend) { /* Empty .eh_frame section. */ free (ehbuf); return FALSE; } /* If .eh_frame section size doesn't fit into int, we cannot handle it (it would need to use 64-bit .eh_frame format anyway). */ if (sec->_raw_size != (unsigned int) sec->_raw_size) goto free_no_table; ptr_size = (elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64) ? 8 : 4; buf = ehbuf; last_cie = NULL; last_cie_ndx = 0; memset (&cie, 0, sizeof (cie)); cie_usage_count = 0; new_size = sec->_raw_size; make_relative = hdr_info->last_cie.make_relative; make_lsda_relative = hdr_info->last_cie.make_lsda_relative; sec_info = bfd_zmalloc (sizeof (struct eh_frame_sec_info) + 99 * sizeof (struct eh_cie_fde)); if (sec_info == NULL) goto free_no_table; sec_info->alloced = 100; #define ENSURE_NO_RELOCS(buf) \ if (cookie->rel < cookie->relend \ && (cookie->rel->r_offset \ < (bfd_size_type) ((buf) - ehbuf)) \ && cookie->rel->r_info != 0) \ goto free_no_table #define SKIP_RELOCS(buf) \ while (cookie->rel < cookie->relend \ && (cookie->rel->r_offset \ < (bfd_size_type) ((buf) - ehbuf))) \ cookie->rel++ #define GET_RELOC(buf) \ ((cookie->rel < cookie->relend \ && (cookie->rel->r_offset \ == (bfd_size_type) ((buf) - ehbuf))) \ ? cookie->rel : NULL) for (;;) { unsigned char *aug; if (sec_info->count == sec_info->alloced) { sec_info = bfd_realloc (sec_info, sizeof (struct eh_frame_sec_info) + (sec_info->alloced + 99) * sizeof (struct eh_cie_fde)); if (sec_info == NULL) goto free_no_table; memset (&sec_info->entry[sec_info->alloced], 0, 100 * sizeof (struct eh_cie_fde)); sec_info->alloced += 100; } last_fde = buf; /* If we are at the end of the section, we still need to decide on whether to output or discard last encountered CIE (if any). */ if ((bfd_size_type) (buf - ehbuf) == sec->_raw_size) hdr.id = (unsigned int) -1; else { if ((bfd_size_type) (buf + 4 - ehbuf) > sec->_raw_size) /* No space for CIE/FDE header length. */ goto free_no_table; hdr.length = bfd_get_32 (abfd, buf); if (hdr.length == 0xffffffff) /* 64-bit .eh_frame is not supported. */ goto free_no_table; buf += 4; if ((bfd_size_type) (buf - ehbuf) + hdr.length > sec->_raw_size) /* CIE/FDE not contained fully in this .eh_frame input section. */ goto free_no_table; sec_info->entry[sec_info->count].offset = last_fde - ehbuf; sec_info->entry[sec_info->count].size = 4 + hdr.length; if (hdr.length == 0) { /* CIE with length 0 must be only the last in the section. */ if ((bfd_size_type) (buf - ehbuf) < sec->_raw_size) goto free_no_table; ENSURE_NO_RELOCS (buf); sec_info->count++; /* Now just finish last encountered CIE processing and break the loop. */ hdr.id = (unsigned int) -1; } else { hdr.id = bfd_get_32 (abfd, buf); buf += 4; if (hdr.id == (unsigned int) -1) goto free_no_table; } } if (hdr.id == 0 || hdr.id == (unsigned int) -1) { unsigned int initial_insn_length; /* CIE */ if (last_cie != NULL) { /* Now check if this CIE is identical to the last CIE, in which case we can remove it provided we adjust all FDEs. Also, it can be removed if we have removed all FDEs using it. */ if ((!info->relocatable && hdr_info->last_cie_sec && (sec->output_section == hdr_info->last_cie_sec->output_section) && cie_compare (&cie, &hdr_info->last_cie) == 0) || cie_usage_count == 0) { new_size -= cie.hdr.length + 4; sec_info->entry[last_cie_ndx].removed = 1; sec_info->entry[last_cie_ndx].sec = hdr_info->last_cie_sec; sec_info->entry[last_cie_ndx].new_offset = hdr_info->last_cie_offset; } else { hdr_info->last_cie = cie; hdr_info->last_cie_sec = sec; hdr_info->last_cie_offset = last_cie - ehbuf; sec_info->entry[last_cie_ndx].make_relative = cie.make_relative; sec_info->entry[last_cie_ndx].make_lsda_relative = cie.make_lsda_relative; sec_info->entry[last_cie_ndx].per_encoding_relative = (cie.per_encoding & 0x70) == DW_EH_PE_pcrel; } } if (hdr.id == (unsigned int) -1) break; last_cie_ndx = sec_info->count; sec_info->entry[sec_info->count].cie = 1; cie_usage_count = 0; memset (&cie, 0, sizeof (cie)); cie.hdr = hdr; cie.version = *buf++; /* Cannot handle unknown versions. */ if (cie.version != 1) goto free_no_table; if (strlen (buf) > sizeof (cie.augmentation) - 1) goto free_no_table; strcpy (cie.augmentation, buf); buf = strchr (buf, '\0') + 1; ENSURE_NO_RELOCS (buf); if (buf[0] == 'e' && buf[1] == 'h') { /* GCC < 3.0 .eh_frame CIE */ /* We cannot merge "eh" CIEs because __EXCEPTION_TABLE__ is private to each CIE, so we don't need it for anything. Just skip it. */ buf += ptr_size; SKIP_RELOCS (buf); } read_uleb128 (cie.code_align, buf); read_sleb128 (cie.data_align, buf); /* Note - in DWARF2 the return address column is an unsigned byte. In DWARF3 it is a ULEB128. We are following DWARF3. For most ports this will not matter as the value will be less than 128. For the others (eg FRV, SH, MMIX, IA64) they need a fixed GCC which conforms to the DWARF3 standard. */ read_uleb128 (cie.ra_column, buf); ENSURE_NO_RELOCS (buf); cie.lsda_encoding = DW_EH_PE_omit; cie.fde_encoding = DW_EH_PE_omit; cie.per_encoding = DW_EH_PE_omit; aug = cie.augmentation; if (aug[0] != 'e' || aug[1] != 'h') { if (*aug == 'z') { aug++; read_uleb128 (cie.augmentation_size, buf); ENSURE_NO_RELOCS (buf); } while (*aug != '\0') switch (*aug++) { case 'L': cie.lsda_encoding = *buf++; ENSURE_NO_RELOCS (buf); if (get_DW_EH_PE_width (cie.lsda_encoding, ptr_size) == 0) goto free_no_table; break; case 'R': cie.fde_encoding = *buf++; ENSURE_NO_RELOCS (buf); if (get_DW_EH_PE_width (cie.fde_encoding, ptr_size) == 0) goto free_no_table; break; case 'P': { int per_width; cie.per_encoding = *buf++; per_width = get_DW_EH_PE_width (cie.per_encoding, ptr_size); if (per_width == 0) goto free_no_table; if ((cie.per_encoding & 0xf0) == DW_EH_PE_aligned) buf = (ehbuf + ((buf - ehbuf + per_width - 1) & ~((bfd_size_type) per_width - 1))); ENSURE_NO_RELOCS (buf); /* Ensure we have a reloc here, against a global symbol. */ if (GET_RELOC (buf) != NULL) { unsigned long r_symndx; #ifdef BFD64 if (ptr_size == 8) r_symndx = ELF64_R_SYM (cookie->rel->r_info); else #endif r_symndx = ELF32_R_SYM (cookie->rel->r_info); if (r_symndx >= cookie->locsymcount) { struct elf_link_hash_entry *h; r_symndx -= cookie->extsymoff; h = cookie->sym_hashes[r_symndx]; while (h->root.type == bfd_link_hash_indirect || h->root.type == bfd_link_hash_warning) h = (struct elf_link_hash_entry *) h->root.u.i.link; cie.personality = h; } cookie->rel++; } buf += per_width; } break; default: /* Unrecognized augmentation. Better bail out. */ goto free_no_table; } } /* For shared libraries, try to get rid of as many RELATIVE relocs as possible. */ if (info->shared && (get_elf_backend_data (abfd) ->elf_backend_can_make_relative_eh_frame (abfd, info, sec)) && (cie.fde_encoding & 0xf0) == DW_EH_PE_absptr) cie.make_relative = 1; if (info->shared && (get_elf_backend_data (abfd) ->elf_backend_can_make_lsda_relative_eh_frame (abfd, info, sec)) && (cie.lsda_encoding & 0xf0) == DW_EH_PE_absptr) cie.make_lsda_relative = 1; /* If FDE encoding was not specified, it defaults to DW_EH_absptr. */ if (cie.fde_encoding == DW_EH_PE_omit) cie.fde_encoding = DW_EH_PE_absptr; initial_insn_length = cie.hdr.length - (buf - last_fde - 4); if (initial_insn_length <= 50) { cie.initial_insn_length = initial_insn_length; memcpy (cie.initial_instructions, buf, initial_insn_length); } buf += initial_insn_length; ENSURE_NO_RELOCS (buf); last_cie = last_fde; } else { /* Ensure this FDE uses the last CIE encountered. */ if (last_cie == NULL || hdr.id != (unsigned int) (buf - 4 - last_cie)) goto free_no_table; ENSURE_NO_RELOCS (buf); if (GET_RELOC (buf) == NULL) /* This should not happen. */ goto free_no_table; if ((*reloc_symbol_deleted_p) (buf - ehbuf, cookie)) { /* This is a FDE against a discarded section. It should be deleted. */ new_size -= hdr.length + 4; sec_info->entry[sec_info->count].removed = 1; } else { if (info->shared && (((cie.fde_encoding & 0xf0) == DW_EH_PE_absptr && cie.make_relative == 0) || (cie.fde_encoding & 0xf0) == DW_EH_PE_aligned)) { /* If a shared library uses absolute pointers which we cannot turn into PC relative, don't create the binary search table, since it is affected by runtime relocations. */ hdr_info->table = FALSE; } cie_usage_count++; hdr_info->fde_count++; } if (cie.lsda_encoding != DW_EH_PE_omit) { unsigned int dummy; aug = buf; buf += 2 * get_DW_EH_PE_width (cie.fde_encoding, ptr_size); if (cie.augmentation[0] == 'z') read_uleb128 (dummy, buf); /* If some new augmentation data is added before LSDA in FDE augmentation area, this need to be adjusted. */ sec_info->entry[sec_info->count].lsda_offset = (buf - aug); } buf = last_fde + 4 + hdr.length; SKIP_RELOCS (buf); } sec_info->entry[sec_info->count].fde_encoding = cie.fde_encoding; sec_info->entry[sec_info->count].lsda_encoding = cie.lsda_encoding; sec_info->count++; } elf_section_data (sec)->sec_info = sec_info; sec->sec_info_type = ELF_INFO_TYPE_EH_FRAME; /* Ok, now we can assign new offsets. */ offset = 0; last_cie_ndx = 0; for (i = 0; i < sec_info->count; i++) { if (! sec_info->entry[i].removed) { sec_info->entry[i].new_offset = offset; offset += sec_info->entry[i].size; if (sec_info->entry[i].cie) { last_cie_ndx = i; make_relative = sec_info->entry[i].make_relative; make_lsda_relative = sec_info->entry[i].make_lsda_relative; } else { sec_info->entry[i].make_relative = make_relative; sec_info->entry[i].make_lsda_relative = make_lsda_relative; sec_info->entry[i].per_encoding_relative = 0; } } else if (sec_info->entry[i].cie && sec_info->entry[i].sec == sec) { /* Need to adjust new_offset too. */ BFD_ASSERT (sec_info->entry[last_cie_ndx].offset == sec_info->entry[i].new_offset); sec_info->entry[i].new_offset = sec_info->entry[last_cie_ndx].new_offset; } } if (hdr_info->last_cie_sec == sec) { BFD_ASSERT (sec_info->entry[last_cie_ndx].offset == hdr_info->last_cie_offset); hdr_info->last_cie_offset = sec_info->entry[last_cie_ndx].new_offset; } /* FIXME: Currently it is not possible to shrink sections to zero size at this point, so build a fake minimal CIE. */ if (new_size == 0) new_size = 16; /* Shrink the sec as needed. */ sec->_cooked_size = new_size; if (sec->_cooked_size == 0) sec->flags |= SEC_EXCLUDE; free (ehbuf); return new_size != sec->_raw_size; free_no_table: if (ehbuf) free (ehbuf); if (sec_info) free (sec_info); hdr_info->table = FALSE; hdr_info->last_cie.hdr.length = 0; return FALSE; }
bfd_boolean bfd_get_file_window (bfd *abfd, file_ptr offset, bfd_size_type size, bfd_window *windowp, bfd_boolean writable) { static size_t pagesize; bfd_window_internal *i = windowp->i; bfd_size_type size_to_alloc = size; if (debug_windows) fprintf (stderr, "bfd_get_file_window (%p, %6ld, %6ld, %p<%p,%lx,%p>, %d)", abfd, (long) offset, (long) size, windowp, windowp->data, (unsigned long) windowp->size, windowp->i, writable); /* Make sure we know the page size, so we can be friendly to mmap. */ if (pagesize == 0) pagesize = getpagesize (); if (pagesize == 0) abort (); if (i == 0) { i = bfd_zmalloc (sizeof (bfd_window_internal)); windowp->i = i; if (i == 0) return FALSE; i->data = 0; } #ifdef HAVE_MMAP if (ok_to_map && (i->data == 0 || i->mapped == 1) && (abfd->flags & BFD_IN_MEMORY) == 0) { file_ptr file_offset, offset2; size_t real_size; int fd; /* Find the real file and the real offset into it. */ while (abfd->my_archive != NULL) { offset += abfd->origin; abfd = abfd->my_archive; } /* Seek into the file, to ensure it is open if cacheable. */ if (abfd->iostream == NULL && (abfd->iovec == NULL || abfd->iovec->bseek (abfd, offset, SEEK_SET) != 0)) return FALSE; fd = fileno ((FILE *) abfd->iostream); /* Compute offsets and size for mmap and for the user's data. */ offset2 = offset % pagesize; if (offset2 < 0) abort (); file_offset = offset - offset2; real_size = offset + size - file_offset; real_size = real_size + pagesize - 1; real_size -= real_size % pagesize; /* If we're re-using a memory region, make sure it's big enough. */ if (i->data && i->size < size) { munmap (i->data, i->size); i->data = 0; } i->data = mmap (i->data, real_size, writable ? PROT_WRITE | PROT_READ : PROT_READ, (writable ? MAP_FILE | MAP_PRIVATE : MAP_FILE | MAP_SHARED), fd, file_offset); if (i->data == (void *) -1) { /* An error happened. Report it, or try using malloc, or something. */ bfd_set_error (bfd_error_system_call); i->data = 0; windowp->data = 0; if (debug_windows) fprintf (stderr, "\t\tmmap failed!\n"); return FALSE; } if (debug_windows) fprintf (stderr, "\n\tmapped %ld at %p, offset is %ld\n", (long) real_size, i->data, (long) offset2); i->size = real_size; windowp->data = (bfd_byte *) i->data + offset2; windowp->size = size; i->mapped = 1; return TRUE; } else if (debug_windows) { if (ok_to_map) fprintf (stderr, _("not mapping: data=%lx mapped=%d\n"), (unsigned long) i->data, (int) i->mapped); else fprintf (stderr, _("not mapping: env var not set\n")); } #else ok_to_map = 0; #endif #ifdef HAVE_MPROTECT if (!writable) { size_to_alloc += pagesize - 1; size_to_alloc -= size_to_alloc % pagesize; } #endif if (debug_windows) fprintf (stderr, "\n\t%s(%6ld)", i->data ? "realloc" : " malloc", (long) size_to_alloc); i->data = bfd_realloc (i->data, size_to_alloc); if (debug_windows) fprintf (stderr, "\t-> %p\n", i->data); i->refcount = 1; if (i->data == NULL) { if (size_to_alloc == 0) return TRUE; return FALSE; } if (bfd_seek (abfd, offset, SEEK_SET) != 0) return FALSE; i->size = bfd_bread (i->data, size, abfd); if (i->size != size) return FALSE; i->mapped = 0; #ifdef HAVE_MPROTECT if (!writable) { if (debug_windows) fprintf (stderr, "\tmprotect (%p, %ld, PROT_READ)\n", i->data, (long) i->size); mprotect (i->data, i->size, PROT_READ); } #endif windowp->data = i->data; windowp->size = i->size; return TRUE; }
/* Process GSD/EGSD record. * Return 0 on success, -1 on error. */ int _bfd_vms_slurp_gsd(bfd * abfd, int objtype) { #if defined(VMS_DEBUG) && VMS_DEBUG static struct flagdescstruct gpsflagdesc[] = { { "PIC", 0x0001 }, { "LIB", 0x0002 }, { "OVR", 0x0004 }, { "REL", 0x0008 }, { "GBL", 0x0010 }, { "SHR", 0x0020 }, { "EXE", 0x0040 }, { "RD", 0x0080 }, { "WRT", 0x0100 }, { "VEC", 0x0200 }, { "NOMOD", 0x0400 }, { "COM", 0x0800 }, { NULL, 0 } }; static struct flagdescstruct gsyflagdesc[] = { { "WEAK", 0x0001 }, { "DEF", 0x0002 }, { "UNI", 0x0004 }, { "REL", 0x0008 }, { "COMM", 0x0010 }, { "VECEP", 0x0020 }, { "NORM", 0x0040 }, { NULL, 0 } }; #endif /* VMS_DEBUG */ int gsd_type, gsd_size; asection *section; unsigned char *vms_rec; flagword new_flags, old_flags; char *name; asymbol *symbol; vms_symbol_entry *entry; unsigned long base_addr; unsigned long align_addr; static unsigned int psect_idx = 0; gsd_size = 0; #if defined(VMS_DEBUG) && VMS_DEBUG vms_debug(2, "GSD/EGSD (%d/%x)\n", objtype, objtype); #endif /* VMS_DEBUG */ switch (objtype) { case EOBJ_S_C_EGSD: PRIV(vms_rec) += 8; /* Skip type, size, l_temp. */ PRIV(rec_size) -= 8; break; case OBJ_S_C_GSD: PRIV(vms_rec) += 1; PRIV(rec_size) -= 1; break; default: return -1; } /* Calculate base address for each section: */ base_addr = 0L; abfd->symcount = 0; while (PRIV(rec_size) > 0) { vms_rec = PRIV(vms_rec); if (objtype == OBJ_S_C_GSD) gsd_type = *vms_rec; else { _bfd_vms_get_header_values(abfd, vms_rec, &gsd_type, &gsd_size); gsd_type += EVAX_OFFSET; } #if defined(VMS_DEBUG) && VMS_DEBUG vms_debug (3, "gsd_type %d\n", gsd_type); #endif switch (gsd_type) { case GSD_S_C_PSC: { /* Program section definition. */ asection *old_section = 0; #if defined(VMS_DEBUG) && VMS_DEBUG vms_debug (4, "GSD_S_C_PSC\n"); #endif /* If this section isn't a bfd section. */ if (PRIV (is_vax) && (psect_idx < (abfd->section_count-1))) { /* Check for temporary section from TIR record. */ if (psect_idx < PRIV (section_count)) old_section = PRIV (sections)[psect_idx]; else old_section = 0; } name = _bfd_vms_save_counted_string (vms_rec + 8); section = bfd_make_section (abfd, name); if (!section) { (*_bfd_error_handler) (_("bfd_make_section (%s) failed"), name); return -1; } old_flags = bfd_getl16 (vms_rec + 2); section->size = bfd_getl32 (vms_rec + 4); /* allocation */ new_flags = vms_secflag_by_name (abfd, vax_section_flags, name, section->size > 0); if (old_flags & EGPS_S_V_REL) new_flags |= SEC_RELOC; if (old_flags & GPS_S_M_OVR) new_flags |= SEC_IS_COMMON; if (!bfd_set_section_flags (abfd, section, new_flags)) { (*_bfd_error_handler) (_("bfd_set_section_flags (%s, %x) failed"), name, new_flags); return -1; } section->alignment_power = vms_rec[1]; align_addr = (1 << section->alignment_power); if ((base_addr % align_addr) != 0) base_addr += (align_addr - (base_addr % align_addr)); section->vma = (bfd_vma)base_addr; base_addr += section->size; /* Global section is common symbol. */ if (old_flags & GPS_S_M_GBL) { entry = _bfd_vms_enter_symbol (abfd, name); if (entry == NULL) { bfd_set_error (bfd_error_no_memory); return -1; } symbol = entry->symbol; symbol->value = 0; symbol->section = section; symbol->flags = (BSF_GLOBAL | BSF_SECTION_SYM | BSF_OLD_COMMON); } /* Copy saved contents if old_section set. */ if (old_section != 0) { section->contents = old_section->contents; if (section->size < old_section->size) { (*_bfd_error_handler) (_("Size mismatch section %s=%lx, %s=%lx"), old_section->name, (unsigned long) old_section->size, section->name, (unsigned long) section->size); return -1; } else if (section->size > old_section->size) { section->contents = (unsigned char *)bfd_realloc(old_section->contents, section->size); if (section->contents == NULL) { bfd_set_error (bfd_error_no_memory); return -1; } } } else { section->contents = (unsigned char *)bfd_zmalloc(section->size); if (section->contents == NULL) { bfd_set_error (bfd_error_no_memory); return -1; } } #if defined(VMS_DEBUG) && VMS_DEBUG vms_debug (4, "gsd psc %d (%s, flags %04x=%s) ", section->index, name, old_flags, flag2str (gpsflagdesc, old_flags)); vms_debug (4, "%d bytes at 0x%08lx (mem %p)\n", section->size, section->vma, section->contents); #endif /* VMS_DEBUG */ gsd_size = vms_rec[8] + 9; psect_idx++; } break; case GSD_S_C_EPM: case GSD_S_C_EPMW: #if defined(VMS_DEBUG) && VMS_DEBUG vms_debug (4, "gsd epm\n"); #endif /* Fall through. */ case GSD_S_C_SYM: case GSD_S_C_SYMW: { int name_offset = 0, value_offset = 0; /* Symbol specification (definition or reference). */ #if defined(VMS_DEBUG) && VMS_DEBUG vms_debug(4, "GSD_S_C_SYM(W)\n"); #endif old_flags = bfd_getl16 (vms_rec + 2); new_flags = BSF_NO_FLAGS; if (old_flags & GSY_S_M_WEAK) new_flags |= BSF_WEAK; switch (gsd_type) { case GSD_S_C_EPM: name_offset = 11; value_offset = 5; new_flags |= BSF_FUNCTION; break; case GSD_S_C_EPMW: name_offset = 12; value_offset = 6; new_flags |= BSF_FUNCTION; break; case GSD_S_C_SYM: if (old_flags & GSY_S_M_DEF) /* Symbol definition. */ name_offset = 9; else name_offset = 4; value_offset = 5; break; case GSD_S_C_SYMW: if (old_flags & GSY_S_M_DEF) /* Symbol definition. */ name_offset = 10; else name_offset = 5; value_offset = 6; break; default: break; } /* end "switch (gsd_type)" */ /* Save symbol in vms_symbol_table: */ entry = _bfd_vms_enter_symbol(abfd, _bfd_vms_save_counted_string(vms_rec + name_offset)); if (entry == NULL) { bfd_set_error (bfd_error_no_memory); return -1; } symbol = entry->symbol; if (old_flags & GSY_S_M_DEF) { /* Symbol definition. */ int psect; symbol->value = bfd_getl32 (vms_rec + value_offset); if ((gsd_type == GSD_S_C_SYMW) || (gsd_type == GSD_S_C_EPMW)) psect = bfd_getl16 (vms_rec + value_offset - 2); else psect = vms_rec[value_offset-1]; symbol->section = (asection *) (size_t) psect; #if defined(VMS_DEBUG) && VMS_DEBUG vms_debug (4, "gsd sym def #%d (%s, %d [%p], %04x=%s)\n", abfd->symcount, symbol->name, (int)symbol->section, symbol->section, old_flags, flag2str (gsyflagdesc, old_flags)); #endif } else { /* Symbol reference. */ symbol->section = bfd_make_section (abfd, BFD_UND_SECTION_NAME); #if defined(VMS_DEBUG) && VMS_DEBUG vms_debug (4, "gsd sym ref #%d (%s, %s [%p], %04x=%s)\n", abfd->symcount, symbol->name, symbol->section->name, symbol->section, old_flags, flag2str (gsyflagdesc, old_flags)); #endif } gsd_size = vms_rec[name_offset] + name_offset + 1; symbol->flags = new_flags; } break; case GSD_S_C_PRO: case GSD_S_C_PROW: #if defined(VMS_DEBUG) && VMS_DEBUG vms_debug (4, "gsd pro\n"); #endif break; case GSD_S_C_IDC: #if defined(VMS_DEBUG) && VMS_DEBUG vms_debug (4, "gsd idc\n"); #endif break; case GSD_S_C_ENV: #if defined(VMS_DEBUG) && VMS_DEBUG vms_debug (4, "gsd env\n"); #endif break; case GSD_S_C_LSY: #if defined(VMS_DEBUG) && VMS_DEBUG vms_debug (4, "gsd lsy\n"); #endif break; case GSD_S_C_LEPM: #if defined(VMS_DEBUG) && VMS_DEBUG vms_debug (4, "gsd lepm\n"); #endif break; case GSD_S_C_LPRO: #if defined(VMS_DEBUG) && VMS_DEBUG vms_debug (4, "gsd lpro\n"); #endif break; case GSD_S_C_SPSC: #if defined(VMS_DEBUG) && VMS_DEBUG vms_debug (4, "gsd spsc\n"); #endif break; case GSD_S_C_SYMV: #if defined(VMS_DEBUG) && VMS_DEBUG vms_debug (4, "gsd symv\n"); #endif break; case GSD_S_C_EPMV: #if defined(VMS_DEBUG) && VMS_DEBUG vms_debug (4, "gsd epmv\n"); #endif break; case GSD_S_C_PROV: #if defined(VMS_DEBUG) && VMS_DEBUG vms_debug (4, "gsd prov\n"); #endif break; case EGSD_S_C_PSC + EVAX_OFFSET: { /* Program section definition. */ name = _bfd_vms_save_counted_string (vms_rec + 12); section = bfd_make_section (abfd, name); if (!section) return -1; old_flags = bfd_getl16 (vms_rec + 6); section->size = bfd_getl32 (vms_rec + 8); /* Allocation. */ new_flags = vms_secflag_by_name (abfd, evax_section_flags, name, section->size > 0); if (old_flags & EGPS_S_V_REL) new_flags |= SEC_RELOC; if (!bfd_set_section_flags (abfd, section, new_flags)) return -1; section->alignment_power = vms_rec[4]; align_addr = (1 << section->alignment_power); if ((base_addr % align_addr) != 0) base_addr += (align_addr - (base_addr % align_addr)); section->vma = (bfd_vma)base_addr; base_addr += section->size; section->contents = (unsigned char *)bfd_zmalloc(section->size); if (section->contents == NULL) return -1; #if defined(VMS_DEBUG) && VMS_DEBUG vms_debug (4, "egsd psc %d (%s, flags %04x=%s) ", section->index, name, old_flags, flag2str (gpsflagdesc, old_flags)); vms_debug (4, "%d bytes at 0x%08lx (mem %p)\n", section->size, section->vma, section->contents); #endif } break; case EGSD_S_C_SYM + EVAX_OFFSET: { /* Symbol specification (definition or reference). */ symbol = bfd_make_empty_symbol (abfd); if (symbol == 0) return -1; old_flags = bfd_getl16 (vms_rec + 6); new_flags = BSF_NO_FLAGS; if (old_flags & EGSY_S_V_WEAK) new_flags |= BSF_WEAK; if (vms_rec[6] & EGSY_S_V_DEF) { /* Symbol definition. */ symbol->name = _bfd_vms_save_counted_string (vms_rec + 32); if (old_flags & EGSY_S_V_NORM) /* Proc def. */ new_flags |= BSF_FUNCTION; symbol->value = bfd_getl64 (vms_rec + 8); symbol->section = (asection *) ((unsigned long) bfd_getl32 (vms_rec + 28)); #if defined(VMS_DEBUG) && VMS_DEBUG vms_debug (4, "egsd sym def #%d (%s, %d, %04x=%s)\n", abfd->symcount, symbol->name, (int) symbol->section, old_flags, flag2str (gsyflagdesc, old_flags)); #endif } else { /* Symbol reference. */ symbol->name = _bfd_vms_save_counted_string (vms_rec + 8); #if defined(VMS_DEBUG) && VMS_DEBUG vms_debug (4, "egsd sym ref #%d (%s, %04x=%s)\n", abfd->symcount, symbol->name, old_flags, flag2str (gsyflagdesc, old_flags)); #endif symbol->section = bfd_make_section (abfd, BFD_UND_SECTION_NAME); } symbol->flags = new_flags; /* Save symbol in vms_symbol_table: */ entry = (vms_symbol_entry *)bfd_hash_lookup(PRIV(vms_symbol_table), symbol->name, TRUE, FALSE); if (entry == NULL) { bfd_set_error(bfd_error_no_memory); return -1; } if (entry->symbol != NULL) { /* FIXME ?, DEC C generates this. */ #if defined(VMS_DEBUG) && VMS_DEBUG vms_debug(4, "EGSD_S_C_SYM: duplicate \"%s\"\n", symbol->name); #endif /* VMS_DEBUG */ } else { entry->symbol = symbol; PRIV(gsd_sym_count)++; abfd->symcount++; } } break; case EGSD_S_C_IDC + EVAX_OFFSET: break; default: (*_bfd_error_handler)(_("unknown gsd/egsd subtype %d"), gsd_type); bfd_set_error(bfd_error_bad_value); return -1; } PRIV(rec_size) -= gsd_size; PRIV(vms_rec) += gsd_size; } if (abfd->symcount > 0) abfd->flags |= HAS_SYMS; return 0; }