Esempio n. 1
0
static gdb_byte *
find_location_expression (struct dwarf2_loclist_baton *baton,
			  size_t *locexpr_length, CORE_ADDR pc)
{
  CORE_ADDR low, high;
  gdb_byte *loc_ptr, *buf_end;
  int length;
  struct objfile *objfile = dwarf2_per_cu_objfile (baton->per_cu);
  struct gdbarch *gdbarch = get_objfile_arch (objfile);
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  unsigned int addr_size = dwarf2_per_cu_addr_size (baton->per_cu);
  CORE_ADDR base_mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1));
  /* Adjust base_address for relocatable objects.  */
  CORE_ADDR base_offset = ANOFFSET (objfile->section_offsets,
				    SECT_OFF_TEXT (objfile));
  CORE_ADDR base_address = baton->base_address + base_offset;

  loc_ptr = baton->data;
  buf_end = baton->data + baton->size;

  while (1)
    {
      if (buf_end - loc_ptr < 2 * addr_size)
	error (_("find_location_expression: Corrupted DWARF expression."));

      low = extract_unsigned_integer (loc_ptr, addr_size, byte_order);
      loc_ptr += addr_size;

      /* A base-address-selection entry.  */
      if (low == base_mask)
	{
	  base_address = dwarf2_read_address (gdbarch,
					      loc_ptr, buf_end, addr_size);
	  loc_ptr += addr_size;
	  continue;
	}

      high = extract_unsigned_integer (loc_ptr, addr_size, byte_order);
      loc_ptr += addr_size;

      /* An end-of-list entry.  */
      if (low == 0 && high == 0)
	return NULL;

      /* Otherwise, a location expression entry.  */
      low += base_address;
      high += base_address;

      length = extract_unsigned_integer (loc_ptr, 2, byte_order);
      loc_ptr += 2;

      if (pc >= low && pc < high)
	{
	  *locexpr_length = length;
	  return loc_ptr;
	}

      loc_ptr += length;
    }
}
static gdb_byte *
find_location_expression (struct dwarf2_loclist_baton *baton,
			  size_t *locexpr_length, CORE_ADDR pc)
{
  CORE_ADDR low, high;
  gdb_byte *loc_ptr, *buf_end;
  int length;
  unsigned int addr_size = gdbarch_addr_bit (current_gdbarch) / TARGET_CHAR_BIT;
  CORE_ADDR base_mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1));
  /* Adjust base_address for relocatable objects.  */
  CORE_ADDR base_offset = ANOFFSET (baton->objfile->section_offsets,
				    SECT_OFF_TEXT (baton->objfile));
  CORE_ADDR base_address = baton->base_address + base_offset;

  loc_ptr = baton->data;
  buf_end = baton->data + baton->size;

  while (1)
    {
      low = dwarf2_read_address (loc_ptr, buf_end, &length);
      loc_ptr += length;
      high = dwarf2_read_address (loc_ptr, buf_end, &length);
      loc_ptr += length;

      /* An end-of-list entry.  */
      if (low == 0 && high == 0)
	return NULL;

      /* A base-address-selection entry.  */
      if ((low & base_mask) == base_mask)
	{
	  base_address = high;
	  continue;
	}

      /* Otherwise, a location expression entry.  */
      low += base_address;
      high += base_address;

      length = extract_unsigned_integer (loc_ptr, 2);
      loc_ptr += 2;

      if (pc >= low && pc < high)
	{
	  *locexpr_length = length;
	  return loc_ptr;
	}

      loc_ptr += length;
    }
}
Esempio n. 3
0
static void
nlm_symfile_read (struct objfile *objfile, int mainline)
{
  bfd *abfd = objfile->obfd;
  struct cleanup *back_to;
  CORE_ADDR offset;
  struct symbol *mainsym;

  init_minimal_symbol_collection ();
  back_to = make_cleanup_discard_minimal_symbols ();

  /* FIXME, should take a section_offsets param, not just an offset.  */

  offset = ANOFFSET (objfile->section_offsets, 0);

  /* Process the NLM export records, which become the bfd's canonical symbol
     table. */

  nlm_symtab_read (abfd, offset, objfile);

  /* Install any minimal symbols that have been collected as the current
     minimal symbols for this objfile. */

  install_minimal_symbols (objfile);
  do_cleanups (back_to);

  stabsect_build_psymtabs (objfile, mainline, ".stab",
			   ".stabstr", ".text");

  mainsym = lookup_symbol (main_name (), NULL, VAR_DOMAIN, NULL, NULL);

  if (mainsym
      && SYMBOL_CLASS (mainsym) == LOC_BLOCK)
    {
      objfile->ei.main_func_lowpc = BLOCK_START (SYMBOL_BLOCK_VALUE (mainsym));
      objfile->ei.main_func_highpc = BLOCK_END (SYMBOL_BLOCK_VALUE (mainsym));
    }

  /* FIXME:  We could locate and read the optional native debugging format
     here and add the symbols to the minimal symbol table. */
}
Esempio n. 4
0
static void
vmap_symtab (struct vmap *vp)
{
  struct objfile *objfile;
  struct section_offsets *new_offsets;
  int i;

  objfile = vp->objfile;
  if (objfile == NULL)
    {
      /* OK, it's not an objfile we opened ourselves.
         Currently, that can only happen with the exec file, so
         relocate the symbols for the symfile.  */
      if (symfile_objfile == NULL)
	return;
      objfile = symfile_objfile;
    }
  else if (!vp->loaded)
    /* If symbols are not yet loaded, offsets are not yet valid.  */
    return;

  new_offsets =
    (struct section_offsets *)
    alloca (SIZEOF_N_SECTION_OFFSETS (objfile->num_sections));

  for (i = 0; i < objfile->num_sections; ++i)
    new_offsets->offsets[i] = ANOFFSET (objfile->section_offsets, i);

  /* The symbols in the object file are linked to the VMA of the section,
     relocate them VMA relative.  */
  new_offsets->offsets[SECT_OFF_TEXT (objfile)] = vp->tstart - vp->tvma;
  new_offsets->offsets[SECT_OFF_DATA (objfile)] = vp->dstart - vp->dvma;
  new_offsets->offsets[SECT_OFF_BSS (objfile)] = vp->dstart - vp->dvma;

  /* Perform the same adjustment as the loader if the .data and
     .bss sections overlap.  */
  new_offsets->offsets[SECT_OFF_BSS (objfile)] += bss_data_overlap (objfile);

  objfile_relocate (objfile, new_offsets);
}
static int
add_pe_forwarded_sym (minimal_symbol_reader &reader,
		      const char *sym_name, const char *forward_dll_name,
		      const char *forward_func_name, int ordinal,
		      const char *dll_name, struct objfile *objfile)
{
  CORE_ADDR vma, baseaddr;
  struct bound_minimal_symbol msymbol;
  enum minimal_symbol_type msymtype;
  char *qualified_name, *bare_name;
  int forward_dll_name_len = strlen (forward_dll_name);
  int forward_func_name_len = strlen (forward_func_name);
  int forward_len = forward_dll_name_len + forward_func_name_len + 2;
  char *forward_qualified_name = (char *) alloca (forward_len);
  short section;

  xsnprintf (forward_qualified_name, forward_len, "%s!%s", forward_dll_name,
	     forward_func_name);


  msymbol = lookup_minimal_symbol_and_objfile (forward_qualified_name);

  if (!msymbol.minsym)
    {
      int i;

      for (i = 0; i < forward_dll_name_len; i++)
	forward_qualified_name[i] = tolower (forward_qualified_name[i]);
      msymbol = lookup_minimal_symbol_and_objfile (forward_qualified_name);
    }

  if (!msymbol.minsym)
    {
      if (debug_coff_pe_read)
	fprintf_unfiltered (gdb_stdlog, _("Unable to find function \"%s\" in"
			    " dll \"%s\", forward of \"%s\" in dll \"%s\"\n"),
			    forward_func_name, forward_dll_name, sym_name,
			    dll_name);
      return 0;
    }

  if (debug_coff_pe_read > 1)
    fprintf_unfiltered (gdb_stdlog, _("Adding forwarded exported symbol"
			" \"%s\" in dll \"%s\", pointing to \"%s\"\n"),
			sym_name, dll_name, forward_qualified_name);

  vma = BMSYMBOL_VALUE_ADDRESS (msymbol);
  msymtype = MSYMBOL_TYPE (msymbol.minsym);
  section = MSYMBOL_SECTION (msymbol.minsym);

  /* Generate a (hopefully unique) qualified name using the first part
     of the dll name, e.g. KERNEL32!AddAtomA.  This matches the style
     used by windbg from the "Microsoft Debugging Tools for Windows".  */

  if (sym_name == NULL || *sym_name == '\0')
    bare_name = xstrprintf ("#%d", ordinal);
  else
    bare_name = xstrdup (sym_name);

  qualified_name = xstrprintf ("%s!%s", dll_name, bare_name);

  /* Note that this code makes a minimal symbol whose value may point
     outside of any section in this objfile.  These symbols can't
     really be relocated properly, but nevertheless we make a stab at
     it, choosing an approach consistent with the history of this
     code.  */
  baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));

  reader.record_with_info (qualified_name, vma - baseaddr, msymtype, section);

  /* Enter the plain name as well, which might not be unique.  */
  reader.record_with_info (bare_name, vma - baseaddr, msymtype, section);
  xfree (qualified_name);
  xfree (bare_name);

  return 1;
}
Esempio n. 6
0
static void
aix5_relocate_main_executable (void)
{
  struct so_list *so;
  struct section_offsets *new_offsets;
  int i;
  int changed = 0;
  struct cleanup *old_chain = make_cleanup (null_cleanup, 0);

  /* Fetch the mappings for the main executable from the map file.  */
  so = build_so_list_from_mapfile (PIDGET (inferior_ptid),
                                   MA_MAINEXEC, MA_MAINEXEC);

  /* Make sure we actually have some mappings to work with.  */
  if (so == NULL)
    {
      warning (_("Could not find main executable in map file"));
      do_cleanups (old_chain);
      return;
    }

  /* Allocate the data structure which'll contain the new offsets to
     relocate by.  Initialize it so it contains the current offsets.  */
  new_offsets = xcalloc (symfile_objfile->num_sections,
			 sizeof (struct section_offsets));
  make_cleanup (xfree, new_offsets);
  for (i = 0; i < symfile_objfile->num_sections; i++)
    new_offsets->offsets[i] = ANOFFSET (symfile_objfile->section_offsets, i);

  /* Iterate over the mappings in the main executable and compute
     the new offset value as appropriate.  */
  for (i = 0; i < so->lm_info->nmappings; i++)
    {
      CORE_ADDR increment = 0;
      struct obj_section *sect;
      bfd *obfd = symfile_objfile->obfd;
      struct lm_mapping *mapping = &so->lm_info->mapping[i];

      ALL_OBJFILE_OSECTIONS (symfile_objfile, sect)
	{
	  int flags = bfd_get_section_flags (obfd, sect->the_bfd_section);
	  if (flags & SEC_ALLOC)
	    {
	      file_ptr filepos = sect->the_bfd_section->filepos;
	      if (map_index_vs_section_name_okay (i,
		    bfd_get_section_name (obfd, sect->the_bfd_section)))
		{
		  int idx = sect->the_bfd_section->index;

		  if (increment == 0)
		    increment = mapping->addr
		      - (bfd_section_vma (obfd, sect->the_bfd_section) 
		         & SECTMAPMASK);

		  if (increment != ANOFFSET (new_offsets, idx))
		    {
		      new_offsets->offsets[idx] = increment;
		      changed = 1;
		    }
		}
	    }
	}
    }
Esempio n. 7
0
void
read_pe_exported_syms (struct objfile *objfile)
{
  bfd *dll = objfile->obfd;
  unsigned long nbnormal, nbforward;
  unsigned long pe_header_offset, opthdr_ofs, num_entries, i;
  unsigned long export_opthdrrva, export_opthdrsize;
  unsigned long export_rva, export_size, nsections, secptr, expptr;
  unsigned long exp_funcbase;
  unsigned char *expdata, *erva;
  unsigned long name_rvas, ordinals, nexp, ordbase;
  char *dll_name = (char *) dll->filename;
  int otherix = PE_SECTION_TABLE_SIZE;
  int is_pe64 = 0;
  int is_pe32 = 0;

  /* Array elements are for text, data and bss in that order
     Initialization with RVA_START > RVA_END guarantees that
     unused sections won't be matched.  */
  struct read_pe_section_data *section_data;
  struct pe_sections_info pe_sections_info;

  struct cleanup *back_to = make_cleanup (null_cleanup, 0);

  char const *target = bfd_get_target (objfile->obfd);

  section_data = xzalloc (PE_SECTION_TABLE_SIZE
			 * sizeof (struct read_pe_section_data));

  make_cleanup (free_current_contents, &section_data);

  for (i=0; i < PE_SECTION_TABLE_SIZE; i++)
    {
      section_data[i].vma_offset = 0;
      section_data[i].rva_start = 1;
      section_data[i].rva_end = 0;
    };
  section_data[PE_SECTION_INDEX_TEXT].ms_type = mst_text;
  section_data[PE_SECTION_INDEX_TEXT].section_name = ".text";
  section_data[PE_SECTION_INDEX_DATA].ms_type = mst_data;
  section_data[PE_SECTION_INDEX_DATA].section_name = ".data";
  section_data[PE_SECTION_INDEX_BSS].ms_type = mst_bss;
  section_data[PE_SECTION_INDEX_BSS].section_name = ".bss";

  is_pe64 = (strcmp (target, "pe-x86-64") == 0
	     || strcmp (target, "pei-x86-64") == 0);
  is_pe32 = (strcmp (target, "pe-i386") == 0
	     || strcmp (target, "pei-i386") == 0
	     || strcmp (target, "pe-arm-wince-little") == 0
	     || strcmp (target, "pei-arm-wince-little") == 0);
  if (!is_pe32 && !is_pe64)
    {
      /* This is not a recognized PE format file.  Abort now, because
	 the code is untested on anything else.  *FIXME* test on
	 further architectures and loosen or remove this test.  */
      do_cleanups (back_to);
      return;
    }

  /* Get pe_header, optional header and numbers of export entries.  */
  pe_header_offset = pe_get32 (dll, 0x3c);
  opthdr_ofs = pe_header_offset + 4 + 20;
  if (is_pe64)
    num_entries = pe_get32 (dll, opthdr_ofs + 108);
  else
    num_entries = pe_get32 (dll, opthdr_ofs + 92);

  if (num_entries < 1)		/* No exports.  */
    {
      do_cleanups (back_to);
      return;
    }
  if (is_pe64)
    {
      export_opthdrrva = pe_get32 (dll, opthdr_ofs + 112);
      export_opthdrsize = pe_get32 (dll, opthdr_ofs + 116);
    }
  else
    {
      export_opthdrrva = pe_get32 (dll, opthdr_ofs + 96);
      export_opthdrsize = pe_get32 (dll, opthdr_ofs + 100);
    }
  nsections = pe_get16 (dll, pe_header_offset + 4 + 2);
  secptr = (pe_header_offset + 4 + 20 +
	    pe_get16 (dll, pe_header_offset + 4 + 16));
  expptr = 0;
  export_size = 0;

  /* Get the rva and size of the export section.  */
  for (i = 0; i < nsections; i++)
    {
      char sname[8];
      unsigned long secptr1 = secptr + 40 * i;
      unsigned long vaddr = pe_get32 (dll, secptr1 + 12);
      unsigned long vsize = pe_get32 (dll, secptr1 + 16);
      unsigned long fptr = pe_get32 (dll, secptr1 + 20);

      bfd_seek (dll, (file_ptr) secptr1, SEEK_SET);
      bfd_bread (sname, (bfd_size_type) sizeof (sname), dll);

      if ((strcmp (sname, ".edata") == 0)
	  || (vaddr <= export_opthdrrva && export_opthdrrva < vaddr + vsize))
	{
	  if (strcmp (sname, ".edata") != 0)
	    {
	      if (debug_coff_pe_read)
		fprintf_unfiltered (gdb_stdlog, _("Export RVA for dll "
				    "\"%s\" is in section \"%s\"\n"),
				    dll_name, sname);
	    }
	  else if (export_opthdrrva != vaddr && debug_coff_pe_read)
	    fprintf_unfiltered (gdb_stdlog, _("Wrong value of export RVA"
				" for dll \"%s\": 0x%lx instead of 0x%lx\n"),
				dll_name, export_opthdrrva, vaddr);
	  expptr = fptr + (export_opthdrrva - vaddr);
	  break;
	}
    }

  export_rva = export_opthdrrva;
  export_size = export_opthdrsize;

  if (export_size == 0)
    {
      /* Empty export table.  */
      do_cleanups (back_to);
      return;
    }

  /* Scan sections and store the base and size of the relevant
     sections.  */
  for (i = 0; i < nsections; i++)
    {
      unsigned long secptr1 = secptr + 40 * i;
      unsigned long vsize = pe_get32 (dll, secptr1 + 8);
      unsigned long vaddr = pe_get32 (dll, secptr1 + 12);
      unsigned long characteristics = pe_get32 (dll, secptr1 + 36);
      char sec_name[SCNNMLEN + 1];
      int sectix;

      bfd_seek (dll, (file_ptr) secptr1 + 0, SEEK_SET);
      bfd_bread (sec_name, (bfd_size_type) SCNNMLEN, dll);
      sec_name[SCNNMLEN] = '\0';

      sectix = read_pe_section_index (sec_name);

      if (sectix != PE_SECTION_INDEX_INVALID)
	{
	  section_data[sectix].rva_start = vaddr;
	  section_data[sectix].rva_end = vaddr + vsize;
	}
      else
	{
	  char *name;

	  section_data = xrealloc (section_data, (otherix + 1)
				   * sizeof (struct read_pe_section_data));
	  name = xstrdup (sec_name);
	  section_data[otherix].section_name = name;
	  make_cleanup (xfree, name);
	  section_data[otherix].rva_start = vaddr;
	  section_data[otherix].rva_end = vaddr + vsize;
	  section_data[otherix].vma_offset = 0;
	  if (characteristics & IMAGE_SCN_CNT_CODE)
	    section_data[otherix].ms_type = mst_text;
	  else if (characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
	    section_data[otherix].ms_type = mst_data;
	  else if (characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
	    section_data[otherix].ms_type = mst_bss;
	  else
	    section_data[otherix].ms_type = mst_unknown;
	  otherix++;
	}
    }

  expdata = (unsigned char *) xmalloc (export_size);
  make_cleanup (xfree, expdata);

  bfd_seek (dll, (file_ptr) expptr, SEEK_SET);
  bfd_bread (expdata, (bfd_size_type) export_size, dll);
  erva = expdata - export_rva;

  nexp = pe_as32 (expdata + 24);
  name_rvas = pe_as32 (expdata + 32);
  ordinals = pe_as32 (expdata + 36);
  ordbase = pe_as32 (expdata + 16);
  exp_funcbase = pe_as32 (expdata + 28);

  /* Use internal dll name instead of full pathname.  */
  dll_name = pe_as32 (expdata + 12) + erva;

  pe_sections_info.nb_sections = otherix;
  pe_sections_info.sections = section_data;

  bfd_map_over_sections (dll, get_section_vmas, &pe_sections_info);

  /* Adjust the vma_offsets in case this PE got relocated. This
     assumes that *all* sections share the same relocation offset
     as the text section.  */
  for (i = 0; i < otherix; i++)
    {
      section_data[i].vma_offset
	+= ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
    }

  /* Truncate name at first dot. Should maybe also convert to all
     lower case for convenience on Windows.  */
  read_pe_truncate_name (dll_name);

  if (debug_coff_pe_read)
    fprintf_unfiltered (gdb_stdlog, _("DLL \"%s\" has %ld export entries,"
			" base=%ld\n"), dll_name, nexp, ordbase);
  nbforward = 0;
  nbnormal = 0;
  /* Iterate through the list of symbols.  */
  for (i = 0; i < nexp; i++)
    {
      /* Pointer to the names vector.  */
      unsigned long name_rva = pe_as32 (erva + name_rvas + i * 4);
      /* Retrieve ordinal value.  */

      unsigned long ordinal = pe_as16 (erva + ordinals + i * 2);


      /* Pointer to the function address vector.  */
      /* This is relatived to ordinal value. */
      unsigned long func_rva = pe_as32 (erva + exp_funcbase +
                                        ordinal * 4);

      /* Find this symbol's section in our own array.  */
      int sectix = 0;
      int section_found = 0;

      /* First handle forward cases.  */
      if (func_rva >= export_rva && func_rva < export_rva + export_size)
	{
	  char *forward_name = (char *) (erva + func_rva);
	  char *funcname = (char *) (erva + name_rva);
	  char *forward_dll_name = forward_name;
	  char *forward_func_name = forward_name;
	  char *sep = strrchr (forward_name, '.');

	  if (sep)
	    {
	      int len = (int) (sep - forward_name);

	      forward_dll_name = alloca (len + 1);
	      strncpy (forward_dll_name, forward_name, len);
	      forward_dll_name[len] = '\0';
	      forward_func_name = ++sep;
	    }
	  if (add_pe_forwarded_sym (funcname, forward_dll_name,
				    forward_func_name, ordinal,
				    dll_name, objfile) != 0)
	    ++nbforward;
	  continue;
	}

      for (sectix = 0; sectix < otherix; ++sectix)
	{
	  if ((func_rva >= section_data[sectix].rva_start)
	      && (func_rva < section_data[sectix].rva_end))
	    {
	      section_found = 1;
	      add_pe_exported_sym (erva + name_rva,
				   func_rva, ordinal,
				   section_data + sectix, dll_name, objfile);
	      ++nbnormal;
	      break;
	    }
	}
      if (!section_found)
	{
	  char *funcname = (char *) (erva + name_rva);

	  if (name_rva == 0)
	    {
	      add_pe_exported_sym (NULL, func_rva, ordinal,
				   section_data, dll_name, objfile);
	      ++nbnormal;
	    }
	  else if (debug_coff_pe_read)
	    fprintf_unfiltered (gdb_stdlog, _("Export name \"%s\" ord. %lu,"
				" RVA 0x%lx in dll \"%s\" not handled\n"),
				funcname, ordinal, func_rva, dll_name);
	}
    }

  if (debug_coff_pe_read)
    fprintf_unfiltered (gdb_stdlog, _("Finished reading \"%s\", exports %ld,"
			" forwards %ld, total %ld/%ld.\n"), dll_name, nbnormal,
			nbforward, nbnormal + nbforward, nexp);
  /* Discard expdata and section_data.  */
  do_cleanups (back_to);
}
static void
som_symtab_read (bfd *abfd, struct objfile *objfile,
		 struct section_offsets *section_offsets)
{
  unsigned int number_of_symbols;
  int val, dynamic;
  char *stringtab;
  asection *shlib_info;
  struct symbol_dictionary_record *buf, *bufp, *endbufp;
  char *symname;
  CONST int symsize = sizeof (struct symbol_dictionary_record);
  CORE_ADDR text_offset, data_offset;


  text_offset = ANOFFSET (section_offsets, 0);
  data_offset = ANOFFSET (section_offsets, 1);

  number_of_symbols = bfd_get_symcount (abfd);

  /* FIXME (alloca): could be quite large. */
  buf = alloca (symsize * number_of_symbols);
  bfd_seek (abfd, obj_som_sym_filepos (abfd), SEEK_SET);
  val = bfd_bread (buf, symsize * number_of_symbols, abfd);
  if (val != symsize * number_of_symbols)
    error ("Couldn't read symbol dictionary!");

  /* FIXME (alloca): could be quite large. */
  stringtab = alloca (obj_som_stringtab_size (abfd));
  bfd_seek (abfd, obj_som_str_filepos (abfd), SEEK_SET);
  val = bfd_bread (stringtab, obj_som_stringtab_size (abfd), abfd);
  if (val != obj_som_stringtab_size (abfd))
    error ("Can't read in HP string table.");

  /* We need to determine if objfile is a dynamic executable (so we
     can do the right thing for ST_ENTRY vs ST_CODE symbols).

     There's nothing in the header which easily allows us to do
     this.

     This code used to rely upon the existence of a $SHLIB_INFO$
     section to make this determination.  HP claims that it is
     more accurate to check for a nonzero text offset, but they
     have not provided any information about why that test is
     more accurate.  */
  dynamic = (text_offset != 0);

  endbufp = buf + number_of_symbols;
  for (bufp = buf; bufp < endbufp; ++bufp)
    {
      enum minimal_symbol_type ms_type;

      QUIT;

      switch (bufp->symbol_scope)
	{
	case SS_UNIVERSAL:
	case SS_EXTERNAL:
	  switch (bufp->symbol_type)
	    {
	    case ST_SYM_EXT:
	    case ST_ARG_EXT:
	      continue;

	    case ST_CODE:
	    case ST_PRI_PROG:
	    case ST_SEC_PROG:
	    case ST_MILLICODE:
	      symname = bufp->name.n_strx + stringtab;
	      ms_type = mst_text;
	      bufp->symbol_value += text_offset;
	      bufp->symbol_value = SMASH_TEXT_ADDRESS (bufp->symbol_value);
	      break;

	    case ST_ENTRY:
	      symname = bufp->name.n_strx + stringtab;
	      /* For a dynamic executable, ST_ENTRY symbols are
	         the stubs, while the ST_CODE symbol is the real
	         function.  */
	      if (dynamic)
		ms_type = mst_solib_trampoline;
	      else
		ms_type = mst_text;
	      bufp->symbol_value += text_offset;
	      bufp->symbol_value = SMASH_TEXT_ADDRESS (bufp->symbol_value);
	      break;

	    case ST_STUB:
	      symname = bufp->name.n_strx + stringtab;
	      ms_type = mst_solib_trampoline;
	      bufp->symbol_value += text_offset;
	      bufp->symbol_value = SMASH_TEXT_ADDRESS (bufp->symbol_value);
	      break;

	    case ST_DATA:
	      symname = bufp->name.n_strx + stringtab;
	      bufp->symbol_value += data_offset;
	      ms_type = mst_data;
	      break;
	    default:
	      continue;
	    }
	  break;

#if 0
	  /* SS_GLOBAL and SS_LOCAL are two names for the same thing (!).  */
	case SS_GLOBAL:
#endif
	case SS_LOCAL:
	  switch (bufp->symbol_type)
	    {
	    case ST_SYM_EXT:
	    case ST_ARG_EXT:
	      continue;

	    case ST_CODE:
	      symname = bufp->name.n_strx + stringtab;
	      ms_type = mst_file_text;
	      bufp->symbol_value += text_offset;
	      bufp->symbol_value = SMASH_TEXT_ADDRESS (bufp->symbol_value);

	    check_strange_names:
	      /* Utah GCC 2.5, FSF GCC 2.6 and later generate correct local
	         label prefixes for stabs, constant data, etc.  So we need
	         only filter out L$ symbols which are left in due to
	         limitations in how GAS generates SOM relocations.

	         When linking in the HPUX C-library the HP linker has
	         the nasty habit of placing section symbols from the literal
	         subspaces in the middle of the program's text.  Filter
	         those out as best we can.  Check for first and last character
	         being '$'. 

	         And finally, the newer HP compilers emit crud like $PIC_foo$N
	         in some circumstance (PIC code I guess).  It's also claimed
	         that they emit D$ symbols too.  What stupidity.  */
	      if ((symname[0] == 'L' && symname[1] == '$')
	      || (symname[0] == '$' && symname[strlen (symname) - 1] == '$')
		  || (symname[0] == 'D' && symname[1] == '$')
		  || (strncmp (symname, "L0\001", 3) == 0)
		  || (strncmp (symname, "$PIC", 4) == 0))
		continue;
	      break;

	    case ST_PRI_PROG:
	    case ST_SEC_PROG:
	    case ST_MILLICODE:
	      symname = bufp->name.n_strx + stringtab;
	      ms_type = mst_file_text;
	      bufp->symbol_value += text_offset;
	      bufp->symbol_value = SMASH_TEXT_ADDRESS (bufp->symbol_value);
	      break;

	    case ST_ENTRY:
	      symname = bufp->name.n_strx + stringtab;
	      /* SS_LOCAL symbols in a shared library do not have
		 export stubs, so we do not have to worry about
		 using mst_file_text vs mst_solib_trampoline here like
		 we do for SS_UNIVERSAL and SS_EXTERNAL symbols above.  */
	      ms_type = mst_file_text;
	      bufp->symbol_value += text_offset;
	      bufp->symbol_value = SMASH_TEXT_ADDRESS (bufp->symbol_value);
	      break;

	    case ST_STUB:
	      symname = bufp->name.n_strx + stringtab;
	      ms_type = mst_solib_trampoline;
	      bufp->symbol_value += text_offset;
	      bufp->symbol_value = SMASH_TEXT_ADDRESS (bufp->symbol_value);
	      break;


	    case ST_DATA:
	      symname = bufp->name.n_strx + stringtab;
	      bufp->symbol_value += data_offset;
	      ms_type = mst_file_data;
	      goto check_strange_names;

	    default:
	      continue;
	    }
	  break;

	  /* This can happen for common symbols when -E is passed to the
	     final link.  No idea _why_ that would make the linker force
	     common symbols to have an SS_UNSAT scope, but it does.

	     This also happens for weak symbols, but their type is
	     ST_DATA.  */
	case SS_UNSAT:
	  switch (bufp->symbol_type)
	    {
	    case ST_STORAGE:
	    case ST_DATA:
	      symname = bufp->name.n_strx + stringtab;
	      bufp->symbol_value += data_offset;
	      ms_type = mst_data;
	      break;

	    default:
	      continue;
	    }
	  break;

	default:
	  continue;
	}

      if (bufp->name.n_strx > obj_som_stringtab_size (abfd))
	error ("Invalid symbol data; bad HP string table offset: %d",
	       bufp->name.n_strx);

      prim_record_minimal_symbol (symname, bufp->symbol_value, ms_type,
				  objfile);
    }
}
Esempio n. 9
0
void
read_pe_exported_syms (struct objfile *objfile)
{
  bfd *dll = objfile->obfd;
  unsigned long pe_header_offset, opthdr_ofs, num_entries, i;
  unsigned long export_rva, export_size, nsections, secptr, expptr;
  unsigned long exp_funcbase;
  unsigned char *expdata, *erva;
  unsigned long name_rvas, ordinals, nexp, ordbase;
  char *dll_name;

  /* Array elements are for text, data and bss in that order
     Initialization with start_rva > end_rva guarantees that
     unused sections won't be matched. */
  struct read_pe_section_data section_data[PE_SECTION_TABLE_SIZE]
    = { {0, 1, 0, mst_text},
  {0, 1, 0, mst_data},
  {0, 1, 0, mst_bss}
  };

  struct cleanup *back_to = 0;

  char const *target = bfd_get_target (objfile->obfd);

  if ((strcmp (target, "pe-i386") != 0) && (strcmp (target, "pei-i386") != 0))
    {
      /* This is not an i386 format file. Abort now, because the code
         is untested on anything else. *FIXME* test on further
         architectures and loosen or remove this test. */
      return;
    }

  /* Get pe_header, optional header and numbers of export entries.  */
  pe_header_offset = pe_get32 (dll, 0x3c);
  opthdr_ofs = pe_header_offset + 4 + 20;
  num_entries = pe_get32 (dll, opthdr_ofs + 92);

  if (num_entries < 1)		/* No exports.  */
    {
      return;
    }

  export_rva = pe_get32 (dll, opthdr_ofs + 96);
  export_size = pe_get32 (dll, opthdr_ofs + 100);
  nsections = pe_get16 (dll, pe_header_offset + 4 + 2);
  secptr = (pe_header_offset + 4 + 20 +
	    pe_get16 (dll, pe_header_offset + 4 + 16));
  expptr = 0;

  /* Get the rva and size of the export section.  */
  for (i = 0; i < nsections; i++)
    {
      char sname[8];
      unsigned long secptr1 = secptr + 40 * i;
      unsigned long vaddr = pe_get32 (dll, secptr1 + 12);
      unsigned long vsize = pe_get32 (dll, secptr1 + 16);
      unsigned long fptr = pe_get32 (dll, secptr1 + 20);

      bfd_seek (dll, (file_ptr) secptr1, SEEK_SET);
      bfd_bread (sname, (bfd_size_type) 8, dll);

      if (vaddr <= export_rva && vaddr + vsize > export_rva)
	{
	  expptr = fptr + (export_rva - vaddr);
	  if (export_rva + export_size > vaddr + vsize)
	    export_size = vsize - (export_rva - vaddr);
	  break;
	}
    }

  if (export_size == 0)
    {
      /* Empty export table. */
      return;
    }

  /* Scan sections and store the base and size of the relevant sections. */
  for (i = 0; i < nsections; i++)
    {
      unsigned long secptr1 = secptr + 40 * i;
      unsigned long vsize = pe_get32 (dll, secptr1 + 8);
      unsigned long vaddr = pe_get32 (dll, secptr1 + 12);
      unsigned long flags = pe_get32 (dll, secptr1 + 36);
      char sec_name[9];
      int sectix;

      sec_name[8] = '\0';
      bfd_seek (dll, (file_ptr) secptr1 + 0, SEEK_SET);
      bfd_bread (sec_name, (bfd_size_type) 8, dll);

      sectix = read_pe_section_index (sec_name);

      if (sectix != PE_SECTION_INDEX_INVALID)
	{
	  section_data[sectix].rva_start = vaddr;
	  section_data[sectix].rva_end = vaddr + vsize;
	}
    }

  expdata = (unsigned char *) xmalloc (export_size);
  back_to = make_cleanup (xfree, expdata);

  bfd_seek (dll, (file_ptr) expptr, SEEK_SET);
  bfd_bread (expdata, (bfd_size_type) export_size, dll);
  erva = expdata - export_rva;

  nexp = pe_as32 (expdata + 24);
  name_rvas = pe_as32 (expdata + 32);
  ordinals = pe_as32 (expdata + 36);
  ordbase = pe_as32 (expdata + 16);
  exp_funcbase = pe_as32 (expdata + 28);

  /* Use internal dll name instead of full pathname. */
  dll_name = pe_as32 (expdata + 12) + erva;

  bfd_map_over_sections (dll, get_section_vmas, section_data);

  /* Adjust the vma_offsets in case this PE got relocated. This
     assumes that *all* sections share the same relocation offset
     as the text section. */
  for (i = 0; i < PE_SECTION_TABLE_SIZE; i++)
    {
      section_data[i].vma_offset
	+= ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
    }

  printf_filtered ("Minimal symbols from %s...", dll_name);
  wrap_here ("");

  /* Truncate name at first dot. Should maybe also convert to all
     lower case for convenience on Windows. */
  read_pe_truncate_name (dll_name);

  /* Iterate through the list of symbols.  */
  for (i = 0; i < nexp; i++)
    {
      /* Pointer to the names vector.  */
      unsigned long name_rva = pe_as32 (erva + name_rvas + i * 4);

      /* Pointer to the function address vector.  */
      unsigned long func_rva = pe_as32 (erva + exp_funcbase + i * 4);

      /* Find this symbol's section in our own array. */
      int sectix = 0;

      for (sectix = 0; sectix < PE_SECTION_TABLE_SIZE; ++sectix)
	{
	  if ((func_rva >= section_data[sectix].rva_start)
	      && (func_rva < section_data[sectix].rva_end))
	    {
	      add_pe_exported_sym (erva + name_rva,
				   func_rva,
				   section_data + sectix, dll_name, objfile);
	      break;
	    }
	}
    }

  /* discard expdata. */
  do_cleanups (back_to);
}
Esempio n. 10
0
static struct mdebug_extra_func_info *
non_heuristic_proc_desc (CORE_ADDR pc, CORE_ADDR *addrptr)
{
    CORE_ADDR startaddr;
    struct mdebug_extra_func_info *proc_desc;
    struct block *b = block_for_pc (pc);
    struct symbol *sym;
    struct obj_section *sec;
    struct mips_objfile_private *priv;

    find_pc_partial_function (pc, NULL, &startaddr, NULL);
    if (addrptr)
        *addrptr = startaddr;

    priv = NULL;

    sec = find_pc_section (pc);
    if (sec != NULL)
    {
        priv = (struct mips_objfile_private *) objfile_data (sec->objfile, mips_pdr_data);

        /* Search the ".pdr" section generated by GAS.  This includes most of
           the information normally found in ECOFF PDRs.  */

        the_bfd = sec->objfile->obfd;
        if (priv == NULL
                && (the_bfd->format == bfd_object
                    && bfd_get_flavour (the_bfd) == bfd_target_elf_flavour
                    && elf_elfheader (the_bfd)->e_ident[EI_CLASS] == ELFCLASS64))
        {
            /* Right now GAS only outputs the address as a four-byte sequence.
               This means that we should not bother with this method on 64-bit
               targets (until that is fixed).  */

            priv = obstack_alloc (&sec->objfile->objfile_obstack,
                                  sizeof (struct mips_objfile_private));
            priv->size = 0;
            set_objfile_data (sec->objfile, mips_pdr_data, priv);
        }
        else if (priv == NULL)
        {
            asection *bfdsec;

            priv = obstack_alloc (&sec->objfile->objfile_obstack,
                                  sizeof (struct mips_objfile_private));

            bfdsec = bfd_get_section_by_name (sec->objfile->obfd, ".pdr");
            if (bfdsec != NULL)
            {
                priv->size = bfd_section_size (sec->objfile->obfd, bfdsec);
                priv->contents = obstack_alloc (&sec->objfile->objfile_obstack,
                                                priv->size);
                bfd_get_section_contents (sec->objfile->obfd, bfdsec,
                                          priv->contents, 0, priv->size);

                /* In general, the .pdr section is sorted.  However, in the
                   presence of multiple code sections (and other corner cases)
                   it can become unsorted.  Sort it so that we can use a faster
                   binary search.  */
                qsort (priv->contents, priv->size / 32, 32,
                       compare_pdr_entries);
            }
            else
                priv->size = 0;

            set_objfile_data (sec->objfile, mips_pdr_data, priv);
        }
        the_bfd = NULL;

        if (priv->size != 0)
        {
            int low, mid, high;
            char *ptr;
            CORE_ADDR pdr_pc;

            low = 0;
            high = priv->size / 32;

            /* We've found a .pdr section describing this objfile.  We want to
               find the entry which describes this code address.  The .pdr
               information is not very descriptive; we have only a function
               start address.  We have to look for the closest entry, because
               the local symbol at the beginning of this function may have
               been stripped - so if we ask the symbol table for the start
               address we may get a preceding global function.  */

            /* First, find the last .pdr entry starting at or before PC.  */
            do
            {
                mid = (low + high) / 2;

                ptr = priv->contents + mid * 32;
                pdr_pc = bfd_get_signed_32 (sec->objfile->obfd, ptr);
                pdr_pc += ANOFFSET (sec->objfile->section_offsets,
                                    SECT_OFF_TEXT (sec->objfile));

                if (pdr_pc > pc)
                    high = mid;
                else
                    low = mid + 1;
            }
            while (low != high);

            /* Both low and high point one past the PDR of interest.  If
               both are zero, that means this PC is before any region
               covered by a PDR, i.e. pdr_pc for the first PDR entry is
               greater than PC.  */
            if (low > 0)
            {
                ptr = priv->contents + (low - 1) * 32;
                pdr_pc = bfd_get_signed_32 (sec->objfile->obfd, ptr);
                pdr_pc += ANOFFSET (sec->objfile->section_offsets,
                                    SECT_OFF_TEXT (sec->objfile));
            }

            /* We don't have a range, so we have no way to know for sure
               whether we're in the correct PDR or a PDR for a preceding
               function and the current function was a stripped local
               symbol.  But if the PDR's PC is at least as great as the
               best guess from the symbol table, assume that it does cover
               the right area; if a .pdr section is present at all then
               nearly every function will have an entry.  The biggest exception
               will be the dynamic linker stubs; conveniently these are
               placed before .text instead of after.  */

            if (pc >= pdr_pc && pdr_pc >= startaddr)
            {
                struct symbol *sym = find_pc_function (pc);

                if (addrptr)
                    *addrptr = pdr_pc;

                /* Fill in what we need of the proc_desc.  */
                proc_desc = (struct mdebug_extra_func_info *)
                            obstack_alloc (&sec->objfile->objfile_obstack,
                                           sizeof (struct mdebug_extra_func_info));
                PROC_LOW_ADDR (proc_desc) = pdr_pc;

                PROC_FRAME_OFFSET (proc_desc)
                    = bfd_get_signed_32 (sec->objfile->obfd, ptr + 20);
                PROC_FRAME_REG (proc_desc) = bfd_get_32 (sec->objfile->obfd,
                                             ptr + 24);
                PROC_REG_MASK (proc_desc) = bfd_get_32 (sec->objfile->obfd,
                                                        ptr + 4);
                PROC_FREG_MASK (proc_desc) = bfd_get_32 (sec->objfile->obfd,
                                             ptr + 12);
                PROC_REG_OFFSET (proc_desc)
                    = bfd_get_signed_32 (sec->objfile->obfd, ptr + 8);
                PROC_FREG_OFFSET (proc_desc)
                    = bfd_get_signed_32 (sec->objfile->obfd, ptr + 16);
                PROC_PC_REG (proc_desc) = bfd_get_32 (sec->objfile->obfd,
                                                      ptr + 28);
                proc_desc->pdr.isym = (long) sym;

                return proc_desc;
            }
        }
    }

    if (b == NULL)
        return NULL;

    if (startaddr > BLOCK_START (b))
    {
        /* This is the "pathological" case referred to in a comment in
           print_frame_info.  It might be better to move this check into
           symbol reading.  */
        return NULL;
    }

    sym = lookup_symbol (MDEBUG_EFI_SYMBOL_NAME, b, LABEL_DOMAIN, 0);

    /* If we never found a PDR for this function in symbol reading, then
       examine prologues to find the information.  */
    if (sym)
    {
        proc_desc = (struct mdebug_extra_func_info *) SYMBOL_VALUE (sym);
        if (PROC_FRAME_REG (proc_desc) == -1)
            return NULL;
        else
            return proc_desc;
    }
    else
        return NULL;
}
Esempio n. 11
0
static void
read_alphacoff_dynamic_symtab (struct section_offsets *section_offsets,
			       struct objfile *objfile)
{
  bfd *abfd = objfile->obfd;
  struct alphacoff_dynsecinfo si;
  char *sym_secptr;
  char *str_secptr;
  char *dyninfo_secptr;
  char *got_secptr;
  bfd_size_type sym_secsize;
  bfd_size_type str_secsize;
  bfd_size_type dyninfo_secsize;
  bfd_size_type got_secsize;
  int sym_count;
  int i;
  int stripped;
  Elfalpha_External_Sym *x_symp;
  char *dyninfo_p;
  char *dyninfo_end;
  int got_entry_size = 8;
  int dt_mips_local_gotno = -1;
  int dt_mips_gotsym = -1;
  struct cleanup *cleanups;

  /* We currently only know how to handle alpha dynamic symbols.  */
  if (bfd_get_arch (abfd) != bfd_arch_alpha)
    return;

  /* Locate the dynamic symbols sections and read them in.  */
  memset ((char *) &si, 0, sizeof (si));
  bfd_map_over_sections (abfd, alphacoff_locate_sections, (void *) & si);
  if (si.sym_sect == NULL || si.str_sect == NULL
      || si.dyninfo_sect == NULL || si.got_sect == NULL)
    return;

  sym_secsize = bfd_get_section_size (si.sym_sect);
  str_secsize = bfd_get_section_size (si.str_sect);
  dyninfo_secsize = bfd_get_section_size (si.dyninfo_sect);
  got_secsize = bfd_get_section_size (si.got_sect);
  sym_secptr = xmalloc (sym_secsize);
  cleanups = make_cleanup (xfree, sym_secptr);
  str_secptr = xmalloc (str_secsize);
  make_cleanup (xfree, str_secptr);
  dyninfo_secptr = xmalloc (dyninfo_secsize);
  make_cleanup (xfree, dyninfo_secptr);
  got_secptr = xmalloc (got_secsize);
  make_cleanup (xfree, got_secptr);

  if (!bfd_get_section_contents (abfd, si.sym_sect, sym_secptr,
				 (file_ptr) 0, sym_secsize))
    return;
  if (!bfd_get_section_contents (abfd, si.str_sect, str_secptr,
				 (file_ptr) 0, str_secsize))
    return;
  if (!bfd_get_section_contents (abfd, si.dyninfo_sect, dyninfo_secptr,
				 (file_ptr) 0, dyninfo_secsize))
    return;
  if (!bfd_get_section_contents (abfd, si.got_sect, got_secptr,
				 (file_ptr) 0, got_secsize))
    return;

  /* Find the number of local GOT entries and the index for the the
     first dynamic symbol in the GOT.  */
  for (dyninfo_p = dyninfo_secptr, dyninfo_end = dyninfo_p + dyninfo_secsize;
       dyninfo_p < dyninfo_end;
       dyninfo_p += sizeof (Elfalpha_External_Dyn))
    {
      Elfalpha_External_Dyn *x_dynp = (Elfalpha_External_Dyn *) dyninfo_p;
      long dyn_tag;

      dyn_tag = bfd_h_get_32 (abfd, (bfd_byte *) x_dynp->d_tag);
      if (dyn_tag == DT_NULL)
	break;
      else if (dyn_tag == DT_MIPS_LOCAL_GOTNO)
	{
	  if (dt_mips_local_gotno < 0)
	    dt_mips_local_gotno
	      = bfd_h_get_32 (abfd, (bfd_byte *) x_dynp->d_un.d_val);
	}
      else if (dyn_tag == DT_MIPS_GOTSYM)
	{
	  if (dt_mips_gotsym < 0)
	    dt_mips_gotsym
	      = bfd_h_get_32 (abfd, (bfd_byte *) x_dynp->d_un.d_val);
	}
    }
  if (dt_mips_local_gotno < 0 || dt_mips_gotsym < 0)
    return;

  /* Scan all dynamic symbols and enter them into the minimal symbol
     table if appropriate.  */
  sym_count = sym_secsize / sizeof (Elfalpha_External_Sym);
  stripped = (bfd_get_symcount (abfd) == 0);

  /* Skip first symbol, which is a null dummy.  */
  for (i = 1, x_symp = (Elfalpha_External_Sym *) sym_secptr + 1;
       i < sym_count;
       i++, x_symp++)
    {
      unsigned long strx;
      char *name;
      bfd_vma sym_value;
      unsigned char sym_info;
      unsigned int sym_shndx;
      int isglobal;
      enum minimal_symbol_type ms_type;

      strx = bfd_h_get_32 (abfd, (bfd_byte *) x_symp->st_name);
      if (strx >= str_secsize)
	continue;
      name = str_secptr + strx;
      if (*name == '\0' || *name == '.')
	continue;

      sym_value = bfd_h_get_64 (abfd, (bfd_byte *) x_symp->st_value);
      sym_info = bfd_h_get_8 (abfd, (bfd_byte *) x_symp->st_info);
      sym_shndx = bfd_h_get_16 (abfd, (bfd_byte *) x_symp->st_shndx);
      if (sym_shndx >= (SHN_LORESERVE & 0xffff))
	sym_shndx += SHN_LORESERVE - (SHN_LORESERVE & 0xffff);
      isglobal = (ELF_ST_BIND (sym_info) == STB_GLOBAL);

      if (sym_shndx == SHN_UNDEF)
	{
	  /* Handle undefined functions which are defined in a shared
	     library.  */
	  if (ELF_ST_TYPE (sym_info) != STT_FUNC
	      || ELF_ST_BIND (sym_info) != STB_GLOBAL)
	    continue;

	  ms_type = mst_solib_trampoline;

	  /* If sym_value is nonzero, it points to the shared library
	     trampoline entry, which is what we are looking for.

	     If sym_value is zero, then we have to get the GOT entry
	     for the symbol.

	     If the GOT entry is nonzero, it represents the quickstart
	     address of the function and we use that as the symbol
	     value.

	     If the GOT entry is zero, the function address has to be
	     resolved by the runtime loader before the executable is
	     started.  We are unable to find any meaningful address
	     for these functions in the executable file, so we skip
	     them.  */
	  if (sym_value == 0)
	    {
	      int got_entry_offset =
		(i - dt_mips_gotsym + dt_mips_local_gotno) * got_entry_size;

	      if (got_entry_offset < 0 || got_entry_offset >= got_secsize)
		continue;
	      sym_value =
		bfd_h_get_64 (abfd,
			      (bfd_byte *) (got_secptr + got_entry_offset));
	      if (sym_value == 0)
		continue;
	    }
	}
      else
	{
	  /* Symbols defined in the executable itself. We only care
	     about them if this is a stripped executable, otherwise
	     they have been retrieved from the normal symbol table
	     already.  */
	  if (!stripped)
	    continue;

	  if (sym_shndx == SHN_MIPS_TEXT)
	    {
	      if (isglobal)
		ms_type = mst_text;
	      else
		ms_type = mst_file_text;
	      sym_value += ANOFFSET (section_offsets, SECT_OFF_TEXT (objfile));
	    }
	  else if (sym_shndx == SHN_MIPS_DATA)
	    {
	      if (isglobal)
		ms_type = mst_data;
	      else
		ms_type = mst_file_data;
	      sym_value += ANOFFSET (section_offsets, SECT_OFF_DATA (objfile));
	    }
	  else if (sym_shndx == SHN_MIPS_ACOMMON)
	    {
	      if (isglobal)
		ms_type = mst_bss;
	      else
		ms_type = mst_file_bss;
	      sym_value += ANOFFSET (section_offsets, SECT_OFF_BSS (objfile));
	    }
	  else if (sym_shndx == SHN_ABS)
	    {
	      ms_type = mst_abs;
	    }
	  else
	    {
	      continue;
	    }
	}

      prim_record_minimal_symbol (name, sym_value, ms_type, objfile);
    }

  do_cleanups (cleanups);
}
Esempio n. 12
0
static void
elf_symtab_read (struct objfile *objfile, int dynamic)
{
  long storage_needed;
  asymbol *sym;
  asymbol **symbol_table;
  long number_of_symbols;
  long i;
  int index;
  struct cleanup *back_to;
  CORE_ADDR symaddr;
  CORE_ADDR offset;
  enum minimal_symbol_type ms_type;
  /* If sectinfo is nonNULL, it contains section info that should end up
     filed in the objfile.  */
  struct stab_section_info *sectinfo = NULL;
  /* If filesym is nonzero, it points to a file symbol, but we haven't
     seen any section info for it yet.  */
  asymbol *filesym = 0;
#ifdef SOFUN_ADDRESS_MAYBE_MISSING
  /* Name of filesym, as saved on the symbol_obstack.  */
  char *filesymname = obsavestring ("", 0, &objfile->symbol_obstack);
#endif
  struct dbx_symfile_info *dbx = objfile->sym_stab_info;
  unsigned long size;
  int stripped = (bfd_get_symcount (objfile->obfd) == 0);

  if (dynamic)
    {
      storage_needed = bfd_get_dynamic_symtab_upper_bound (objfile->obfd);

      /* Nothing to be done if there is no dynamic symtab.  */
      if (storage_needed < 0)
	return;
    }
  else
    {
      storage_needed = bfd_get_symtab_upper_bound (objfile->obfd);
      if (storage_needed < 0)
	error ("Can't read symbols from %s: %s", bfd_get_filename (objfile->obfd),
	       bfd_errmsg (bfd_get_error ()));
    }
  if (storage_needed > 0)
    {
      symbol_table = (asymbol **) xmalloc (storage_needed);
      back_to = make_cleanup (xfree, symbol_table);
      if (dynamic)
	number_of_symbols = bfd_canonicalize_dynamic_symtab (objfile->obfd,
							     symbol_table);
      else
	number_of_symbols = bfd_canonicalize_symtab (objfile->obfd, symbol_table);
      if (number_of_symbols < 0)
	error ("Can't read symbols from %s: %s", bfd_get_filename (objfile->obfd),
	       bfd_errmsg (bfd_get_error ()));

      for (i = 0; i < number_of_symbols; i++)
	{
	  sym = symbol_table[i];
	  if (sym->name == NULL || *sym->name == '\0')
	    {
	      /* Skip names that don't exist (shouldn't happen), or names
	         that are null strings (may happen). */
	      continue;
	    }

          offset = ANOFFSET (objfile->section_offsets, sym->section->index);
	  if (dynamic
	      && sym->section == &bfd_und_section
	      && (sym->flags & BSF_FUNCTION))
	    {
	      struct minimal_symbol *msym;

	      /* Symbol is a reference to a function defined in
	         a shared library.
	         If its value is non zero then it is usually the address
	         of the corresponding entry in the procedure linkage table,
	         plus the desired section offset.
	         If its value is zero then the dynamic linker has to resolve
	         the symbol. We are unable to find any meaningful address
	         for this symbol in the executable file, so we skip it.  */
	      symaddr = sym->value;
	      if (symaddr == 0)
		continue;
	      symaddr += offset;
	      msym = record_minimal_symbol_and_info
		((char *) sym->name, symaddr,
		 mst_solib_trampoline, NULL, sym->section, objfile);
#ifdef SOFUN_ADDRESS_MAYBE_MISSING
	      if (msym != NULL)
		msym->filename = filesymname;
#endif
	      continue;
	    }

	  /* If it is a nonstripped executable, do not enter dynamic
	     symbols, as the dynamic symbol table is usually a subset
	     of the main symbol table.  */
	  if (dynamic && !stripped)
	    continue;
	  if (sym->flags & BSF_FILE)
	    {
	      /* STT_FILE debugging symbol that helps stabs-in-elf debugging.
	         Chain any old one onto the objfile; remember new sym.  */
	      if (sectinfo != NULL)
		{
		  sectinfo->next = dbx->stab_section_info;
		  dbx->stab_section_info = sectinfo;
		  sectinfo = NULL;
		}
	      filesym = sym;
#ifdef SOFUN_ADDRESS_MAYBE_MISSING
	      filesymname =
		obsavestring ((char *) filesym->name, strlen (filesym->name),
			      &objfile->symbol_obstack);
#endif
	    }
	  else if (sym->flags & (BSF_GLOBAL | BSF_LOCAL | BSF_WEAK))
	    {
	      struct minimal_symbol *msym;

	      /* Select global/local/weak symbols.  Note that bfd puts abs
	         symbols in their own section, so all symbols we are
	         interested in will have a section. */
	      /* Bfd symbols are section relative. */
	      symaddr = sym->value + sym->section->vma;
	      /* Relocate all non-absolute symbols by the section offset.  */
	      if (sym->section != &bfd_abs_section)
		{
		  symaddr += offset;
		}
	      /* For non-absolute symbols, use the type of the section
	         they are relative to, to intuit text/data.  Bfd provides
	         no way of figuring this out for absolute symbols. */
	      if (sym->section == &bfd_abs_section)
		{
		  /* This is a hack to get the minimal symbol type
		     right for Irix 5, which has absolute addresses
		     with special section indices for dynamic symbols. */
		  unsigned short shndx =
		  ((elf_symbol_type *) sym)->internal_elf_sym.st_shndx;

		  switch (shndx)
		    {
		    case SHN_MIPS_TEXT:
		      ms_type = mst_text;
		      break;
		    case SHN_MIPS_DATA:
		      ms_type = mst_data;
		      break;
		    case SHN_MIPS_ACOMMON:
		      ms_type = mst_bss;
		      break;
		    default:
		      ms_type = mst_abs;
		    }

		  /* If it is an Irix dynamic symbol, skip section name
		     symbols, relocate all others by section offset. */
		  if (ms_type != mst_abs)
		    {
		      if (sym->name[0] == '.')
			continue;
		      symaddr += offset;
		    }
		}
	      else if (sym->section->flags & SEC_CODE)
		{
		  if (sym->flags & BSF_GLOBAL)
		    {
		      ms_type = mst_text;
		    }
		  else if ((sym->name[0] == '.' && sym->name[1] == 'L')
			   || ((sym->flags & BSF_LOCAL)
			       && sym->name[0] == '$'
			       && sym->name[1] == 'L'))
		    /* Looks like a compiler-generated label.  Skip
		       it.  The assembler should be skipping these (to
		       keep executables small), but apparently with
		       gcc on the (OBSOLETE) delta m88k SVR4, it
		       loses.  So to have us check too should be
		       harmless (but I encourage people to fix this in
		       the assembler instead of adding checks here).  */
		    continue;
		  else
		    {
		      ms_type = mst_file_text;
		    }
		}
	      else if (sym->section->flags & SEC_ALLOC)
		{
		  if (sym->flags & (BSF_GLOBAL | BSF_WEAK))
		    {
		      if (sym->section->flags & SEC_LOAD)
			{
			  ms_type = mst_data;
			}
		      else
			{
			  ms_type = mst_bss;
			}
		    }
		  else if (sym->flags & BSF_LOCAL)
		    {
		      /* Named Local variable in a Data section.  Check its
		         name for stabs-in-elf.  The STREQ macro checks the
		         first character inline, so we only actually do a
		         strcmp function call on names that start with 'B'
		         or 'D' */
		      index = SECT_OFF_MAX;
		      if (STREQ ("Bbss.bss", sym->name))
			{
			  index = SECT_OFF_BSS (objfile);
			}
		      else if (STREQ ("Ddata.data", sym->name))
			{
			  index = SECT_OFF_DATA (objfile);
			}
		      else if (STREQ ("Drodata.rodata", sym->name))
			{
			  index = SECT_OFF_RODATA (objfile);
			}
		      if (index != SECT_OFF_MAX)
			{
			  /* Found a special local symbol.  Allocate a
			     sectinfo, if needed, and fill it in.  */
			  if (sectinfo == NULL)
			    {
			      sectinfo = (struct stab_section_info *)
				xmmalloc (objfile->md, sizeof (*sectinfo));
			      memset (sectinfo, 0,
				      sizeof (*sectinfo));
			      if (filesym == NULL)
				{
				  complain (&section_info_complaint,
					    sym->name);
				}
			      else
				{
				  sectinfo->filename =
				    (char *) filesym->name;
				}
			    }
			  if (index != -1)
			    { 
			      if (sectinfo->sections[index] != 0)
				{
				  complain (&section_info_dup_complaint,
					    sectinfo->filename);
				}
			    }
			  else
			    internal_error (__FILE__, __LINE__,
					    "Section index uninitialized.");
			  /* Bfd symbols are section relative. */
			  symaddr = sym->value + sym->section->vma;
			  /* Relocate non-absolute symbols by the section offset. */
			  if (sym->section != &bfd_abs_section)
			    {
			      symaddr += offset;
			    }
			  if (index != -1)
			    sectinfo->sections[index] = symaddr;
			  else
			    internal_error (__FILE__, __LINE__,
					    "Section index uninitialized.");
			  /* The special local symbols don't go in the
			     minimal symbol table, so ignore this one. */
			  continue;
			}
		      /* Not a special stabs-in-elf symbol, do regular
		         symbol processing. */
		      if (sym->section->flags & SEC_LOAD)
			{
			  ms_type = mst_file_data;
			}
		      else
			{
			  ms_type = mst_file_bss;
			}
		    }
		  else
		    {
		      ms_type = mst_unknown;
		    }
		}
	      else
		{
		  /* FIXME:  Solaris2 shared libraries include lots of
		     odd "absolute" and "undefined" symbols, that play 
		     hob with actions like finding what function the PC
		     is in.  Ignore them if they aren't text, data, or bss.  */
		  /* ms_type = mst_unknown; */
		  continue;	/* Skip this symbol. */
		}
	      /* Pass symbol size field in via BFD.  FIXME!!!  */
	      size = ((elf_symbol_type *) sym)->internal_elf_sym.st_size;
	      msym = record_minimal_symbol_and_info
		((char *) sym->name, symaddr,
		 ms_type, (void *) size, sym->section, objfile);
#ifdef SOFUN_ADDRESS_MAYBE_MISSING
	      if (msym != NULL)
		msym->filename = filesymname;
#endif
	      ELF_MAKE_MSYMBOL_SPECIAL (sym, msym);
	    }
	}
      do_cleanups (back_to);
    }
}
Esempio n. 13
0
static void
som_symtab_read (bfd *abfd, struct objfile *objfile,
                 struct section_offsets *section_offsets)
{
    struct cleanup *cleanup;
    struct gdbarch *gdbarch = get_objfile_arch (objfile);
    unsigned int number_of_symbols;
    int val, dynamic;
    char *stringtab;
    asection *shlib_info;
    struct som_external_symbol_dictionary_record *buf, *bufp, *endbufp;
    char *symname;
    const int symsize = sizeof (struct som_external_symbol_dictionary_record);


    number_of_symbols = bfd_get_symcount (abfd);

    /* Allocate a buffer to read in the debug info.
       We avoid using alloca because the memory size could be so large
       that we could hit the stack size limit.  */
    buf = xmalloc (symsize * number_of_symbols);
    cleanup = make_cleanup (xfree, buf);
    bfd_seek (abfd, obj_som_sym_filepos (abfd), SEEK_SET);
    val = bfd_bread (buf, symsize * number_of_symbols, abfd);
    if (val != symsize * number_of_symbols)
        error (_("Couldn't read symbol dictionary!"));

    /* Allocate a buffer to read in the som stringtab section of
       the debugging info.  Again, we avoid using alloca because
       the data could be so large that we could potentially hit
       the stack size limitat.  */
    stringtab = xmalloc (obj_som_stringtab_size (abfd));
    make_cleanup (xfree, stringtab);
    bfd_seek (abfd, obj_som_str_filepos (abfd), SEEK_SET);
    val = bfd_bread (stringtab, obj_som_stringtab_size (abfd), abfd);
    if (val != obj_som_stringtab_size (abfd))
        error (_("Can't read in HP string table."));

    /* We need to determine if objfile is a dynamic executable (so we
       can do the right thing for ST_ENTRY vs ST_CODE symbols).

       There's nothing in the header which easily allows us to do
       this.

       This code used to rely upon the existence of a $SHLIB_INFO$
       section to make this determination.  HP claims that it is
       more accurate to check for a nonzero text offset, but they
       have not provided any information about why that test is
       more accurate.  */
    dynamic = (ANOFFSET (section_offsets, SECT_OFF_TEXT (objfile)) != 0);

    endbufp = buf + number_of_symbols;
    for (bufp = buf; bufp < endbufp; ++bufp)
    {
        enum minimal_symbol_type ms_type;
        unsigned int flags = bfd_getb32 (bufp->flags);
        unsigned int symbol_type
            = (flags >> SOM_SYMBOL_TYPE_SH) & SOM_SYMBOL_TYPE_MASK;
        unsigned int symbol_scope
            = (flags >> SOM_SYMBOL_SCOPE_SH) & SOM_SYMBOL_SCOPE_MASK;
        CORE_ADDR symbol_value = bfd_getb32 (bufp->symbol_value);
        asection *section = NULL;

        QUIT;

        /* Compute the section.  */
        switch (symbol_scope)
        {
        case SS_EXTERNAL:
            if (symbol_type != ST_STORAGE)
                section = bfd_und_section_ptr;
            else
                section = bfd_com_section_ptr;
            break;

        case SS_UNSAT:
            if (symbol_type != ST_STORAGE)
                section = bfd_und_section_ptr;
            else
                section = bfd_com_section_ptr;
            break;

        case SS_UNIVERSAL:
            section = bfd_section_from_som_symbol (abfd, bufp);
            break;

        case SS_LOCAL:
            section = bfd_section_from_som_symbol (abfd, bufp);
            break;
        }

        switch (symbol_scope)
        {
        case SS_UNIVERSAL:
        case SS_EXTERNAL:
            switch (symbol_type)
            {
            case ST_SYM_EXT:
            case ST_ARG_EXT:
                continue;

            case ST_CODE:
            case ST_PRI_PROG:
            case ST_SEC_PROG:
            case ST_MILLICODE:
                symname = bfd_getb32 (bufp->name) + stringtab;
                ms_type = mst_text;
                symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value);
                break;

            case ST_ENTRY:
                symname = bfd_getb32 (bufp->name) + stringtab;
                /* For a dynamic executable, ST_ENTRY symbols are
                   the stubs, while the ST_CODE symbol is the real
                   function.  */
                if (dynamic)
                    ms_type = mst_solib_trampoline;
                else
                    ms_type = mst_text;
                symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value);
                break;

            case ST_STUB:
                symname = bfd_getb32 (bufp->name) + stringtab;
                ms_type = mst_solib_trampoline;
                symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value);
                break;

            case ST_DATA:
                symname = bfd_getb32 (bufp->name) + stringtab;
                ms_type = mst_data;
                break;
            default:
                continue;
            }
            break;

#if 0
        /* SS_GLOBAL and SS_LOCAL are two names for the same thing (!).  */
        case SS_GLOBAL:
#endif
        case SS_LOCAL:
            switch (symbol_type)
            {
            case ST_SYM_EXT:
            case ST_ARG_EXT:
                continue;

            case ST_CODE:
                symname = bfd_getb32 (bufp->name) + stringtab;
                ms_type = mst_file_text;
                symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value);

check_strange_names:
                /* Utah GCC 2.5, FSF GCC 2.6 and later generate correct local
                   label prefixes for stabs, constant data, etc.  So we need
                   only filter out L$ symbols which are left in due to
                   limitations in how GAS generates SOM relocations.

                   When linking in the HPUX C-library the HP linker has
                   the nasty habit of placing section symbols from the literal
                   subspaces in the middle of the program's text.  Filter
                   those out as best we can.  Check for first and last character
                   being '$'.

                   And finally, the newer HP compilers emit crud like $PIC_foo$N
                   in some circumstance (PIC code I guess).  It's also claimed
                   that they emit D$ symbols too.  What stupidity.  */
                if ((symname[0] == 'L' && symname[1] == '$')
                        || (symname[0] == '$' && symname[strlen (symname) - 1] == '$')
                        || (symname[0] == 'D' && symname[1] == '$')
                        || (strncmp (symname, "L0\001", 3) == 0)
                        || (strncmp (symname, "$PIC", 4) == 0))
                    continue;
                break;

            case ST_PRI_PROG:
            case ST_SEC_PROG:
            case ST_MILLICODE:
                symname = bfd_getb32 (bufp->name) + stringtab;
                ms_type = mst_file_text;
                symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value);
                break;

            case ST_ENTRY:
                symname = bfd_getb32 (bufp->name) + stringtab;
                /* SS_LOCAL symbols in a shared library do not have
                export stubs, so we do not have to worry about
                 using mst_file_text vs mst_solib_trampoline here like
                 we do for SS_UNIVERSAL and SS_EXTERNAL symbols above.  */
                ms_type = mst_file_text;
                symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value);
                break;

            case ST_STUB:
                symname = bfd_getb32 (bufp->name) + stringtab;
                ms_type = mst_solib_trampoline;
                symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value);
                break;


            case ST_DATA:
                symname = bfd_getb32 (bufp->name) + stringtab;
                ms_type = mst_file_data;
                goto check_strange_names;

            default:
                continue;
            }
            break;

        /* This can happen for common symbols when -E is passed to the
           final link.  No idea _why_ that would make the linker force
           common symbols to have an SS_UNSAT scope, but it does.

           This also happens for weak symbols, but their type is
           ST_DATA.  */
        case SS_UNSAT:
            switch (symbol_type)
            {
            case ST_STORAGE:
            case ST_DATA:
                symname = bfd_getb32 (bufp->name) + stringtab;
                ms_type = mst_data;
                break;

            default:
                continue;
            }
            break;

        default:
            continue;
        }

        if (bfd_getb32 (bufp->name) > obj_som_stringtab_size (abfd))
            error (_("Invalid symbol data; bad HP string table offset: %s"),
                   plongest (bfd_getb32 (bufp->name)));

        if (bfd_is_const_section (section))
        {
            struct obj_section *iter;

            ALL_OBJFILE_OSECTIONS (objfile, iter)
            {
                CORE_ADDR start;
                CORE_ADDR len;

                if (bfd_is_const_section (iter->the_bfd_section))
                    continue;

                start = bfd_get_section_vma (iter->objfile->obfd,
                                             iter->the_bfd_section);
                len = bfd_get_section_size (iter->the_bfd_section);
                if (start <= symbol_value && symbol_value < start + len)
                {
                    section = iter->the_bfd_section;
                    break;
                }
            }
        }

        prim_record_minimal_symbol_and_info (symname, symbol_value, ms_type,
                                             gdb_bfd_section_index (objfile->obfd,
                                                     section),
                                             objfile);
    }
Esempio n. 14
0
static int
amd64_windows_find_unwind_info (struct gdbarch *gdbarch, CORE_ADDR pc,
				CORE_ADDR *unwind_info,
				CORE_ADDR *image_base,
				CORE_ADDR *start_rva,
				CORE_ADDR *end_rva)
{
  struct obj_section *sec;
  pe_data_type *pe;
  IMAGE_DATA_DIRECTORY *dir;
  struct objfile *objfile;
  unsigned long lo, hi;
  CORE_ADDR base;
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);

  /* Get the corresponding exception directory.  */
  sec = find_pc_section (pc);
  if (sec == NULL)
    return -1;
  objfile = sec->objfile;
  pe = pe_data (sec->objfile->obfd);
  dir = &pe->pe_opthdr.DataDirectory[PE_EXCEPTION_TABLE];

  base = pe->pe_opthdr.ImageBase
    + ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
  *image_base = base;

  /* Find the entry.

     Note: This does not handle dynamically added entries (for JIT
     engines).  For this, we would need to ask the kernel directly,
     which means getting some info from the native layer.  For the
     rest of the code, however, it's probably faster to search
     the entry ourselves.  */
  lo = 0;
  hi = dir->Size / sizeof (struct external_pex64_runtime_function);
  *unwind_info = 0;
  while (lo <= hi)
    {
      unsigned long mid = lo + (hi - lo) / 2;
      struct external_pex64_runtime_function d;
      CORE_ADDR sa, ea;

      if (target_read_memory (base + dir->VirtualAddress + mid * sizeof (d),
			      (gdb_byte *) &d, sizeof (d)) != 0)
	return -1;

      sa = extract_unsigned_integer (d.rva_BeginAddress, 4, byte_order);
      ea = extract_unsigned_integer (d.rva_EndAddress, 4, byte_order);
      if (pc < base + sa)
	hi = mid - 1;
      else if (pc >= base + ea)
	lo = mid + 1;
      else if (pc >= base + sa && pc < base + ea)
	{
	  /* Got it.  */
	  *start_rva = sa;
	  *end_rva = ea;
	  *unwind_info =
	    extract_unsigned_integer (d.rva_UnwindData, 4, byte_order);
	  break;
	}
      else
	break;
    }

  if (frame_debug)
    fprintf_unfiltered
      (gdb_stdlog,
       "amd64_windows_find_unwind_data:  image_base=%s, unwind_data=%s\n",
       paddress (gdbarch, base), paddress (gdbarch, *unwind_info));

  if (*unwind_info & 1)
    {
      /* Unofficially documented unwind info redirection, when UNWIND_INFO
	 address is odd (http://www.codemachine.com/article_x64deepdive.html).
      */
      struct external_pex64_runtime_function d;
      CORE_ADDR sa, ea;

      if (target_read_memory (base + (*unwind_info & ~1),
			      (gdb_byte *) &d, sizeof (d)) != 0)
	return -1;

      *start_rva =
	extract_unsigned_integer (d.rva_BeginAddress, 4, byte_order);
      *end_rva = extract_unsigned_integer (d.rva_EndAddress, 4, byte_order);
      *unwind_info =
	extract_unsigned_integer (d.rva_UnwindData, 4, byte_order);

    }
  return 0;
}