Branch data Line data Source code
1 : : /* Find line information for given file/line/column triple. 2 : : Copyright (C) 2005-2009 Red Hat, Inc. 3 : : This file is part of elfutils. 4 : : Written by Ulrich Drepper <drepper@redhat.com>, 2005. 5 : : 6 : : This file is free software; you can redistribute it and/or modify 7 : : it under the terms of either 8 : : 9 : : * the GNU Lesser General Public License as published by the Free 10 : : Software Foundation; either version 3 of the License, or (at 11 : : your option) any later version 12 : : 13 : : or 14 : : 15 : : * the GNU General Public License as published by the Free 16 : : Software Foundation; either version 2 of the License, or (at 17 : : your option) any later version 18 : : 19 : : or both in parallel, as here. 20 : : 21 : : elfutils is distributed in the hope that it will be useful, but 22 : : WITHOUT ANY WARRANTY; without even the implied warranty of 23 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 24 : : General Public License for more details. 25 : : 26 : : You should have received copies of the GNU General Public License and 27 : : the GNU Lesser General Public License along with this program. If 28 : : not, see <http://www.gnu.org/licenses/>. */ 29 : : 30 : : #ifdef HAVE_CONFIG_H 31 : : # include <config.h> 32 : : #endif 33 : : 34 : : #include <assert.h> 35 : : #include <limits.h> 36 : : #include <stdlib.h> 37 : : #include <string.h> 38 : : 39 : : #include "libdwP.h" 40 : : 41 : : 42 : : int 43 : 0 : dwarf_getsrc_file (Dwarf *dbg, const char *fname, int lineno, int column, 44 : : Dwarf_Line ***srcsp, size_t *nsrcs) 45 : : { 46 [ # # ]: 0 : if (dbg == NULL) 47 : : return -1; 48 : : 49 : 0 : bool is_basename = strchr (fname, '/') == NULL; 50 : : 51 [ # # ]: 0 : size_t max_match = *nsrcs ?: ~0u; 52 : 0 : size_t act_match = *nsrcs; 53 : 0 : size_t cur_match = 0; 54 [ # # ]: 0 : Dwarf_Line **match = *nsrcs == 0 ? NULL : *srcsp; 55 : : 56 : : size_t cuhl; 57 : : Dwarf_Off noff; 58 : : for (Dwarf_Off off = 0; 59 [ # # ]: 0 : INTUSE(dwarf_nextcu) (dbg, off, &noff, &cuhl, NULL, NULL, NULL) == 0; 60 : 0 : off = noff) 61 : : { 62 : 0 : Dwarf_Die cudie_mem; 63 : 0 : Dwarf_Die *cudie = INTUSE(dwarf_offdie) (dbg, off + cuhl, &cudie_mem); 64 [ # # ]: 0 : if (cudie == NULL) 65 : 0 : continue; 66 : : 67 : : /* Get the line number information for this file. */ 68 : 0 : Dwarf_Lines *lines; 69 : 0 : size_t nlines; 70 [ # # ]: 0 : if (INTUSE(dwarf_getsrclines) (cudie, &lines, &nlines) != 0) 71 : : { 72 : : /* Ignore a CU that just has no DW_AT_stmt_list at all. */ 73 : 0 : int error = INTUSE(dwarf_errno) (); 74 [ # # ]: 0 : if (error == 0) 75 : 0 : continue; 76 : 0 : __libdw_seterrno (error); 77 : 0 : return -1; 78 : : } 79 : : 80 : : /* Search through all the line number records for a matching 81 : : file and line/column number. If any of the numbers is zero, 82 : : no match is performed. */ 83 : : unsigned int lastfile = UINT_MAX; 84 : : bool lastmatch = false; 85 [ # # ]: 0 : for (size_t cnt = 0; cnt < nlines; ++cnt) 86 : : { 87 : 0 : Dwarf_Line *line = &lines->info[cnt]; 88 : : 89 [ # # ]: 0 : if (lastfile != line->file) 90 : : { 91 : 0 : lastfile = line->file; 92 [ # # ]: 0 : if (lastfile >= line->files->nfiles) 93 : : { 94 : 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF); 95 : 0 : return -1; 96 : : } 97 : : 98 : : /* Match the name with the name the user provided. */ 99 : 0 : const char *fname2 = line->files->info[lastfile].name; 100 [ # # ]: 0 : if (is_basename) 101 : 0 : lastmatch = strcmp (xbasename (fname2), fname) == 0; 102 : : else 103 : 0 : lastmatch = strcmp (fname2, fname) == 0; 104 : : } 105 [ # # ]: 0 : if (!lastmatch) 106 : 0 : continue; 107 : : 108 : : /* See whether line and possibly column match. */ 109 [ # # ]: 0 : if (lineno != 0 110 [ # # ]: 0 : && (lineno > line->line 111 [ # # # # ]: 0 : || (column != 0 && column > line->column))) 112 : : /* Cannot match. */ 113 : 0 : continue; 114 : : 115 : : /* Determine whether this is the best match so far. */ 116 : : size_t inner; 117 [ # # ]: 0 : for (inner = 0; inner < cur_match; ++inner) 118 [ # # ]: 0 : if (match[inner]->files == line->files 119 [ # # ]: 0 : && match[inner]->file == line->file) 120 : : break; 121 [ # # ]: 0 : if (inner < cur_match 122 [ # # ]: 0 : && (match[inner]->line != line->line 123 [ # # ]: 0 : || match[inner]->line != lineno 124 [ # # ]: 0 : || (column != 0 125 [ # # ]: 0 : && (match[inner]->column != line->column 126 [ # # ]: 0 : || match[inner]->column != column)))) 127 : : { 128 : : /* We know about this file already. If this is a better 129 : : match for the line number, use it. */ 130 [ # # ]: 0 : if (match[inner]->line >= line->line 131 [ # # ]: 0 : && (match[inner]->line != line->line 132 [ # # ]: 0 : || match[inner]->column >= line->column)) 133 : : /* Use the new line. Otherwise the old one. */ 134 : 0 : match[inner] = line; 135 : 0 : continue; 136 : : } 137 : : 138 [ # # ]: 0 : if (cur_match < max_match) 139 : : { 140 [ # # ]: 0 : if (cur_match == act_match) 141 : : { 142 : : /* Enlarge the array for the results. */ 143 : 0 : act_match += 10; 144 : 0 : Dwarf_Line **newp = realloc (match, 145 : : act_match 146 : : * sizeof (Dwarf_Line *)); 147 [ # # ]: 0 : if (newp == NULL) 148 : : { 149 : 0 : free (match); 150 : 0 : __libdw_seterrno (DWARF_E_NOMEM); 151 : 0 : return -1; 152 : : } 153 : : match = newp; 154 : : } 155 : : 156 : 0 : match[cur_match++] = line; 157 : : } 158 : : } 159 : : 160 : : /* If we managed to find as many matches as the user requested 161 : : already, there is no need to go on to the next CU. */ 162 [ # # ]: 0 : if (cur_match == max_match) 163 : : break; 164 : : } 165 : : 166 [ # # ]: 0 : if (cur_match > 0) 167 : : { 168 [ # # # # ]: 0 : assert (*nsrcs == 0 || *srcsp == match); 169 : : 170 : 0 : *nsrcs = cur_match; 171 : 0 : *srcsp = match; 172 : : 173 : 0 : return 0; 174 : : } 175 : : 176 : 0 : __libdw_seterrno (DWARF_E_NO_MATCH); 177 : 0 : return -1; 178 : : }