Home | History | Annotate | Download | only in libdw
      1 /* Find entry breakpoint locations for a function.
      2    Copyright (C) 2005-2009 Red Hat, Inc.
      3    This file is part of Red Hat elfutils.
      4 
      5    Red Hat elfutils is free software; you can redistribute it and/or modify
      6    it under the terms of the GNU General Public License as published by the
      7    Free Software Foundation; version 2 of the License.
      8 
      9    Red Hat elfutils is distributed in the hope that it will be useful, but
     10    WITHOUT ANY WARRANTY; without even the implied warranty of
     11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12    General Public License for more details.
     13 
     14    You should have received a copy of the GNU General Public License along
     15    with Red Hat elfutils; if not, write to the Free Software Foundation,
     16    Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
     17 
     18    In addition, as a special exception, Red Hat, Inc. gives You the
     19    additional right to link the code of Red Hat elfutils with code licensed
     20    under any Open Source Initiative certified open source license
     21    (http://www.opensource.org/licenses/index.php) which requires the
     22    distribution of source code with any binary distribution and to
     23    distribute linked combinations of the two.  Non-GPL Code permitted under
     24    this exception must only link to the code of Red Hat elfutils through
     25    those well defined interfaces identified in the file named EXCEPTION
     26    found in the source code files (the "Approved Interfaces").  The files
     27    of Non-GPL Code may instantiate templates or use macros or inline
     28    functions from the Approved Interfaces without causing the resulting
     29    work to be covered by the GNU General Public License.  Only Red Hat,
     30    Inc. may make changes or additions to the list of Approved Interfaces.
     31    Red Hat's grant of this exception is conditioned upon your not adding
     32    any new exceptions.  If you wish to add a new Approved Interface or
     33    exception, please contact Red Hat.  You must obey the GNU General Public
     34    License in all respects for all of the Red Hat elfutils code and other
     35    code used in conjunction with Red Hat elfutils except the Non-GPL Code
     36    covered by this exception.  If you modify this file, you may extend this
     37    exception to your version of the file, but you are not obligated to do
     38    so.  If you do not wish to provide this exception without modification,
     39    you must delete this exception statement from your version and license
     40    this file solely under the GPL without exception.
     41 
     42    Red Hat elfutils is an included package of the Open Invention Network.
     43    An included package of the Open Invention Network is a package for which
     44    Open Invention Network licensees cross-license their patents.  No patent
     45    license is granted, either expressly or impliedly, by designation as an
     46    included package.  Should you wish to participate in the Open Invention
     47    Network licensing program, please visit www.openinventionnetwork.com
     48    <http://www.openinventionnetwork.com>.  */
     49 
     50 #ifdef HAVE_CONFIG_H
     51 # include <config.h>
     52 #endif
     53 #include "libdwP.h"
     54 #include <dwarf.h>
     55 #include <stdlib.h>
     56 
     57 
     58 int
     59 dwarf_entry_breakpoints (die, bkpts)
     60      Dwarf_Die *die;
     61      Dwarf_Addr **bkpts;
     62 {
     63   int nbkpts = 0;
     64   *bkpts = NULL;
     65 
     66   /* Add one breakpoint location to the result vector.  */
     67   inline int add_bkpt (Dwarf_Addr pc)
     68     {
     69       Dwarf_Addr *newlist = realloc (*bkpts, ++nbkpts * sizeof newlist[0]);
     70       if (newlist == NULL)
     71 	{
     72 	  free (*bkpts);
     73 	  *bkpts = NULL;
     74 	  __libdw_seterrno (DWARF_E_NOMEM);
     75 	  return -1;
     76 	}
     77       newlist[nbkpts - 1] = pc;
     78       *bkpts = newlist;
     79       return nbkpts;
     80     }
     81 
     82   /* Fallback result, break at the entrypc/lowpc value.  */
     83   inline int entrypc_bkpt (void)
     84     {
     85       Dwarf_Addr pc;
     86       return INTUSE(dwarf_entrypc) (die, &pc) < 0 ? -1 : add_bkpt (pc);
     87     }
     88 
     89   /* Fetch the CU's line records to look for this DIE's addresses.  */
     90   Dwarf_Die cudie = CUDIE (die->cu);
     91   Dwarf_Lines *lines;
     92   size_t nlines;
     93   if (INTUSE(dwarf_getsrclines) (&cudie, &lines, &nlines) < 0)
     94     {
     95       int error = INTUSE (dwarf_errno) ();
     96       if (error == 0)		/* CU has no DW_AT_stmt_list.  */
     97 	return entrypc_bkpt ();
     98       __libdw_seterrno (error);
     99       return -1;
    100     }
    101 
    102   /* Search a contiguous PC range for prologue-end markers.
    103      If DWARF, look for proper markers.
    104      Failing that, if ADHOC, look for the ad hoc convention.  */
    105   inline int search_range (Dwarf_Addr low, Dwarf_Addr high,
    106 			   bool dwarf, bool adhoc)
    107     {
    108       size_t l = 0, u = nlines;
    109       while (l < u)
    110 	{
    111 	  size_t idx = (l + u) / 2;
    112 	  if (lines->info[idx].addr < low)
    113 	    l = idx + 1;
    114 	  else if (lines->info[idx].addr > low)
    115 	    u = idx;
    116 	  else if (lines->info[idx].end_sequence)
    117 	    l = idx + 1;
    118 	  else
    119 	    {
    120 	      l = idx;
    121 	      break;
    122 	    }
    123 	}
    124       if (l < u)
    125 	{
    126 	  if (dwarf)
    127 	    for (size_t i = l; i < u && lines->info[i].addr < high; ++i)
    128 	      if (lines->info[i].prologue_end
    129 		  && add_bkpt (lines->info[i].addr) < 0)
    130 		return -1;
    131 	  if (adhoc && nbkpts == 0)
    132 	    while (++l < nlines && lines->info[l].addr < high)
    133 	      if (!lines->info[l].end_sequence)
    134 		return add_bkpt (lines->info[l].addr);
    135 	  return nbkpts;
    136 	}
    137       __libdw_seterrno (DWARF_E_INVALID_DWARF);
    138       return -1;
    139     }
    140 
    141   /* Search each contiguous address range for DWARF prologue_end markers.  */
    142 
    143   Dwarf_Addr base;
    144   Dwarf_Addr begin;
    145   Dwarf_Addr end;
    146   ptrdiff_t offset = INTUSE(dwarf_ranges) (die, 0, &base, &begin, &end);
    147   if (offset < 0)
    148     return -1;
    149 
    150   /* Most often there is a single contiguous PC range for the DIE.  */
    151   if (offset == 1)
    152     return search_range (begin, end, true, true) ?: entrypc_bkpt ();
    153 
    154   Dwarf_Addr lowpc = (Dwarf_Addr) -1l;
    155   Dwarf_Addr highpc = (Dwarf_Addr) -1l;
    156   while (offset > 0)
    157     {
    158       /* We have an address range entry.  */
    159       if (search_range (begin, end, true, false) < 0)
    160 	return -1;
    161 
    162       if (begin < lowpc)
    163 	{
    164 	  lowpc = begin;
    165 	  highpc = end;
    166 	}
    167 
    168       offset = INTUSE(dwarf_ranges) (die, offset, &base, &begin, &end);
    169     }
    170 
    171   /* If we didn't find any proper DWARF markers, then look in the
    172      lowest-addressed range for an ad hoc marker.  Failing that,
    173      fall back to just using the entrypc value.  */
    174   return (nbkpts
    175 	  ?: (lowpc == (Dwarf_Addr) -1l ? 0
    176 	      : search_range (lowpc, highpc, false, true))
    177 	  ?: entrypc_bkpt ());
    178 }
    179