* solib-svr4.c (read_program_header): New function.

(scan_dyntag_auxv): New function.
	(elf_locate_base): Use it if scan_dyntag fails.
	(find_program_interpreter): New function.
	(enable_break): Use it instead of .interp section.
This commit is contained in:
Ulrich Weigand
2008-08-26 17:33:51 +00:00
parent f1838a9841
commit 97ec2c2fb8
2 changed files with 205 additions and 16 deletions

View File

@ -1,3 +1,11 @@
2008-08-26 Ulrich Weigand <uweigand@de.ibm.com>
* solib-svr4.c (read_program_header): New function.
(scan_dyntag_auxv): New function.
(elf_locate_base): Use it if scan_dyntag fails.
(find_program_interpreter): New function.
(enable_break): Use it instead of .interp section.
2008-08-26 Ulrich Weigand <uweigand@de.ibm.com> 2008-08-26 Ulrich Weigand <uweigand@de.ibm.com>
* remote.h (remote_filename_p, remote_bfd_open): Add prototypes. * remote.h (remote_filename_p, remote_bfd_open): Add prototypes.

View File

@ -374,6 +374,137 @@ bfd_lookup_symbol (bfd *abfd, char *symname)
return symaddr; return symaddr;
} }
/* Read program header TYPE from inferior memory. The header is found
by scanning the OS auxillary vector.
Return a pointer to allocated memory holding the program header contents,
or NULL on failure. If sucessful, and unless P_SECT_SIZE is NULL, the
size of those contents is returned to P_SECT_SIZE. Likewise, the target
architecture size (32-bit or 64-bit) is returned to P_ARCH_SIZE. */
static gdb_byte *
read_program_header (int type, int *p_sect_size, int *p_arch_size)
{
CORE_ADDR at_phdr, at_phent, at_phnum;
int arch_size, sect_size;
CORE_ADDR sect_addr;
gdb_byte *buf;
/* Get required auxv elements from target. */
if (target_auxv_search (&current_target, AT_PHDR, &at_phdr) <= 0)
return 0;
if (target_auxv_search (&current_target, AT_PHENT, &at_phent) <= 0)
return 0;
if (target_auxv_search (&current_target, AT_PHNUM, &at_phnum) <= 0)
return 0;
if (!at_phdr || !at_phnum)
return 0;
/* Determine ELF architecture type. */
if (at_phent == sizeof (Elf32_External_Phdr))
arch_size = 32;
else if (at_phent == sizeof (Elf64_External_Phdr))
arch_size = 64;
else
return 0;
/* Find .dynamic section via the PT_DYNAMIC PHDR. */
if (arch_size == 32)
{
Elf32_External_Phdr phdr;
int i;
/* Search for requested PHDR. */
for (i = 0; i < at_phnum; i++)
{
if (target_read_memory (at_phdr + i * sizeof (phdr),
(gdb_byte *)&phdr, sizeof (phdr)))
return 0;
if (extract_unsigned_integer ((gdb_byte *)phdr.p_type, 4) == type)
break;
}
if (i == at_phnum)
return 0;
/* Retrieve address and size. */
sect_addr = extract_unsigned_integer ((gdb_byte *)phdr.p_vaddr, 4);
sect_size = extract_unsigned_integer ((gdb_byte *)phdr.p_memsz, 4);
}
else
{
Elf64_External_Phdr phdr;
int i;
/* Search for requested PHDR. */
for (i = 0; i < at_phnum; i++)
{
if (target_read_memory (at_phdr + i * sizeof (phdr),
(gdb_byte *)&phdr, sizeof (phdr)))
return 0;
if (extract_unsigned_integer ((gdb_byte *)phdr.p_type, 4) == type)
break;
}
if (i == at_phnum)
return 0;
/* Retrieve address and size. */
sect_addr = extract_unsigned_integer ((gdb_byte *)phdr.p_vaddr, 8);
sect_size = extract_unsigned_integer ((gdb_byte *)phdr.p_memsz, 8);
}
/* Read in requested program header. */
buf = xmalloc (sect_size);
if (target_read_memory (sect_addr, buf, sect_size))
{
xfree (buf);
return NULL;
}
if (p_arch_size)
*p_arch_size = arch_size;
if (p_sect_size)
*p_sect_size = sect_size;
return buf;
}
/* Return program interpreter string. */
static gdb_byte *
find_program_interpreter (void)
{
gdb_byte *buf = NULL;
/* If we have an exec_bfd, use its section table. */
if (exec_bfd
&& bfd_get_flavour (exec_bfd) == bfd_target_elf_flavour)
{
struct bfd_section *interp_sect;
interp_sect = bfd_get_section_by_name (exec_bfd, ".interp");
if (interp_sect != NULL)
{
CORE_ADDR sect_addr = bfd_section_vma (exec_bfd, interp_sect);
int sect_size = bfd_section_size (exec_bfd, interp_sect);
buf = xmalloc (sect_size);
bfd_get_section_contents (exec_bfd, interp_sect, buf, 0, sect_size);
}
}
/* If we didn't find it, use the target auxillary vector. */
if (!buf)
buf = read_program_header (PT_INTERP, NULL, NULL);
return buf;
}
/* Scan for DYNTAG in .dynamic section of ABFD. If DYNTAG is found 1 is /* Scan for DYNTAG in .dynamic section of ABFD. If DYNTAG is found 1 is
returned and the corresponding PTR is set. */ returned and the corresponding PTR is set. */
@ -451,6 +582,59 @@ scan_dyntag (int dyntag, bfd *abfd, CORE_ADDR *ptr)
return 0; return 0;
} }
/* Scan for DYNTAG in .dynamic section of the target's main executable,
found by consulting the OS auxillary vector. If DYNTAG is found 1 is
returned and the corresponding PTR is set. */
static int
scan_dyntag_auxv (int dyntag, CORE_ADDR *ptr)
{
int sect_size, arch_size, step;
long dyn_tag;
CORE_ADDR dyn_ptr;
gdb_byte *bufend, *bufstart, *buf;
/* Read in .dynamic section. */
buf = bufstart = read_program_header (PT_DYNAMIC, &sect_size, &arch_size);
if (!buf)
return 0;
/* Iterate over BUF and scan for DYNTAG. If found, set PTR and return. */
step = (arch_size == 32) ? sizeof (Elf32_External_Dyn)
: sizeof (Elf64_External_Dyn);
for (bufend = buf + sect_size;
buf < bufend;
buf += step)
{
if (arch_size == 32)
{
Elf32_External_Dyn *dynp = (Elf32_External_Dyn *) buf;
dyn_tag = extract_unsigned_integer ((gdb_byte *) dynp->d_tag, 4);
dyn_ptr = extract_unsigned_integer ((gdb_byte *) dynp->d_un.d_ptr, 4);
}
else
{
Elf64_External_Dyn *dynp = (Elf64_External_Dyn *) buf;
dyn_tag = extract_unsigned_integer ((gdb_byte *) dynp->d_tag, 8);
dyn_ptr = extract_unsigned_integer ((gdb_byte *) dynp->d_un.d_ptr, 8);
}
if (dyn_tag == DT_NULL)
break;
if (dyn_tag == dyntag)
{
if (ptr)
*ptr = dyn_ptr;
xfree (bufstart);
return 1;
}
}
xfree (bufstart);
return 0;
}
/* /*
@ -485,7 +669,8 @@ elf_locate_base (void)
/* Look for DT_MIPS_RLD_MAP first. MIPS executables use this /* Look for DT_MIPS_RLD_MAP first. MIPS executables use this
instead of DT_DEBUG, although they sometimes contain an unused instead of DT_DEBUG, although they sometimes contain an unused
DT_DEBUG. */ DT_DEBUG. */
if (scan_dyntag (DT_MIPS_RLD_MAP, exec_bfd, &dyn_ptr)) if (scan_dyntag (DT_MIPS_RLD_MAP, exec_bfd, &dyn_ptr)
|| scan_dyntag_auxv (DT_MIPS_RLD_MAP, &dyn_ptr))
{ {
gdb_byte *pbuf; gdb_byte *pbuf;
int pbuf_size = TYPE_LENGTH (builtin_type_void_data_ptr); int pbuf_size = TYPE_LENGTH (builtin_type_void_data_ptr);
@ -498,7 +683,8 @@ elf_locate_base (void)
} }
/* Find DT_DEBUG. */ /* Find DT_DEBUG. */
if (scan_dyntag (DT_DEBUG, exec_bfd, &dyn_ptr)) if (scan_dyntag (DT_DEBUG, exec_bfd, &dyn_ptr)
|| scan_dyntag_auxv (DT_DEBUG, &dyn_ptr))
return dyn_ptr; return dyn_ptr;
/* This may be a static executable. Look for the symbol /* This may be a static executable. Look for the symbol
@ -964,6 +1150,7 @@ enable_break (void)
struct minimal_symbol *msymbol; struct minimal_symbol *msymbol;
char **bkpt_namep; char **bkpt_namep;
asection *interp_sect; asection *interp_sect;
gdb_byte *interp_name;
CORE_ADDR sym_addr; CORE_ADDR sym_addr;
/* First, remove all the solib event breakpoints. Their addresses /* First, remove all the solib event breakpoints. Their addresses
@ -1026,13 +1213,11 @@ enable_break (void)
} }
} }
/* Find the .interp section; if not found, warn the user and drop /* Find the program interpreter; if not found, warn the user and drop
into the old breakpoint at symbol code. */ into the old breakpoint at symbol code. */
interp_sect = bfd_get_section_by_name (exec_bfd, ".interp"); interp_name = find_program_interpreter ();
if (interp_sect) if (interp_name)
{ {
unsigned int interp_sect_size;
char *buf;
CORE_ADDR load_addr = 0; CORE_ADDR load_addr = 0;
int load_addr_found = 0; int load_addr_found = 0;
int loader_found_in_list = 0; int loader_found_in_list = 0;
@ -1041,13 +1226,7 @@ enable_break (void)
struct target_ops *tmp_bfd_target; struct target_ops *tmp_bfd_target;
volatile struct gdb_exception ex; volatile struct gdb_exception ex;
/* Read the contents of the .interp section into a local buffer;
the contents specify the dynamic linker this program uses. */
sym_addr = 0; sym_addr = 0;
interp_sect_size = bfd_section_size (exec_bfd, interp_sect);
buf = alloca (interp_sect_size);
bfd_get_section_contents (exec_bfd, interp_sect,
buf, 0, interp_sect_size);
/* Now we need to figure out where the dynamic linker was /* Now we need to figure out where the dynamic linker was
loaded so that we can load its symbols and place a breakpoint loaded so that we can load its symbols and place a breakpoint
@ -1060,7 +1239,7 @@ enable_break (void)
TRY_CATCH (ex, RETURN_MASK_ALL) TRY_CATCH (ex, RETURN_MASK_ALL)
{ {
tmp_bfd = solib_bfd_open (buf); tmp_bfd = solib_bfd_open (interp_name);
} }
if (tmp_bfd == NULL) if (tmp_bfd == NULL)
goto bkpt_at_symbol; goto bkpt_at_symbol;
@ -1075,7 +1254,7 @@ enable_break (void)
so = master_so_list (); so = master_so_list ();
while (so) while (so)
{ {
if (svr4_same_1 (buf, so->so_original_name)) if (svr4_same_1 (interp_name, so->so_original_name))
{ {
load_addr_found = 1; load_addr_found = 1;
loader_found_in_list = 1; loader_found_in_list = 1;
@ -1104,7 +1283,7 @@ enable_break (void)
if (!loader_found_in_list) if (!loader_found_in_list)
{ {
debug_loader_name = xstrdup (buf); debug_loader_name = xstrdup (interp_name);
debug_loader_offset_p = 1; debug_loader_offset_p = 1;
debug_loader_offset = load_addr; debug_loader_offset = load_addr;
solib_add (NULL, 0, &current_target, auto_solib_add); solib_add (NULL, 0, &current_target, auto_solib_add);
@ -1152,12 +1331,14 @@ enable_break (void)
if (sym_addr != 0) if (sym_addr != 0)
{ {
create_solib_event_breakpoint (load_addr + sym_addr); create_solib_event_breakpoint (load_addr + sym_addr);
xfree (interp_name);
return 1; return 1;
} }
/* For whatever reason we couldn't set a breakpoint in the dynamic /* For whatever reason we couldn't set a breakpoint in the dynamic
linker. Warn and drop into the old code. */ linker. Warn and drop into the old code. */
bkpt_at_symbol: bkpt_at_symbol:
xfree (interp_name);
warning (_("Unable to find dynamic linker breakpoint function.\n" warning (_("Unable to find dynamic linker breakpoint function.\n"
"GDB will be unable to debug shared library initializers\n" "GDB will be unable to debug shared library initializers\n"
"and track explicitly loaded dynamic code.")); "and track explicitly loaded dynamic code."));