dwarf2.c

来自「基于4个mips核的noc设计」· C语言 代码 · 共 1,670 行 · 第 1/3 页

C
1,670
字号
    }  return false;}/* DWARF2 Compilation unit functions.  *//* Scan over each die in a comp. unit looking for functions to add   to the function table.  */static booleanscan_unit_for_functions (unit)     struct comp_unit *unit;{  bfd *abfd = unit->abfd;  char *info_ptr = unit->first_child_die_ptr;  int nesting_level = 1;  while (nesting_level)    {      unsigned int abbrev_number, bytes_read, i;      struct abbrev_info *abbrev;      struct attribute attr;      struct funcinfo *func;      char* name = 0;      abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);      info_ptr += bytes_read;      if (! abbrev_number)	{	  nesting_level--;	  continue;	}      abbrev = lookup_abbrev (abbrev_number,unit->abbrevs);      if (! abbrev)	{	  (*_bfd_error_handler) (_("Dwarf Error: Could not find abbrev number %d."),			     abbrev_number);	  bfd_set_error (bfd_error_bad_value);	  return false;	}      if (abbrev->tag == DW_TAG_subprogram)	{	  func = (struct funcinfo*) bfd_zalloc (abfd, sizeof (struct funcinfo));	  func->prev_func = unit->function_table;	  unit->function_table = func;	}      else	func = NULL;      for (i = 0; i < abbrev->num_attrs; ++i)	{	  info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, info_ptr);	  if (func)	    {	      switch (attr.name)		{		case DW_AT_name:		  name = DW_STRING (&attr);		  /* Prefer DW_AT_MIPS_linkage_name over DW_AT_name.  */		  if (func->name == NULL)		    func->name = DW_STRING (&attr);		  break;		case DW_AT_MIPS_linkage_name:		  func->name = DW_STRING (&attr);		  break;		case DW_AT_low_pc:		  func->low = DW_ADDR (&attr);		  break;		case DW_AT_high_pc:		  func->high = DW_ADDR (&attr);		  break;		default:		  break;		}	    }	  else	    {	      switch (attr.name)		{		case DW_AT_name:		  name = DW_STRING (&attr);		  break;		default:		  break;		}	    }	}      if (abbrev->has_children)	nesting_level++;    }  return true;}/* Parse a DWARF2 compilation unit starting at INFO_PTR.  This   includes the compilation unit header that proceeds the DIE's, but   does not include the length field that preceeds each compilation   unit header.  END_PTR points one past the end of this comp unit.   If ABBREV_LENGTH is 0, then the length of the abbreviation offset   is assumed to be four bytes.  Otherwise, it it is the size given.   This routine does not read the whole compilation unit; only enough   to get to the line number information for the compilation unit.  */static struct comp_unit *parse_comp_unit (abfd, stash, unit_length, abbrev_length)     bfd* abfd;     struct dwarf2_debug *stash;     bfd_vma unit_length;     unsigned int abbrev_length;{  struct comp_unit* unit;  unsigned short version;  unsigned int abbrev_offset = 0;  unsigned char addr_size;  struct abbrev_info** abbrevs;  unsigned int abbrev_number, bytes_read, i;  struct abbrev_info *abbrev;  struct attribute attr;  char *info_ptr = stash->info_ptr;  char *end_ptr = info_ptr + unit_length;  version = read_2_bytes (abfd, info_ptr);  info_ptr += 2;  BFD_ASSERT (abbrev_length == 0	      || abbrev_length == 4	      || abbrev_length == 8);  if (abbrev_length == 0 || abbrev_length == 4)    abbrev_offset = read_4_bytes (abfd, info_ptr);  else if (abbrev_length == 8)    abbrev_offset = read_8_bytes (abfd, info_ptr);  info_ptr += abbrev_length;  addr_size = read_1_byte (abfd, info_ptr);  info_ptr += 1;  if (version != 2)    {      (*_bfd_error_handler) (_("Dwarf Error: found dwarf version '%hu', this reader only handles version 2 information."), version );      bfd_set_error (bfd_error_bad_value);      return 0;    }  if (addr_size > sizeof (bfd_vma))    {      (*_bfd_error_handler) (_("Dwarf Error: found address size '%u', this reader can not handle sizes greater than '%u'."),			 addr_size,			 sizeof (bfd_vma));      bfd_set_error (bfd_error_bad_value);      return 0;    }  if (addr_size != 2 && addr_size != 4 && addr_size != 8)    {      (*_bfd_error_handler) ("Dwarf Error: found address size '%u', this reader can only handle address sizes '2', '4' and '8'.", addr_size );      bfd_set_error (bfd_error_bad_value);      return 0;    }  /* Read the abbrevs for this compilation unit into a table.  */  abbrevs = read_abbrevs (abfd, abbrev_offset, stash);  if (! abbrevs)      return 0;  abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);  info_ptr += bytes_read;  if (! abbrev_number)    {      (*_bfd_error_handler) (_("Dwarf Error: Bad abbrev number: %d."),			 abbrev_number);      bfd_set_error (bfd_error_bad_value);      return 0;    }  abbrev = lookup_abbrev (abbrev_number, abbrevs);  if (! abbrev)    {      (*_bfd_error_handler) (_("Dwarf Error: Could not find abbrev number %d."),			 abbrev_number);      bfd_set_error (bfd_error_bad_value);      return 0;    }  unit = (struct comp_unit*) bfd_zalloc (abfd, sizeof (struct comp_unit));  unit->abfd = abfd;  unit->addr_size = addr_size;  unit->abbrevs = abbrevs;  unit->end_ptr = end_ptr;  for (i = 0; i < abbrev->num_attrs; ++i)    {      info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, info_ptr);      /* Store the data if it is of an attribute we want to keep in a	 partial symbol table.  */      switch (attr.name)	{	case DW_AT_stmt_list:	  unit->stmtlist = 1;	  unit->line_offset = DW_UNSND (&attr);	  break;	case DW_AT_name:	  unit->name = DW_STRING (&attr);	  break;	case DW_AT_low_pc:	  unit->arange.low = DW_ADDR (&attr);	  break;	case DW_AT_high_pc:	  unit->arange.high = DW_ADDR (&attr);	  break;	case DW_AT_comp_dir:	  {	    char* comp_dir = DW_STRING (&attr);	    if (comp_dir)	      {		/* Irix 6.2 native cc prepends <machine>.: to the compilation		   directory, get rid of it.  */		char *cp = (char*) strchr (comp_dir, ':');		if (cp && cp != comp_dir && cp[-1] == '.' && cp[1] == '/')		  comp_dir = cp + 1;	      }	    unit->comp_dir = comp_dir;	    break;	  }	default:	  break;	}    }  unit->first_child_die_ptr = info_ptr;  return unit;}/* Return true if UNIT contains the address given by ADDR.  */static booleancomp_unit_contains_address (unit, addr)     struct comp_unit* unit;     bfd_vma addr;{  struct arange *arange;  if (unit->error)    return 0;  arange = &unit->arange;  do    {      if (addr >= arange->low && addr < arange->high)	return 1;      arange = arange->next;    }  while (arange);  return 0;}/* If UNIT contains ADDR, set the output parameters to the values for   the line containing ADDR.  The output parameters, FILENAME_PTR,   FUNCTIONNAME_PTR, and LINENUMBER_PTR, are pointers to the objects   to be filled in.   Return true of UNIT contains ADDR, and no errors were encountered;   false otherwise.  */static booleancomp_unit_find_nearest_line (unit, addr,			     filename_ptr, functionname_ptr, linenumber_ptr,			     stash)     struct comp_unit* unit;     bfd_vma addr;     const char **filename_ptr;     const char **functionname_ptr;     unsigned int *linenumber_ptr;     struct dwarf2_debug *stash;{  boolean line_p;  boolean func_p;  if (unit->error)    return false;  if (! unit->line_table)    {      if (! unit->stmtlist)	{	  unit->error = 1;	  return false;	}      unit->line_table = decode_line_info (unit, stash);      if (! unit->line_table)	{	  unit->error = 1;	  return false;	}      if (! scan_unit_for_functions (unit))	{	  unit->error = 1;	  return false;	}    }  line_p = lookup_address_in_line_info_table (unit->line_table,					      addr,					      filename_ptr,					      linenumber_ptr);  func_p = lookup_address_in_function_table (unit->function_table,					     addr,					     functionname_ptr);  return line_p || func_p;}/* Locate a section in a BFD containing debugging info.  The search starts from the   section after AFTER_SEC, or from the first section in the BFD if AFTER_SEC is   NULL.  The search works by examining the names of the sections.  There are two   permissiable names.  The first is .debug_info.  This is the standard DWARF2 name.   The second is a prefix .gnu.linkonce.wi.  This is a variation on the .debug_info   section which has a checksum describing the contents appended onto the name.  This   allows the linker to identify and discard duplicate debugging sections for   different compilation units.  */#define DWARF2_DEBUG_INFO ".debug_info"#define GNU_LINKONCE_INFO ".gnu.linkonce.wi."static asection *find_debug_info (abfd, after_sec)     bfd * abfd;     asection * after_sec;{  asection * msec;  if (after_sec)    msec = after_sec->next;  else    msec = abfd->sections;  while (msec)    {      if (strcmp (msec->name, DWARF2_DEBUG_INFO) == 0)	return msec;      if (strncmp (msec->name, GNU_LINKONCE_INFO, strlen (GNU_LINKONCE_INFO)) == 0)	return msec;      msec = msec->next;    }  return NULL;}/* The DWARF2 version of find_nearest line.  Return true if the line   is found without error.  ADDR_SIZE is the number of bytes in the   initial .debug_info length field and in the abbreviation offset.   You may use zero to indicate that the default value should be   used.  */boolean_bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,			       filename_ptr, functionname_ptr,			       linenumber_ptr,			       addr_size, pinfo)     bfd *abfd;     asection *section;     asymbol **symbols ATTRIBUTE_UNUSED;     bfd_vma offset;     const char **filename_ptr;     const char **functionname_ptr;     unsigned int *linenumber_ptr;     unsigned int addr_size;     PTR *pinfo;{  /* Read each compilation unit from the section .debug_info, and check     to see if it contains the address we are searching for.  If yes,     lookup the address, and return the line number info.  If no, go     on to the next compilation unit.     We keep a list of all the previously read compilation units, and     a pointer to the next un-read compilation unit.  Check the     previously read units before reading more.  */  struct dwarf2_debug *stash = (struct dwarf2_debug *) *pinfo;  /* What address are we looking for?  */  bfd_vma addr = offset + section->vma;  struct comp_unit* each;  *filename_ptr = NULL;  *functionname_ptr = NULL;  *linenumber_ptr = 0;  /* The DWARF2 spec says that the initial length field, and the     offset of the abbreviation table, should both be 4-byte values.     However, some compilers do things differently.  */  if (addr_size == 0)    addr_size = 4;  BFD_ASSERT (addr_size == 4 || addr_size == 8);  if (! stash)    {      unsigned long total_size;      asection *msec;      stash =	(struct dwarf2_debug*) bfd_zalloc (abfd, sizeof (struct dwarf2_debug));      if (! stash)	return false;      *pinfo = (PTR) stash;      msec = find_debug_info (abfd, NULL);      if (! msec)	/* No dwarf2 info.  Note that at this point the stash	   has been allocated, but contains zeros, this lets	   future calls to this function fail quicker.  */	 return false;      /* There can be more than one DWARF2 info section in a BFD these days.         Read them all in and produce one large stash.  We do this in two	 passes - in the first pass we just accumulate the section sizes.	 In the second pass we read in the section's contents.  The allows	 us to avoid reallocing the data as we add sections to the stash.  */      for (total_size = 0; msec; msec = find_debug_info (abfd, msec))	total_size += msec->_raw_size;      stash->info_ptr = (char *) bfd_alloc (abfd, total_size);      if (stash->info_ptr == NULL)	return false;      stash->info_ptr_end = stash->info_ptr;      for (msec = find_debug_info (abfd, NULL);	   msec;	   msec = find_debug_info (abfd, msec))	{	  unsigned long size;	  unsigned long start;	  size = msec->_raw_size;	  if (size == 0)	    continue;	  start = stash->info_ptr_end - stash->info_ptr;	  if (! bfd_get_section_contents (abfd, msec, stash->info_ptr + start, 0, size))	    continue;	  stash->info_ptr_end = stash->info_ptr + start + size;	}      BFD_ASSERT (stash->info_ptr_end = stash->info_ptr + total_size);    }  /* FIXME: There is a problem with the contents of the     .debug_info section.  The 'low' and 'high' addresses of the     comp_units are computed by relocs against symbols in the     .text segment.  We need these addresses in order to determine     the nearest line number, and so we have to resolve the     relocs.  There is a similar problem when the .debug_line     section is processed as well (e.g., there may be relocs     against the operand of the DW_LNE_set_address operator).     Unfortunately getting hold of the reloc information is hard...     For now, this means that disassembling object files (as     opposed to fully executables) does not always work as well as     we would like.  */  /* A null info_ptr indicates that there is no dwarf2 info     (or that an error occured while setting up the stash).  */  if (! stash->info_ptr)    return false;  /* Check the previously read comp. units first.  */  for (each = stash->all_comp_units; each; each = each->next_unit)    if (comp_unit_contains_address (each, addr))      return comp_unit_find_nearest_line (each, addr, filename_ptr,					  functionname_ptr, linenumber_ptr,					  stash);  /* Read each remaining comp. units checking each as they are read.  */  while (stash->info_ptr < stash->info_ptr_end)    {      struct comp_unit* each;      bfd_vma length;      boolean found;      if (addr_size == 4)	length = read_4_bytes (abfd, stash->info_ptr);      else	length = read_8_bytes (abfd, stash->info_ptr);      stash->info_ptr += addr_size;      if (length > 0)        {	  each = parse_comp_unit (abfd, stash, length, addr_size);	  stash->info_ptr += length;	  if (each)	    {	      each->next_unit = stash->all_comp_units;	      stash->all_comp_units = each;	      /* DW_AT_low_pc and DW_AT_high_pc are optional for		 compilation units.  If we don't have them (i.e.,		 unit->high == 0), we need to consult the line info		 table to see if a compilation unit contains the given		 address.  */	      if (each->arange.high > 0)		{		  if (comp_unit_contains_address (each, addr))		    return comp_unit_find_nearest_line (each, addr,						       filename_ptr,						       functionname_ptr,						       linenumber_ptr,						       stash);		}	      else		{		  found = comp_unit_find_nearest_line (each, addr,						       filename_ptr,						       functionname_ptr,						       linenumber_ptr,						       stash);		  if (found)		    return true;		}	    }	}    }  return false;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?