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