aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog34
-rw-r--r--bfd/bfd-in2.h8
-rw-r--r--bfd/bfd.c4
-rw-r--r--bfd/dwarf2.c432
-rw-r--r--bfd/elf-bfd.h3
-rw-r--r--bfd/elf.c11
-rw-r--r--bfd/libbfd-in.h8
-rw-r--r--bfd/libbfd.c10
-rw-r--r--bfd/libbfd.h8
-rw-r--r--bfd/targets.c4
-rw-r--r--binutils/ChangeLog6
-rw-r--r--binutils/nm.c7
12 files changed, 528 insertions, 7 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 2aef89f..39626c1 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,5 +1,39 @@
2005-06-06 H.J. Lu <hongjiu.lu@intel.com>
+ PR 990
+ * bfd.c (bfd_find_line): New.
+
+ * dwarf2.c (comp_unit): Add variable_table.
+ (funcinfo): Add file, line, and sec.
+ (varinfo): New.
+ (lookup_symbol_in_function_table): New.
+ (lookup_symbol_in_variable_table): New.
+ (scan_unit_for_functions): Renamed to ...
+ (scan_unit_for_symbols): This. Handle DW_TAG_entry_point and
+ DW_TAG_variable.
+ (comp_unit_find_nearest_line): Updated.
+ (comp_unit_find_line): New.
+ (_bfd_dwarf2_find_line): New.
+
+ * elf-bfd.h (_bfd_elf_find_line): New.
+ (_bfd_generic_find_line): New. Defined.
+
+ * elf.c (_bfd_elf_find_line): New.
+
+ * libbfd-in.h (_bfd_dwarf2_find_line): New.
+ (_bfd_generic_find_line): New.
+
+ * bfd-in2.h: Regenerated.
+ * libbfd.h: Likewise.
+
+ * libbfd.c (_bfd_generic_find_line): New.
+
+ * targets.c (BFD_JUMP_TABLE_SYMBOLS): Initialize _bfd_find_line
+ with _bfd_generic_find_line.
+ (bfd_target): Add _bfd_find_line.
+
+2005-06-06 H.J. Lu <hongjiu.lu@intel.com>
+
* dwarf2.c (decode_line_info): Properly set low_pc.
2005-06-06 Alan Modra <amodra@bigpond.net.au>
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index f4b82b8..93d8668 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -4307,6 +4307,10 @@ bfd_boolean bfd_set_private_flags (bfd *abfd, flagword flags);
BFD_SEND (abfd, _bfd_find_nearest_line, \
(abfd, sec, syms, off, file, func, line))
+#define bfd_find_line(abfd, syms, sym, file, line) \
+ BFD_SEND (abfd, _bfd_find_line, \
+ (abfd, syms, sym, file, line))
+
#define bfd_find_inliner_info(abfd, file, func, line) \
BFD_SEND (abfd, _bfd_find_inliner_info, \
(abfd, file, func, line))
@@ -4647,6 +4651,7 @@ typedef struct bfd_target
NAME##_bfd_is_target_special_symbol, \
NAME##_get_lineno, \
NAME##_find_nearest_line, \
+ _bfd_generic_find_line, \
NAME##_find_inliner_info, \
NAME##_bfd_make_debug_symbol, \
NAME##_read_minisymbols, \
@@ -4669,6 +4674,9 @@ typedef struct bfd_target
bfd_boolean (*_bfd_find_nearest_line)
(bfd *, struct bfd_section *, struct bfd_symbol **, bfd_vma,
const char **, const char **, unsigned int *);
+ bfd_boolean (*_bfd_find_line)
+ (bfd *, struct bfd_symbol **, struct bfd_symbol *,
+ const char **, unsigned int *);
bfd_boolean (*_bfd_find_inliner_info)
(bfd *, const char **, const char **, unsigned int *);
/* Back-door to allow format-aware applications to create debug symbols
diff --git a/bfd/bfd.c b/bfd/bfd.c
index f62411b..908d794 100644
--- a/bfd/bfd.c
+++ b/bfd/bfd.c
@@ -1161,6 +1161,10 @@ DESCRIPTION
. BFD_SEND (abfd, _bfd_find_nearest_line, \
. (abfd, sec, syms, off, file, func, line))
.
+.#define bfd_find_line(abfd, syms, sym, file, line) \
+. BFD_SEND (abfd, _bfd_find_line, \
+. (abfd, syms, sym, file, line))
+.
.#define bfd_find_inliner_info(abfd, file, func, line) \
. BFD_SEND (abfd, _bfd_find_inliner_info, \
. (abfd, file, func, line))
diff --git a/bfd/dwarf2.c b/bfd/dwarf2.c
index 1b08f28..410a51e 100644
--- a/bfd/dwarf2.c
+++ b/bfd/dwarf2.c
@@ -182,6 +182,9 @@ struct comp_unit
/* A list of the functions found in this comp. unit. */
struct funcinfo *function_table;
+ /* A list of the variables found in this comp. unit. */
+ struct varinfo *variable_table;
+
/* Pointer to dwarf2_debug structure. */
struct dwarf2_debug *stash;
@@ -697,10 +700,29 @@ struct funcinfo
struct funcinfo *caller_func; /* Pointer to function one scope higher */
char *caller_file; /* Source location file name where caller_func inlines this func */
int caller_line; /* Source location line number where caller_func inlines this func */
+ char *file; /* Source location file name */
+ int line; /* Source location line number */
int tag;
int nesting_level;
char *name;
struct arange arange;
+ asection *sec; /* Where the symbol is defined */
+};
+
+struct varinfo
+{
+ /* Pointer to previous variable in list of all variables */
+ struct varinfo *prev_var;
+ /* Source location file name */
+ char *file;
+ /* Source location line number */
+ int line;
+ int tag;
+ char *name;
+ /* Where the symbol is defined */
+ asection *sec;
+ /* Is this a stack variable? */
+ unsigned int stack: 1;
};
/* Adds a new entry to the line_info list in the line_info_table, ensuring
@@ -1424,6 +1446,84 @@ lookup_address_in_function_table (struct comp_unit *unit,
}
}
+/* If SYM at ADDR is within function table of UNIT, set FILENAME_PTR
+ and LINENUMBER_PTR, and return TRUE. */
+
+static bfd_boolean
+lookup_symbol_in_function_table (struct comp_unit *unit,
+ asymbol *sym,
+ bfd_vma addr,
+ const char **filename_ptr,
+ unsigned int *linenumber_ptr)
+{
+ struct funcinfo* each_func;
+ struct funcinfo* best_fit = NULL;
+ struct arange *arange;
+ const char *name = bfd_asymbol_name (sym);
+ asection *sec = bfd_get_section (sym);
+
+ for (each_func = unit->function_table;
+ each_func;
+ each_func = each_func->prev_func)
+ {
+ for (arange = &each_func->arange;
+ arange;
+ arange = arange->next)
+ {
+ if ((!each_func->sec || each_func->sec == sec)
+ && addr >= arange->low
+ && addr < arange->high
+ && strcmp (name, each_func->name) == 0
+ && (!best_fit
+ || ((arange->high - arange->low)
+ < (best_fit->arange.high - best_fit->arange.low))))
+ best_fit = each_func;
+ }
+ }
+
+ if (best_fit)
+ {
+ best_fit->sec = sec;
+ *filename_ptr = best_fit->file;
+ *linenumber_ptr = best_fit->line;
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+/* Variable table functions. */
+
+/* If SYM is within variable table of UNIT, set FILENAME_PTR and
+ LINENUMBER_PTR, and return TRUE. */
+
+static bfd_boolean
+lookup_symbol_in_variable_table (struct comp_unit *unit,
+ asymbol *sym,
+ const char **filename_ptr,
+ unsigned int *linenumber_ptr)
+{
+ const char *name = bfd_asymbol_name (sym);
+ asection *sec = bfd_get_section (sym);
+ struct varinfo* each;
+
+ for (each = unit->variable_table; each; each = each->prev_var)
+ if (each->stack == 0
+ && (!each->sec || each->sec == sec)
+ && strcmp (name, each->name) == 0)
+ break;
+
+ if (each)
+ {
+ each->sec = sec;
+ *filename_ptr = each->file;
+ *linenumber_ptr = each->line;
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
static char *
find_abstract_instance_name (struct comp_unit *unit, bfd_uint64_t die_ref)
{
@@ -1513,10 +1613,10 @@ read_rangelist (struct comp_unit *unit, struct arange *arange, bfd_uint64_t offs
/* DWARF2 Compilation unit functions. */
/* Scan over each die in a comp. unit looking for functions to add
- to the function table. */
+ to the function table and variables to the variable table. */
static bfd_boolean
-scan_unit_for_functions (struct comp_unit *unit)
+scan_unit_for_symbols (struct comp_unit *unit)
{
bfd *abfd = unit->abfd;
bfd_byte *info_ptr = unit->first_child_die_ptr;
@@ -1528,6 +1628,7 @@ scan_unit_for_functions (struct comp_unit *unit)
struct abbrev_info *abbrev;
struct attribute attr;
struct funcinfo *func;
+ struct varinfo *var;
bfd_vma low_pc = 0;
bfd_vma high_pc = 0;
@@ -1549,7 +1650,9 @@ scan_unit_for_functions (struct comp_unit *unit)
return FALSE;
}
+ var = NULL;
if (abbrev->tag == DW_TAG_subprogram
+ || abbrev->tag == DW_TAG_entry_point
|| abbrev->tag == DW_TAG_inlined_subroutine)
{
bfd_size_type amt = sizeof (struct funcinfo);
@@ -1560,7 +1663,18 @@ scan_unit_for_functions (struct comp_unit *unit)
unit->function_table = func;
}
else
- func = NULL;
+ {
+ func = NULL;
+ if (abbrev->tag == DW_TAG_variable)
+ {
+ bfd_size_type amt = sizeof (struct varinfo);
+ var = bfd_zalloc (abfd, amt);
+ var->tag = abbrev->tag;
+ var->stack = 1;
+ var->prev_var = unit->variable_table;
+ unit->variable_table = var;
+ }
+ }
for (i = 0; i < abbrev->num_attrs; ++i)
{
@@ -1604,6 +1718,60 @@ scan_unit_for_functions (struct comp_unit *unit)
read_rangelist (unit, &func->arange, attr.u.val);
break;
+ case DW_AT_decl_file:
+ func->file = concat_filename (unit->line_table,
+ attr.u.val);
+ break;
+
+ case DW_AT_decl_line:
+ func->line = attr.u.val;
+ break;
+
+ default:
+ break;
+ }
+ }
+ else if (var)
+ {
+ switch (attr.name)
+ {
+ case DW_AT_name:
+ var->name = attr.u.str;
+ break;
+
+ case DW_AT_decl_file:
+ var->file = concat_filename (unit->line_table,
+ attr.u.val);
+ break;
+
+ case DW_AT_decl_line:
+ var->line = attr.u.val;
+ break;
+
+ case DW_AT_external:
+ if (attr.u.val != 0)
+ var->stack = 0;
+ break;
+
+ case DW_AT_location:
+ if (var->stack)
+ {
+ switch (attr.form)
+ {
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ if (*attr.u.blk->data == DW_OP_addr)
+ var->stack = 0;
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
default:
break;
}
@@ -1844,7 +2012,7 @@ comp_unit_find_nearest_line (struct comp_unit *unit,
}
if (unit->first_child_die_ptr < unit->end_ptr
- && ! scan_unit_for_functions (unit))
+ && ! scan_unit_for_symbols (unit))
{
unit->error = 1;
return FALSE;
@@ -1862,6 +2030,58 @@ comp_unit_find_nearest_line (struct comp_unit *unit,
return line_p || func_p;
}
+/* If UNIT contains SYM at ADDR, set the output parameters to the
+ values for the line containing SYM. The output parameters,
+ FILENAME_PTR, and LINENUMBER_PTR, are pointers to the objects to be
+ filled in.
+
+ Return TRUE if UNIT contains SYM, and no errors were encountered;
+ FALSE otherwise. */
+
+static bfd_boolean
+comp_unit_find_line (struct comp_unit *unit,
+ asymbol *sym,
+ bfd_vma addr,
+ const char **filename_ptr,
+ unsigned int *linenumber_ptr,
+ struct dwarf2_debug *stash)
+{
+ if (unit->error)
+ return FALSE;
+
+ if (! unit->line_table)
+ {
+ if (! unit->stmtlist)
+ {
+ unit->error = 1;
+ return FALSE;
+ }
+
+ unit->line_table = decode_line_info (unit, stash);
+
+ if (! unit->line_table)
+ {
+ unit->error = 1;
+ return FALSE;
+ }
+
+ if (unit->first_child_die_ptr < unit->end_ptr
+ && ! scan_unit_for_symbols (unit))
+ {
+ unit->error = 1;
+ return FALSE;
+ }
+ }
+
+ if (sym->flags & BSF_FUNCTION)
+ return lookup_symbol_in_function_table (unit, sym, addr,
+ filename_ptr,
+ linenumber_ptr);
+ else
+ return lookup_symbol_in_variable_table (unit, sym, filename_ptr,
+ linenumber_ptr);
+}
+
/* Locate a section in a BFD containing debugging info. The search starts
from the section after AFTER_SEC, or from the first section in the BFD if
AFTER_SEC is NULL. The search works by examining the names of the
@@ -2107,6 +2327,210 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd,
return FALSE;
}
+/* The DWARF2 version of find_line. Return TRUE if the line is found
+ without error. */
+
+bfd_boolean
+_bfd_dwarf2_find_line (bfd *abfd,
+ asymbol **symbols,
+ asymbol *symbol,
+ const char **filename_ptr,
+ unsigned int *linenumber_ptr,
+ unsigned int addr_size,
+ void **pinfo)
+{
+ /* Read each compilation unit from the section .debug_info, and check
+ to see if it contains the address we are searching for. If yes,
+ lookup the address, and return the line number info. If no, go
+ on to the next compilation unit.
+
+ We keep a list of all the previously read compilation units, and
+ a pointer to the next un-read compilation unit. Check the
+ previously read units before reading more. */
+ struct dwarf2_debug *stash;
+
+ /* What address are we looking for? */
+ bfd_vma addr;
+
+ struct comp_unit* each;
+
+ asection *section;
+
+ bfd_boolean found;
+
+ section = bfd_get_section (symbol);
+
+ addr = symbol->value;
+ if (section->output_section)
+ addr += section->output_section->vma + section->output_offset;
+ else
+ addr += section->vma;
+
+ *filename_ptr = NULL;
+ stash = *pinfo;
+ *filename_ptr = NULL;
+ *linenumber_ptr = 0;
+
+ if (! stash)
+ {
+ bfd_size_type total_size;
+ asection *msec;
+ bfd_size_type amt = sizeof (struct dwarf2_debug);
+
+ stash = bfd_zalloc (abfd, amt);
+ if (! stash)
+ return FALSE;
+
+ *pinfo = stash;
+
+ msec = find_debug_info (abfd, NULL);
+ if (! msec)
+ /* No dwarf2 info. Note that at this point the stash
+ has been allocated, but contains zeros, this lets
+ future calls to this function fail quicker. */
+ return FALSE;
+
+ /* There can be more than one DWARF2 info section in a BFD these days.
+ Read them all in and produce one large stash. We do this in two
+ passes - in the first pass we just accumulate the section sizes.
+ In the second pass we read in the section's contents. The allows
+ us to avoid reallocing the data as we add sections to the stash. */
+ for (total_size = 0; msec; msec = find_debug_info (abfd, msec))
+ total_size += msec->size;
+
+ stash->info_ptr = bfd_alloc (abfd, total_size);
+ if (stash->info_ptr == NULL)
+ return FALSE;
+
+ stash->info_ptr_end = stash->info_ptr;
+
+ for (msec = find_debug_info (abfd, NULL);
+ msec;
+ msec = find_debug_info (abfd, msec))
+ {
+ bfd_size_type size;
+ bfd_size_type start;
+
+ size = msec->size;
+ if (size == 0)
+ continue;
+
+ start = stash->info_ptr_end - stash->info_ptr;
+
+ if ((bfd_simple_get_relocated_section_contents
+ (abfd, msec, stash->info_ptr + start, symbols)) == NULL)
+ continue;
+
+ stash->info_ptr_end = stash->info_ptr + start + size;
+ }
+
+ BFD_ASSERT (stash->info_ptr_end == stash->info_ptr + total_size);
+
+ stash->sec = find_debug_info (abfd, NULL);
+ stash->sec_info_ptr = stash->info_ptr;
+ stash->syms = symbols;
+ }
+
+ /* A null info_ptr indicates that there is no dwarf2 info
+ (or that an error occured while setting up the stash). */
+ if (! stash->info_ptr)
+ return FALSE;
+
+ stash->inliner_chain = NULL;
+
+ /* Check the previously read comp. units first. */
+ for (each = stash->all_comp_units; each; each = each->next_unit)
+ if ((symbol->flags & BSF_FUNCTION) == 0
+ || comp_unit_contains_address (each, addr))
+ {
+ found = comp_unit_find_line (each, symbol, addr, filename_ptr,
+ linenumber_ptr, stash);
+ if (found)
+ return found;
+ }
+
+ /* The DWARF2 spec says that the initial length field, and the
+ offset of the abbreviation table, should both be 4-byte values.
+ However, some compilers do things differently. */
+ if (addr_size == 0)
+ addr_size = 4;
+ BFD_ASSERT (addr_size == 4 || addr_size == 8);
+
+ /* Read each remaining comp. units checking each as they are read. */
+ while (stash->info_ptr < stash->info_ptr_end)
+ {
+ bfd_vma length;
+ unsigned int offset_size = addr_size;
+ bfd_byte *info_ptr_unit = stash->info_ptr;
+
+ length = read_4_bytes (abfd, stash->info_ptr);
+ /* A 0xffffff length is the DWARF3 way of indicating we use
+ 64-bit offsets, instead of 32-bit offsets. */
+ if (length == 0xffffffff)
+ {
+ offset_size = 8;
+ length = read_8_bytes (abfd, stash->info_ptr + 4);
+ stash->info_ptr += 12;
+ }
+ /* A zero length is the IRIX way of indicating 64-bit offsets,
+ mostly because the 64-bit length will generally fit in 32
+ bits, and the endianness helps. */
+ else if (length == 0)
+ {
+ offset_size = 8;
+ length = read_4_bytes (abfd, stash->info_ptr + 4);
+ stash->info_ptr += 8;
+ }
+ /* In the absence of the hints above, we assume addr_size-sized
+ offsets, for backward-compatibility with pre-DWARF3 64-bit
+ platforms. */
+ else if (addr_size == 8)
+ {
+ length = read_8_bytes (abfd, stash->info_ptr);
+ stash->info_ptr += 8;
+ }
+ else
+ stash->info_ptr += 4;
+
+ if (length > 0)
+ {
+ each = parse_comp_unit (abfd, stash, length, info_ptr_unit,
+ offset_size);
+ stash->info_ptr += length;
+
+ if ((bfd_vma) (stash->info_ptr - stash->sec_info_ptr)
+ == stash->sec->size)
+ {
+ stash->sec = find_debug_info (abfd, stash->sec);
+ stash->sec_info_ptr = stash->info_ptr;
+ }
+
+ if (each)
+ {
+ each->next_unit = stash->all_comp_units;
+ stash->all_comp_units = each;
+
+ /* DW_AT_low_pc and DW_AT_high_pc are optional for
+ compilation units. If we don't have them (i.e.,
+ unit->high == 0), we need to consult the line info
+ table to see if a compilation unit contains the given
+ address. */
+ found = (((symbol->flags & BSF_FUNCTION) == 0
+ || each->arange.high <= 0
+ || comp_unit_contains_address (each, addr))
+ && comp_unit_find_line (each, symbol, addr,
+ filename_ptr,
+ linenumber_ptr,
+ stash));
+ if (found)
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
bfd_boolean
_bfd_dwarf2_find_inliner_info (bfd *abfd ATTRIBUTE_UNUSED,
const char **filename_ptr,
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 53f2845..7c75891 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -1488,6 +1488,9 @@ extern bfd_boolean _bfd_elf_set_arch_mach
extern bfd_boolean _bfd_elf_find_nearest_line
(bfd *, asection *, asymbol **, bfd_vma, const char **, const char **,
unsigned int *);
+extern bfd_boolean _bfd_elf_find_line
+ (bfd *, asymbol **, asymbol *, const char **, unsigned int *);
+#define _bfd_generic_find_line _bfd_elf_find_line
extern bfd_boolean _bfd_elf_find_inliner_info
(bfd *, const char **, const char **, unsigned int *);
#define _bfd_elf_read_minisymbols _bfd_generic_read_minisymbols
diff --git a/bfd/elf.c b/bfd/elf.c
index 4ff1d25..189e099 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -6672,6 +6672,17 @@ _bfd_elf_find_nearest_line (bfd *abfd,
return TRUE;
}
+/* Find the line for a symbol. */
+
+bfd_boolean
+_bfd_elf_find_line (bfd *abfd, asymbol **symbols, asymbol *symbol,
+ const char **filename_ptr, unsigned int *line_ptr)
+{
+ return _bfd_dwarf2_find_line (abfd, symbols, symbol,
+ filename_ptr, line_ptr, 0,
+ &elf_tdata (abfd)->dwarf2_find_line_info);
+}
+
/* After a call to bfd_find_nearest_line, successive calls to
bfd_find_inliner_info can be used to get source information about
each level of function inlining that terminated at the address
diff --git a/bfd/libbfd-in.h b/bfd/libbfd-in.h
index 84236f9..2c690a4 100644
--- a/bfd/libbfd-in.h
+++ b/bfd/libbfd-in.h
@@ -428,6 +428,14 @@ extern bfd_boolean _bfd_dwarf2_find_nearest_line
(bfd *, asection *, asymbol **, bfd_vma, const char **, const char **,
unsigned int *, unsigned int, void **);
+/* Find the line using DWARF 2 debugging information. */
+extern bfd_boolean _bfd_dwarf2_find_line
+ (bfd *, asymbol **, asymbol *, const char **,
+ unsigned int *, unsigned int, void **);
+
+bfd_boolean _bfd_generic_find_line
+ (bfd *, asymbol **, asymbol *, const char **, unsigned int *);
+
/* Find inliner info after calling bfd_find_nearest_line. */
extern bfd_boolean _bfd_dwarf2_find_inliner_info
(bfd *, const char **, const char **, unsigned int *, void **);
diff --git a/bfd/libbfd.c b/bfd/libbfd.c
index c66a570..92f0089 100644
--- a/bfd/libbfd.c
+++ b/bfd/libbfd.c
@@ -918,3 +918,13 @@ read_signed_leb128 (bfd *abfd ATTRIBUTE_UNUSED,
*bytes_read_ptr = num_read;
return result;
}
+
+bfd_boolean
+_bfd_generic_find_line (bfd *abfd ATTRIBUTE_UNUSED,
+ asymbol **symbols ATTRIBUTE_UNUSED,
+ asymbol *symbol ATTRIBUTE_UNUSED,
+ const char **filename_ptr ATTRIBUTE_UNUSED,
+ unsigned int *linenumber_ptr ATTRIBUTE_UNUSED)
+{
+ return FALSE;
+}
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index f2d51ef..a318744 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -433,6 +433,14 @@ extern bfd_boolean _bfd_dwarf2_find_nearest_line
(bfd *, asection *, asymbol **, bfd_vma, const char **, const char **,
unsigned int *, unsigned int, void **);
+/* Find the line using DWARF 2 debugging information. */
+extern bfd_boolean _bfd_dwarf2_find_line
+ (bfd *, asymbol **, asymbol *, const char **,
+ unsigned int *, unsigned int, void **);
+
+bfd_boolean _bfd_generic_find_line
+ (bfd *, asymbol **, asymbol *, const char **, unsigned int *);
+
/* Find inliner info after calling bfd_find_nearest_line. */
extern bfd_boolean _bfd_dwarf2_find_inliner_info
(bfd *, const char **, const char **, unsigned int *, void **);
diff --git a/bfd/targets.c b/bfd/targets.c
index 50b3eeb..3bfde1b0 100644
--- a/bfd/targets.c
+++ b/bfd/targets.c
@@ -349,6 +349,7 @@ BFD_JUMP_TABLE macros.
. NAME##_bfd_is_target_special_symbol, \
. NAME##_get_lineno, \
. NAME##_find_nearest_line, \
+. _bfd_generic_find_line, \
. NAME##_find_inliner_info, \
. NAME##_bfd_make_debug_symbol, \
. NAME##_read_minisymbols, \
@@ -371,6 +372,9 @@ BFD_JUMP_TABLE macros.
. bfd_boolean (*_bfd_find_nearest_line)
. (bfd *, struct bfd_section *, struct bfd_symbol **, bfd_vma,
. const char **, const char **, unsigned int *);
+. bfd_boolean (*_bfd_find_line)
+. (bfd *, struct bfd_symbol **, struct bfd_symbol *,
+. const char **, unsigned int *);
. bfd_boolean (*_bfd_find_inliner_info)
. (bfd *, const char **, const char **, unsigned int *);
. {* Back-door to allow format-aware applications to create debug symbols
diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index 7b93900..8018ed9 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,3 +1,9 @@
+2005-06-06 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR 990
+ * nm.c (print_symbol): Call bfd_find_line before
+ bfd_find_nearest_line.
+
2005-06-06 Alan Modra <amodra@bigpond.net.au>
* NEWS: Mention new powerpc ld support.
diff --git a/binutils/nm.c b/binutils/nm.c
index 511e6d3..999a6db 100644
--- a/binutils/nm.c
+++ b/binutils/nm.c
@@ -905,9 +905,10 @@ print_symbol (bfd *abfd, asymbol *sym, bfd_vma ssize, bfd *archive_bfd)
}
else if (bfd_get_section (sym)->owner == abfd)
{
- if (bfd_find_nearest_line (abfd, bfd_get_section (sym), syms,
- sym->value, &filename, &functionname,
- &lineno)
+ if ((bfd_find_line (abfd, syms, sym, &filename, &lineno)
+ || bfd_find_nearest_line (abfd, bfd_get_section (sym),
+ syms, sym->value, &filename,
+ &functionname, &lineno))
&& filename != NULL
&& lineno != 0)
printf ("\t%s:%u", filename, lineno);