+
+/* 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 (¤t_target, AT_PHDR, &at_phdr) <= 0)
+ return 0;
+ if (target_auxv_search (¤t_target, AT_PHENT, &at_phent) <= 0)
+ return 0;
+ if (target_auxv_search (¤t_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;
+}
+
+