Support _debuglink recursions.

2006-10-08  Soren Sandmann <sandmann@daimi.au.dk>

	* binfile.c (find_separate_debug_file): Support _debuglink
	recursions.

	* elfparser.c: Check that the sections have valid types before
	using them.
This commit is contained in:
Soren Sandmann
2006-10-08 17:45:09 +00:00
committed by Søren Sandmann Pedersen
parent 29a4acaa94
commit c27e5debc5
5 changed files with 154 additions and 39 deletions

View File

@ -1,3 +1,11 @@
2006-10-08 Soren Sandmann <sandmann@daimi.au.dk>
* binfile.c (find_separate_debug_file): Support _debuglink
recursions.
* elfparser.c: Check that the sections have valid types before
using them.
2006-10-08 Soren Sandmann <sandmann@daimi.au.dk> 2006-10-08 Soren Sandmann <sandmann@daimi.au.dk>
* Delete various debug spew * Delete various debug spew

37
TODO
View File

@ -28,25 +28,21 @@ Before 1.0.4:
* Consider renaming sysprof-module.[ch] to sysprof.[ch] to move it closer to * Consider renaming sysprof-module.[ch] to sysprof.[ch] to move it closer to
kernel naming conventions. kernel naming conventions.
* Get rid of include of "../config.h" as that won't work in the kernel. * Get rid of include of "../config.h" as that won't work in the latest
kernel. done in HEAD, need to check what if anything breaks with older
kernels.
Before 1.2: Before 1.2:
* Try reproducing crash when profiling xrender demo
* Fix (potential) performance issues in symbol lookup. * Fix (potential) performance issues in symbol lookup.
* Elf bugs: * Elf bugs:
- when an elf file is read, it should be checked that the various
sections are of the right type. For example the debug information
for emacs is just a stub file where all the sections are NOBITS.
- Also error handling for bin_parser is necessary. - Also error handling for bin_parser is necessary.
- Can .gnu_debuglink recurse? - don't loop infinitely if there are cycles in the debuglink graph.
yes, it can, and we should probably not crash if there are
cycles in the graph. * Find out why all apps have an "In file /usr/bin/<app binary>" below
_libc_main. If possible, maybe make up a name for it.
* Strategies for taking reliable stacktraces. * Strategies for taking reliable stacktraces.
@ -656,6 +652,25 @@ Later:
-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ALREADY DONE -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -=-=-=-=-=-=-=-=-=-=-=-=-=-=- ALREADY DONE -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
- when an elf file is read, it should be checked that the various
sections are of the right type. For example the debug information
for emacs is just a stub file where all the sections are NOBITS.
* Try reproducing crash when profiling xrender demo
- it looks like it crashes when it attempts to read /usr/bin/python
- apparently what's going on is that one of the symbols in python's
dynamic symbol table has a completely crazy 'st_name' offset.
DONE: we didn't actually need to read the name at all,
but still should find out why that value is so weird.
It looks like there is something strange going on with that file.
All the dynsyms have weird info/type values, yet nm and readelf
have no problems displaying it.
- Can .gnu_debuglink recurse?
yes, it can, and we should probably not crash if there are
cycles in the graph.
* Find out why we are getting bogus symbols reported for /usr/bin/Xorg * Find out why we are getting bogus symbols reported for /usr/bin/Xorg
Like this: Like this:

View File

@ -88,8 +88,9 @@ separate_debug_file_exists (const char *name, guint32 crc)
static const char *const debug_file_directory = "/usr/lib/debug"; static const char *const debug_file_directory = "/usr/lib/debug";
static ElfParser * static ElfParser *
find_separate_debug_file (ElfParser *elf, get_debug_file (ElfParser *elf,
const char *filename) const char *filename,
char **new_name)
{ {
const char *basename; const char *basename;
char *dir; char *dir;
@ -104,7 +105,7 @@ find_separate_debug_file (ElfParser *elf,
basename = elf_parser_get_debug_link (elf, &crc32); basename = elf_parser_get_debug_link (elf, &crc32);
if (!basename) if (!basename)
return elf; return NULL;
dir = g_path_get_dirname (filename); dir = g_path_get_dirname (filename);
@ -116,7 +117,11 @@ find_separate_debug_file (ElfParser *elf,
{ {
result = separate_debug_file_exists (tries[i], crc32); result = separate_debug_file_exists (tries[i], crc32);
if (result) if (result)
{
if (new_name)
*new_name = g_strdup (tries[i]);
break; break;
}
} }
g_free (dir); g_free (dir);
@ -124,15 +129,40 @@ find_separate_debug_file (ElfParser *elf,
for (i = 0; i < 3; ++i) for (i = 0; i < 3; ++i)
g_free (tries[i]); g_free (tries[i]);
if (result) return result;
}
static ElfParser *
find_separate_debug_file (ElfParser *elf,
const char *filename)
{
ElfParser *debug;
char *debug_name = NULL;
char *fname;
fname = g_strdup (filename);
/* FIXME: there is an infinite loop if there are cycles in
* the debug_link graph
*/
do
{ {
elf_parser_free (elf); debug = get_debug_file (elf, fname, &debug_name);
return result;
} if (debug)
else {
{ elf_parser_free (elf);
return elf; elf = debug;
g_free (fname);
fname = debug_name;
}
} }
while (debug);
g_free (fname);
return elf;
} }
static GHashTable *bin_files; static GHashTable *bin_files;
@ -163,7 +193,7 @@ bin_file_new (const char *filename)
if (bf->elf) if (bf->elf)
bf->text_offset = elf_parser_get_text_offset (bf->elf); bf->text_offset = elf_parser_get_text_offset (bf->elf);
bf->elf = find_separate_debug_file (bf->elf, filename); bf->elf = find_separate_debug_file (bf->elf, filename); /* find_separate_debug_file (bf->elf, filename); */
bf->inode = read_inode (filename); bf->inode = read_inode (filename);
bf->filename = g_strdup (filename); bf->filename = g_strdup (filename);
bf->undefined_name = g_strdup_printf ("In file %s", filename); bf->undefined_name = g_strdup_printf ("In file %s", filename);
@ -210,6 +240,14 @@ bin_file_lookup_symbol (BinFile *bin_file,
return (const BinSymbol *)sym; return (const BinSymbol *)sym;
} }
} }
#if 0
else
g_print ("no elf file for %s\n", bin_file->filename);
#endif
#if 0
g_print ("%lx undefined in %s (textoffset %d)\n", address + bin_file->text_offset, bin_file->filename, bin_file->text_offset);
#endif
return (const BinSymbol *)bin_file->undefined_name; return (const BinSymbol *)bin_file->undefined_name;
} }

View File

@ -19,6 +19,7 @@ struct Section
gsize size; gsize size;
gboolean allocated; gboolean allocated;
gulong load_address; gulong load_address;
guint type;
}; };
struct ElfParser struct ElfParser
@ -80,6 +81,8 @@ section_new (BinRecord *record,
else else
section->load_address = 0; section->load_address = 0;
section->type = bin_record_get_uint (record, "sh_type");
return section; return section;
} }
@ -91,7 +94,8 @@ section_free (Section *section)
static const Section * static const Section *
find_section (ElfParser *parser, find_section (ElfParser *parser,
const char *name) const char *name,
guint type)
{ {
int i; int i;
@ -103,7 +107,7 @@ find_section (ElfParser *parser,
{ {
Section *section = parser->sections[i]; Section *section = parser->sections[i];
if (strcmp (section->name, name) == 0) if (strcmp (section->name, name) == 0 && section->type == type)
{ {
#if 0 #if 0
g_print ("found it as number %d with offset %d\n", i, section->offset); g_print ("found it as number %d with offset %d\n", i, section->offset);
@ -191,6 +195,10 @@ elf_parser_new (const char *filename,
if (!file) if (!file)
return NULL; return NULL;
#if 0
g_print ("elf parser new : %s\n", filename);
#endif
data = (guchar *)g_mapped_file_get_contents (file); data = (guchar *)g_mapped_file_get_contents (file);
length = g_mapped_file_get_length (file); length = g_mapped_file_get_length (file);
@ -200,6 +208,11 @@ elf_parser_new (const char *filename,
parser = parser_new_from_data (data, length); parser = parser_new_from_data (data, length);
#if 0
g_print ("Elf file: %s (debug: %s)\n",
filename, elf_parser_get_debug_link (parser, NULL));
#endif
parser->file = file; parser->file = file;
return parser; return parser;
@ -370,15 +383,29 @@ read_table (ElfParser *parser,
{ {
guint info; guint info;
gulong addr; gulong addr;
const char *name;
gulong offset; gulong offset;
#if 0
const char *name;
#endif
bin_record_index (symbol, i); bin_record_index (symbol, i);
info = bin_record_get_uint (symbol, "st_info"); info = bin_record_get_uint (symbol, "st_info");
#if 0
g_print ("info: %d => %d %d\n", info, info & 0xf, info >> 4);
#endif
#if 0
g_print ("func: %d global %d local: %d\n", STT_FUNC, STB_GLOBAL, STB_LOCAL);
#endif
#if 0
g_print ("%d, name off: %d\n", i, bin_record_get_uint (symbol, "st_name"));
#endif
addr = bin_record_get_uint (symbol, "st_value"); addr = bin_record_get_uint (symbol, "st_value");
#if 0
name = bin_record_get_string_indirect (symbol, "st_name", name = bin_record_get_string_indirect (symbol, "st_name",
str_table->offset); str_table->offset);
#endif
offset = bin_record_get_offset (symbol); offset = bin_record_get_offset (symbol);
if (addr != 0 && if (addr != 0 &&
@ -389,10 +416,22 @@ read_table (ElfParser *parser,
parser->symbols[n_functions].address = addr; parser->symbols[n_functions].address = addr;
parser->symbols[n_functions].offset = offset; parser->symbols[n_functions].offset = offset;
#if 0
g_print ("name: %s\n",
bin_record_get_string_indirect (symbol, "st_name",
str_table->offset));
g_print ("%lx\n", parser->symbols[n_functions].address);
#endif
n_functions++; n_functions++;
} }
} }
#if 0
g_print ("%d functions found \n", n_functions);
#endif
bin_record_free (symbol); bin_record_free (symbol);
#if 0 #if 0
@ -413,10 +452,10 @@ read_table (ElfParser *parser,
static void static void
read_symbols (ElfParser *parser) read_symbols (ElfParser *parser)
{ {
const Section *symtab = find_section (parser, ".symtab"); const Section *symtab = find_section (parser, ".symtab", SHT_SYMTAB);
const Section *strtab = find_section (parser, ".strtab"); const Section *strtab = find_section (parser, ".strtab", SHT_STRTAB);
const Section *dynsym = find_section (parser, ".dynsym"); const Section *dynsym = find_section (parser, ".dynsym", SHT_SYMTAB);
const Section *dynstr = find_section (parser, ".dynstr"); const Section *dynstr = find_section (parser, ".dynstr", SHT_STRTAB);
if (symtab && strtab) if (symtab && strtab)
{ {
@ -513,9 +552,13 @@ elf_parser_lookup_symbol (ElfParser *parser,
if (parser->n_symbols == 0) if (parser->n_symbols == 0)
return NULL; return NULL;
text = find_section (parser, ".text"); text = find_section (parser, ".text", SHT_PROGBITS);
if (!text) if (!text)
return NULL; {
text = find_section (parser, ".text", SHT_NOBITS);
if (!text)
return NULL;
}
address += text->load_address; address += text->load_address;
@ -558,10 +601,14 @@ elf_parser_get_text_offset (ElfParser *parser)
g_return_val_if_fail (parser != NULL, (gulong)-1); g_return_val_if_fail (parser != NULL, (gulong)-1);
text = find_section (parser, ".text"); text = find_section (parser, ".text", SHT_PROGBITS);
if (!text) if (!text)
return (gulong)-1; {
text = find_section (parser, ".text", SHT_NOBITS);
if (!text)
return (gulong)-1;
}
return text->offset; return text->offset;
} }
@ -569,7 +616,8 @@ elf_parser_get_text_offset (ElfParser *parser)
const char * const char *
elf_parser_get_debug_link (ElfParser *parser, guint32 *crc32) elf_parser_get_debug_link (ElfParser *parser, guint32 *crc32)
{ {
const Section *debug_link = find_section (parser, ".gnu_debuglink"); const Section *debug_link = find_section (parser, ".gnu_debuglink",
SHT_PROGBITS);
const gchar *result; const gchar *result;
if (!debug_link) if (!debug_link)
@ -581,7 +629,8 @@ elf_parser_get_debug_link (ElfParser *parser, guint32 *crc32)
bin_parser_align (parser->parser, 4); bin_parser_align (parser->parser, 4);
*crc32 = bin_parser_get_uint32 (parser->parser); if (crc32)
*crc32 = bin_parser_get_uint32 (parser->parser);
return result; return result;
} }
@ -589,7 +638,7 @@ elf_parser_get_debug_link (ElfParser *parser, guint32 *crc32)
const guchar * const guchar *
elf_parser_get_eh_frame (ElfParser *parser) elf_parser_get_eh_frame (ElfParser *parser)
{ {
const Section *eh_frame = find_section (parser, ".eh_frame"); const Section *eh_frame = find_section (parser, ".eh_frame", SHT_PROGBITS);
if (eh_frame) if (eh_frame)
return bin_parser_get_data (parser->parser) + eh_frame->offset; return bin_parser_get_data (parser->parser) + eh_frame->offset;

View File

@ -586,6 +586,11 @@ process_lookup_symbol (Process *process, gulong address)
g_print ("address before: \n"); g_print ("address before: \n");
#endif #endif
#if 0
g_print ("%s is mapped at %lx + %lx\n", map->filename, map->start, map->offset);
g_print ("incoming address: %lx\n", address);
#endif
address -= map->start; address -= map->start;
address += map->offset; address += map->offset;