aboutsummaryrefslogtreecommitdiff
path: root/gdb/solib-svr4.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/solib-svr4.c')
-rw-r--r--gdb/solib-svr4.c99
1 files changed, 99 insertions, 0 deletions
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
index 8378eca..398123f 100644
--- a/gdb/solib-svr4.c
+++ b/gdb/solib-svr4.c
@@ -3093,6 +3093,37 @@ svr4_truncate_ptr (CORE_ADDR addr)
return addr & (((CORE_ADDR) 1 << gdbarch_ptr_bit (current_inferior ()->arch ())) - 1);
}
+/* Find the LOAD-able program header in ABFD that contains ASECT. Return
+ NULL if no such header can be found. */
+
+static Elf_Internal_Phdr *
+find_loadable_elf_internal_phdr (bfd *abfd, bfd_section *asect)
+{
+ Elf_Internal_Ehdr *ehdr = elf_tdata (abfd)->elf_header;
+ Elf_Internal_Phdr *phdr = elf_tdata (abfd)->phdr;
+
+ for (int i = 0; i < ehdr->e_phnum; i++)
+ {
+ if (phdr[i].p_type == PT_LOAD)
+ {
+ /* A section without the SEC_LOAD flag is a no-bits section
+ (e.g. .bss) and has zero size within ABFD. */
+ ULONGEST section_file_size
+ = (((bfd_section_flags (asect) & SEC_LOAD) != 0)
+ ? bfd_section_size (asect)
+ : 0);
+
+ if (asect->filepos >= phdr[i].p_offset
+ && ((asect->filepos + section_file_size)
+ <= (phdr[i].p_offset + phdr[i].p_filesz)))
+ return &phdr[i];
+ }
+ }
+
+ return nullptr;
+}
+
+/* Implement solib_ops::relocate_section_addresses() for svr4 targets. */
static void
svr4_relocate_section_addresses (solib &so, target_section *sec)
@@ -3101,6 +3132,74 @@ svr4_relocate_section_addresses (solib &so, target_section *sec)
sec->addr = svr4_truncate_ptr (sec->addr + lm_addr_check (so, abfd));
sec->endaddr = svr4_truncate_ptr (sec->endaddr + lm_addr_check (so, abfd));
+
+ struct bfd_section *asect = sec->the_bfd_section;
+ gdb_assert (asect != nullptr);
+
+ /* Update the address range of SO based on ASECT. */
+ if ((bfd_section_flags (asect) & SEC_ALLOC) != 0
+ && bfd_get_flavour (abfd) == bfd_target_elf_flavour)
+ {
+ /* First, SO must cover the contents of ASECT. */
+ if (so.addr_low == 0 || sec->addr < so.addr_low)
+ so.addr_low = sec->addr;
+
+ if (so.addr_high == 0 || sec->endaddr > so.addr_high)
+ so.addr_high = sec->endaddr;
+
+ gdb_assert (so.addr_low <= so.addr_high);
+
+ /* But we can do better. Find the program header which contains
+ ASECT, and figure out its extents. This gives an larger possible
+ region for SO. */
+ Elf_Internal_Phdr *phdr = find_loadable_elf_internal_phdr (abfd, asect);
+
+ if (phdr != nullptr)
+ {
+ /* Figure out the alignment required by this segment. */
+ ULONGEST minpagesize = get_elf_backend_data (abfd)->minpagesize;
+ ULONGEST segment_alignment
+ = std::max (minpagesize, static_cast<ULONGEST> (phdr->p_align));
+ ULONGEST at_pagesz;
+ if (target_auxv_search (AT_PAGESZ, &at_pagesz) > 0)
+ segment_alignment = std::max (segment_alignment, at_pagesz);
+
+ /* The offset of this section within the segment. */
+ ULONGEST section_offset = asect->vma - phdr->p_vaddr;
+
+ /* The start address for the segment, without alignment. */
+ CORE_ADDR unaligned_start = sec->addr - section_offset;
+
+ /* And the start address with downward alignment. */
+ CORE_ADDR aligned_start
+ = align_down (unaligned_start, segment_alignment);
+
+ /* The end address of the segment depends on its size. Start
+ with the size as described in the ELF. This check of the
+ memory size and file size is what BFD does, so assume it
+ knows best and copy this logic. */
+ ULONGEST seg_size = std::max (phdr->p_memsz, phdr->p_filesz);
+
+ /* But by aligning the start address down we need to also include
+ that difference in the segment size. */
+ seg_size += (unaligned_start - aligned_start);
+
+ /* And align the segment size upward. */
+ seg_size = align_up (seg_size, segment_alignment);
+
+ /* Finally, we can compute the end address. */
+ CORE_ADDR end = aligned_start + seg_size;
+
+ /* And now we can update the extend of SO. */
+ if (so.addr_low == 0 || aligned_start < so.addr_low)
+ so.addr_low = aligned_start;
+
+ if (so.addr_high == 0 || end > so.addr_high)
+ so.addr_high = end;
+
+ gdb_assert (so.addr_low <= so.addr_high);
+ }
+ }
}