|
Packit |
032894 |
/* Find line information for given file/line/column triple.
|
|
Packit |
032894 |
Copyright (C) 2005-2009 Red Hat, Inc.
|
|
Packit |
032894 |
This file is part of elfutils.
|
|
Packit |
032894 |
Written by Ulrich Drepper <drepper@redhat.com>, 2005.
|
|
Packit |
032894 |
|
|
Packit |
032894 |
This file is free software; you can redistribute it and/or modify
|
|
Packit |
032894 |
it under the terms of either
|
|
Packit |
032894 |
|
|
Packit |
032894 |
* the GNU Lesser General Public License as published by the Free
|
|
Packit |
032894 |
Software Foundation; either version 3 of the License, or (at
|
|
Packit |
032894 |
your option) any later version
|
|
Packit |
032894 |
|
|
Packit |
032894 |
or
|
|
Packit |
032894 |
|
|
Packit |
032894 |
* the GNU General Public License as published by the Free
|
|
Packit |
032894 |
Software Foundation; either version 2 of the License, or (at
|
|
Packit |
032894 |
your option) any later version
|
|
Packit |
032894 |
|
|
Packit |
032894 |
or both in parallel, as here.
|
|
Packit |
032894 |
|
|
Packit |
032894 |
elfutils is distributed in the hope that it will be useful, but
|
|
Packit |
032894 |
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
032894 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
032894 |
General Public License for more details.
|
|
Packit |
032894 |
|
|
Packit |
032894 |
You should have received copies of the GNU General Public License and
|
|
Packit |
032894 |
the GNU Lesser General Public License along with this program. If
|
|
Packit |
032894 |
not, see <http://www.gnu.org/licenses/>. */
|
|
Packit |
032894 |
|
|
Packit |
032894 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
032894 |
# include <config.h>
|
|
Packit |
032894 |
#endif
|
|
Packit |
032894 |
|
|
Packit |
032894 |
#include <assert.h>
|
|
Packit |
032894 |
#include <limits.h>
|
|
Packit |
032894 |
#include <stdlib.h>
|
|
Packit |
032894 |
#include <string.h>
|
|
Packit |
032894 |
|
|
Packit |
032894 |
#include "libdwP.h"
|
|
Packit |
032894 |
|
|
Packit |
032894 |
|
|
Packit |
032894 |
int
|
|
Packit |
032894 |
dwarf_getsrc_file (Dwarf *dbg, const char *fname, int lineno, int column,
|
|
Packit |
032894 |
Dwarf_Line ***srcsp, size_t *nsrcs)
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
if (dbg == NULL)
|
|
Packit |
032894 |
return -1;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
bool is_basename = strchr (fname, '/') == NULL;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
size_t max_match = *nsrcs ?: ~0u;
|
|
Packit |
032894 |
size_t act_match = *nsrcs;
|
|
Packit |
032894 |
size_t cur_match = 0;
|
|
Packit |
032894 |
Dwarf_Line **match = *nsrcs == 0 ? NULL : *srcsp;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
size_t cuhl;
|
|
Packit |
032894 |
Dwarf_Off noff;
|
|
Packit |
032894 |
for (Dwarf_Off off = 0;
|
|
Packit |
032894 |
INTUSE(dwarf_nextcu) (dbg, off, &noff, &cuhl, NULL, NULL, NULL) == 0;
|
|
Packit |
032894 |
off = noff)
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
Dwarf_Die cudie_mem;
|
|
Packit |
032894 |
Dwarf_Die *cudie = INTUSE(dwarf_offdie) (dbg, off + cuhl, &cudie_mem);
|
|
Packit |
032894 |
if (cudie == NULL)
|
|
Packit |
032894 |
continue;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
/* Get the line number information for this file. */
|
|
Packit |
032894 |
Dwarf_Lines *lines;
|
|
Packit |
032894 |
size_t nlines;
|
|
Packit |
032894 |
if (INTUSE(dwarf_getsrclines) (cudie, &lines, &nlines) != 0)
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
/* Ignore a CU that just has no DW_AT_stmt_list at all. */
|
|
Packit |
032894 |
int error = INTUSE(dwarf_errno) ();
|
|
Packit |
032894 |
if (error == 0)
|
|
Packit |
032894 |
continue;
|
|
Packit |
032894 |
__libdw_seterrno (error);
|
|
Packit |
032894 |
return -1;
|
|
Packit |
032894 |
}
|
|
Packit |
032894 |
|
|
Packit |
032894 |
/* Search through all the line number records for a matching
|
|
Packit |
032894 |
file and line/column number. If any of the numbers is zero,
|
|
Packit |
032894 |
no match is performed. */
|
|
Packit |
032894 |
unsigned int lastfile = UINT_MAX;
|
|
Packit |
032894 |
bool lastmatch = false;
|
|
Packit |
032894 |
for (size_t cnt = 0; cnt < nlines; ++cnt)
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
Dwarf_Line *line = &lines->info[cnt];
|
|
Packit |
032894 |
|
|
Packit |
032894 |
if (lastfile != line->file)
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
lastfile = line->file;
|
|
Packit |
032894 |
if (lastfile >= line->files->nfiles)
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
__libdw_seterrno (DWARF_E_INVALID_DWARF);
|
|
Packit |
032894 |
return -1;
|
|
Packit |
032894 |
}
|
|
Packit |
032894 |
|
|
Packit |
032894 |
/* Match the name with the name the user provided. */
|
|
Packit |
032894 |
const char *fname2 = line->files->info[lastfile].name;
|
|
Packit |
032894 |
if (is_basename)
|
|
Packit |
032894 |
lastmatch = strcmp (basename (fname2), fname) == 0;
|
|
Packit |
032894 |
else
|
|
Packit |
032894 |
lastmatch = strcmp (fname2, fname) == 0;
|
|
Packit |
032894 |
}
|
|
Packit |
032894 |
if (!lastmatch)
|
|
Packit |
032894 |
continue;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
/* See whether line and possibly column match. */
|
|
Packit |
032894 |
if (lineno != 0
|
|
Packit |
032894 |
&& (lineno > line->line
|
|
Packit |
032894 |
|| (column != 0 && column > line->column)))
|
|
Packit |
032894 |
/* Cannot match. */
|
|
Packit |
032894 |
continue;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
/* Determine whether this is the best match so far. */
|
|
Packit |
032894 |
size_t inner;
|
|
Packit |
032894 |
for (inner = 0; inner < cur_match; ++inner)
|
|
Packit |
032894 |
if (match[inner]->files == line->files
|
|
Packit |
032894 |
&& match[inner]->file == line->file)
|
|
Packit |
032894 |
break;
|
|
Packit |
032894 |
if (inner < cur_match
|
|
Packit |
032894 |
&& (match[inner]->line != line->line
|
|
Packit |
032894 |
|| match[inner]->line != lineno
|
|
Packit |
032894 |
|| (column != 0
|
|
Packit |
032894 |
&& (match[inner]->column != line->column
|
|
Packit |
032894 |
|| match[inner]->column != column))))
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
/* We know about this file already. If this is a better
|
|
Packit |
032894 |
match for the line number, use it. */
|
|
Packit |
032894 |
if (match[inner]->line >= line->line
|
|
Packit |
032894 |
&& (match[inner]->line != line->line
|
|
Packit |
032894 |
|| match[inner]->column >= line->column))
|
|
Packit |
032894 |
/* Use the new line. Otherwise the old one. */
|
|
Packit |
032894 |
match[inner] = line;
|
|
Packit |
032894 |
continue;
|
|
Packit |
032894 |
}
|
|
Packit |
032894 |
|
|
Packit |
032894 |
if (cur_match < max_match)
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
if (cur_match == act_match)
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
/* Enlarge the array for the results. */
|
|
Packit |
032894 |
act_match += 10;
|
|
Packit |
032894 |
Dwarf_Line **newp = realloc (match,
|
|
Packit |
032894 |
act_match
|
|
Packit |
032894 |
* sizeof (Dwarf_Line *));
|
|
Packit |
032894 |
if (newp == NULL)
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
free (match);
|
|
Packit |
032894 |
__libdw_seterrno (DWARF_E_NOMEM);
|
|
Packit |
032894 |
return -1;
|
|
Packit |
032894 |
}
|
|
Packit |
032894 |
match = newp;
|
|
Packit |
032894 |
}
|
|
Packit |
032894 |
|
|
Packit |
032894 |
match[cur_match++] = line;
|
|
Packit |
032894 |
}
|
|
Packit |
032894 |
}
|
|
Packit |
032894 |
|
|
Packit |
032894 |
/* If we managed to find as many matches as the user requested
|
|
Packit |
032894 |
already, there is no need to go on to the next CU. */
|
|
Packit |
032894 |
if (cur_match == max_match)
|
|
Packit |
032894 |
break;
|
|
Packit |
032894 |
}
|
|
Packit |
032894 |
|
|
Packit |
032894 |
if (cur_match > 0)
|
|
Packit |
032894 |
{
|
|
Packit |
032894 |
assert (*nsrcs == 0 || *srcsp == match);
|
|
Packit |
032894 |
|
|
Packit |
032894 |
*nsrcs = cur_match;
|
|
Packit |
032894 |
*srcsp = match;
|
|
Packit |
032894 |
|
|
Packit |
032894 |
return 0;
|
|
Packit |
032894 |
}
|
|
Packit |
032894 |
|
|
Packit |
032894 |
__libdw_seterrno (DWARF_E_NO_MATCH);
|
|
Packit |
032894 |
return -1;
|
|
Packit |
032894 |
}
|