[patch] Fixes problem setting breakpoint in dynamic loader

PAUL GILLIAM
2006-05-25T00:21:41Z

[-- Attachment #1: Type: text/plain, Size: 999 bytes --]

On PowerPC-64, with 64-bit executables, GDB has been giving this message
for a while:

warning: Unable to find dynamic linker breakpoint function.
GDB will be unable to debug shared library initializers
and track explicitly loaded dynamic code.

This is because "enable_break()" in solib-svr4.c was looking for the
symbol "._dl_debug_state" in the 64-bit dynamic loader and not finding
it. This should not be a surprise because these 'dot' symbols have not
been used for a while.

The reason that the non-'dot' symbol was also passed by, is that it
points into a data section and the existing code only checked code
sections.

If none of the symbols on the list was found in a code section, the
attached patch looks in data sections. When it finds one, and the data
section is either '.plt' or '.opd', then the address points to a
function descriptor which is then used to find the corresponding code
address where the breakpoint can be set.

OK to commit?

-=# Paul #=-

[-- Attachment #2: loader_break.diff --]
[-- Type: text/x-patch, Size: 4204 bytes --]

2006-05-24 Paul Gilliam <pgilliam@us.ibm.com

* solib-svr4.c (enable_break): Resolve break address when the
symbol is found in the data section.

diff -Naur old/solib-svr4.c new/solib-svr4.c
--- old/solib-svr4.c 2006-05-24 15:50:42.000000000 -0700
+++ new/solib-svr4.c 2006-05-24 15:51:36.000000000 -0700
@@ -85,16 +85,6 @@
"rtld_db_dlactivity",
"_rtld_debug_state",

- /* On the 64-bit PowerPC, the linker symbol with the same name as
- the C function points to a function descriptor, not to the entry
- point. The linker symbol whose name is the C function name
- prefixed with a '.' points to the function's entry point. So
- when we look through this table, we ignore symbols that point
- into the data section (thus skipping the descriptor's symbol),
- and eventually try this one, giving us the real entry point
- address. */
- "._dl_debug_state",
-
NULL
};

@@ -1043,20 +1033,75 @@
/* Now try to set a breakpoint in the dynamic linker. */
for (bkpt_namep = solib_break_names; *bkpt_namep != NULL; bkpt_namep++)
{
- /* On ABI's that use function descriptors, there are usually
- two linker symbols associated with each C function: one
- pointing at the actual entry point of the machine code,
- and one pointing at the function's descriptor. The
- latter symbol has the same name as the C function.
-
- What we're looking for here is the machine code entry
- point, so we are only interested in symbols in code
- sections. */
+ /* What we're looking for here is the machine code entry point,
+ so we are only interested in symbols in code sections.
+
+ On ABI's that use function descriptors, the linker symbol with
+ the same name as a C funtion points to that functions descriptor.
+ when those function descriptors are in the code section, they
+ contain executable code and we can set a breakpoint there. */
sym_addr = bfd_lookup_symbol (tmp_bfd, *bkpt_namep, SEC_CODE);
if (sym_addr != 0)
break;
}

+ if (sym_addr == 0)
+ {
+ CORE_ADDR sect_offset;
+
+ /* No symbol was found in a code section, so look in the data
+ sections. This will only happen when the linker symbol points
+ to a function descriptor that is in a data section. */
+ for (bkpt_namep = solib_break_names; *bkpt_namep!=NULL; bkpt_namep++)
+ {
+ /* On ABI's that use function descriptors that are in the data
+ section,
+ sym_addr = bfd_lookup_symbol (tmp_bfd, *bkpt_namep, SEC_DATA);
+ if (sym_addr != 0)
+ break;
+ }
+ if (sym_addr == 0)
+ {
+ target_close (tmp_bfd_target, 0);
+ goto bkpt_at_symbol;
+ }
+
+ /* On some ABI's, the function descriptor we need will be in the
+ ".plt" section. In others, it will be in the ".opd" section. */
+ if (sym_addr + load_addr >= interp_plt_sect_low
+ && sym_addr + load_addr < interp_plt_sect_high)
+ {
+ interp_sect = bfd_get_section_by_name (tmp_bfd, ".plt");
+ sect_offset = interp_plt_sect_low - load_addr;
+ }
+ else
+ {
+ interp_sect = bfd_get_section_by_name (tmp_bfd, ".opd");
+ if (interp_sect != 0)
+ {
+ sect_offset = bfd_section_vma (tmp_bfd, interp_sect);
+ if (sym_addr < sect_offset)
+ interp_sect == 0;
+ else if (sym_addr - sect_offset >=
+ bfd_section_size (tmp_bfd, interp_sect))
+ interp_sect == 0;
+ }
+ }
+ if (interp_sect != 0)
+ {
+ /* Try to convert the function descriptor we found above, into
+ the address we need. It will be relocated below by adding
+ "load_addr" to it. */
+ char *buf = alloca (sizeof (LONGEST));
+ if (bfd_get_section_contents (tmp_bfd, interp_sect, buf,
+ sym_addr - sect_offset,
+ sizeof (LONGEST)))
+ sym_addr = extract_unsigned_integer (buf, sizeof (LONGEST));
+ else
+ sym_addr = 0;
+ }
+ }
+
/* We're done with both the temporary bfd and target. Remember,
closing the target closes the underlying bfd. */
target_close (tmp_bfd_target, 0);