diff --git a/ChangeLog b/ChangeLog index 789abb43..9a798947 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2006-10-08 Soren Sandmann + + * 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 * Delete various debug spew diff --git a/TODO b/TODO index 6e8aa47d..ef347c09 100644 --- a/TODO +++ b/TODO @@ -28,25 +28,21 @@ Before 1.0.4: * Consider renaming sysprof-module.[ch] to sysprof.[ch] to move it closer to 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: -* Try reproducing crash when profiling xrender demo - * Fix (potential) performance issues in symbol lookup. * 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. - - Can .gnu_debuglink recurse? - yes, it can, and we should probably not crash if there are - cycles in the graph. + - don't loop infinitely if there are cycles in the debuglink graph. + + * Find out why all apps have an "In file /usr/bin/" below + _libc_main. If possible, maybe make up a name for it. * Strategies for taking reliable stacktraces. @@ -656,6 +652,25 @@ Later: -=-=-=-=-=-=-=-=-=-=-=-=-=-=- 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 Like this: diff --git a/binfile.c b/binfile.c index 9e13b317..fac12482 100644 --- a/binfile.c +++ b/binfile.c @@ -88,8 +88,9 @@ separate_debug_file_exists (const char *name, guint32 crc) static const char *const debug_file_directory = "/usr/lib/debug"; static ElfParser * -find_separate_debug_file (ElfParser *elf, - const char *filename) +get_debug_file (ElfParser *elf, + const char *filename, + char **new_name) { const char *basename; char *dir; @@ -104,7 +105,7 @@ find_separate_debug_file (ElfParser *elf, basename = elf_parser_get_debug_link (elf, &crc32); if (!basename) - return elf; + return NULL; dir = g_path_get_dirname (filename); @@ -116,7 +117,11 @@ find_separate_debug_file (ElfParser *elf, { result = separate_debug_file_exists (tries[i], crc32); if (result) + { + if (new_name) + *new_name = g_strdup (tries[i]); break; + } } g_free (dir); @@ -124,15 +129,40 @@ find_separate_debug_file (ElfParser *elf, for (i = 0; i < 3; ++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); - return result; - } - else - { - return elf; + debug = get_debug_file (elf, fname, &debug_name); + + if (debug) + { + elf_parser_free (elf); + elf = debug; + + g_free (fname); + fname = debug_name; + } } + while (debug); + + g_free (fname); + + return elf; } static GHashTable *bin_files; @@ -163,7 +193,7 @@ bin_file_new (const char *filename) if (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->filename = g_strdup (filename); bf->undefined_name = g_strdup_printf ("In file %s", filename); @@ -210,7 +240,15 @@ bin_file_lookup_symbol (BinFile *bin_file, 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; } diff --git a/elfparser.c b/elfparser.c index 7784995d..e3855b57 100644 --- a/elfparser.c +++ b/elfparser.c @@ -19,6 +19,7 @@ struct Section gsize size; gboolean allocated; gulong load_address; + guint type; }; struct ElfParser @@ -79,7 +80,9 @@ section_new (BinRecord *record, section->load_address = bin_record_get_uint (record, "sh_addr"); else section->load_address = 0; - + + section->type = bin_record_get_uint (record, "sh_type"); + return section; } @@ -91,7 +94,8 @@ section_free (Section *section) static const Section * find_section (ElfParser *parser, - const char *name) + const char *name, + guint type) { int i; @@ -103,7 +107,7 @@ find_section (ElfParser *parser, { Section *section = parser->sections[i]; - if (strcmp (section->name, name) == 0) + if (strcmp (section->name, name) == 0 && section->type == type) { #if 0 g_print ("found it as number %d with offset %d\n", i, section->offset); @@ -190,6 +194,10 @@ elf_parser_new (const char *filename, if (!file) return NULL; + +#if 0 + g_print ("elf parser new : %s\n", filename); +#endif data = (guchar *)g_mapped_file_get_contents (file); length = g_mapped_file_get_length (file); @@ -197,9 +205,14 @@ elf_parser_new (const char *filename, #if 0 g_print ("data %p: for %s\n", data, filename); #endif - + 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; return parser; @@ -370,15 +383,29 @@ read_table (ElfParser *parser, { guint info; gulong addr; - const char *name; gulong offset; - +#if 0 + const char *name; +#endif + bin_record_index (symbol, i); 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"); +#if 0 name = bin_record_get_string_indirect (symbol, "st_name", str_table->offset); +#endif offset = bin_record_get_offset (symbol); if (addr != 0 && @@ -388,10 +415,22 @@ read_table (ElfParser *parser, { parser->symbols[n_functions].address = addr; 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++; } } + +#if 0 + g_print ("%d functions found \n", n_functions); +#endif bin_record_free (symbol); @@ -413,10 +452,10 @@ read_table (ElfParser *parser, static void read_symbols (ElfParser *parser) { - const Section *symtab = find_section (parser, ".symtab"); - const Section *strtab = find_section (parser, ".strtab"); - const Section *dynsym = find_section (parser, ".dynsym"); - const Section *dynstr = find_section (parser, ".dynstr"); + const Section *symtab = find_section (parser, ".symtab", SHT_SYMTAB); + const Section *strtab = find_section (parser, ".strtab", SHT_STRTAB); + const Section *dynsym = find_section (parser, ".dynsym", SHT_SYMTAB); + const Section *dynstr = find_section (parser, ".dynstr", SHT_STRTAB); if (symtab && strtab) { @@ -513,9 +552,13 @@ elf_parser_lookup_symbol (ElfParser *parser, if (parser->n_symbols == 0) return NULL; - text = find_section (parser, ".text"); + text = find_section (parser, ".text", SHT_PROGBITS); if (!text) - return NULL; + { + text = find_section (parser, ".text", SHT_NOBITS); + if (!text) + return NULL; + } address += text->load_address; @@ -558,10 +601,14 @@ elf_parser_get_text_offset (ElfParser *parser) g_return_val_if_fail (parser != NULL, (gulong)-1); - text = find_section (parser, ".text"); + text = find_section (parser, ".text", SHT_PROGBITS); if (!text) - return (gulong)-1; + { + text = find_section (parser, ".text", SHT_NOBITS); + if (!text) + return (gulong)-1; + } return text->offset; } @@ -569,7 +616,8 @@ elf_parser_get_text_offset (ElfParser *parser) const char * 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; if (!debug_link) @@ -581,7 +629,8 @@ elf_parser_get_debug_link (ElfParser *parser, guint32 *crc32) bin_parser_align (parser->parser, 4); - *crc32 = bin_parser_get_uint32 (parser->parser); + if (crc32) + *crc32 = bin_parser_get_uint32 (parser->parser); return result; } @@ -589,7 +638,7 @@ elf_parser_get_debug_link (ElfParser *parser, guint32 *crc32) const guchar * 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) return bin_parser_get_data (parser->parser) + eh_frame->offset; diff --git a/process.c b/process.c index 96edab49..e757a77f 100644 --- a/process.c +++ b/process.c @@ -585,6 +585,11 @@ process_lookup_symbol (Process *process, gulong address) g_print ("address before: \n"); #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->offset;