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 42int 43dwarf_getsrc_file (Dwarf *dbg, const char *fname, int lineno, int column, 44 Dwarf_Line ***srcsp, size_t *nsrcs) 45{ 46 if (dbg == NULL) 47 return -1; 48 49 bool is_basename = strchr (fname, '/') == NULL; 50 51 size_t max_match = *nsrcs ?: ~0u; 52 size_t act_match = *nsrcs; 53 size_t cur_match = 0; 54 Dwarf_Line **match = *nsrcs == 0 ? NULL : *srcsp; 55 56 size_t cuhl; 57 Dwarf_Off noff; 58 for (Dwarf_Off off = 0; 59 INTUSE(dwarf_nextcu) (dbg, off, &noff, &cuhl, NULL, NULL, NULL) == 0; 60 off = noff) 61 { 62 Dwarf_Die cudie_mem; 63 Dwarf_Die *cudie = INTUSE(dwarf_offdie) (dbg, off + cuhl, &cudie_mem); 64 if (cudie == NULL) 65 continue; 66 67 /* Get the line number information for this file. */ 68 Dwarf_Lines *lines; 69 size_t nlines; 70 if (INTUSE(dwarf_getsrclines) (cudie, &lines, &nlines) != 0) 71 { 72 /* Ignore a CU that just has no DW_AT_stmt_list at all. */ 73 int error = INTUSE(dwarf_errno) (); 74 if (error == 0) 75 continue; 76 __libdw_seterrno (error); 77 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 for (size_t cnt = 0; cnt < nlines; ++cnt) 86 { 87 Dwarf_Line *line = &lines->info[cnt]; 88 89 if (lastfile != line->file) 90 { 91 lastfile = line->file; 92 if (lastfile >= line->files->nfiles) 93 { 94 __libdw_seterrno (DWARF_E_INVALID_DWARF); 95 return -1; 96 } 97 98 /* Match the name with the name the user provided. */ 99 const char *fname2 = line->files->info[lastfile].name; 100 if (is_basename) 101 lastmatch = strcmp (basename (fname2), fname) == 0; 102 else 103 lastmatch = strcmp (fname2, fname) == 0; 104 } 105 if (!lastmatch) 106 continue; 107 108 /* See whether line and possibly column match. */ 109 if (lineno != 0 110 && (lineno > line->line 111 || (column != 0 && column > line->column))) 112 /* Cannot match. */ 113 continue; 114 115 /* Determine whether this is the best match so far. */ 116 size_t inner; 117 for (inner = 0; inner < cur_match; ++inner) 118 if (match[inner]->files == line->files 119 && match[inner]->file == line->file) 120 break; 121 if (inner < cur_match 122 && (match[inner]->line != line->line 123 || match[inner]->line != lineno 124 || (column != 0 125 && (match[inner]->column != line->column 126 || 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 if (match[inner]->line >= line->line 131 && (match[inner]->line != line->line 132 || match[inner]->column >= line->column)) 133 /* Use the new line. Otherwise the old one. */ 134 match[inner] = line; 135 continue; 136 } 137 138 if (cur_match < max_match) 139 { 140 if (cur_match == act_match) 141 { 142 /* Enlarge the array for the results. */ 143 act_match += 10; 144 Dwarf_Line **newp = realloc (match, 145 act_match 146 * sizeof (Dwarf_Line *)); 147 if (newp == NULL) 148 { 149 free (match); 150 __libdw_seterrno (DWARF_E_NOMEM); 151 return -1; 152 } 153 match = newp; 154 } 155 156 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 if (cur_match == max_match) 163 break; 164 } 165 166 if (cur_match > 0) 167 { 168 assert (*nsrcs == 0 || *srcsp == match); 169 170 *nsrcs = cur_match; 171 *srcsp = match; 172 173 return 0; 174 } 175 176 __libdw_seterrno (DWARF_E_NO_MATCH); 177 return -1; 178} 179