Blame libdw/dwarf_entry_breakpoints.c

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