summaryrefslogtreecommitdiff
path: root/libdwfl/dwfl_module_addrsym.c
diff options
context:
space:
mode:
Diffstat (limited to 'libdwfl/dwfl_module_addrsym.c')
-rw-r--r--libdwfl/dwfl_module_addrsym.c47
1 files changed, 22 insertions, 25 deletions
diff --git a/libdwfl/dwfl_module_addrsym.c b/libdwfl/dwfl_module_addrsym.c
index f16de116..72280d11 100644
--- a/libdwfl/dwfl_module_addrsym.c
+++ b/libdwfl/dwfl_module_addrsym.c
@@ -1,5 +1,5 @@
/* Find debugging and symbol information for a module in libdwfl.
- Copyright (C) 2005, 2006, 2007 Red Hat, Inc.
+ Copyright (C) 2005, 2006, 2007, 2008 Red Hat, Inc.
This file is part of Red Hat elfutils.
Red Hat elfutils is free software; you can redistribute it and/or modify
@@ -49,6 +49,9 @@
#include "libdwflP.h"
+/* Returns the name of the symbol "closest" to ADDR.
+ Never returns symbols at addresses above ADDR. */
+
const char *
dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr,
GElf_Sym *closest_sym, GElf_Word *shndxp)
@@ -65,15 +68,6 @@ dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr,
if (shndx >= SHN_LORESERVE)
return sym->st_value == addr;
- /* Ignore section and other special symbols. */
- switch (GELF_ST_TYPE (sym->st_info))
- {
- case STT_SECTION:
- case STT_FILE:
- case STT_TLS:
- return false;
- }
-
/* Figure out what section ADDR lies in. */
if (addr_shndx == SHN_UNDEF)
{
@@ -108,7 +102,7 @@ dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr,
GElf_Word sizeless_shndx = SHN_UNDEF;
/* Keep track of the lowest address a relevant sizeless symbol could have. */
- GElf_Addr min_label = addr;
+ GElf_Addr min_label = 0;
/* Look through the symbol table for a matching symbol. */
for (int i = 1; i < syments; ++i)
@@ -116,23 +110,23 @@ dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr,
GElf_Sym sym;
GElf_Word shndx;
const char *name = INTUSE(dwfl_module_getsym) (mod, i, &sym, &shndx);
- if (name != NULL
+ if (name != NULL && name[0] != '\0'
+ && sym.st_shndx != SHN_UNDEF
&& sym.st_value <= addr
- && (sym.st_size == 0 || addr - sym.st_value < sym.st_size))
+ && GELF_ST_TYPE (sym.st_info) != STT_SECTION
+ && GELF_ST_TYPE (sym.st_info) != STT_FILE
+ && GELF_ST_TYPE (sym.st_info) != STT_TLS)
{
- /* Even if we don't choose this symbol, its existence
- excludes any sizeless symbol (assembly label) that
- is inside its bounds. */
- if (sym.st_value + sym.st_size > addr)
+ /* Even if we don't choose this symbol, its existence excludes
+ any sizeless symbol (assembly label) that is below its upper
+ bound. */
+ if (sym.st_value + sym.st_size > min_label)
min_label = sym.st_value + sym.st_size;
- /* This symbol is a better candidate than the current one
- if it's a named symbol, not a section or file symbol,
- and is closer to ADDR or is global when it was local. */
- if (name[0] != '\0'
- && GELF_ST_TYPE (sym.st_info) != STT_SECTION
- && GELF_ST_TYPE (sym.st_info) != STT_FILE)
+ if (sym.st_size == 0 || addr - sym.st_value < sym.st_size)
{
+ /* This symbol is a better candidate than the current one
+ if it's closer to ADDR or is global when it was local. */
if (closest_name == NULL
|| closest_sym->st_value < sym.st_value
|| (GELF_ST_BIND (closest_sym->st_info)
@@ -156,10 +150,13 @@ dwfl_module_addrsym (Dwfl_Module *mod, GElf_Addr addr,
}
}
/* When the beginning of its range is no closer,
- the end of its range might be. */
+ the end of its range might be. But do not
+ replace a global symbol with a local! */
else if (sym.st_size != 0
&& closest_sym->st_value == sym.st_value
- && closest_sym->st_size > sym.st_size)
+ && closest_sym->st_size > sym.st_size
+ && (GELF_ST_BIND (closest_sym->st_info)
+ <= GELF_ST_BIND (sym.st_info)))
{
*closest_sym = sym;
closest_shndx = shndx;