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