gdb: show full shared library memory range in 'info sharedlibrary'
Checks
Context |
Check |
Description |
linaro-tcwg-bot/tcwg_gdb_build--master-aarch64 |
success
|
Build passed
|
linaro-tcwg-bot/tcwg_gdb_build--master-arm |
fail
|
Build failed
|
linaro-tcwg-bot/tcwg_gdb_check--master-aarch64 |
success
|
Test passed
|
Commit Message
On GNU/Linux (and other targets that use solib-svr4.c) the 'info
sharedlibrary' command displays the address range for the .text
section of each library. This is a fallback behaviour implemented in
solib_map_sections (in solib.c), for targets which are not able to
provide any better information.
The manual doesn't really explain what the address range given means,
and the .text fallback certainly isn't described. The manual for
'info sharedlibrary' just says:
'info share REGEX'
'info sharedlibrary REGEX'
Print the names of the shared libraries which are currently loaded
that match REGEX. If REGEX is omitted then print all shared
libraries that are loaded.
In this commit I propose that we should change GDB so that the full
library address range is listed for GNU/Linux (and other solib-svr4
targets). Though it is certainly useful to know where the .text for a
library is, not all code is placed into the .text section, and data,
or course, is stored elsewhere, so the choice of .text, though not a
crazy default, is still a pretty arbitrary choice.
We do also have 'maintenance info sections', which can be used to find
the location of a specific section. This is of course, a maintenance
command, but we could make this into a real user command if we wanted,
so the information lost by this change to 'info sharedlibrary' is
still available if needed.
There is one small problem. After this commit, GDB is still under
reporting the extents of some libraries, in some cases.
What I observe is that sometimes, for reasons that I don't currently
understand, the run-time linker will over allocate memory for the .bss
like sections, e.g. the ELF says that 1 page is required, but 2 or 4
pages will be allocated instead. As a result, GDB will under report
the extent of the library, with the end address being lower than
expected. This isn't always the case though, in many cases the
allocates are as I would expect, and GDB reports the correct values.
However, as we have been under reporting for many years, I think this
update, which gets things a lot closer to reality, is a big step in
the right direction. We can always improve the results more later
on if/when the logic behind the over allocations become clearer.
For testing I've compared the output of 'info proc mappings' with the
output of 'info sharedlibrary' (using a script), using GDB to debug
itself, on Fedora Linux running on AArch64, PPC64, S390, and X86-64,
and other than the over allocation problem described above, the
results all look good to me.
---
gdb/NEWS | 7 ++++
gdb/doc/gdb.texinfo | 6 +++
gdb/solib-svr4.c | 99 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 112 insertions(+)
base-commit: a6bc00ff35a42d6d555aa8de97d427074151ae47
Comments
> From: Andrew Burgess <aburgess@redhat.com>
> Cc: Andrew Burgess <aburgess@redhat.com>
> Date: Fri, 7 Mar 2025 10:58:51 +0000
>
> On GNU/Linux (and other targets that use solib-svr4.c) the 'info
> sharedlibrary' command displays the address range for the .text
> section of each library. This is a fallback behaviour implemented in
> solib_map_sections (in solib.c), for targets which are not able to
> provide any better information.
>
> The manual doesn't really explain what the address range given means,
> and the .text fallback certainly isn't described. The manual for
> 'info sharedlibrary' just says:
>
> 'info share REGEX'
> 'info sharedlibrary REGEX'
> Print the names of the shared libraries which are currently loaded
> that match REGEX. If REGEX is omitted then print all shared
> libraries that are loaded.
>
> In this commit I propose that we should change GDB so that the full
> library address range is listed for GNU/Linux (and other solib-svr4
> targets). Though it is certainly useful to know where the .text for a
> library is, not all code is placed into the .text section, and data,
> or course, is stored elsewhere, so the choice of .text, though not a
> crazy default, is still a pretty arbitrary choice.
>
> We do also have 'maintenance info sections', which can be used to find
> the location of a specific section. This is of course, a maintenance
> command, but we could make this into a real user command if we wanted,
> so the information lost by this change to 'info sharedlibrary' is
> still available if needed.
>
> There is one small problem. After this commit, GDB is still under
> reporting the extents of some libraries, in some cases.
>
> What I observe is that sometimes, for reasons that I don't currently
> understand, the run-time linker will over allocate memory for the .bss
> like sections, e.g. the ELF says that 1 page is required, but 2 or 4
> pages will be allocated instead. As a result, GDB will under report
> the extent of the library, with the end address being lower than
> expected. This isn't always the case though, in many cases the
> allocates are as I would expect, and GDB reports the correct values.
>
> However, as we have been under reporting for many years, I think this
> update, which gets things a lot closer to reality, is a big step in
> the right direction. We can always improve the results more later
> on if/when the logic behind the over allocations become clearer.
>
> For testing I've compared the output of 'info proc mappings' with the
> output of 'info sharedlibrary' (using a script), using GDB to debug
> itself, on Fedora Linux running on AArch64, PPC64, S390, and X86-64,
> and other than the over allocation problem described above, the
> results all look good to me.
> ---
> gdb/NEWS | 7 ++++
> gdb/doc/gdb.texinfo | 6 +++
> gdb/solib-svr4.c | 99 +++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 112 insertions(+)
Thanks, the documentation parts are okay.
However, what would it take to make this feature support more than
just GNU/Linux and FreeBSD? What is missing to support this, say, on
Windows?
Reviewed-By: Eli Zaretskii <eliz@gnu.org>
>>>>> "Andrew" == Andrew Burgess <aburgess@redhat.com> writes:
Andrew> In this commit I propose that we should change GDB so that the full
Andrew> library address range is listed for GNU/Linux (and other solib-svr4
Andrew> targets). Though it is certainly useful to know where the .text for a
Andrew> library is, not all code is placed into the .text section, and data,
Andrew> or course, is stored elsewhere, so the choice of .text, though not a
Andrew> crazy default, is still a pretty arbitrary choice.
FWIW this patch seems reasonable to me, though I wouldn't exactly say I
had reviewed it.
Tom
>>>>> "Eli" == Eli Zaretskii <eliz@gnu.org> writes:
Eli> However, what would it take to make this feature support more than
Eli> just GNU/Linux and FreeBSD? What is missing to support this, say, on
Eli> Windows?
Maybe windows-nat.c:windows_make_so would have to be changed to record
the full address range.
Tom
On 3/7/25 5:58 AM, Andrew Burgess wrote:
> On GNU/Linux (and other targets that use solib-svr4.c) the 'info
> sharedlibrary' command displays the address range for the .text
> section of each library. This is a fallback behaviour implemented in
> solib_map_sections (in solib.c), for targets which are not able to
> provide any better information.
>
> The manual doesn't really explain what the address range given means,
> and the .text fallback certainly isn't described. The manual for
> 'info sharedlibrary' just says:
>
> 'info share REGEX'
> 'info sharedlibrary REGEX'
> Print the names of the shared libraries which are currently loaded
> that match REGEX. If REGEX is omitted then print all shared
> libraries that are loaded.
>
> In this commit I propose that we should change GDB so that the full
> library address range is listed for GNU/Linux (and other solib-svr4
> targets). Though it is certainly useful to know where the .text for a
> library is, not all code is placed into the .text section, and data,
> or course, is stored elsewhere, so the choice of .text, though not a
> crazy default, is still a pretty arbitrary choice.
>
> We do also have 'maintenance info sections', which can be used to find
> the location of a specific section. This is of course, a maintenance
> command, but we could make this into a real user command if we wanted,
> so the information lost by this change to 'info sharedlibrary' is
> still available if needed.
>
> There is one small problem. After this commit, GDB is still under
> reporting the extents of some libraries, in some cases.
>
> What I observe is that sometimes, for reasons that I don't currently
> understand, the run-time linker will over allocate memory for the .bss
> like sections, e.g. the ELF says that 1 page is required, but 2 or 4
> pages will be allocated instead. As a result, GDB will under report
> the extent of the library, with the end address being lower than
> expected. This isn't always the case though, in many cases the
> allocates are as I would expect, and GDB reports the correct values.
>
> However, as we have been under reporting for many years, I think this
> update, which gets things a lot closer to reality, is a big step in
> the right direction. We can always improve the results more later
> on if/when the logic behind the over allocations become clearer.
>
> For testing I've compared the output of 'info proc mappings' with the
> output of 'info sharedlibrary' (using a script), using GDB to debug
> itself, on Fedora Linux running on AArch64, PPC64, S390, and X86-64,
> and other than the over allocation problem described above, the
> results all look good to me.
I appreciate this change, having only the text section's range also
bugged me for years.
Now all I'm missing is a command where you pass an address and it tells
you which section of which SO contains this address :) (or if it exists,
I keep forgetting about it).
> 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, 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 = unaligned_start & ~(segment_alignment - 1);
Would the function align_down (from gdbsupport) work here?
> +
> + /* 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 = (phdr->p_memsz > phdr->p_filesz
> + ? 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 = ((seg_size + (segment_alignment - 1))
> + & ~(segment_alignment - 1));
Would the function align_up (from gdbsupport) work here?
Simon
Eli Zaretskii <eliz@gnu.org> writes:
>> From: Andrew Burgess <aburgess@redhat.com>
>> Cc: Andrew Burgess <aburgess@redhat.com>
>> Date: Fri, 7 Mar 2025 10:58:51 +0000
>>
>> On GNU/Linux (and other targets that use solib-svr4.c) the 'info
>> sharedlibrary' command displays the address range for the .text
>> section of each library. This is a fallback behaviour implemented in
>> solib_map_sections (in solib.c), for targets which are not able to
>> provide any better information.
>>
>> The manual doesn't really explain what the address range given means,
>> and the .text fallback certainly isn't described. The manual for
>> 'info sharedlibrary' just says:
>>
>> 'info share REGEX'
>> 'info sharedlibrary REGEX'
>> Print the names of the shared libraries which are currently loaded
>> that match REGEX. If REGEX is omitted then print all shared
>> libraries that are loaded.
>>
>> In this commit I propose that we should change GDB so that the full
>> library address range is listed for GNU/Linux (and other solib-svr4
>> targets). Though it is certainly useful to know where the .text for a
>> library is, not all code is placed into the .text section, and data,
>> or course, is stored elsewhere, so the choice of .text, though not a
>> crazy default, is still a pretty arbitrary choice.
>>
>> We do also have 'maintenance info sections', which can be used to find
>> the location of a specific section. This is of course, a maintenance
>> command, but we could make this into a real user command if we wanted,
>> so the information lost by this change to 'info sharedlibrary' is
>> still available if needed.
>>
>> There is one small problem. After this commit, GDB is still under
>> reporting the extents of some libraries, in some cases.
>>
>> What I observe is that sometimes, for reasons that I don't currently
>> understand, the run-time linker will over allocate memory for the .bss
>> like sections, e.g. the ELF says that 1 page is required, but 2 or 4
>> pages will be allocated instead. As a result, GDB will under report
>> the extent of the library, with the end address being lower than
>> expected. This isn't always the case though, in many cases the
>> allocates are as I would expect, and GDB reports the correct values.
>>
>> However, as we have been under reporting for many years, I think this
>> update, which gets things a lot closer to reality, is a big step in
>> the right direction. We can always improve the results more later
>> on if/when the logic behind the over allocations become clearer.
>>
>> For testing I've compared the output of 'info proc mappings' with the
>> output of 'info sharedlibrary' (using a script), using GDB to debug
>> itself, on Fedora Linux running on AArch64, PPC64, S390, and X86-64,
>> and other than the over allocation problem described above, the
>> results all look good to me.
>> ---
>> gdb/NEWS | 7 ++++
>> gdb/doc/gdb.texinfo | 6 +++
>> gdb/solib-svr4.c | 99 +++++++++++++++++++++++++++++++++++++++++++++
>> 3 files changed, 112 insertions(+)
>
> Thanks, the documentation parts are okay.
>
> However, what would it take to make this feature support more than
> just GNU/Linux and FreeBSD? What is missing to support this, say, on
> Windows?
Hi Eli,
Sorry for the delay, I had to dig out my Windows machine and have a
little play around before I commented.
Windows makes use of solib-target.c to supply its solib_ops via this
code in windows-tdep.c:
windows_so_ops = solib_target_so_ops;
windows_so_ops.solib_create_inferior_hook
= windows_solib_create_inferior_hook;
set_gdbarch_so_ops (gdbarch, &windows_so_ops);
This means we're using standard 'solib_target_so_ops' but with
'solib_create_inferior_hook' overridden to be Windows specific.
The interesting solib_ops hook as far as this patch goes is actually,
'relocate_section_addresses', and interestingly, if we look at
solib_target_relocate_section_addresses (solib-target.c) we see that it
does do some adjustment of solib:addr_low and solib::addr_high for each
solib it processes.
What it appears to do is set the "low" address to the lowest section
base, and the high address to the highest 'base + section-size'.
What does this mean? Well, my expectation is that, on Windows, 'info
sharedlibrary' will show an extent which is the lowest (allocatable)
section start through to the highest section end address. Which I think
is better than the old Linux behaviour (just showing .text extents), but
is probably not as good as this patch, which takes into account how an
ELF would be loaded into memory.
To make Windows "better", I guess someone with knowledge of file loading
on Windows would need to either update
solib_target_relocate_section_addresses (risky, targets other than
Windows use that too), or, more likely, create a Windows specific
version of solib_target_relocate_section_addresses, which then takes
into account how an executable is loaded on Windows in order to figure
out the full extends of the library in memory.
The changes in this patch are specifically tied to ELF, and how ELF is
loaded. I'd guess Windows file loading is probably similar at some
level, but isn't going to be exactly the same, so this would need to be
something done in Windows specific code I think.
Hope this helps,
Thanks,
Andrew
>
> Reviewed-By: Eli Zaretskii <eliz@gnu.org>
Simon Marchi <simark@simark.ca> writes:
> On 3/7/25 5:58 AM, Andrew Burgess wrote:
>> On GNU/Linux (and other targets that use solib-svr4.c) the 'info
>> sharedlibrary' command displays the address range for the .text
>> section of each library. This is a fallback behaviour implemented in
>> solib_map_sections (in solib.c), for targets which are not able to
>> provide any better information.
>>
>> The manual doesn't really explain what the address range given means,
>> and the .text fallback certainly isn't described. The manual for
>> 'info sharedlibrary' just says:
>>
>> 'info share REGEX'
>> 'info sharedlibrary REGEX'
>> Print the names of the shared libraries which are currently loaded
>> that match REGEX. If REGEX is omitted then print all shared
>> libraries that are loaded.
>>
>> In this commit I propose that we should change GDB so that the full
>> library address range is listed for GNU/Linux (and other solib-svr4
>> targets). Though it is certainly useful to know where the .text for a
>> library is, not all code is placed into the .text section, and data,
>> or course, is stored elsewhere, so the choice of .text, though not a
>> crazy default, is still a pretty arbitrary choice.
>>
>> We do also have 'maintenance info sections', which can be used to find
>> the location of a specific section. This is of course, a maintenance
>> command, but we could make this into a real user command if we wanted,
>> so the information lost by this change to 'info sharedlibrary' is
>> still available if needed.
>>
>> There is one small problem. After this commit, GDB is still under
>> reporting the extents of some libraries, in some cases.
>>
>> What I observe is that sometimes, for reasons that I don't currently
>> understand, the run-time linker will over allocate memory for the .bss
>> like sections, e.g. the ELF says that 1 page is required, but 2 or 4
>> pages will be allocated instead. As a result, GDB will under report
>> the extent of the library, with the end address being lower than
>> expected. This isn't always the case though, in many cases the
>> allocates are as I would expect, and GDB reports the correct values.
>>
>> However, as we have been under reporting for many years, I think this
>> update, which gets things a lot closer to reality, is a big step in
>> the right direction. We can always improve the results more later
>> on if/when the logic behind the over allocations become clearer.
>>
>> For testing I've compared the output of 'info proc mappings' with the
>> output of 'info sharedlibrary' (using a script), using GDB to debug
>> itself, on Fedora Linux running on AArch64, PPC64, S390, and X86-64,
>> and other than the over allocation problem described above, the
>> results all look good to me.
>
> I appreciate this change, having only the text section's range also
> bugged me for years.
>
> Now all I'm missing is a command where you pass an address and it tells
> you which section of which SO contains this address :) (or if it exists,
> I keep forgetting about it).
I'm not aware of any such command, but I'd like to rewrite 'maint info
sections' as a user command, 'info sections', which would have a bunch
of filtering options, e.g. filter by solib name (all sections within
that library), filter by address (solib/section containing the address),
filter by section name (all sections from all solib with that name),
filter by section attribute (like the existing maint command does).
I don't know when I'd have time to work on this though...
>
>> 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, 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 = unaligned_start & ~(segment_alignment - 1);
>
> Would the function align_down (from gdbsupport) work here?
>
>> +
>> + /* 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 = (phdr->p_memsz > phdr->p_filesz
>> + ? 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 = ((seg_size + (segment_alignment - 1))
>> + & ~(segment_alignment - 1));
>
> Would the function align_up (from gdbsupport) work here?
Both of these work as required. I posted a V2 with this change.
Thanks,
Andrew
@@ -40,6 +40,13 @@ show riscv numeric-register-names
(e.g 'x1') or their abi names (e.g. 'ra').
Defaults to 'off', matching the old behaviour (abi names).
+* Changed commands
+
+info sharedlibrary
+ On Linux and FreeBSD, the addresses shown in the output of this
+ command are now for the full memory range allocated to the shared
+ library.
+
* Python API
** New class gdb.Color for dealing with colors.
@@ -22161,6 +22161,12 @@ Files
that match @var{regex}. If @var{regex} is omitted then print
all shared libraries that are loaded.
+For each library, @value{GDBN} also lists the address range allocated
+to that library if it can be determined. If the address range cannot
+be determined then the address range for the @code{.text} section from
+the library will be listed. If the @code{.text} section cannot be
+found then no addresses will be listed.Q
+
@kindex info dll
@item info dll @var{regex}
This is an alias of @code{info sharedlibrary}.
@@ -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, 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 = unaligned_start & ~(segment_alignment - 1);
+
+ /* 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 = (phdr->p_memsz > phdr->p_filesz
+ ? 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 = ((seg_size + (segment_alignment - 1))
+ & ~(segment_alignment - 1));
+
+ /* 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);
+ }
+ }
}