Example #1
0
static struct mdebug_extra_func_info *
non_heuristic_proc_desc (CORE_ADDR pc, CORE_ADDR *addrptr)
{
    CORE_ADDR startaddr;
    struct mdebug_extra_func_info *proc_desc;
    struct block *b = block_for_pc (pc);
    struct symbol *sym;
    struct obj_section *sec;
    struct mips_objfile_private *priv;

    find_pc_partial_function (pc, NULL, &startaddr, NULL);
    if (addrptr)
        *addrptr = startaddr;

    priv = NULL;

    sec = find_pc_section (pc);
    if (sec != NULL)
    {
        priv = (struct mips_objfile_private *) objfile_data (sec->objfile, mips_pdr_data);

        /* Search the ".pdr" section generated by GAS.  This includes most of
           the information normally found in ECOFF PDRs.  */

        the_bfd = sec->objfile->obfd;
        if (priv == NULL
                && (the_bfd->format == bfd_object
                    && bfd_get_flavour (the_bfd) == bfd_target_elf_flavour
                    && elf_elfheader (the_bfd)->e_ident[EI_CLASS] == ELFCLASS64))
        {
            /* Right now GAS only outputs the address as a four-byte sequence.
               This means that we should not bother with this method on 64-bit
               targets (until that is fixed).  */

            priv = obstack_alloc (&sec->objfile->objfile_obstack,
                                  sizeof (struct mips_objfile_private));
            priv->size = 0;
            set_objfile_data (sec->objfile, mips_pdr_data, priv);
        }
        else if (priv == NULL)
        {
            asection *bfdsec;

            priv = obstack_alloc (&sec->objfile->objfile_obstack,
                                  sizeof (struct mips_objfile_private));

            bfdsec = bfd_get_section_by_name (sec->objfile->obfd, ".pdr");
            if (bfdsec != NULL)
            {
                priv->size = bfd_section_size (sec->objfile->obfd, bfdsec);
                priv->contents = obstack_alloc (&sec->objfile->objfile_obstack,
                                                priv->size);
                bfd_get_section_contents (sec->objfile->obfd, bfdsec,
                                          priv->contents, 0, priv->size);

                /* In general, the .pdr section is sorted.  However, in the
                   presence of multiple code sections (and other corner cases)
                   it can become unsorted.  Sort it so that we can use a faster
                   binary search.  */
                qsort (priv->contents, priv->size / 32, 32,
                       compare_pdr_entries);
            }
            else
                priv->size = 0;

            set_objfile_data (sec->objfile, mips_pdr_data, priv);
        }
        the_bfd = NULL;

        if (priv->size != 0)
        {
            int low, mid, high;
            char *ptr;
            CORE_ADDR pdr_pc;

            low = 0;
            high = priv->size / 32;

            /* We've found a .pdr section describing this objfile.  We want to
               find the entry which describes this code address.  The .pdr
               information is not very descriptive; we have only a function
               start address.  We have to look for the closest entry, because
               the local symbol at the beginning of this function may have
               been stripped - so if we ask the symbol table for the start
               address we may get a preceding global function.  */

            /* First, find the last .pdr entry starting at or before PC.  */
            do
            {
                mid = (low + high) / 2;

                ptr = priv->contents + mid * 32;
                pdr_pc = bfd_get_signed_32 (sec->objfile->obfd, ptr);
                pdr_pc += ANOFFSET (sec->objfile->section_offsets,
                                    SECT_OFF_TEXT (sec->objfile));

                if (pdr_pc > pc)
                    high = mid;
                else
                    low = mid + 1;
            }
            while (low != high);

            /* Both low and high point one past the PDR of interest.  If
               both are zero, that means this PC is before any region
               covered by a PDR, i.e. pdr_pc for the first PDR entry is
               greater than PC.  */
            if (low > 0)
            {
                ptr = priv->contents + (low - 1) * 32;
                pdr_pc = bfd_get_signed_32 (sec->objfile->obfd, ptr);
                pdr_pc += ANOFFSET (sec->objfile->section_offsets,
                                    SECT_OFF_TEXT (sec->objfile));
            }

            /* We don't have a range, so we have no way to know for sure
               whether we're in the correct PDR or a PDR for a preceding
               function and the current function was a stripped local
               symbol.  But if the PDR's PC is at least as great as the
               best guess from the symbol table, assume that it does cover
               the right area; if a .pdr section is present at all then
               nearly every function will have an entry.  The biggest exception
               will be the dynamic linker stubs; conveniently these are
               placed before .text instead of after.  */

            if (pc >= pdr_pc && pdr_pc >= startaddr)
            {
                struct symbol *sym = find_pc_function (pc);

                if (addrptr)
                    *addrptr = pdr_pc;

                /* Fill in what we need of the proc_desc.  */
                proc_desc = (struct mdebug_extra_func_info *)
                            obstack_alloc (&sec->objfile->objfile_obstack,
                                           sizeof (struct mdebug_extra_func_info));
                PROC_LOW_ADDR (proc_desc) = pdr_pc;

                PROC_FRAME_OFFSET (proc_desc)
                    = bfd_get_signed_32 (sec->objfile->obfd, ptr + 20);
                PROC_FRAME_REG (proc_desc) = bfd_get_32 (sec->objfile->obfd,
                                             ptr + 24);
                PROC_REG_MASK (proc_desc) = bfd_get_32 (sec->objfile->obfd,
                                                        ptr + 4);
                PROC_FREG_MASK (proc_desc) = bfd_get_32 (sec->objfile->obfd,
                                             ptr + 12);
                PROC_REG_OFFSET (proc_desc)
                    = bfd_get_signed_32 (sec->objfile->obfd, ptr + 8);
                PROC_FREG_OFFSET (proc_desc)
                    = bfd_get_signed_32 (sec->objfile->obfd, ptr + 16);
                PROC_PC_REG (proc_desc) = bfd_get_32 (sec->objfile->obfd,
                                                      ptr + 28);
                proc_desc->pdr.isym = (long) sym;

                return proc_desc;
            }
        }
    }

    if (b == NULL)
        return NULL;

    if (startaddr > BLOCK_START (b))
    {
        /* This is the "pathological" case referred to in a comment in
           print_frame_info.  It might be better to move this check into
           symbol reading.  */
        return NULL;
    }

    sym = lookup_symbol (MDEBUG_EFI_SYMBOL_NAME, b, LABEL_DOMAIN, 0);

    /* If we never found a PDR for this function in symbol reading, then
       examine prologues to find the information.  */
    if (sym)
    {
        proc_desc = (struct mdebug_extra_func_info *) SYMBOL_VALUE (sym);
        if (PROC_FRAME_REG (proc_desc) == -1)
            return NULL;
        else
            return proc_desc;
    }
    else
        return NULL;
}
static alpha_extra_func_info_t
heuristic_proc_desc (CORE_ADDR start_pc,
                     CORE_ADDR limit_pc,
                     struct frame_info *next_frame,
                     struct frame_saved_regs *saved_regs_p)
{
  CORE_ADDR sp = read_next_frame_reg (next_frame, SP_REGNUM);
  CORE_ADDR cur_pc;
  int frame_size;
  int has_frame_reg = 0;
  unsigned long reg_mask = 0;
  int pcreg = -1;

  if (start_pc == 0)
    return 0;

  memset (&temp_proc_desc, '\0', sizeof (temp_proc_desc));
  if (saved_regs_p != 0)
    memset (saved_regs_p, '\0', sizeof (struct frame_saved_regs));

  PROC_LOW_ADDR (&temp_proc_desc) = start_pc;

  if (start_pc + 200 < limit_pc)
    limit_pc = start_pc + 200;

  frame_size = 0;
  for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += 4)
    {
      unsigned int word;
      int status;

      status = read_memory_safe4 (cur_pc, &word);
      if (status)
	return 0;

      if ((word & 0xffff0000) == 0x23de0000)	/* lda $sp,n($sp) */
	{
	  if (word & 0x8000)
	    frame_size += (-word) & 0xffff;
	  else
	    /* Exit loop if a positive stack adjustment is found, which
	       usually means that the stack cleanup code in the function
	       epilogue is reached.  */
	    break;
	}
      else if ((word & 0xfc1f0000) == 0xb41e0000	/* stq reg,n($sp) */
	       && (word & 0xffff0000) != 0xb7fe0000)	/* reg != $zero */
	{
	  int reg = (word & 0x03e00000) >> 21;

	  reg_mask |= 1 << reg;
	  if (saved_regs_p != 0)
	    saved_regs_p->regs[reg] = sp + (short) word;

	  /* Starting with OSF/1-3.2C, the system libraries are shipped
	     without local symbols, but they still contain procedure
	     descriptors without a symbol reference. GDB is currently
	     unable to find these procedure descriptors and uses
	     heuristic_proc_desc instead.
	     As some low level compiler support routines (__div*, __add*)
	     use a non-standard return address register, we have to
	     add some heuristics to determine the return address register,
	     or stepping over these routines will fail.
	     Usually the return address register is the first register
	     saved on the stack, but assembler optimization might
	     rearrange the register saves.
	     So we recognize only a few registers (t7, t9, ra) within
	     the procedure prologue as valid return address registers.
	     If we encounter a return instruction, we extract the
	     the return address register from it.

	     FIXME: Rewriting GDB to access the procedure descriptors,
	     e.g. via the minimal symbol table, might obviate this hack.  */
	  if (pcreg == -1
	      && cur_pc < (start_pc + 80)
	      && (reg == T7_REGNUM || reg == T9_REGNUM || reg == RA_REGNUM))
	    pcreg = reg;
	}
      else if ((word & 0xffe0ffff) == 0x6be08001)	/* ret zero,reg,1 */