Thu Nov 19 16:02:46 1998 Dave Brolley <brolley@cygnus.com>
[deliverable/binutils-gdb.git] / bfd / elf.c
index c4417e2cb06a087bb13c260c69ff760c9d32557e..b4328c588fda113e7b8d9acd4ed438995439d3ac 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -199,8 +199,7 @@ _bfd_elf_swap_versym_out (abfd, src, dst)
 }
 
 /* Standard ELF hash function.  Do not change this function; you will
-   cause invalid hash tables to be generated.  (Well, you would if this
-   were being used yet.)  */
+   cause invalid hash tables to be generated.  */
 unsigned long
 bfd_elf_hash (name)
      CONST unsigned char *name;
@@ -215,7 +214,9 @@ bfd_elf_hash (name)
       if ((g = (h & 0xf0000000)) != 0)
        {
          h ^= g >> 24;
-         h &= ~g;
+         /* The ELF ABI says `h &= ~g', but this is equivalent in
+            this case and on some machines one insn instead of two.  */
+         h ^= g;
        }
     }
   return h;
@@ -1363,9 +1364,9 @@ bfd_section_from_phdr (abfd, hdr, index)
   char namebuf[64];
   int split;
 
-  split = ((hdr->p_memsz > 0) &&
-          (hdr->p_filesz > 0) &&
-          (hdr->p_memsz > hdr->p_filesz));
+  split = ((hdr->p_memsz > 0)
+           && (hdr->p_filesz > 0)
+           && (hdr->p_memsz > hdr->p_filesz));
   sprintf (namebuf, split ? "segment%da" : "segment%d", index);
   name = bfd_alloc (abfd, strlen (namebuf) + 1);
   if (!name)
@@ -2392,7 +2393,7 @@ elf_sort_sections (arg1, arg2)
     {
       if (TOEND (sec2))
        return sec1->target_index - sec2->target_index;
-      else 
+      else
        return 1;
     }
 
@@ -2481,7 +2482,7 @@ assign_file_positions_for_segments (abfd)
   filehdr_paddr = 0;
   phdrs_vaddr = 0;
   phdrs_paddr = 0;
-  
+
   for (m = elf_tdata (abfd)->segment_map, p = phdrs;
        m != NULL;
        m = m->next, p++)
@@ -2536,7 +2537,7 @@ assign_file_positions_for_segments (abfd)
       p->p_offset = 0;
       p->p_filesz = 0;
       p->p_memsz = 0;
-      
+
       if (m->includes_filehdr)
        {
          if (! m->p_flags_valid)
@@ -2555,7 +2556,7 @@ assign_file_positions_for_segments (abfd)
                  bfd_set_error (bfd_error_bad_value);
                  return false;
                }
-             
+
              p->p_vaddr -= off;
              if (! m->p_paddr_valid)
                p->p_paddr -= off;
@@ -2571,7 +2572,7 @@ assign_file_positions_for_segments (abfd)
        {
          if (! m->p_flags_valid)
            p->p_flags |= PF_R;
-         
+
          if (m->includes_filehdr)
            {
              if (p->p_type == PT_LOAD)
@@ -2583,7 +2584,7 @@ assign_file_positions_for_segments (abfd)
          else
            {
              p->p_offset = bed->s->sizeof_ehdr;
-             
+
              if (m->count > 0)
                {
                  BFD_ASSERT (p->p_type == PT_LOAD);
@@ -2591,7 +2592,7 @@ assign_file_positions_for_segments (abfd)
                  if (! m->p_paddr_valid)
                    p->p_paddr -= off - p->p_offset;
                }
-             
+
              if (p->p_type == PT_LOAD)
                {
                  phdrs_vaddr = p->p_vaddr;
@@ -2600,12 +2601,13 @@ assign_file_positions_for_segments (abfd)
              else
                phdrs_vaddr = bed->maxpagesize + bed->s->sizeof_ehdr;
            }
-         
+
          p->p_filesz += alloc * bed->s->sizeof_phdr;
          p->p_memsz += alloc * bed->s->sizeof_phdr;
        }
 
-      if (p->p_type == PT_LOAD || p->p_type == PT_NOTE)
+      if (p->p_type == PT_LOAD
+         || (p->p_type == PT_NOTE && abfd->format == bfd_core))
        {
          if (! m->includes_filehdr && ! m->includes_phdrs)
            p->p_offset = off;
@@ -2620,7 +2622,7 @@ assign_file_positions_for_segments (abfd)
        }
 
       voff = off;
-      
+
       for (i = 0, secpp = m->sections; i < m->count; i++, secpp++)
        {
          asection *sec;
@@ -2631,7 +2633,7 @@ assign_file_positions_for_segments (abfd)
          flags = sec->flags;
          align = 1 << bfd_get_section_alignment (abfd, sec);
 
-         /* The section may have artificial alignment forced by a 
+         /* The section may have artificial alignment forced by a
             link script.  Notice this case by the gap between the
             cumulative phdr vma and the section's vma.  */
          if (p->p_vaddr + p->p_memsz < sec->vma)
@@ -2648,7 +2650,7 @@ assign_file_positions_for_segments (abfd)
          if (p->p_type == PT_LOAD)
            {
              bfd_signed_vma adjust;
-             
+
              if ((flags & SEC_LOAD) != 0)
                {
                  adjust = sec->lma - (p->p_paddr + p->p_memsz);
@@ -2680,7 +2682,7 @@ assign_file_positions_for_segments (abfd)
                      (* _bfd_error_handler)
                        (_("       whereas segment starts at 0x%x"),
                         p->p_paddr);
-                     
+
                      return false;
                    }
                  p->p_memsz += adjust;
@@ -2699,12 +2701,12 @@ assign_file_positions_for_segments (abfd)
              if ((flags & SEC_LOAD) != 0
                  || (flags & SEC_HAS_CONTENTS) != 0)
                off += sec->_raw_size;
-             
+
              if ((flags & SEC_ALLOC) != 0)
                voff += sec->_raw_size;
            }
 
-         if (p->p_type == PT_NOTE)
+         if (p->p_type == PT_NOTE && abfd->format == bfd_core)
            {
              if (i == 0)       /* the actual "note" segment */
                {               /* this one actually contains everything. */
@@ -2891,8 +2893,8 @@ assign_file_positions_except_relocs (abfd)
   file_ptr off;
   struct elf_backend_data *bed = get_elf_backend_data (abfd);
 
-  if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0 &&
-      abfd->format != bfd_core)
+  if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0
+      && abfd->format != bfd_core)
     {
       Elf_Internal_Shdr **hdrpp;
       unsigned int i;
@@ -2919,7 +2921,7 @@ assign_file_positions_except_relocs (abfd)
              hdr->sh_offset = -1;
              continue;
            }
-         
+
          off = _bfd_elf_assign_file_position_for_section (hdr, off, true);
        }
     }
@@ -2966,7 +2968,7 @@ assign_file_positions_except_relocs (abfd)
            hdr->sh_offset = -1;
          else
            off = _bfd_elf_assign_file_position_for_section (hdr, off, true);
-       }                  
+       }
     }
 
   /* Place the section headers.  */
@@ -3065,6 +3067,9 @@ prep_headers (abfd)
     case bfd_arch_d30v:
       i_ehdrp->e_machine = EM_CYGNUS_D30V;
       break;
+    case bfd_arch_fr30:
+      i_ehdrp->e_machine = EM_CYGNUS_FR30;
+      break;
     case bfd_arch_v850:
       switch (bfd_get_mach (abfd))
        {
@@ -3342,7 +3347,7 @@ copy_private_bfd_data (ibfd, obfd)
   unsigned int i;
   unsigned int num_segments;
   boolean phdr_included = false;
-  
+
   if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
       || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
     return true;
@@ -3364,11 +3369,13 @@ copy_private_bfd_data (ibfd, obfd)
 
   /* Special case: corefile "NOTE" section containing regs, prpsinfo etc. */
 
-#define IS_COREFILE_NOTE(p, s)                                               \
-           (p->p_type == PT_NOTE &&                                         \
-            s->vma == 0 && s->lma == 0 && s->_cooked_size == 0 &&           \
-            (bfd_vma) s->filepos >= p->p_offset &&                          \
-            (bfd_vma) s->filepos + s->_raw_size <= p->p_offset + p->p_filesz)
+#define IS_COREFILE_NOTE(p, s)                                          \
+           (p->p_type == PT_NOTE                                       \
+            && ibfd->format == bfd_core                                \
+            && s->vma == 0 && s->lma == 0                              \
+            && (bfd_vma) s->filepos >= p->p_offset                     \
+            && (bfd_vma) s->filepos + s->_raw_size                     \
+            <= p->p_offset + p->p_filesz)
 
   /* The complicated case when p_vaddr is 0 is to handle the Solaris
      linker, which generates a PT_INTERP section with p_vaddr and
@@ -3405,9 +3412,9 @@ copy_private_bfd_data (ibfd, obfd)
       for (s = ibfd->sections; s != NULL; s = s->next)
        if (s->output_section != NULL)
          {
-           if ((IS_CONTAINED_BY (s->vma, s->_raw_size, p->p_vaddr, p) ||
-                IS_SOLARIS_PT_INTERP (p, s)) &&
-               (s->flags & SEC_ALLOC) != 0)
+           if ((IS_CONTAINED_BY (s->vma, s->_raw_size, p->p_vaddr, p)
+                || IS_SOLARIS_PT_INTERP (p, s))
+               && (s->flags & SEC_ALLOC) != 0)
              ++csecs;
            else if (IS_COREFILE_NOTE (p, s))
              ++csecs;
@@ -3452,19 +3459,19 @@ copy_private_bfd_data (ibfd, obfd)
          /* Special segments, such as the PT_PHDR segment, may contain
             no sections, but ordinary, loadable segments should contain
             something.  */
-         
+
          if (p->p_type == PT_LOAD)
              _bfd_error_handler
                (_("%s: warning: Empty loadable segment detected\n"),
                 bfd_get_filename (ibfd));
-         
+
          m->count = 0;
          *pm = m;
          pm = &m->next;
-         
+
          continue;
        }
-      
+
       /* Now scan the sections in the input BFD again and attempt
         to add their corresponding output sections to the segment map.
         The problem here is how to handle an output section which has
@@ -3473,7 +3480,7 @@ copy_private_bfd_data (ibfd, obfd)
         1. None of the sections have been moved.
            In this case we can continue to use the segment LMA from the
            input BFD.
-           
+
         2. All of the sections have been moved by the same amount.
            In this case we can change the segment's LMA to match the LMA
            of the first section.
@@ -3487,23 +3494,23 @@ copy_private_bfd_data (ibfd, obfd)
         4. The sections have been moved, but not be the same amount.
            In this case we can change the segment's LMA to match the LMA
            of the first section and we will have to create a new segment
-           or segments to contain the other sections. 
-           
+           or segments to contain the other sections.
+
         In order to save time, we allocate an array to hold the section
         pointers that we are interested in.  As these sections get assigned
         to a segment, they are removed from this array.  */
-      
+
       sections = (asection **) bfd_malloc (sizeof (asection *) * csecs);
       if (sections == NULL)
        return false;
-      
+
       /* Step One: Scan for segment vs section LMA conflicts.
         Also add the sections to the section array allocated above.
         Also add the sections to the current segment.  In the common
         case, where the sections have not been moved, this means that
         we have completely filled the segment, and there is nothing
         more to do.  */
-      
+
       isec = 0;
       matching_lma = false;
       suggested_lma = 0;
@@ -3511,15 +3518,15 @@ copy_private_bfd_data (ibfd, obfd)
       for (j = 0, s = ibfd->sections; s != NULL; s = s->next)
        {
          os = s->output_section;
-         
+
          if ((((IS_CONTAINED_BY (s->vma, s->_raw_size, p->p_vaddr, p)
                 || IS_SOLARIS_PT_INTERP (p, s))
-               && (s->flags & SEC_ALLOC) != 0) 
+               && (s->flags & SEC_ALLOC) != 0)
               || IS_COREFILE_NOTE (p, s))
              && os != NULL)
            {
              sections[j++] = s;
-             
+
              /* The Solaris native linker always sets p_paddr to 0.
                 We try to catch that case here, and set it to the
                 correct value.  */
@@ -3538,12 +3545,12 @@ copy_private_bfd_data (ibfd, obfd)
 
              /* Match up the physical address of the segment with the
                 LMA address of the output section.  */
-             if (IS_CONTAINED_BY (os->lma, os->_raw_size, m->p_paddr, p) ||
-                 IS_COREFILE_NOTE (p, s))
+             if (IS_CONTAINED_BY (os->lma, os->_raw_size, m->p_paddr, p)
+                 || IS_COREFILE_NOTE (p, s))
                {
                  if (matching_lma == 0)
                    matching_lma = os->lma;
-                 
+
                  /* We assume that if the section fits within the segment
                     that it does not overlap any other section within that
                     segment.  */
@@ -3579,7 +3586,7 @@ copy_private_bfd_data (ibfd, obfd)
 
          m->p_paddr = matching_lma;
        }
-      else 
+      else
        {
          /* None of the sections fitted inside the current segment.
             Change the current segment's physical address to match
@@ -3600,19 +3607,19 @@ copy_private_bfd_data (ibfd, obfd)
        {
          m->count = 0;
          suggested_lma = 0;
-         
+
          /* Fill the current segment with sections that fit.  */
          for (j = 0; j < csecs; j++)
            {
              s = sections[j];
-             
+
              if (s == NULL)
                continue;
-             
+
              os = s->output_section;
-             
-             if (IS_CONTAINED_BY (os->lma, os->_raw_size, m->p_paddr, p) ||
-                 IS_COREFILE_NOTE (p, s))
+
+             if (IS_CONTAINED_BY (os->lma, os->_raw_size, m->p_paddr, p)
+                 || IS_COREFILE_NOTE (p, s))
                {
                  if (m->count == 0)
                    {
@@ -3621,11 +3628,11 @@ copy_private_bfd_data (ibfd, obfd)
                      if (os->lma != m->p_paddr)
                        abort ();
                    }
-                 else 
+                 else
                    {
                      asection * prev_sec;
                      bfd_vma maxpagesize;
-                     
+
                      prev_sec = m->sections[m->count - 1];
                      maxpagesize = get_elf_backend_data (obfd)->maxpagesize;
 
@@ -3637,7 +3644,7 @@ copy_private_bfd_data (ibfd, obfd)
                        {
                          if (suggested_lma == 0)
                            suggested_lma = os->lma;
-                         
+
                          continue;
                        }
                    }
@@ -3651,7 +3658,7 @@ copy_private_bfd_data (ibfd, obfd)
            }
 
          BFD_ASSERT (m->count > 0);
-         
+
          /* Add the current segment to the list of built segments.  */
          *pm = m;
          pm = &m->next;
@@ -3672,7 +3679,7 @@ copy_private_bfd_data (ibfd, obfd)
              /* Initialise the fields of the segment map.  Set the physical
                 physical address to the LMA of the first section that has
                 not yet been assigned.  */
-             
+
              m->next             = NULL;
              m->p_type           = p->p_type;
              m->p_flags          = p->p_flags;
@@ -3708,7 +3715,7 @@ copy_private_bfd_data (ibfd, obfd)
   if (mfirst != NULL)
     {
       struct elf_segment_map* prev;
-      
+
       prev = mfirst;
       for (m = mfirst->next; m != NULL; prev = m, m = m->next)
        {
@@ -3726,7 +3733,7 @@ copy_private_bfd_data (ibfd, obfd)
        }
     }
 #endif
-  
+
 #undef IS_CONTAINED_BY
 #undef IS_SOLARIS_PT_INTERP
 #undef IS_COREFILE_NOTE
@@ -3913,7 +3920,8 @@ swap_out_syms (abfd, sttp, relocatable_p)
 
        type_ptr = elf_symbol_from (abfd, syms[idx]);
 
-       if (bfd_is_com_section (syms[idx]->section))
+       if ((flags & BSF_SECTION_SYM) == 0
+           && bfd_is_com_section (syms[idx]->section))
          {
            /* ELF common symbols put the alignment into the `value' field,
               and the size into the `size' field.  This is backwards from
@@ -4001,15 +4009,19 @@ swap_out_syms (abfd, sttp, relocatable_p)
        else
          type = STT_NOTYPE;
 
-       if (bfd_is_com_section (syms[idx]->section))
+        /* Processor-specific types */
+        if (bed->elf_backend_get_symbol_type)
+          type = (*bed->elf_backend_get_symbol_type) (&type_ptr->internal_elf_sym, type);
+
+       if (flags & BSF_SECTION_SYM)
+         sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
+       else if (bfd_is_com_section (syms[idx]->section))
          sym.st_info = ELF_ST_INFO (STB_GLOBAL, type);
        else if (bfd_is_und_section (syms[idx]->section))
          sym.st_info = ELF_ST_INFO (((flags & BSF_WEAK)
                                      ? STB_WEAK
                                      : STB_GLOBAL),
                                     type);
-       else if (flags & BSF_SECTION_SYM)
-         sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
        else if (flags & BSF_FILE)
          sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE);
        else
@@ -4510,11 +4522,16 @@ _bfd_elf_find_nearest_line (abfd,
   bfd_vma low_func;
   asymbol **p;
 
-  if (_bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
+  if (_bfd_dwarf1_find_nearest_line (abfd, section, symbols, offset,
                                     filename_ptr, functionname_ptr, 
                                     line_ptr))
     return true;
 
+  if (_bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
+                                    filename_ptr, functionname_ptr,
+                                    line_ptr))
+    return true;
+
   if (! _bfd_stab_section_find_nearest_line (abfd, symbols, section, offset,
                                             &found, filename_ptr,
                                             functionname_ptr, line_ptr,
@@ -4635,11 +4652,11 @@ _bfd_elf_validate_reloc (abfd, areloc)
 {
   /* Check whether we really have an ELF howto. */
 
-  if ((*areloc->sym_ptr_ptr)->the_bfd->xvec != abfd->xvec) 
+  if ((*areloc->sym_ptr_ptr)->the_bfd->xvec != abfd->xvec)
     {
       bfd_reloc_code_real_type code;
       reloc_howto_type *howto;
-      
+
       /* Alien reloc: Try to determine its type to replace it with an
         equivalent ELF reloc. */
 
@@ -4648,22 +4665,22 @@ _bfd_elf_validate_reloc (abfd, areloc)
          switch (areloc->howto->bitsize)
            {
            case 8:
-             code = BFD_RELOC_8_PCREL; 
+             code = BFD_RELOC_8_PCREL;
              break;
            case 12:
-             code = BFD_RELOC_12_PCREL; 
+             code = BFD_RELOC_12_PCREL;
              break;
            case 16:
-             code = BFD_RELOC_16_PCREL; 
+             code = BFD_RELOC_16_PCREL;
              break;
            case 24:
-             code = BFD_RELOC_24_PCREL; 
+             code = BFD_RELOC_24_PCREL;
              break;
            case 32:
-             code = BFD_RELOC_32_PCREL; 
+             code = BFD_RELOC_32_PCREL;
              break;
            case 64:
-             code = BFD_RELOC_64_PCREL; 
+             code = BFD_RELOC_64_PCREL;
              break;
            default:
              goto fail;
@@ -4684,22 +4701,22 @@ _bfd_elf_validate_reloc (abfd, areloc)
          switch (areloc->howto->bitsize)
            {
            case 8:
-             code = BFD_RELOC_8; 
+             code = BFD_RELOC_8;
              break;
            case 14:
-             code = BFD_RELOC_14; 
+             code = BFD_RELOC_14;
              break;
            case 16:
-             code = BFD_RELOC_16; 
+             code = BFD_RELOC_16;
              break;
            case 26:
-             code = BFD_RELOC_26; 
+             code = BFD_RELOC_26;
              break;
            case 32:
-             code = BFD_RELOC_32; 
+             code = BFD_RELOC_32;
              break;
            case 64:
-             code = BFD_RELOC_64; 
+             code = BFD_RELOC_64;
              break;
            default:
              goto fail;
@@ -4754,3 +4771,445 @@ _bfd_elf_rel_vtable_reloc_fn (abfd, re, symbol, data, is, obfd, errmsg)
 {
   return bfd_reloc_ok;
 }
+
+\f
+/* Elf core file support.  Much of this only works on native
+   toolchains, since we rely on knowing the
+   machine-dependent procfs structure in order to pick
+   out details about the corefile. */
+
+#ifdef HAVE_SYS_PROCFS_H
+# include <sys/procfs.h>
+#endif
+
+
+/* Define offsetof for those systems which lack it. */
+
+#ifndef offsetof
+# define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
+#endif
+
+
+/* FIXME: this is kinda wrong, but it's what gdb wants. */
+
+static int
+elfcore_make_pid (abfd)
+     bfd* abfd;
+{
+  return ((elf_tdata (abfd)->core_lwpid << 16)
+         + (elf_tdata (abfd)->core_pid));
+}
+
+
+/* If there isn't a section called NAME, make one, using
+   data from SECT.  Note, this function will generate a
+   reference to NAME, so you shouldn't deallocate or
+   overwrite it. */
+
+static boolean
+elfcore_maybe_make_sect (abfd, name, sect)
+     bfd* abfd;
+     char* name;
+     asection* sect;
+{
+  asection* sect2;
+
+  if (bfd_get_section_by_name (abfd, name) != NULL)
+    return true;
+
+  sect2 = bfd_make_section (abfd, name);
+  if (sect2 == NULL)
+    return false;
+
+  sect2->_raw_size = sect->_raw_size;
+  sect2->filepos = sect->filepos;
+  sect2->flags = sect->flags;
+  sect2->alignment_power = sect->alignment_power;
+  return true;
+}
+
+
+/* prstatus_t exists on:
+     solaris 2.[567]
+     linux 2.[01] + glibc
+     unixware 4.2
+*/
+
+#if defined (HAVE_PRSTATUS_T)
+static boolean
+elfcore_grok_prstatus (abfd, note)
+     bfd* abfd;
+     Elf_Internal_Note* note;
+{
+  prstatus_t prstat;
+  char buf[100];
+  char* name;
+  asection* sect;
+
+  if (note->descsz != sizeof (prstat))
+    return true;
+
+  memcpy (&prstat, note->descdata, sizeof (prstat));
+
+  elf_tdata (abfd)->core_signal = prstat.pr_cursig;
+  elf_tdata (abfd)->core_pid = prstat.pr_pid;
+
+  /* pr_who exists on:
+       solaris 2.[567]
+       unixware 4.2
+     pr_who doesn't exist on:
+       linux 2.[01]
+  */
+#if defined (HAVE_PRSTATUS_T_PR_WHO)
+  elf_tdata (abfd)->core_lwpid = prstat.pr_who;
+#endif
+
+  /* Make a ".reg/999" section. */
+
+  sprintf (buf, ".reg/%d", elfcore_make_pid (abfd));
+  name = bfd_alloc (abfd, strlen (buf) + 1);
+  if (name == NULL)
+    return false;
+  strcpy (name, buf);
+
+  sect = bfd_make_section (abfd, name);
+  if (sect == NULL)
+    return false;
+  sect->_raw_size = sizeof (prstat.pr_reg);
+  sect->filepos = note->descpos + offsetof (prstatus_t, pr_reg);
+  sect->flags = SEC_HAS_CONTENTS;
+  sect->alignment_power = 2;
+
+  if (! elfcore_maybe_make_sect (abfd, ".reg", sect))
+    return false;
+
+  return true;
+}
+#endif /* defined (HAVE_PRSTATUS_T) */
+
+
+/* There isn't a consistent prfpregset_t across platforms,
+   but it doesn't matter, because we don't have to pick this
+   data structure apart. */
+
+static boolean
+elfcore_grok_prfpreg (abfd, note)
+     bfd* abfd;
+     Elf_Internal_Note* note;
+{
+  char buf[100];
+  char* name;
+  asection* sect;
+
+  /* Make a ".reg2/999" section. */
+
+  sprintf (buf, ".reg2/%d", elfcore_make_pid (abfd));
+  name = bfd_alloc (abfd, strlen (buf) + 1);
+  if (name == NULL)
+    return false;
+  strcpy (name, buf);
+
+  sect = bfd_make_section (abfd, name);
+  if (sect == NULL)
+    return false;
+  sect->_raw_size = note->descsz;
+  sect->filepos = note->descpos;
+  sect->flags = SEC_HAS_CONTENTS;
+  sect->alignment_power = 2;
+
+  if (! elfcore_maybe_make_sect (abfd, ".reg2", sect))
+    return false;
+
+  return true;
+}
+
+
+/* return a malloc'ed copy of a string at START which is at
+   most MAX bytes long, possibly without a terminating '\0'.
+   the copy will always have a terminating '\0'. */
+
+static char*
+elfcore_strndup (abfd, start, max)
+     bfd* abfd;
+     char* start;
+     int max;
+{
+  char* dup;
+  char* end = memchr (start, '\0', max);
+  int len;
+
+  if (end == NULL)
+    len = max;
+  else
+    len = end - start;
+
+  dup = bfd_alloc (abfd, len + 1);
+  if (dup == NULL)
+    return NULL;
+
+  memcpy (dup, start, len);
+  dup[len] = '\0';
+
+  return dup;
+}
+
+
+#if defined (HAVE_PRPSINFO_T)
+# define elfcore_psinfo_t prpsinfo_t
+#endif
+
+#if defined (HAVE_PSINFO_T)
+# define elfcore_psinfo_t psinfo_t
+#endif
+
+
+#if defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T)
+static boolean
+elfcore_grok_psinfo (abfd, note)
+     bfd* abfd;
+     Elf_Internal_Note* note;
+{
+  elfcore_psinfo_t psinfo;
+
+  if (note->descsz != sizeof (elfcore_psinfo_t))
+    return true;
+
+  memcpy (&psinfo, note->descdata, note->descsz);
+
+  elf_tdata (abfd)->core_program
+    = elfcore_strndup (abfd, psinfo.pr_fname, sizeof (psinfo.pr_fname));
+
+  elf_tdata (abfd)->core_command
+    = elfcore_strndup (abfd, psinfo.pr_psargs, sizeof (psinfo.pr_psargs));
+
+  /* Note that for some reason, a spurious space is tacked
+     onto the end of the args in some (at least one anyway)
+     implementations, so strip it off if it exists. */
+
+  {
+    char* command = elf_tdata (abfd)->core_command;
+    int n = strlen (command);
+
+    if (0 < n && command[n - 1] == ' ')
+      command[n - 1] = '\0';
+  }
+
+  return true;
+}
+#endif /* defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T) */
+
+
+#if defined (HAVE_PSTATUS_T)
+static boolean
+elfcore_grok_pstatus (abfd, note)
+     bfd* abfd;
+     Elf_Internal_Note* note;
+{
+  pstatus_t pstat;
+
+  if (note->descsz != sizeof (pstat))
+    return true;
+
+  memcpy (&pstat, note->descdata, sizeof (pstat));
+
+  elf_tdata (abfd)->core_pid = pstat.pr_pid;
+
+  /* Could grab some more details from the "representative"
+     lwpstatus_t in pstat.pr_lwp, but we'll catch it all in an
+     NT_LWPSTATUS note, presumably. */
+
+  return true;
+}
+#endif /* defined (HAVE_PSTATUS_T) */
+
+
+#if defined (HAVE_LWPSTATUS_T)
+static boolean
+elfcore_grok_lwpstatus (abfd, note)
+     bfd* abfd;
+     Elf_Internal_Note* note;
+{
+  lwpstatus_t lwpstat;
+  char buf[100];
+  char* name;
+  asection* sect;
+
+  if (note->descsz != sizeof (lwpstat))
+    return true;
+
+  memcpy (&lwpstat, note->descdata, sizeof (lwpstat));
+
+  elf_tdata (abfd)->core_lwpid = lwpstat.pr_lwpid;
+  elf_tdata (abfd)->core_signal = lwpstat.pr_cursig;
+
+  /* Make a ".reg/999" section. */
+
+  sprintf (buf, ".reg/%d", elfcore_make_pid (abfd));
+  name = bfd_alloc (abfd, strlen (buf) + 1);
+  if (name == NULL)
+    return false;
+  strcpy (name, buf);
+
+  sect = bfd_make_section (abfd, name);
+  if (sect == NULL)
+    return false;
+
+#if defined (HAVE_LWPSTATUS_T_PR_CONTEXT)
+  sect->_raw_size = sizeof (lwpstat.pr_context.uc_mcontext.gregs);
+  sect->filepos = note->descpos
+    + offsetof (lwpstatus_t, pr_context.uc_mcontext.gregs);
+#endif
+
+#if defined (HAVE_LWPSTATUS_T_PR_REG)
+  sect->_raw_size = sizeof (lwpstat.pr_reg);
+  sect->filepos = note->descpos + offsetof (lwpstatus_t, pr_reg);
+#endif
+
+  sect->flags = SEC_HAS_CONTENTS;
+  sect->alignment_power = 2;
+
+  if (!elfcore_maybe_make_sect (abfd, ".reg", sect))
+    return false;
+
+  /* Make a ".reg2/999" section */
+
+  sprintf (buf, ".reg2/%d", elfcore_make_pid (abfd));
+  name = bfd_alloc (abfd, strlen (buf) + 1);
+  if (name == NULL)
+    return false;
+  strcpy (name, buf);
+
+  sect = bfd_make_section (abfd, name);
+  if (sect == NULL)
+    return false;
+
+#if defined (HAVE_LWPSTATUS_T_PR_CONTEXT)
+  sect->_raw_size = sizeof (lwpstat.pr_context.uc_mcontext.fpregs);
+  sect->filepos = note->descpos
+    + offsetof (lwpstatus_t, pr_context.uc_mcontext.fpregs);
+#endif
+
+#if defined (HAVE_LWPSTATUS_T_PR_FPREG)
+  sect->_raw_size = sizeof (lwpstat.pr_fpreg);
+  sect->filepos = note->descpos + offsetof (lwpstatus_t, pr_fpreg);
+#endif
+
+  sect->flags = SEC_HAS_CONTENTS;
+  sect->alignment_power = 2;
+
+  if (!elfcore_maybe_make_sect (abfd, ".reg2", sect))
+    return false;
+
+  return true;
+}
+#endif /* defined (HAVE_LWPSTATUS_T) */
+
+
+
+static boolean
+elfcore_grok_note (abfd, note)
+     bfd* abfd;
+     Elf_Internal_Note* note;
+{
+  switch (note->type)
+    {
+    default:
+      return true;
+
+#if defined (HAVE_PRSTATUS_T)
+    case NT_PRSTATUS:
+      return elfcore_grok_prstatus (abfd, note);
+#endif
+
+#if defined (HAVE_PSTATUS_T)
+    case NT_PSTATUS:
+      return elfcore_grok_pstatus (abfd, note);
+#endif
+
+#if defined (HAVE_LWPSTATUS_T)
+    case NT_LWPSTATUS:
+      return elfcore_grok_lwpstatus (abfd, note);
+#endif
+
+    case NT_FPREGSET:          /* FIXME: rename to NT_PRFPREG */
+      return elfcore_grok_prfpreg (abfd, note);
+
+#if defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T)
+    case NT_PRPSINFO:
+    case NT_PSINFO:
+      return elfcore_grok_psinfo (abfd, note);
+#endif
+    }
+}
+
+
+static boolean
+elfcore_read_notes (abfd, offset, size)
+     bfd* abfd;
+     bfd_vma offset;
+     bfd_vma size;
+{
+  char* buf;
+  char* p;
+
+  if (size <= 0)
+    return true;
+
+  if (bfd_seek (abfd, offset, SEEK_SET) == -1)
+    return false;
+
+  buf = bfd_malloc ((size_t) size);
+  if (buf == NULL)
+    return false;
+
+  if (bfd_read (buf, size, 1, abfd) != size)
+    {
+    error:
+      free (buf);
+      return false;
+    }
+
+  p = buf;
+  while (p < buf + size)
+    {
+      /* FIXME: bad alignment assumption. */
+      Elf_External_Note* xnp = (Elf_External_Note*) p;
+      Elf_Internal_Note in;
+
+      in.type = bfd_h_get_32 (abfd, (bfd_byte *) xnp->type);
+
+      in.namesz = bfd_h_get_32 (abfd, (bfd_byte *) xnp->namesz);
+      in.namedata = xnp->name;
+
+      in.descsz = bfd_h_get_32 (abfd, (bfd_byte *) xnp->descsz);
+      in.descdata = in.namedata + BFD_ALIGN (in.namesz, 4);
+      in.descpos = offset + (in.descdata - buf);
+
+      if (! elfcore_grok_note (abfd, &in))
+       goto error;
+
+      p = in.descdata + BFD_ALIGN (in.descsz, 4);
+    }
+
+  free (buf);
+  return true;
+}
+
+
+
+boolean
+_bfd_elfcore_section_from_phdr (abfd, phdr, sec_num)
+     bfd* abfd;
+     Elf_Internal_Phdr* phdr;
+     int sec_num;
+{
+  if (! bfd_section_from_phdr (abfd, phdr, sec_num))
+    return false;
+
+  if (phdr->p_type == PT_NOTE
+      && ! elfcore_read_notes (abfd, phdr->p_offset, phdr->p_filesz))
+    return false;
+
+  return true;
+}
+
This page took 0.033993 seconds and 4 git commands to generate.