void
dwarf2_tailcall_sniffer_first (struct frame_info *this_frame,
			       void **tailcall_cachep,
			       const LONGEST *entry_cfa_sp_offsetp)
{
  CORE_ADDR prev_pc = 0, prev_sp = 0;	/* GCC warning.  */
  int prev_sp_p = 0;
  CORE_ADDR this_pc;
  struct gdbarch *prev_gdbarch;
  struct call_site_chain *chain = NULL;
  struct tailcall_cache *cache;
  volatile struct gdb_exception except;

  gdb_assert (*tailcall_cachep == NULL);

  /* PC may be after the function if THIS_FRAME calls noreturn function,
     get_frame_address_in_block will decrease it by 1 in such case.  */
  this_pc = get_frame_address_in_block (this_frame);

  /* Catch any unwinding errors.  */
  TRY_CATCH (except, RETURN_MASK_ERROR)
    {
      int sp_regnum;

      prev_gdbarch = frame_unwind_arch (this_frame);

      /* Simulate frame_unwind_pc without setting this_frame->prev_pc.p.  */
      prev_pc = gdbarch_unwind_pc (prev_gdbarch, this_frame);

      /* call_site_find_chain can throw an exception.  */
      chain = call_site_find_chain (prev_gdbarch, prev_pc, this_pc);

      if (entry_cfa_sp_offsetp == NULL)
	break;
      sp_regnum = gdbarch_sp_regnum (prev_gdbarch);
      if (sp_regnum == -1)
	break;
      prev_sp = frame_unwind_register_unsigned (this_frame, sp_regnum);
      prev_sp_p = 1;
    }
Пример #2
0
void
dwarf2_tailcall_sniffer_first (struct frame_info *this_frame,
			       void **tailcall_cachep,
			       const LONGEST *entry_cfa_sp_offsetp)
{
  CORE_ADDR prev_pc = 0, prev_sp = 0;	/* GCC warning.  */
  int prev_sp_p = 0;
  CORE_ADDR this_pc;
  struct gdbarch *prev_gdbarch;
  struct call_site_chain *chain = NULL;
  struct tailcall_cache *cache;

  gdb_assert (*tailcall_cachep == NULL);

  /* PC may be after the function if THIS_FRAME calls noreturn function,
     get_frame_address_in_block will decrease it by 1 in such case.  */
  this_pc = get_frame_address_in_block (this_frame);

  /* Catch any unwinding errors.  */
  TRY
    {
      int sp_regnum;

      prev_gdbarch = frame_unwind_arch (this_frame);

      /* Simulate frame_unwind_pc without setting this_frame->prev_pc.p.  */
      prev_pc = gdbarch_unwind_pc (prev_gdbarch, this_frame);

      /* call_site_find_chain can throw an exception.  */
      chain = call_site_find_chain (prev_gdbarch, prev_pc, this_pc);

      if (entry_cfa_sp_offsetp == NULL)
	break;
      sp_regnum = gdbarch_sp_regnum (prev_gdbarch);
      if (sp_regnum == -1)
	break;
      prev_sp = frame_unwind_register_unsigned (this_frame, sp_regnum);
      prev_sp_p = 1;
    }
  CATCH (except, RETURN_MASK_ERROR)
    {
      if (entry_values_debug)
	exception_print (gdb_stdout, except);
      return;
    }
  END_CATCH

  /* Ambiguous unwind or unambiguous unwind verified as matching.  */
  if (chain == NULL || chain->length == 0)
    {
      xfree (chain);
      return;
    }

  cache = cache_new_ref1 (this_frame);
  *tailcall_cachep = cache;
  cache->chain = chain;
  cache->prev_pc = prev_pc;
  cache->chain_levels = pretended_chain_levels (chain);
  cache->prev_sp_p = prev_sp_p;
  if (cache->prev_sp_p)
    {
      cache->prev_sp = prev_sp;
      cache->entry_cfa_sp_offset = *entry_cfa_sp_offsetp;
    }
  gdb_assert (cache->chain_levels > 0);
}