1da0c48c4Sopenharmony_ci/* Find entry breakpoint locations for a function.
2da0c48c4Sopenharmony_ci   Copyright (C) 2005-2009 Red Hat, Inc.
3da0c48c4Sopenharmony_ci   This file is part of elfutils.
4da0c48c4Sopenharmony_ci
5da0c48c4Sopenharmony_ci   This file is free software; you can redistribute it and/or modify
6da0c48c4Sopenharmony_ci   it under the terms of either
7da0c48c4Sopenharmony_ci
8da0c48c4Sopenharmony_ci     * the GNU Lesser General Public License as published by the Free
9da0c48c4Sopenharmony_ci       Software Foundation; either version 3 of the License, or (at
10da0c48c4Sopenharmony_ci       your option) any later version
11da0c48c4Sopenharmony_ci
12da0c48c4Sopenharmony_ci   or
13da0c48c4Sopenharmony_ci
14da0c48c4Sopenharmony_ci     * the GNU General Public License as published by the Free
15da0c48c4Sopenharmony_ci       Software Foundation; either version 2 of the License, or (at
16da0c48c4Sopenharmony_ci       your option) any later version
17da0c48c4Sopenharmony_ci
18da0c48c4Sopenharmony_ci   or both in parallel, as here.
19da0c48c4Sopenharmony_ci
20da0c48c4Sopenharmony_ci   elfutils is distributed in the hope that it will be useful, but
21da0c48c4Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
22da0c48c4Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23da0c48c4Sopenharmony_ci   General Public License for more details.
24da0c48c4Sopenharmony_ci
25da0c48c4Sopenharmony_ci   You should have received copies of the GNU General Public License and
26da0c48c4Sopenharmony_ci   the GNU Lesser General Public License along with this program.  If
27da0c48c4Sopenharmony_ci   not, see <http://www.gnu.org/licenses/>.  */
28da0c48c4Sopenharmony_ci
29da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H
30da0c48c4Sopenharmony_ci# include <config.h>
31da0c48c4Sopenharmony_ci#endif
32da0c48c4Sopenharmony_ci#include "libdwP.h"
33da0c48c4Sopenharmony_ci#include <dwarf.h>
34da0c48c4Sopenharmony_ci#include <stdlib.h>
35da0c48c4Sopenharmony_ci
36da0c48c4Sopenharmony_ci
37da0c48c4Sopenharmony_ci/* Add one breakpoint location to the result vector.  */
38da0c48c4Sopenharmony_cistatic inline int
39da0c48c4Sopenharmony_ciadd_bkpt (Dwarf_Addr pc, Dwarf_Addr **bkpts, int *pnbkpts)
40da0c48c4Sopenharmony_ci{
41da0c48c4Sopenharmony_ci  Dwarf_Addr *newlist = realloc (*bkpts, ++(*pnbkpts) * sizeof newlist[0]);
42da0c48c4Sopenharmony_ci  if (newlist == NULL)
43da0c48c4Sopenharmony_ci    {
44da0c48c4Sopenharmony_ci      free (*bkpts);
45da0c48c4Sopenharmony_ci      *bkpts = NULL;
46da0c48c4Sopenharmony_ci      __libdw_seterrno (DWARF_E_NOMEM);
47da0c48c4Sopenharmony_ci      return -1;
48da0c48c4Sopenharmony_ci    }
49da0c48c4Sopenharmony_ci  newlist[*pnbkpts - 1] = pc;
50da0c48c4Sopenharmony_ci  *bkpts = newlist;
51da0c48c4Sopenharmony_ci  return *pnbkpts;
52da0c48c4Sopenharmony_ci}
53da0c48c4Sopenharmony_ci
54da0c48c4Sopenharmony_ci/* Fallback result, break at the entrypc/lowpc value.  */
55da0c48c4Sopenharmony_cistatic inline int
56da0c48c4Sopenharmony_cientrypc_bkpt (Dwarf_Die *die, Dwarf_Addr **bkpts, int *pnbkpts)
57da0c48c4Sopenharmony_ci{
58da0c48c4Sopenharmony_ci  Dwarf_Addr pc;
59da0c48c4Sopenharmony_ci  return INTUSE(dwarf_entrypc) (die, &pc) < 0 ? -1 : add_bkpt (pc, bkpts, pnbkpts);
60da0c48c4Sopenharmony_ci}
61da0c48c4Sopenharmony_ci
62da0c48c4Sopenharmony_ci/* Search a contiguous PC range for prologue-end markers.
63da0c48c4Sopenharmony_ci   If DWARF, look for proper markers.
64da0c48c4Sopenharmony_ci   Failing that, if ADHOC, look for the ad hoc convention.  */
65da0c48c4Sopenharmony_cistatic inline int
66da0c48c4Sopenharmony_cisearch_range (Dwarf_Addr low, Dwarf_Addr high,
67da0c48c4Sopenharmony_ci	      bool dwarf, bool adhoc,
68da0c48c4Sopenharmony_ci              Dwarf_Lines *lines, size_t nlines,
69da0c48c4Sopenharmony_ci              Dwarf_Addr **bkpts, int *pnbkpts)
70da0c48c4Sopenharmony_ci{
71da0c48c4Sopenharmony_ci      size_t l = 0, u = nlines;
72da0c48c4Sopenharmony_ci      while (l < u)
73da0c48c4Sopenharmony_ci	{
74da0c48c4Sopenharmony_ci	  size_t idx = (l + u) / 2;
75da0c48c4Sopenharmony_ci	  if (lines->info[idx].addr < low)
76da0c48c4Sopenharmony_ci	    l = idx + 1;
77da0c48c4Sopenharmony_ci	  else if (lines->info[idx].addr > low)
78da0c48c4Sopenharmony_ci	    u = idx;
79da0c48c4Sopenharmony_ci	  else if (lines->info[idx].end_sequence)
80da0c48c4Sopenharmony_ci	    l = idx + 1;
81da0c48c4Sopenharmony_ci	  else
82da0c48c4Sopenharmony_ci	    {
83da0c48c4Sopenharmony_ci	      l = idx;
84da0c48c4Sopenharmony_ci	      break;
85da0c48c4Sopenharmony_ci	    }
86da0c48c4Sopenharmony_ci	}
87da0c48c4Sopenharmony_ci      if (l < u)
88da0c48c4Sopenharmony_ci	{
89da0c48c4Sopenharmony_ci	  if (dwarf)
90da0c48c4Sopenharmony_ci	    for (size_t i = l; i < u && lines->info[i].addr < high; ++i)
91da0c48c4Sopenharmony_ci	      if (lines->info[i].prologue_end
92da0c48c4Sopenharmony_ci		  && add_bkpt (lines->info[i].addr, bkpts, pnbkpts) < 0)
93da0c48c4Sopenharmony_ci		return -1;
94da0c48c4Sopenharmony_ci	  if (adhoc && *pnbkpts == 0)
95da0c48c4Sopenharmony_ci	    while (++l < nlines && lines->info[l].addr < high)
96da0c48c4Sopenharmony_ci	      if (!lines->info[l].end_sequence)
97da0c48c4Sopenharmony_ci		return add_bkpt (lines->info[l].addr, bkpts, pnbkpts);
98da0c48c4Sopenharmony_ci	  return *pnbkpts;
99da0c48c4Sopenharmony_ci	}
100da0c48c4Sopenharmony_ci      __libdw_seterrno (DWARF_E_INVALID_DWARF);
101da0c48c4Sopenharmony_ci      return -1;
102da0c48c4Sopenharmony_ci}
103da0c48c4Sopenharmony_ci
104da0c48c4Sopenharmony_ciint
105da0c48c4Sopenharmony_cidwarf_entry_breakpoints (Dwarf_Die *die, Dwarf_Addr **bkpts)
106da0c48c4Sopenharmony_ci{
107da0c48c4Sopenharmony_ci  int nbkpts = 0;
108da0c48c4Sopenharmony_ci  *bkpts = NULL;
109da0c48c4Sopenharmony_ci
110da0c48c4Sopenharmony_ci  /* Fetch the CU's line records to look for this DIE's addresses.  */
111da0c48c4Sopenharmony_ci  Dwarf_Die cudie = CUDIE (die->cu);
112da0c48c4Sopenharmony_ci  Dwarf_Lines *lines;
113da0c48c4Sopenharmony_ci  size_t nlines;
114da0c48c4Sopenharmony_ci  if (INTUSE(dwarf_getsrclines) (&cudie, &lines, &nlines) < 0)
115da0c48c4Sopenharmony_ci    {
116da0c48c4Sopenharmony_ci      int error = INTUSE (dwarf_errno) ();
117da0c48c4Sopenharmony_ci      if (error == 0)		/* CU has no DW_AT_stmt_list.  */
118da0c48c4Sopenharmony_ci	return entrypc_bkpt (die, bkpts, &nbkpts);
119da0c48c4Sopenharmony_ci      __libdw_seterrno (error);
120da0c48c4Sopenharmony_ci      return -1;
121da0c48c4Sopenharmony_ci    }
122da0c48c4Sopenharmony_ci
123da0c48c4Sopenharmony_ci  /* Search each contiguous address range for DWARF prologue_end markers.  */
124da0c48c4Sopenharmony_ci
125da0c48c4Sopenharmony_ci  Dwarf_Addr base;
126da0c48c4Sopenharmony_ci  Dwarf_Addr begin;
127da0c48c4Sopenharmony_ci  Dwarf_Addr end;
128da0c48c4Sopenharmony_ci  ptrdiff_t offset = INTUSE(dwarf_ranges) (die, 0, &base, &begin, &end);
129da0c48c4Sopenharmony_ci  if (offset < 0)
130da0c48c4Sopenharmony_ci    return -1;
131da0c48c4Sopenharmony_ci
132da0c48c4Sopenharmony_ci  /* Most often there is a single contiguous PC range for the DIE.  */
133da0c48c4Sopenharmony_ci  if (offset == 1)
134da0c48c4Sopenharmony_ci    return search_range (begin, end, true, true, lines, nlines, bkpts, &nbkpts)
135da0c48c4Sopenharmony_ci        ?: entrypc_bkpt (die, bkpts, &nbkpts);
136da0c48c4Sopenharmony_ci
137da0c48c4Sopenharmony_ci  Dwarf_Addr lowpc = (Dwarf_Addr) -1l;
138da0c48c4Sopenharmony_ci  Dwarf_Addr highpc = (Dwarf_Addr) -1l;
139da0c48c4Sopenharmony_ci  while (offset > 0)
140da0c48c4Sopenharmony_ci    {
141da0c48c4Sopenharmony_ci      /* We have an address range entry.  */
142da0c48c4Sopenharmony_ci      if (search_range (begin, end, true, false,
143da0c48c4Sopenharmony_ci                        lines, nlines, bkpts, &nbkpts) < 0)
144da0c48c4Sopenharmony_ci	return -1;
145da0c48c4Sopenharmony_ci
146da0c48c4Sopenharmony_ci      if (begin < lowpc)
147da0c48c4Sopenharmony_ci	{
148da0c48c4Sopenharmony_ci	  lowpc = begin;
149da0c48c4Sopenharmony_ci	  highpc = end;
150da0c48c4Sopenharmony_ci	}
151da0c48c4Sopenharmony_ci
152da0c48c4Sopenharmony_ci      offset = INTUSE(dwarf_ranges) (die, offset, &base, &begin, &end);
153da0c48c4Sopenharmony_ci    }
154da0c48c4Sopenharmony_ci
155da0c48c4Sopenharmony_ci  /* If we didn't find any proper DWARF markers, then look in the
156da0c48c4Sopenharmony_ci     lowest-addressed range for an ad hoc marker.  Failing that,
157da0c48c4Sopenharmony_ci     fall back to just using the entrypc value.  */
158da0c48c4Sopenharmony_ci  return (nbkpts
159da0c48c4Sopenharmony_ci	  ?: (lowpc == (Dwarf_Addr) -1l ? 0
160da0c48c4Sopenharmony_ci	      : search_range (lowpc, highpc, false, true,
161da0c48c4Sopenharmony_ci	                      lines, nlines, bkpts, &nbkpts))
162da0c48c4Sopenharmony_ci	  ?: entrypc_bkpt (die, bkpts, &nbkpts));
163da0c48c4Sopenharmony_ci}
164