--- binutils-2.15/binutils/readelf.c.orig 2004-12-18 15:31:44.000000000 +0530 +++ binutils-2.15/binutils/readelf.c 2004-12-18 19:31:17.000000000 +0530 @@ -162,6 +162,8 @@ int do_debug_loc; int do_arch; int do_notes; int is_32bit_elf; +int do_com_sym; +int do_debug_and_comm_sym; /* A dynamic array of flags indicating which sections require dumping. */ char *dump_sects = NULL; @@ -1202,7 +1204,7 @@ dump_relocations (FILE *file, if (psym->st_shndx < SHN_LORESERVE) sec_index = psym->st_shndx; - else if (psym->st_shndx > SHN_LORESERVE) + else if (psym->st_shndx > SHN_HIRESERVE) sec_index = psym->st_shndx - (SHN_HIRESERVE + 1 - SHN_LORESERVE); @@ -2376,6 +2378,7 @@ struct option options[] = {"use-dynamic", no_argument, 0, 'D'}, {"hex-dump", required_argument, 0, 'x'}, {"debug-dump", optional_argument, 0, OPTION_DEBUG_DUMP}, + {"common-symb", optional_argument, 0, 'P'}, {"unwind", no_argument, 0, 'u'}, #ifdef SUPPORT_DISASSEMBLY {"instruction-dump", required_argument, 0, 'i'}, @@ -2387,6 +2390,7 @@ struct option options[] = {0, no_argument, 0, 0} }; + static void usage (void) { @@ -2395,6 +2399,7 @@ usage (void) fprintf (stdout, _(" Options are:\n\ -a --all Equivalent to: -h -l -S -s -r -d -V -A -I\n\ -h --file-header Display the ELF file header\n\ + -P --common-symb Display the common symbol if built for debug\n\ -l --program-headers Display the program headers\n\ --segments An alias for --program-headers\n\ -S --section-headers Display the sections' header\n\ @@ -2466,7 +2471,7 @@ parse_args (int argc, char **argv) usage (); while ((c = getopt_long - (argc, argv, "ersuahnldSDAIw::x:i:vVWH", options, NULL)) != EOF) + (argc, argv, "ersuahnldSDAPIw::x:i:vVWH", options, NULL)) != EOF) { char *cp; int section; @@ -2479,7 +2484,12 @@ parse_args (int argc, char **argv) case 'H': usage (); break; - + case 'P': + do_com_sym++; + do_dump++; + do_debug_info = 1; + do_debug_and_comm_sym++; + break; case 'a': do_syms++; do_reloc++; @@ -2607,6 +2617,7 @@ parse_args (int argc, char **argv) break; case OPTION_DEBUG_DUMP: do_dump++; + do_debug_and_comm_sym++; if (optarg == 0) do_debugging = 1; else @@ -2719,7 +2730,7 @@ parse_args (int argc, char **argv) if (!do_dynamic && !do_syms && !do_reloc && !do_unwind && !do_sections && !do_segments && !do_header && !do_dump && !do_version - && !do_histogram && !do_debugging && !do_arch && !do_notes) + && !do_histogram && !do_debugging && !do_arch && !do_notes && !do_com_sym) usage (); else if (argc < 3) { @@ -5628,6 +5639,87 @@ get_dynamic_data (FILE *file, unsigned i return i_data; } +/* Get the size of symbol from symbol table whose name is passed. +This function is added to support --common-symb option. */ + +static int +get_symbol_size (FILE *file, char *symbol_name,unsigned long *uvalue) +{ + Elf_Internal_Shdr *section; + int *buckets = NULL; + int *chains = NULL; + int size; + char symb_name[32] = "_"; + strcat((char *)symb_name,symbol_name); + + if (do_syms && !do_using_dynamic) + { + unsigned int i; + for (i = 0, section = section_headers; + i < elf_header.e_shnum; + i++, section++) + { + unsigned int si; + char *strtab; + Elf_Internal_Sym *symtab; + Elf_Internal_Sym *psym; + + if (section->sh_type != SHT_SYMTAB + && section->sh_type != SHT_DYNSYM) + continue; + symtab = GET_ELF_SYMBOLS (file, section); + if (symtab == NULL) + continue; + + if (section->sh_link == elf_header.e_shstrndx) + strtab = string_table; + else + { + Elf_Internal_Shdr *string_sec; + string_sec = SECTION_HEADER (section->sh_link); + strtab = get_data (NULL, file, string_sec->sh_offset, + string_sec->sh_size, _("string table")); + } + + for (si = 0, psym = symtab; + si < section->sh_size / section->sh_entsize; + si++, psym++) + { + if (strcmp(symb_name,(char *)(strtab + psym->st_name)) == 0) + { + *uvalue = (unsigned long)psym->st_value; + size = (int)psym->st_size; + strcpy (symb_name,"_"); + free (symtab); + + if (strtab != string_table) + free (strtab); + if (buckets != NULL) + { + free (buckets); + free (chains); + } + /* got the symbol, return size */ + return size; + } + } + free (symtab); + if (strtab != string_table) + free (strtab); + } + } + else + { + if (buckets != NULL) + { + free (buckets); + free (chains); + } + return 0; + } + return 0; +} + /* Dump the symbol table. */ static int process_symbol_table (FILE *file) @@ -6778,6 +6870,8 @@ display_debug_pubnames (Elf_Internal_Shd return 1; } +unsigned long comm_sym_break = 0; + static char * get_TAG_name (unsigned long tag) { @@ -6851,7 +6945,7 @@ get_TAG_name (unsigned long tag) default: { static char buffer[100]; - + comm_sym_break = 1; sprintf (buffer, _("Unknown TAG value: %lx"), tag); return buffer; } @@ -6964,7 +7058,7 @@ get_AT_name (unsigned long attribute) default: { static char buffer[100]; - + comm_sym_break = 1; sprintf (buffer, _("Unknown AT value: %lx"), attribute); return buffer; } @@ -8000,6 +8094,7 @@ read_and_display_attr_value (unsigned lo default: warn (_("Unrecognized form: %d\n"), form); + comm_sym_break = 1; break; } @@ -8179,6 +8274,176 @@ read_and_display_attr_value (unsigned lo return data; } +/* This function is added to support --common-symb option. +Read the data associated with attribute passed. */ + +static unsigned char * +read_attr_value_comm_sym (unsigned long attribute, + unsigned long form, + unsigned char *data, + unsigned long cu_offset, + unsigned long pointer_size, + unsigned long offset_size, + int dwarf_version, + unsigned long *attr_data, + unsigned long entry_tag) +{ + unsigned long uvalue = 0; + unsigned char *block_start = NULL; + int bytes_read; + + switch (form) + { + default: + break; + + case DW_FORM_ref_addr: + if (dwarf_version == 2) + { + uvalue = byte_get (data, pointer_size); + data += pointer_size; + *attr_data = uvalue; + } + else if (dwarf_version == 3) + { + uvalue = byte_get (data, offset_size); + data += offset_size; + *attr_data = uvalue; + } + else + { + error (_("Internal error: DWARF version is not 2 or 3.\n")); + } + break; + + case DW_FORM_addr: + uvalue = byte_get (data, pointer_size); + data += pointer_size; + *attr_data = uvalue; + break; + + case DW_FORM_strp: + uvalue = byte_get (data, offset_size); + data += offset_size; + *attr_data = uvalue; + break; + + case DW_FORM_ref1: + case DW_FORM_flag: + case DW_FORM_data1: + uvalue = byte_get (data++, 1); + *attr_data = uvalue; + break; + + case DW_FORM_ref2: + case DW_FORM_data2: + uvalue = byte_get (data, 2); + data += 2; + *attr_data = uvalue; + break; + + case DW_FORM_ref4: + case DW_FORM_data4: + uvalue = byte_get (data, 4); + data += 4; + *attr_data = uvalue; + break; + + case DW_FORM_sdata: + uvalue = read_leb128 (data, & bytes_read, 1); + data += bytes_read; + *attr_data = uvalue; + break; + + case DW_FORM_ref_udata: + case DW_FORM_udata: + uvalue = read_leb128 (data, & bytes_read, 0); + data += bytes_read; + *attr_data = uvalue; + break; + + case DW_FORM_indirect: + form = read_leb128 (data, & bytes_read, 0); + data += bytes_read; + *attr_data = uvalue; + return read_attr_value_comm_sym (attribute, form, data, cu_offset, + pointer_size, offset_size, + dwarf_version,&uvalue, entry_tag); + } + + switch (form) + { + case DW_FORM_ref_addr: + case DW_FORM_addr: + case DW_FORM_flag: + case DW_FORM_data1: + case DW_FORM_data2: + case DW_FORM_data4: + case DW_FORM_sdata: + case DW_FORM_udata: + case DW_FORM_indirect: + break; + + case DW_FORM_ref1: + case DW_FORM_ref2: + case DW_FORM_ref4: + case DW_FORM_ref_udata: + *attr_data = (unsigned long)(uvalue + cu_offset); + break; + + case DW_FORM_ref8: + case DW_FORM_data8: + uvalue = byte_get (data, 4); + byte_get (data + 4, 4); + data += 8; + *attr_data = uvalue; + break; + + case DW_FORM_string: + data += strlen ((char *) data) + 1; + break; + + case DW_FORM_block: + uvalue = read_leb128 (data, & bytes_read, 0); + block_start = data + bytes_read; + *attr_data = uvalue; + data = (block_start += uvalue); + break; + + case DW_FORM_block1: + uvalue = byte_get (data, 1); + block_start = data + 1; + *attr_data = uvalue; + data = (block_start += uvalue); + break; + + case DW_FORM_block2: + uvalue = byte_get (data, 2); + block_start = data + 2; + *attr_data = uvalue; + data = (block_start += uvalue); + break; + + case DW_FORM_block4: + uvalue = byte_get (data, 4); + block_start = data + 4; + *attr_data = uvalue; + data = (block_start += uvalue); + break; + + case DW_FORM_strp: + if (!strcmp("DW_TAG_compile_unit",get_TAG_name (entry_tag))) + comm_sym_break = 1; + break; + + default: + comm_sym_break = 1; + warn (_("Unrecognized form: %d\n"), form); + break; + } + return data; +} + static unsigned char * read_and_display_attr (unsigned long attribute, unsigned long form, @@ -8195,6 +8460,392 @@ read_and_display_attr (unsigned long att return data; } +/* This function is added to support --common-symb option. +It returns the base type and byte size of symbol whose node (offset) is passed. +It scans the .debug_info section. */ + +static unsigned long +get_symbol_base_type_and_size (Elf_Internal_Shdr *section, + unsigned char *start, FILE *file, + unsigned int Node, + char *type, + unsigned long *byte_size) +{ + unsigned char *end = start + section->sh_size; + unsigned char *section_begin = start; + unsigned long attr_data; + + load_debug_str (file); + load_debug_loc (file); + + while ((start < end) && (!comm_sym_break)) + { + DWARF2_Internal_CompUnit compunit; + unsigned char *hdrptr; + unsigned char *cu_abbrev_offset_ptr; + unsigned char *tags; + int level; + unsigned long cu_offset; + int offset_size; + int initial_length_size; + + hdrptr = start; + + compunit.cu_length = byte_get (hdrptr, 4); + hdrptr += 4; + + if (compunit.cu_length == 0xffffffff) + { + compunit.cu_length = byte_get (hdrptr, 8); + hdrptr += 8; + offset_size = 8; + initial_length_size = 12; + } + else + { + offset_size = 4; + initial_length_size = 4; + } + + compunit.cu_version = byte_get (hdrptr, 2); + hdrptr += 2; + cu_offset = start - section_begin; + start += compunit.cu_length + initial_length_size; + + if (elf_header.e_type == ET_REL) + return 0; + + cu_abbrev_offset_ptr = hdrptr; + compunit.cu_abbrev_offset = byte_get (hdrptr, offset_size); + hdrptr += offset_size; + compunit.cu_pointer_size = byte_get (hdrptr, 1); + hdrptr += 1; + + tags = hdrptr; + free_abbrevs (); + + /* Read in the abbrevs used by this compilation unit */ + { + Elf_Internal_Shdr *sec; + unsigned char *begin; + + /* Process the .debug_abbrev section */ + sec = find_section (".debug_abbrev"); + if (sec == NULL) + { + warn (_("Unable to locate .debug_abbrev section!\n")); + return 0; + } + + begin = get_data (NULL, file, sec->sh_offset, sec->sh_size, + _("debug_abbrev section data")); + if (!begin) + return 0; + + process_abbrev_section (begin + compunit.cu_abbrev_offset, + begin + sec->sh_size); + free (begin); + } + + level = 0; + while ((tags < start) && (!comm_sym_break)) + { + int bytes_read; + unsigned long abbrev_number; + abbrev_entry *entry; + abbrev_attr *attr; + + abbrev_number = read_leb128 (tags, & bytes_read, 0); + tags += bytes_read; + + /* A null DIE marks the end of a list of children */ + if (abbrev_number == 0) + { + --level; + continue; + } + + /* Scan through the abbreviation list until we reach the correct entry */ + for (entry = first_abbrev; + entry && entry->entry != abbrev_number; + entry = entry->next) + continue; + + if (entry == NULL) + { + warn (_("Unable to locate entry %lu in the abbreviation table\n"), + abbrev_number); + return 0; + } + unsigned long cur_node = (unsigned long) (tags - section_begin - bytes_read); + + for (attr = entry->first_attr; attr; attr = attr->next) + { + if ((Node == cur_node) + && (!strcmp("DW_AT_name",get_AT_name (attr->attribute)) + && (!strcmp("DW_TAG_base_type",get_TAG_name (entry->tag)) + || (!strcmp("DW_TAG_typedef",get_TAG_name (entry->tag))) + || (!strcmp("DW_TAG_structure_type",get_TAG_name (entry->tag))) + || (!strcmp("DW_TAG_union_type",get_TAG_name (entry->tag)))))) + { + strcpy((char *)type,(const char *)tags); + } + + tags = read_attr_value_comm_sym (attr->attribute, + attr->form,tags, cu_offset, + compunit.cu_pointer_size, + offset_size, compunit.cu_version, + &attr_data, entry->tag); + + if (Node == cur_node) + { + if (!strcmp("DW_AT_byte_size",get_AT_name (attr->attribute))) + { + *byte_size = attr_data; + return 0; + } + if (!strcmp("DW_AT_type",get_AT_name (attr->attribute))) + return attr_data; + } + } + if (entry->children) + ++level; + } + } + return 0; +} + +unsigned char type[33] = ""; +/* store the symbol type */ + +/* This function is added to support --common-symb option. +It scans through the .debug_info section and list the given details +for common symbols (Name, Basetype, Base_size, Size, Elements, Value) +It gives number of elements array type symbol or one for non array variables. +As it is using .debug_info and symtab for reading all the details, user +program should be built in debug mode. */ + +static int +display_common_symbol (Elf_Internal_Shdr *section, + unsigned char *start, + FILE *file) +{ + Elf_Internal_Shdr *section1 = section; + unsigned char *end = start + section->sh_size; + unsigned char *section_begin = start; + unsigned char *start1 = start; + unsigned long byte_size; + unsigned long uTemp2; + bfd_boolean header = 0; + + if (!do_com_sym) + return 0; + + load_debug_str (file); + load_debug_loc (file); + + while ((start < end) && (!comm_sym_break)) + { + DWARF2_Internal_CompUnit compunit; + unsigned char *hdrptr; + unsigned char *cu_abbrev_offset_ptr; + unsigned char *tags; + int level; + unsigned long cu_offset; + int offset_size; + int initial_length_size; + + hdrptr = start; + compunit.cu_length = byte_get (hdrptr, 4); + hdrptr += 4; + + if (compunit.cu_length == 0xffffffff) + { + compunit.cu_length = byte_get (hdrptr, 8); + hdrptr += 8; + offset_size = 8; + initial_length_size = 12; + } + else + { + offset_size = 4; + initial_length_size = 4; + } + + compunit.cu_version = byte_get (hdrptr, 2); + hdrptr += 2; + cu_offset = start - section_begin; + start += compunit.cu_length + initial_length_size; + + if (elf_header.e_type == ET_REL) + return 0; + + cu_abbrev_offset_ptr = hdrptr; + compunit.cu_abbrev_offset = byte_get (hdrptr, offset_size); + hdrptr += offset_size; + compunit.cu_pointer_size = byte_get (hdrptr, 1); + hdrptr += 1; + tags = hdrptr; + + if (compunit.cu_version != 2 && compunit.cu_version != 3) + { + warn (_("Only version 2 and 3 DWARF debug information is currently supported.\n")); + continue; + } + free_abbrevs (); + + /* Read in the abbrevs used by this compilation unit */ + { + Elf_Internal_Shdr *sec; + unsigned char *begin; + + /* Locate the .debug_abbrev section and process it */ + sec = find_section (".debug_abbrev"); + if (sec == NULL) + { + warn (_("Unable to locate .debug_abbrev section!\n")); + return 0; + } + + begin = get_data (NULL, file, sec->sh_offset, sec->sh_size, + _("debug_abbrev section data")); + if (!begin) + return 0; + + process_abbrev_section (begin + compunit.cu_abbrev_offset, + begin + sec->sh_size); + free (begin); + } + + level = 0; + while ((tags < start) && (!comm_sym_break)) + { + int bytes_read; + unsigned long abbrev_number; + abbrev_entry *entry; + abbrev_attr *attr; + abbrev_number = read_leb128 (tags, & bytes_read, 0); + tags += bytes_read; + + /* A null DIE marks the end of a list of children */ + if (abbrev_number == 0) + { + --level; + continue; + } + + /* Scan through the abbreviation list until we reach the correct entry */ + for (entry = first_abbrev; + entry && entry->entry != abbrev_number; + entry = entry->next) + continue; + + if (entry == NULL) + { + warn (_("Unable to locate entry %lu in the abbreviation table\n"), + abbrev_number); + return 0; + } + unsigned long cur_node = (unsigned long) (tags - section_begin - bytes_read); + + for (attr = entry->first_attr; attr; attr = attr->next) + { + unsigned long ret_node; + unsigned long sym_value; + int size; + int len; + + if (!comm_sym_break) + { + if (!strcmp("DW_TAG_variable",get_TAG_name (entry->tag)) + && (1 == level)) + { + while(cur_node) + { + ret_node = get_symbol_base_type_and_size (section1, start1, + file, cur_node, + (char *)type, + &byte_size); + cur_node = ret_node; + } + + /* print header once */ + if (!header) + { + printf ("\nCommon Symbols List:\n"); + printf (_("Common symbol Basetype Base_size Size Elements Value")); + header++; + } + + /* print symbol name */ + if (DW_AT_name == attr->attribute) + { + printf (_("\n%s"), tags); + len = strlen (tags); + if (len < 20) + { + while (len < 20) + { + printf (_(" ")); + ++len; + } + len = 0; + } + do_syms++; + size = get_symbol_size (file, tags,&sym_value); + do_syms--; + } + + /* Display symbol type, byte_size, size and value */ + if ((0 == ret_node) && (DW_AT_type == attr->attribute)) + { + printf (_(" %s"), type); + len = strlen (type); + if (len < 20) + { + while (len < 20) + { + printf (_(" ")); + ++len; + } + len = 0; + } + + printf (_(" %d \t\t"), byte_size); + printf (_(" %d \t\t"), size); + + if (size >= byte_size) + printf (_(" %d \t "), (size/byte_size)); + else + printf (_(" 0 \t\t")); + + printf (_(" %lx \t\t"), sym_value); + } + } + tags = read_attr_value_comm_sym(attr->attribute, + attr->form, + tags, cu_offset, + compunit.cu_pointer_size, + offset_size, + compunit.cu_version, + &uTemp2, entry->tag); + } + else + { + printf (_("\n")); + break; + } + } + if (entry->children) + ++level; + } + } + free_debug_str (); + free_debug_loc (); + printf (_("\n")); + return 1; +} + static int display_debug_info (Elf_Internal_Shdr *section, unsigned char *start, @@ -9384,13 +10035,62 @@ display_debug_section (Elf_Internal_Shdr return 1; } +/* This function is added to support --common-symb option. +Need to process debug section before call to display_common_symbol */ + +static int +process_debug_section_comm_sym (Elf_Internal_Shdr *section, FILE *file) +{ + char *name = SECTION_NAME (section); + bfd_size_type length; + unsigned char *start; + int i; + + length = section->sh_size; + if (length == 0) + { + printf (_("\nSection '%s' has no debugging data.\n"), name); + return 0; + } + start = get_data (NULL, file, section->sh_offset, length, + _("debug section data")); + if (!start) + return 0; + + /* See if we know how to display the contents of this section. */ + if (strncmp (name, ".gnu.linkonce.wi.", 17) == 0) + name = ".debug_info"; + + display_common_symbol (section, start, file); + i = 0; + + if (i == -1) + printf (_("Unrecognized debug section: %s\n"), name); + free (start); + + /* If we loaded in the abbrev section at some point, + we must release it here. */ + free_abbrevs (); + return 1; + + if (i == -1) + printf (_("Unrecognized debug section: %s\n"), name); + free (start); + + /* If we loaded in the abbrev section at some point, + we must release it here. */ + + free_abbrevs (); + return 1; +} + static int process_section_contents (FILE *file) { Elf_Internal_Shdr *section; unsigned int i; - if (! do_dump) + if ((! do_dump) && (!do_com_sym)) return 1; for (i = 0, section = section_headers; @@ -9404,13 +10104,31 @@ process_section_contents (FILE *file) if (dump_sects[i] & HEX_DUMP) dump_section (section, file); - if (dump_sects[i] & DEBUG_DUMP) - display_debug_section (section, file); + if (!do_com_sym) + { + if (dump_sects[i] & DEBUG_DUMP) + display_debug_section (section, file); + } + else + { + if (do_debug_and_comm_sym > 1) + { + if (dump_sects[i] & DEBUG_DUMP) + display_debug_section (section, file); + if (strcmp(SECTION_NAME (section), ".debug_info") == 0) + { + process_debug_section_comm_sym (section, file); + } + } + else if(strcmp(SECTION_NAME (section), ".debug_info") == 0) + { + process_debug_section_comm_sym (section, file); + break; + } + } } - - if (i < num_dump_sects) + if ((i < num_dump_sects) && (!do_com_sym)) warn (_("Some sections were not dumped because they do not exist!\n")); - return 1; } @@ -10655,3 +11373,4 @@ main (int argc, char **argv) return err; } +