Blame libdw/dwarf_entry_breakpoints.c

Packit 032894
/* Find entry breakpoint locations for a function.
Packit 032894
   Copyright (C) 2005-2009 Red Hat, Inc.
Packit 032894
   This file is part of elfutils.
Packit 032894
Packit 032894
   This file is free software; you can redistribute it and/or modify
Packit 032894
   it under the terms of either
Packit 032894
Packit 032894
     * the GNU Lesser General Public License as published by the Free
Packit 032894
       Software Foundation; either version 3 of the License, or (at
Packit 032894
       your option) any later version
Packit 032894
Packit 032894
   or
Packit 032894
Packit 032894
     * the GNU General Public License as published by the Free
Packit 032894
       Software Foundation; either version 2 of the License, or (at
Packit 032894
       your option) any later version
Packit 032894
Packit 032894
   or both in parallel, as here.
Packit 032894
Packit 032894
   elfutils is distributed in the hope that it will be useful, but
Packit 032894
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 032894
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 032894
   General Public License for more details.
Packit 032894
Packit 032894
   You should have received copies of the GNU General Public License and
Packit 032894
   the GNU Lesser General Public License along with this program.  If
Packit 032894
   not, see <http://www.gnu.org/licenses/>.  */
Packit 032894
Packit 032894
#ifdef HAVE_CONFIG_H
Packit 032894
# include <config.h>
Packit 032894
#endif
Packit 032894
#include "libdwP.h"
Packit 032894
#include <dwarf.h>
Packit 032894
#include <stdlib.h>
Packit 032894
Packit 032894
Packit 032894
/* Add one breakpoint location to the result vector.  */
Packit 032894
static inline int
Packit 032894
add_bkpt (Dwarf_Addr pc, Dwarf_Addr **bkpts, int *pnbkpts)
Packit 032894
{
Packit 032894
  Dwarf_Addr *newlist = realloc (*bkpts, ++(*pnbkpts) * sizeof newlist[0]);
Packit 032894
  if (newlist == NULL)
Packit 032894
    {
Packit 032894
      free (*bkpts);
Packit 032894
      *bkpts = NULL;
Packit 032894
      __libdw_seterrno (DWARF_E_NOMEM);
Packit 032894
      return -1;
Packit 032894
    }
Packit 032894
  newlist[*pnbkpts - 1] = pc;
Packit 032894
  *bkpts = newlist;
Packit 032894
  return *pnbkpts;
Packit 032894
}
Packit 032894
Packit 032894
/* Fallback result, break at the entrypc/lowpc value.  */
Packit 032894
static inline int
Packit 032894
entrypc_bkpt (Dwarf_Die *die, Dwarf_Addr **bkpts, int *pnbkpts)
Packit 032894
{
Packit 032894
  Dwarf_Addr pc;
Packit 032894
  return INTUSE(dwarf_entrypc) (die, &pc) < 0 ? -1 : add_bkpt (pc, bkpts, pnbkpts);
Packit 032894
}
Packit 032894
Packit 032894
/* Search a contiguous PC range for prologue-end markers.
Packit 032894
   If DWARF, look for proper markers.
Packit 032894
   Failing that, if ADHOC, look for the ad hoc convention.  */
Packit 032894
static inline int
Packit 032894
search_range (Dwarf_Addr low, Dwarf_Addr high,
Packit 032894
	      bool dwarf, bool adhoc,
Packit 032894
              Dwarf_Lines *lines, size_t nlines,
Packit 032894
              Dwarf_Addr **bkpts, int *pnbkpts)
Packit 032894
{
Packit 032894
      size_t l = 0, u = nlines;
Packit 032894
      while (l < u)
Packit 032894
	{
Packit 032894
	  size_t idx = (l + u) / 2;
Packit 032894
	  if (lines->info[idx].addr < low)
Packit 032894
	    l = idx + 1;
Packit 032894
	  else if (lines->info[idx].addr > low)
Packit 032894
	    u = idx;
Packit 032894
	  else if (lines->info[idx].end_sequence)
Packit 032894
	    l = idx + 1;
Packit 032894
	  else
Packit 032894
	    {
Packit 032894
	      l = idx;
Packit 032894
	      break;
Packit 032894
	    }
Packit 032894
	}
Packit 032894
      if (l < u)
Packit 032894
	{
Packit 032894
	  if (dwarf)
Packit 032894
	    for (size_t i = l; i < u && lines->info[i].addr < high; ++i)
Packit 032894
	      if (lines->info[i].prologue_end
Packit 032894
		  && add_bkpt (lines->info[i].addr, bkpts, pnbkpts) < 0)
Packit 032894
		return -1;
Packit 032894
	  if (adhoc && *pnbkpts == 0)
Packit 032894
	    while (++l < nlines && lines->info[l].addr < high)
Packit 032894
	      if (!lines->info[l].end_sequence)
Packit 032894
		return add_bkpt (lines->info[l].addr, bkpts, pnbkpts);
Packit 032894
	  return *pnbkpts;
Packit 032894
	}
Packit 032894
      __libdw_seterrno (DWARF_E_INVALID_DWARF);
Packit 032894
      return -1;
Packit 032894
}
Packit 032894
Packit 032894
int
Packit 032894
dwarf_entry_breakpoints (Dwarf_Die *die, Dwarf_Addr **bkpts)
Packit 032894
{
Packit 032894
  int nbkpts = 0;
Packit 032894
  *bkpts = NULL;
Packit 032894
Packit 032894
  /* Fetch the CU's line records to look for this DIE's addresses.  */
Packit 032894
  Dwarf_Die cudie = CUDIE (die->cu);
Packit 032894
  Dwarf_Lines *lines;
Packit 032894
  size_t nlines;
Packit 032894
  if (INTUSE(dwarf_getsrclines) (&cudie, &lines, &nlines) < 0)
Packit 032894
    {
Packit 032894
      int error = INTUSE (dwarf_errno) ();
Packit 032894
      if (error == 0)		/* CU has no DW_AT_stmt_list.  */
Packit 032894
	return entrypc_bkpt (die, bkpts, &nbkpts);
Packit 032894
      __libdw_seterrno (error);
Packit 032894
      return -1;
Packit 032894
    }
Packit 032894
Packit 032894
  /* Search each contiguous address range for DWARF prologue_end markers.  */
Packit 032894
Packit 032894
  Dwarf_Addr base;
Packit 032894
  Dwarf_Addr begin;
Packit 032894
  Dwarf_Addr end;
Packit 032894
  ptrdiff_t offset = INTUSE(dwarf_ranges) (die, 0, &base, &begin, &end;;
Packit 032894
  if (offset < 0)
Packit 032894
    return -1;
Packit 032894
Packit 032894
  /* Most often there is a single contiguous PC range for the DIE.  */
Packit 032894
  if (offset == 1)
Packit 032894
    return search_range (begin, end, true, true, lines, nlines, bkpts, &nbkpts)
Packit 032894
        ?: entrypc_bkpt (die, bkpts, &nbkpts);
Packit 032894
Packit 032894
  Dwarf_Addr lowpc = (Dwarf_Addr) -1l;
Packit 032894
  Dwarf_Addr highpc = (Dwarf_Addr) -1l;
Packit 032894
  while (offset > 0)
Packit 032894
    {
Packit 032894
      /* We have an address range entry.  */
Packit 032894
      if (search_range (begin, end, true, false,
Packit 032894
                        lines, nlines, bkpts, &nbkpts) < 0)
Packit 032894
	return -1;
Packit 032894
Packit 032894
      if (begin < lowpc)
Packit 032894
	{
Packit 032894
	  lowpc = begin;
Packit 032894
	  highpc = end;
Packit 032894
	}
Packit 032894
Packit 032894
      offset = INTUSE(dwarf_ranges) (die, offset, &base, &begin, &end;;
Packit 032894
    }
Packit 032894
Packit 032894
  /* If we didn't find any proper DWARF markers, then look in the
Packit 032894
     lowest-addressed range for an ad hoc marker.  Failing that,
Packit 032894
     fall back to just using the entrypc value.  */
Packit 032894
  return (nbkpts
Packit 032894
	  ?: (lowpc == (Dwarf_Addr) -1l ? 0
Packit 032894
	      : search_range (lowpc, highpc, false, true,
Packit 032894
	                      lines, nlines, bkpts, &nbkpts))
Packit 032894
	  ?: entrypc_bkpt (die, bkpts, &nbkpts));
Packit 032894
}