public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] Readelf patch to group common symbols.
@ 2004-12-13 13:32 Prafulla Thakare
  2004-12-16 11:54 ` Nick Clifton
  0 siblings, 1 reply; 4+ messages in thread
From: Prafulla Thakare @ 2004-12-13 13:32 UTC (permalink / raw)
  To: binutils

[-- Attachment #1: Type: text/plain, Size: 1451 bytes --]

Hi,

Please find attached the patch for readelf. This is developed to group
all the 
common symbols from different compilation unit if built in debug mode. 
Switch "--common-symb" or "-P" is added to readelf. The common symbol 
information is derived from .debug_info and symtab section.

It displays the following information about any common symbol: 
1. Name of Common symbol \
2. Basetype 
3. Base_size 
4. Size 
5. Elements (Number of elements if array or one) 
6. Value 

Following is the simple test case:
/***********************************************************************
*********/
//Test.c
int iVar;
int main()
{
return 0;
}
/*
$sh-elf-gcc -g Test.c
$sh-elf-readelf a.out --common-symb 
Output:
Common Symbols List:
Common symbol        Basetype 		Base_size 	Size
Elements  Value
iVar                 int                  4 		 4
1 	    2f24
*/
/***********************************************************************
*********/

Regards,
Prafulla Thakare
KPIT Cummins InfoSystems Ltd.
Pune, India

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Free download of GNU based tool-chains for Renesas' SH and H8 Series. 
The following site also offers free technical support to its users. 
Visit http://www.kpitgnutools.com for details. 
Latest versions of KPIT GNU tools are released on Oct 1, 2004.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

[-- Attachment #2: comm_sym.patch --]
[-- Type: application/octet-stream, Size: 22190 bytes --]

--- ./binutils-2.15/binutils/readelf.c.orig	2004-12-09 14:01:02.000000000 +0530
+++ ./binutils-2.15/binutils/readelf.c	2004-12-09 14:02:23.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,89 @@ 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 +6872,8 @@ display_debug_pubnames (Elf_Internal_Shd
   return 1;
 }
 
+unsigned long uBreak = 0;
+
 static char *
 get_TAG_name (unsigned long tag)
 {
@@ -6851,7 +6947,7 @@ get_TAG_name (unsigned long tag)
     default:
       {
 	static char buffer[100];
-
+    	uBreak = 1;
 	sprintf (buffer, _("Unknown TAG value: %lx"), tag);
 	return buffer;
       }
@@ -6964,7 +7060,7 @@ get_AT_name (unsigned long attribute)
     default:
       {
 	static char buffer[100];
-
+    	uBreak = 1;
 	sprintf (buffer, _("Unknown AT value: %lx"), attribute);
 	return buffer;
       }
@@ -8000,6 +8096,7 @@ read_and_display_attr_value (unsigned lo
 
     default:
       warn (_("Unrecognized form: %d\n"), form);
+	  uBreak = 1;
       break;
     }
 
@@ -8179,6 +8276,175 @@ 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)))
+		  uBreak = 1;
+      break;
+
+    default:
+      uBreak = 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 +8461,395 @@ 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) && (!uBreak))
+  {
+      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) && (!uBreak))
+	{
+	  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) && (!uBreak))
+  {
+      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) && (!uBreak))
+      {
+		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 uValue;
+		  int size, len;
+
+		  if (!uBreak)
+		  {
+			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 only
+				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,&uValue);
+					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"), uValue);
+				}
+			}
+
+			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,
@@ -9383,6 +10038,58 @@ 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)
@@ -9390,7 +10097,7 @@ 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,11 +10111,32 @@ 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 +11383,4 @@ main (int argc, char **argv)
 
   return err;
 }
+

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] Readelf patch to group common symbols.
  2004-12-13 13:32 [PATCH] Readelf patch to group common symbols Prafulla Thakare
@ 2004-12-16 11:54 ` Nick Clifton
  0 siblings, 0 replies; 4+ messages in thread
From: Nick Clifton @ 2004-12-16 11:54 UTC (permalink / raw)
  To: Prafulla Thakare; +Cc: binutils

Hi Prafulla,

> Please find attached the patch for readelf. This is developed to group
> all the common symbols from different compilation unit if built in debug
 > mode.

Thanks for submitting this patch.  Unfortunately I have some issues with it:

   * Why is this feature necessary ?  Surely this information can be 
gleaned from the switches already supported by readelf ?

   * Does KPIT have an FSF assignment in place ?  I could only find one:

     KPIT InfoSystems Ltd.	2002-02-26
       Assigns past and future changes. (tc-sh.c)
       anandk@kpit.com (Anandkumar Keshavan)

   * The new code in the patch does not follow the GNU Coding Standard.

   * Since this patch adds a new feature to readelf there should be 
patches to binutils/NEWS to announce it and binutils/doc/binutils.texi 
to document it.

   * A binutils testsuite entry to check the new functionality provided 
by the patch would be very welcome.

I hope that you will consider these issues and get back to us with a 
revised patch.

Cheers
   Nick

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] Readelf patch to group common symbols.
  2004-12-21  6:43 Prafulla Thakare
@ 2004-12-21 17:48 ` Nick Clifton
  0 siblings, 0 replies; 4+ messages in thread
From: Nick Clifton @ 2004-12-21 17:48 UTC (permalink / raw)
  To: Prafulla Thakare; +Cc: binutils

Hi Prafulla,

Thank you very much for submitting the revised patch.  Unfortunately now 
that I have looked more closely at it I have some other serious concerns 
with it, vis:

   * Not reusing code:
       The patch basically repeats the contents of the 
display_debug_info() function twice more in 
get_symbol_base_type_and_size() and display_common_symbol().  This is a 
very bad idea.  If so much code is in common with three routines it 
should be extracted and made into a single function called by three 
parents.  There are other instances of code duplication in the patch as 
well.

   * Target specific coding:
       It appears that this patch has been developed for a target which 
prefixes its symbols with a leading underscore, because in your 
get_symbol_size() function there is this code at the start:

   +  char symb_name[32] = "_";
   +  strcat((char *)symb_name,symbol_name);

The code should be fixed so that it will work with targets which are not 
prefixing their symbols.  (Note, because of gcc's -fleading-underscore 
switch you cannot make a static decision on a per-target basis).

   * Not made against current sources:
      The patch does not appear to have been created against the current 
mainline binutils sources in the CVS repository.  This makes it very 
hard for me to apply and test the patch.

   * Not making use of existing code:
       The patch includes code to print the name of a common symbol and 
then pad the name out to 20 spaces.  The print_symbol() function can 
already do this in a much more effiicient manner.

   * Performing redundant strcmps:
       The patch uses strcmp to check the name of a tag or attribute 
against a fixed string.  This is very inefficient.  It would be much 
better to just perform a direct comparison.  ie:

	(!strcmp("DW_AT_name",get_AT_name (attr->attribute))

should be:

         (attr->attribute == DW_AT_name)

Cheers
   Nick

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] Readelf patch to group common symbols.
@ 2004-12-21  6:43 Prafulla Thakare
  2004-12-21 17:48 ` Nick Clifton
  0 siblings, 1 reply; 4+ messages in thread
From: Prafulla Thakare @ 2004-12-21  6:43 UTC (permalink / raw)
  To: binutils; +Cc: nickc

[-- Attachment #1: Type: text/plain, Size: 3089 bytes --]

Hi Nick,

Thanks for your comments. 

>Thanks for submitting this patch.  Unfortunately I have some issues 
>with it:
* Why is this feature necessary ?  Surely this information can be
gleaned from 
the switches already supported by readelf ?
--> Yes, this information can be gleaned from the switches already
supported by
readelf. However, following are the reasons for adding this new switch
to readelf.

1. This patch collects the common symbols information which is
scattered. 

2. If common symbol is of array type, then the information about number 
of elements is not explicitly available with any existing readelf
switches. 
The newly added option provides this information to user directly. 

3. With existing options, to get the base type and base size of common
symbol, 
user need to manually browse the readelf output file generated using 
--debug-dump. As we know, --debug-dump generates quite a lot stuff in
output, 
so searching for this information manually can be tedious job. The newly
added 
switch is doing this work for the end user.

* Does KPIT have an FSF assignment in place ?  I could only find one:
  KPIT InfoSystems Ltd.	2002-02-26
  Assigns past and future changes. (tc-sh.c)
  anandk@kpit.com (Anandkumar Keshavan)
-->Yes, KPIT has a corporate FSF assignment.

* The new code in the patch does not follow the GNU Coding Standard.
--> Attached patch is corrected as per GNU coding standard.
Following is the Change log for the attached patches:

2004-12-21  Prafulla Thakare	<prafullat@kpitcummins.com>

	* binutils/readelf.c : Added option --common-symb to display the

        common symbol details if built for debug.
	* binutils/testsuite/binutils-all/readelf.exp : Test case for 
        newly added option --common-symb
	* binutils/testsuite/binutils-all/readelf.P : Expected output
file.
	* binutils/doc/binutils.texi : Help about new option
--common-symb 
        added.
	* binutils/NEWS : Information about new option --common-symb
added.

* Since this patch adds a new feature to readelf there should be 
patches to binutils/NEWS to announce it and binutils/doc/binutils.texi 
to document it.
--> The patches for binutils/NEWS (news.patch) to announce it and
binutils/doc/binutils.texi (binutil_texi.patch) to document it are
attached.

* A binutils testsuite entry to check the new functionality provided 
by the patch would be very welcome.
--> Patch (read_exp.patch) for adding the entry in testsuite is
attached. 
File readelf.P is to be added in
"binutils-2.15/binutils/testsuite/binutils-all" 
folder.

Regards,
Prafulla Thakare,
KPIT Cummins InfoSystems Ltd.
Pune, India

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Free download of GNU based tool-chains for Renesas' SH and H8 Series. 
The following site also offers free technical support to its users. 
Visit http://www.kpitgnutools.com for details. 
Latest versions of KPIT GNU tools are released on Oct 1, 2004.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

[-- Attachment #2: readelf.P --]
[-- Type: application/octet-stream, Size: 341 bytes --]


Common Symbols List:
Common symbol        Basetype 		Base_size 	Size 		Elements  Value
common               int                  4 		 4 		 1 	  .* 		
global               int                  4 		 4 		 1 	  .* 		
local                int                  4 		 4 		 1 	  .* 		
string               unsigned char        1 		 7 		 7 	  .* 		


[-- Attachment #3: read_exp.patch --]
[-- Type: application/octet-stream, Size: 505 bytes --]

--- binutils-2.15/binutils/testsuite/binutils-all/readelf.exp.orig	2004-12-17 11:28:35.000000000 +0530
+++ binutils-2.15/binutils/testsuite/binutils-all/readelf.exp	2004-12-17 11:33:32.000000000 +0530
@@ -341,3 +341,15 @@ readelf_test -s $tempfile readelf.ss {}
 readelf_test -r $tempfile readelf.r  {}
 
 readelf_wi_test
+
+if ![is_remote host] {
+   set tempfile tmpdir/testprog;
+} else {
+   set tempfile [remote_download host tmpdir/bintestprog]
+}
+
+readelf_test -P $tempfile readelf.P  {}
+
+
+
+

[-- Attachment #4: comm_sym.patch --]
[-- Type: application/octet-stream, Size: 24492 bytes --]

--- 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;
 }
+

[-- Attachment #5: news.patch --]
[-- Type: application/octet-stream, Size: 438 bytes --]

--- binutils-2.15/binutils/NEWS.orig	2004-12-17 12:36:55.000000000 +0530
+++ binutils-2.15/binutils/NEWS	2004-12-17 12:35:28.000000000 +0530
@@ -1,4 +1,7 @@
 -*- text -*-
+* Added --common-symb switch to readelf. This option is added to group the common symbol
+  details.
+
 * objcopy and strip can now take wildcard patterns in symbol names specified on
   the command line provided that the --wildcard switch is used to enable them.
 

[-- Attachment #6: binutil_texi.patch --]
[-- Type: application/octet-stream, Size: 898 bytes --]

--- binutils-2.15/binutils/doc/binutils.texi.orig	2004-12-17 12:23:00.000000000 +0530
+++ binutils-2.15/binutils/doc/binutils.texi	2004-12-17 12:25:47.000000000 +0530
@@ -3119,6 +3119,7 @@ the Info entries for @file{binutils}.
 @c man begin SYNOPSIS readelf
 readelf [@option{-a}|@option{--all}] 
         [@option{-h}|@option{--file-header}]
+        [@option{-P}|@option{--common-symb}]
         [@option{-l}|@option{--program-headers}|@option{--segments}]
         [@option{-S}|@option{--section-headers}|@option{--sections}]
         [@option{-e}|@option{--headers}]
@@ -3176,6 +3177,11 @@ Equivalent to specifiying @option{--file
 Displays the information contained in the ELF header at the start of the
 file.
 
+@item -P
+@itemx --common-symb
+@cindex Common symbols information
+Display the common symbol details if built for debug.
+
 @item -l
 @itemx --program-headers
 @itemx --segments

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2004-12-21 17:48 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-12-13 13:32 [PATCH] Readelf patch to group common symbols Prafulla Thakare
2004-12-16 11:54 ` Nick Clifton
2004-12-21  6:43 Prafulla Thakare
2004-12-21 17:48 ` Nick Clifton

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).