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 : /* Add one breakpoint location to the result vector. */
38 : static inline int
39 35 : add_bkpt (Dwarf_Addr pc, Dwarf_Addr **bkpts, int *pnbkpts)
40 : {
41 35 : Dwarf_Addr *newlist = realloc (*bkpts, ++(*pnbkpts) * sizeof newlist[0]);
42 35 : if (newlist == NULL)
43 : {
44 0 : free (*bkpts);
45 0 : *bkpts = NULL;
46 0 : __libdw_seterrno (DWARF_E_NOMEM);
47 0 : return -1;
48 : }
49 35 : newlist[*pnbkpts - 1] = pc;
50 35 : *bkpts = newlist;
51 35 : return *pnbkpts;
52 : }
53 :
54 : /* Fallback result, break at the entrypc/lowpc value. */
55 : static inline int
56 2 : entrypc_bkpt (Dwarf_Die *die, Dwarf_Addr **bkpts, int *pnbkpts)
57 : {
58 : Dwarf_Addr pc;
59 2 : return INTUSE(dwarf_entrypc) (die, &pc) < 0 ? -1 : add_bkpt (pc, bkpts, pnbkpts);
60 : }
61 :
62 : /* Search a contiguous PC range for prologue-end markers.
63 : If DWARF, look for proper markers.
64 : Failing that, if ADHOC, look for the ad hoc convention. */
65 : static inline int
66 35 : search_range (Dwarf_Addr low, Dwarf_Addr high,
67 : bool dwarf, bool adhoc,
68 : Dwarf_Lines *lines, size_t nlines,
69 : Dwarf_Addr **bkpts, int *pnbkpts)
70 : {
71 35 : size_t l = 0, u = nlines;
72 166 : while (l < u)
73 : {
74 131 : size_t idx = (l + u) / 2;
75 131 : if (lines->info[idx].addr < low)
76 34 : l = idx + 1;
77 97 : else if (lines->info[idx].addr > low)
78 : u = idx;
79 39 : else if (lines->info[idx].end_sequence)
80 4 : l = idx + 1;
81 : else
82 : {
83 : l = idx;
84 : break;
85 : }
86 : }
87 35 : if (l < u)
88 : {
89 35 : if (dwarf)
90 50 : for (size_t i = l; i < u && lines->info[i].addr < high; ++i)
91 50 : if (lines->info[i].prologue_end
92 0 : && add_bkpt (lines->info[i].addr, bkpts, pnbkpts) < 0)
93 : return -1;
94 35 : if (adhoc && *pnbkpts == 0)
95 37 : while (++l < nlines && lines->info[l].addr < high)
96 35 : if (!lines->info[l].end_sequence)
97 33 : return add_bkpt (lines->info[l].addr, bkpts, pnbkpts);
98 2 : return *pnbkpts;
99 : }
100 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF);
101 0 : return -1;
102 : }
103 :
104 : int
105 35 : dwarf_entry_breakpoints (Dwarf_Die *die, Dwarf_Addr **bkpts)
106 : {
107 35 : int nbkpts = 0;
108 35 : *bkpts = NULL;
109 :
110 : /* Fetch the CU's line records to look for this DIE's addresses. */
111 70 : Dwarf_Die cudie = CUDIE (die->cu);
112 : Dwarf_Lines *lines;
113 : size_t nlines;
114 35 : if (INTUSE(dwarf_getsrclines) (&cudie, &lines, &nlines) < 0)
115 : {
116 0 : int error = INTUSE (dwarf_errno) ();
117 0 : if (error == 0) /* CU has no DW_AT_stmt_list. */
118 0 : return entrypc_bkpt (die, bkpts, &nbkpts);
119 0 : __libdw_seterrno (error);
120 0 : return -1;
121 : }
122 :
123 : /* Search each contiguous address range for DWARF prologue_end markers. */
124 :
125 : Dwarf_Addr base;
126 : Dwarf_Addr begin;
127 : Dwarf_Addr end;
128 35 : ptrdiff_t offset = INTUSE(dwarf_ranges) (die, 0, &base, &begin, &end);
129 35 : if (offset < 0)
130 : return -1;
131 :
132 : /* Most often there is a single contiguous PC range for the DIE. */
133 35 : if (offset == 1)
134 70 : return search_range (begin, end, true, true, lines, nlines, bkpts, &nbkpts)
135 35 : ?: entrypc_bkpt (die, bkpts, &nbkpts);
136 :
137 : Dwarf_Addr lowpc = (Dwarf_Addr) -1l;
138 : Dwarf_Addr highpc = (Dwarf_Addr) -1l;
139 0 : while (offset > 0)
140 : {
141 : /* We have an address range entry. */
142 0 : if (search_range (begin, end, true, false,
143 : lines, nlines, bkpts, &nbkpts) < 0)
144 : return -1;
145 :
146 0 : if (begin < lowpc)
147 : {
148 0 : lowpc = begin;
149 0 : highpc = end;
150 : }
151 :
152 0 : offset = INTUSE(dwarf_ranges) (die, offset, &base, &begin, &end);
153 : }
154 :
155 : /* If we didn't find any proper DWARF markers, then look in the
156 : lowest-addressed range for an ad hoc marker. Failing that,
157 : fall back to just using the entrypc value. */
158 0 : return (nbkpts
159 0 : ?: (lowpc == (Dwarf_Addr) -1l ? 0
160 0 : : search_range (lowpc, highpc, false, true,
161 : lines, nlines, bkpts, &nbkpts))
162 0 : ?: entrypc_bkpt (die, bkpts, &nbkpts));
163 : }
|