Fix illegal memory accesses in readelf when parsing a corrupt binary.
[binutils-gdb.git] / binutils / readelf.c
index cb464511cb11075a020d7fc1dfab60ee70579970..20df6f899609536adc50ca69fd4c3c84267c42f9 100644 (file)
@@ -1,5 +1,5 @@
 /* readelf.c -- display contents of an ELF format file
-   Copyright (C) 1998-2016 Free Software Foundation, Inc.
+   Copyright (C) 1998-2017 Free Software Foundation, Inc.
 
    Originally developed by Eric Youngdale <eric@andante.jic.com>
    Modifications by Nick Clifton <nickc@redhat.com>
 #include "elf/metag.h"
 #include "elf/microblaze.h"
 #include "elf/mips.h"
+#include "elf/riscv.h"
 #include "elf/mmix.h"
 #include "elf/mn10200.h"
 #include "elf/mn10300.h"
 #include "elf/pj.h"
 #include "elf/ppc.h"
 #include "elf/ppc64.h"
+#include "elf/pru.h"
 #include "elf/rl78.h"
 #include "elf/rx.h"
 #include "elf/s390.h"
@@ -287,7 +289,7 @@ enum versioned_symbol_info
   symbol_public
 };
 
-static const char * get_symbol_version_string
+static const char *get_symbol_version_string
   (FILE *file, int is_dynsym, const char *strtab,
    unsigned long int strtab_size, unsigned int si,
    Elf_Internal_Sym *psym, enum versioned_symbol_info *sym_info,
@@ -674,8 +676,14 @@ find_section_in_set (const char * name, unsigned int * set)
   if (set != NULL)
     {
       while ((i = *set++) > 0)
-       if (streq (SECTION_NAME (section_headers + i), name))
-         return section_headers + i;
+       {
+         /* See PR 21156 for a reproducer.  */
+         if (i >= elf_header.e_shnum)
+           continue; /* FIXME: Should we issue an error message ?  */
+
+         if (streq (SECTION_NAME (section_headers + i), name))
+           return section_headers + i;
+       }
     }
 
   return find_section (name);
@@ -775,6 +783,8 @@ guess_is_rela (unsigned int e_machine)
     case EM_OR1K:
     case EM_PPC64:
     case EM_PPC:
+    case EM_TI_PRU:
+    case EM_RISCV:
     case EM_RL78:
     case EM_RX:
     case EM_S390:
@@ -1314,6 +1324,10 @@ dump_relocations (FILE * file,
          rtype = elf_mips_reloc_type (type);
          break;
 
+       case EM_RISCV:
+         rtype = elf_riscv_reloc_type (type);
+         break;
+
        case EM_ALPHA:
          rtype = elf_alpha_reloc_type (type);
          break;
@@ -1477,6 +1491,10 @@ dump_relocations (FILE * file,
        case EM_ALTERA_NIOS2:
          rtype = elf_nios2_reloc_type (type);
          break;
+
+       case EM_TI_PRU:
+         rtype = elf_pru_reloc_type (type);
+         break;
        }
 
       if (rtype == NULL)
@@ -1966,7 +1984,7 @@ get_solaris_dynamic_type (unsigned long type)
     case 0x7ffffffe: return "USED";
     case 0x7fffffff: return "FILTER";
 
-    default: return NULL;      
+    default: return NULL;
     }
 }
 
@@ -2327,6 +2345,7 @@ get_machine_name (unsigned e_machine)
     case EM_CR16:
     case EM_MICROBLAZE:
     case EM_MICROBLAZE_OLD:    return "Xilinx MicroBlaze";
+    case EM_RISCV:             return "RISC-V";
     case EM_RL78:              return "Renesas RL78";
     case EM_RX:                        return "Renesas RX";
     case EM_METAG:             return "Imagination Technologies Meta processor architecture";
@@ -2347,8 +2366,8 @@ get_machine_name (unsigned e_machine)
     case EM_OPEN8:             return "Open8 8-bit RISC soft processor core";
     case EM_VIDEOCORE5:                return "Broadcom VideoCore V processor";
     case EM_56800EX:           return "Freescale 56800EX Digital Signal Controller (DSC)";
-    case EM_BA1 :              return "Beyond BA1 CPU architecture";
-    case EM_BA2 :              return "Beyond BA2 CPU architecture";
+    case EM_BA1              return "Beyond BA1 CPU architecture";
+    case EM_BA2              return "Beyond BA2 CPU architecture";
     case EM_XCORE:             return "XMOS xCORE processor family";
     case EM_MCHP_PIC:          return "Microchip 8-bit PIC(r) family";
     case EM_KM32:              return "KM211 KM32 32-bit processor";
@@ -2356,14 +2375,14 @@ get_machine_name (unsigned e_machine)
     case EM_KMX16:             return "KM211 KMX16 16-bit processor";
     case EM_KMX8:              return "KM211 KMX8 8-bit processor";
     case EM_KVARC:             return "KM211 KVARC processor";
-    case EM_CDP :              return "Paneve CDP architecture family";
+    case EM_CDP              return "Paneve CDP architecture family";
     case EM_COGE:              return "Cognitive Smart Memory Processor";
     case EM_COOL:              return "Bluechip Systems CoolEngine";
     case EM_NORC:              return "Nanoradio Optimized RISC";
     case EM_CSR_KALIMBA:       return "CSR Kalimba architecture family";
-    case EM_Z80 :              return "Zilog Z80";
+    case EM_Z80              return "Zilog Z80";
     case EM_AMDGPU:            return "AMD GPU architecture";
-    case EM_RISCV:             return "RISC-V";
+    case EM_TI_PRU:            return "TI PRU I/O processor";
     default:
       snprintf (buff, sizeof (buff), _("<unknown>: 0x%x"), e_machine);
       return buff;
@@ -3308,6 +3327,30 @@ get_machine_flags (unsigned e_flags, unsigned e_machine)
          decode_NDS32_machine_flags (e_flags, buf, sizeof buf);
          break;
 
+       case EM_RISCV:
+         if (e_flags & EF_RISCV_RVC)
+           strcat (buf, ", RVC");
+
+         switch (e_flags & EF_RISCV_FLOAT_ABI)
+           {
+           case EF_RISCV_FLOAT_ABI_SOFT:
+             strcat (buf, ", soft-float ABI");
+             break;
+
+           case EF_RISCV_FLOAT_ABI_SINGLE:
+             strcat (buf, ", single-float ABI");
+             break;
+
+           case EF_RISCV_FLOAT_ABI_DOUBLE:
+             strcat (buf, ", double-float ABI");
+             break;
+
+           case EF_RISCV_FLOAT_ABI_QUAD:
+             strcat (buf, ", quad-float ABI");
+             break;
+           }
+         break;
+
        case EM_SH:
          switch ((e_flags & EF_SH_MACH_MASK))
            {
@@ -3784,7 +3827,7 @@ get_segment_type (unsigned long p_type)
          if (result != NULL)
            return result;
 
-         sprintf (buff, "LOPROC+%lx", p_type - PT_LOPROC);
+         sprintf (buff, "LOPROC+%#lx", p_type - PT_LOPROC);
        }
       else if ((p_type >= PT_LOOS) && (p_type <= PT_HIOS))
        {
@@ -3809,7 +3852,7 @@ get_segment_type (unsigned long p_type)
          if (result != NULL)
            return result;
 
-         sprintf (buff, "LOOS+%lx", p_type - PT_LOOS);
+         sprintf (buff, "LOOS+%#lx", p_type - PT_LOOS);
        }
       else
        snprintf (buff, sizeof (buff), _("<unknown>: %lx"), p_type);
@@ -4099,7 +4142,18 @@ get_section_type_name (unsigned int sh_type)
              if (elf_header.e_ident[EI_OSABI] == ELFOSABI_SOLARIS)
                result = get_solaris_section_type (sh_type);
              else
-               result = NULL;
+               {
+                 switch (sh_type)
+                   {
+                   case SHT_GNU_INCREMENTAL_INPUTS: result = "GNU_INCREMENTAL_INPUTS"; break;
+                   case SHT_GNU_ATTRIBUTES: result = "GNU_ATTRIBUTES"; break;
+                   case SHT_GNU_HASH: result = "GNU_HASH"; break;
+                   case SHT_GNU_LIBLIST: result = "GNU_LIBLIST"; break;
+                   default:
+                     result = NULL;
+                     break;
+                   }
+               }
              break;
            }
 
@@ -4757,6 +4811,7 @@ process_program_headers (FILE * file)
 {
   Elf_Internal_Phdr * segment;
   unsigned int i;
+  Elf_Internal_Phdr * previous_load = NULL;
 
   if (elf_header.e_phnum == 0)
     {
@@ -4886,15 +4941,45 @@ process_program_headers (FILE * file)
                      (segment->p_flags & PF_R ? 'R' : ' '),
                      (segment->p_flags & PF_W ? 'W' : ' '),
                      (segment->p_flags & PF_X ? 'E' : ' '));
-             print_vma (segment->p_align, HEX);
+             print_vma (segment->p_align, PREFIX_HEX);
            }
-       }
 
-      if (do_segments)
-       putc ('\n', stdout);
+         putc ('\n', stdout);
+       }
 
       switch (segment->p_type)
        {
+       case PT_LOAD:
+#if 0 /* Do not warn about out of order PT_LOAD segments.  Although officially
+        required by the ELF standard, several programs, including the Linux
+        kernel, make use of non-ordered segments.  */
+         if (previous_load
+             && previous_load->p_vaddr > segment->p_vaddr)
+           error (_("LOAD segments must be sorted in order of increasing VirtAddr\n"));
+#endif
+         if (segment->p_memsz < segment->p_filesz)
+           error (_("the segment's file size is larger than its memory size\n"));
+         previous_load = segment;
+         break;
+
+       case PT_PHDR:
+         /* PR 20815 - Verify that the program header is loaded into memory.  */
+         if (i > 0 && previous_load != NULL)
+           error (_("the PHDR segment must occur before any LOAD segment\n"));
+         if (elf_header.e_machine != EM_PARISC)
+           {
+             unsigned int j;
+
+             for (j = 1; j < elf_header.e_phnum; j++)
+               if (program_headers[j].p_vaddr <= segment->p_vaddr
+                   && (program_headers[j].p_vaddr + program_headers[j].p_memsz)
+                   >= (segment->p_vaddr + segment->p_filesz))
+                 break;
+             if (j == elf_header.e_phnum)
+               error (_("the PHDR segment is not covered by a LOAD segment\n"));
+           }
+         break;
+
        case PT_DYNAMIC:
          if (dynamic_addr)
            error (_("more than one dynamic segment\n"));
@@ -5647,12 +5732,18 @@ get_elf_section_flags (bfd_vma sh_flags)
 }
 
 static unsigned int
-get_compression_header (Elf_Internal_Chdr *chdr, unsigned char *buf)
+get_compression_header (Elf_Internal_Chdr *chdr, unsigned char *buf, bfd_size_type size)
 {
   if (is_32bit_elf)
     {
       Elf32_External_Chdr *echdr = (Elf32_External_Chdr *) buf;
 
+      if (size < sizeof (* echdr))
+       {
+         error (_("Compressed section is too small even for a compression header\n"));
+         return 0;
+       }
+
       chdr->ch_type = BYTE_GET (echdr->ch_type);
       chdr->ch_size = BYTE_GET (echdr->ch_size);
       chdr->ch_addralign = BYTE_GET (echdr->ch_addralign);
@@ -5662,6 +5753,12 @@ get_compression_header (Elf_Internal_Chdr *chdr, unsigned char *buf)
     {
       Elf64_External_Chdr *echdr = (Elf64_External_Chdr *) buf;
 
+      if (size < sizeof (* echdr))
+       {
+         error (_("Compressed section is too small even for a compression header\n"));
+         return 0;
+       }
+
       chdr->ch_type = BYTE_GET (echdr->ch_type);
       chdr->ch_size = BYTE_GET (echdr->ch_size);
       chdr->ch_addralign = BYTE_GET (echdr->ch_addralign);
@@ -5965,7 +6062,7 @@ process_section_headers (FILE * file)
        case SHT_REL:
        case SHT_RELA:
          if (section->sh_link < 1
-             || section->sh_link > elf_header.e_shnum
+             || section->sh_link >= elf_header.e_shnum
              || (section_headers[section->sh_link].sh_type != SHT_SYMTAB
                  && section_headers[section->sh_link].sh_type != SHT_DYNSYM))
            warn (_("[%2u]: Link field (%u) should index a symtab section.\n"),
@@ -5979,7 +6076,7 @@ process_section_headers (FILE * file)
        case SHT_GNU_verdef:
        case SHT_GNU_LIBLIST:
          if (section->sh_link < 1
-             || section->sh_link > elf_header.e_shnum
+             || section->sh_link >= elf_header.e_shnum
              || section_headers[section->sh_link].sh_type != SHT_STRTAB)
            warn (_("[%2u]: Link field (%u) should index a string section.\n"),
                  i, section->sh_link);
@@ -6012,7 +6109,7 @@ process_section_headers (FILE * file)
        case SHT_REL:
        case SHT_RELA:
          if (section->sh_info < 1
-             || section->sh_info > elf_header.e_shnum
+             || section->sh_info >= elf_header.e_shnum
              || (section_headers[section->sh_info].sh_type != SHT_PROGBITS
                  && section_headers[section->sh_info].sh_type != SHT_NOBITS
                  && section_headers[section->sh_info].sh_type != SHT_NOTE
@@ -6024,8 +6121,8 @@ process_section_headers (FILE * file)
                  && (streq (SECTION_NAME (section), ".rel.dyn")
                      || streq (SECTION_NAME (section), ".rela.dyn")))
                /* The .rel.dyn and .rela.dyn sections have an sh_info field
-                  of zero.  No idea why.  I would have expected the index
-                  of the .plt section.  */
+                  of zero.  The relocations in these sections may apply
+                  to many different sections.  */
                   ;
              else
                warn (_("[%2u]: Info field (%u) should index a relocatable section.\n"),
@@ -6055,11 +6152,13 @@ process_section_headers (FILE * file)
          if (section->sh_type == SHT_NOBITS)
            /* NOBITS section headers with non-zero sh_info fields can be
               created when a binary is stripped of everything but its debug
-              information.  The stripped sections have their headers preserved but their types set to SHT_NOBITS.  so do not check this type of section.  */
+              information.  The stripped sections have their headers
+              preserved but their types set to SHT_NOBITS.  So do not check
+              this type of section.  */
            ;
          else if (section->sh_flags & SHF_INFO_LINK)
            {
-             if (section->sh_info < 1 || section->sh_info > elf_header.e_shnum)
+             if (section->sh_info < 1 || section->sh_info >= elf_header.e_shnum)
                warn (_("[%2u]: Expected link to another section in info field"), i);
            }
          else if (section->sh_type < SHT_LOOS && section->sh_info != 0)
@@ -6241,7 +6340,7 @@ process_section_headers (FILE * file)
                {
                  Elf_Internal_Chdr chdr;
 
-                 (void) get_compression_header (&chdr, buf);
+                 (void) get_compression_header (&chdr, buf, sizeof (buf));
 
                  if (chdr.ch_type == ELFCOMPRESS_ZLIB)
                    printf ("       ZLIB, ");
@@ -9924,7 +10023,7 @@ process_version_sections (FILE * file)
                int j;
                int isum;
 
-               /* Check for very large indicies.  */
+               /* Check for very large indices.  */
                if (idx > (size_t) (endbuf - (char *) edefs))
                  break;
 
@@ -9949,7 +10048,7 @@ process_version_sections (FILE * file)
                        ent.vd_ndx, ent.vd_cnt);
 
                /* Check for overflow.  */
-               if (ent.vd_aux > (size_t) (endbuf - vstart))
+               if (ent.vd_aux + sizeof (* eaux) > (size_t) (endbuf - vstart))
                  break;
 
                vstart += ent.vd_aux;
@@ -11514,16 +11613,32 @@ process_syminfo (FILE * file ATTRIBUTE_UNUSED)
   return 1;
 }
 
+#define IN_RANGE(START,END,ADDR,OFF)           \
+  (((ADDR) >= (START)) && ((ADDR) + (OFF) < (END)))
+
 /* Check to see if the given reloc needs to be handled in a target specific
    manner.  If so then process the reloc and return TRUE otherwise return
-   FALSE.  */
+   FALSE.
+
+   If called with reloc == NULL, then this is a signal that reloc processing
+   for the current section has finished, and any saved state should be
+   discarded.  */
 
 static bfd_boolean
 target_specific_reloc_handling (Elf_Internal_Rela * reloc,
                                unsigned char *     start,
-                               Elf_Internal_Sym *  symtab)
+                               unsigned char *     end,
+                               Elf_Internal_Sym *  symtab,
+                               unsigned long       num_syms)
 {
-  unsigned int reloc_type = get_reloc_type (reloc->r_info);
+  unsigned int reloc_type = 0;
+  unsigned long sym_index = 0;
+
+  if (reloc)
+    {
+      reloc_type = get_reloc_type (reloc->r_info);
+      sym_index = get_reloc_symindex (reloc->r_info);
+    }
 
   switch (elf_header.e_machine)
     {
@@ -11532,6 +11647,12 @@ target_specific_reloc_handling (Elf_Internal_Rela * reloc,
       {
        static Elf_Internal_Sym * saved_sym = NULL;
 
+       if (reloc == NULL)
+         {
+           saved_sym = NULL;
+           return TRUE;
+         }
+
        switch (reloc_type)
          {
          case 10: /* R_MSP430_SYM_DIFF */
@@ -11539,7 +11660,12 @@ target_specific_reloc_handling (Elf_Internal_Rela * reloc,
              break;
            /* Fall through.  */
          case 21: /* R_MSP430X_SYM_DIFF */
-           saved_sym = symtab + get_reloc_symindex (reloc->r_info);
+           /* PR 21139.  */
+           if (sym_index >= num_syms)
+             error (_("MSP430 SYM_DIFF reloc contains invalid symbol index %lu\n"),
+                    sym_index);
+           else
+             saved_sym = symtab + sym_index;
            return TRUE;
 
          case 1: /* R_MSP430_32 or R_MSP430_ABS32 */
@@ -11561,13 +11687,24 @@ target_specific_reloc_handling (Elf_Internal_Rela * reloc,
          handle_sym_diff:
            if (saved_sym != NULL)
              {
+               int reloc_size = reloc_type == 1 ? 4 : 2;
                bfd_vma value;
 
-               value = reloc->r_addend
-                 + (symtab[get_reloc_symindex (reloc->r_info)].st_value
-                    - saved_sym->st_value);
+               if (sym_index >= num_syms)
+                 error (_("MSP430 reloc contains invalid symbol index %lu\n"),
+                        sym_index);
+               else
+                 {
+                   value = reloc->r_addend + (symtab[sym_index].st_value
+                                              - saved_sym->st_value);
 
-               byte_put (start + reloc->r_offset, value, reloc_type == 1 ? 4 : 2);
+                   if (IN_RANGE (start, end, start + reloc->r_offset, reloc_size))
+                     byte_put (start + reloc->r_offset, value, reloc_size);
+                   else
+                     /* PR 21137 */
+                     error (_("MSP430 sym diff reloc contains invalid offset: 0x%lx\n"),
+                            (long) reloc->r_offset);
+                 }
 
                saved_sym = NULL;
                return TRUE;
@@ -11587,24 +11724,45 @@ target_specific_reloc_handling (Elf_Internal_Rela * reloc,
       {
        static Elf_Internal_Sym * saved_sym = NULL;
 
+       if (reloc == NULL)
+         {
+           saved_sym = NULL;
+           return TRUE;
+         }
+
        switch (reloc_type)
          {
          case 34: /* R_MN10300_ALIGN */
            return TRUE;
          case 33: /* R_MN10300_SYM_DIFF */
-           saved_sym = symtab + get_reloc_symindex (reloc->r_info);
+           if (sym_index >= num_syms)
+             error (_("MN10300_SYM_DIFF reloc contains invalid symbol index %lu\n"),
+                    sym_index);
+           else
+             saved_sym = symtab + sym_index;
            return TRUE;
+
          case 1: /* R_MN10300_32 */
          case 2: /* R_MN10300_16 */
            if (saved_sym != NULL)
              {
+               int reloc_size = reloc_type == 1 ? 4 : 2;
                bfd_vma value;
 
-               value = reloc->r_addend
-                 + (symtab[get_reloc_symindex (reloc->r_info)].st_value
-                    - saved_sym->st_value);
+               if (sym_index >= num_syms)
+                 error (_("MN10300 reloc contains invalid symbol index %lu\n"),
+                        sym_index);
+               else
+                 {
+                   value = reloc->r_addend + (symtab[sym_index].st_value
+                                              - saved_sym->st_value);
 
-               byte_put (start + reloc->r_offset, value, reloc_type == 1 ? 4 : 2);
+                   if (IN_RANGE (start, end, start + reloc->r_offset, reloc_size))
+                     byte_put (start + reloc->r_offset, value, reloc_size);
+                   else
+                     error (_("MN10300 sym diff reloc contains invalid offset: 0x%lx\n"),
+                            (long) reloc->r_offset);
+                 }
 
                saved_sym = NULL;
                return TRUE;
@@ -11624,12 +11782,24 @@ target_specific_reloc_handling (Elf_Internal_Rela * reloc,
        static bfd_vma saved_sym2 = 0;
        static bfd_vma value;
 
+       if (reloc == NULL)
+         {
+           saved_sym1 = saved_sym2 = 0;
+           return TRUE;
+         }
+
        switch (reloc_type)
          {
          case 0x80: /* R_RL78_SYM.  */
            saved_sym1 = saved_sym2;
-           saved_sym2 = symtab[get_reloc_symindex (reloc->r_info)].st_value;
-           saved_sym2 += reloc->r_addend;
+           if (sym_index >= num_syms)
+             error (_("RL78_SYM reloc contains invalid symbol index %lu\n"),
+                    sym_index);
+           else
+             {
+               saved_sym2 = symtab[sym_index].st_value;
+               saved_sym2 += reloc->r_addend;
+             }
            return TRUE;
 
          case 0x83: /* R_RL78_OPsub.  */
@@ -11639,12 +11809,20 @@ target_specific_reloc_handling (Elf_Internal_Rela * reloc,
            break;
 
          case 0x41: /* R_RL78_ABS32.  */
-           byte_put (start + reloc->r_offset, value, 4);
+           if (IN_RANGE (start, end, start + reloc->r_offset, 4))
+             byte_put (start + reloc->r_offset, value, 4);
+           else
+             error (_("RL78 sym diff reloc contains invalid offset: 0x%lx\n"),
+                    (long) reloc->r_offset);
            value = 0;
            return TRUE;
 
          case 0x43: /* R_RL78_ABS16.  */
-           byte_put (start + reloc->r_offset, value, 2);
+           if (IN_RANGE (start, end, start + reloc->r_offset, 2))
+             byte_put (start + reloc->r_offset, value, 2);
+           else
+             error (_("RL78 sym diff reloc contains invalid offset: 0x%lx\n"),
+                    (long) reloc->r_offset);
            value = 0;
            return TRUE;
 
@@ -11685,7 +11863,8 @@ is_32bit_abs_reloc (unsigned int reloc_type)
     case EM_960:
       return reloc_type == 2; /* R_960_32.  */
     case EM_AARCH64:
-      return reloc_type == 258; /* R_AARCH64_ABS32 */
+      return (reloc_type == 258
+             || reloc_type == 1); /* R_AARCH64_ABS32 || R_AARCH64_P32_ABS32 */
     case EM_ADAPTEVA_EPIPHANY:
       return reloc_type == 3;
     case EM_ALPHA:
@@ -11788,6 +11967,10 @@ is_32bit_abs_reloc (unsigned int reloc_type)
       return reloc_type == 1; /* R_PPC64_ADDR32.  */
     case EM_PPC:
       return reloc_type == 1; /* R_PPC_ADDR32.  */
+    case EM_TI_PRU:
+      return reloc_type == 11; /* R_PRU_BFD_RELOC_32.  */
+    case EM_RISCV:
+      return reloc_type == 1; /* R_RISCV_32.  */
     case EM_RL78:
       return reloc_type == 1; /* R_RL78_DIR32.  */
     case EM_RX:
@@ -11941,6 +12124,8 @@ is_64bit_abs_reloc (unsigned int reloc_type)
       return reloc_type == 80; /* R_PARISC_DIR64.  */
     case EM_PPC64:
       return reloc_type == 38; /* R_PPC64_ADDR64.  */
+    case EM_RISCV:
+      return reloc_type == 2; /* R_RISCV_64.  */
     case EM_SPARC32PLUS:
     case EM_SPARCV9:
     case EM_SPARC:
@@ -12066,6 +12251,8 @@ is_16bit_abs_reloc (unsigned int reloc_type)
       return reloc_type == 9; /* R_NIOS_16.  */
     case EM_OR1K:
       return reloc_type == 2; /* R_OR1K_16.  */
+    case EM_TI_PRU:
+      return reloc_type == 8; /* R_PRU_BFD_RELOC_16.  */
     case EM_TI_C6000:
       return reloc_type == 2; /* R_C6000_ABS16.  */
     case EM_VISIUM:
@@ -12112,6 +12299,7 @@ is_none_reloc (unsigned int reloc_type)
     case EM_PARISC:  /* R_PARISC_NONE.  */
     case EM_PPC64:   /* R_PPC64_NONE.  */
     case EM_PPC:     /* R_PPC_NONE.  */
+    case EM_RISCV:   /* R_RISCV_NONE.  */
     case EM_S390:    /* R_390_NONE.  */
     case EM_S390_OLD:
     case EM_SH:      /* R_SH_NONE.  */
@@ -12141,6 +12329,11 @@ is_none_reloc (unsigned int reloc_type)
              || reloc_type == 205  /* R_NDS32_DIFF16.  */
              || reloc_type == 206  /* R_NDS32_DIFF32.  */
              || reloc_type == 207  /* R_NDS32_ULEB128.  */);
+    case EM_TI_PRU:
+      return (reloc_type == 0       /* R_PRU_NONE.  */
+             || reloc_type == 65   /* R_PRU_DIFF8.  */
+             || reloc_type == 66   /* R_PRU_DIFF16.  */
+             || reloc_type == 67   /* R_PRU_DIFF32.  */);
     case EM_XTENSA_OLD:
     case EM_XTENSA:
       return (reloc_type == 0      /* R_XTENSA_NONE.  */
@@ -12255,7 +12448,7 @@ apply_relocations (void *                     file,
 
          reloc_type = get_reloc_type (rp->r_info);
 
-         if (target_specific_reloc_handling (rp, start, symtab))
+         if (target_specific_reloc_handling (rp, start, end, symtab, num_syms))
            continue;
          else if (is_none_reloc (reloc_type))
            continue;
@@ -12351,6 +12544,9 @@ apply_relocations (void *                     file,
        }
 
       free (symtab);
+      /* Let the target specific reloc processing code know that
+        we have finished with these relocs.  */
+      target_specific_reloc_handling (NULL, NULL, NULL, NULL, 0);
 
       if (relocs_return)
        {
@@ -12479,7 +12675,8 @@ dump_section_as_strings (Elf_Internal_Shdr * section, FILE * file)
        {
          Elf_Internal_Chdr chdr;
          unsigned int compression_header_size
-           = get_compression_header (& chdr, (unsigned char *) start);
+           = get_compression_header (& chdr, (unsigned char *) start,
+                                     num_bytes);
 
          if (chdr.ch_type != ELFCOMPRESS_ZLIB)
            {
@@ -12514,10 +12711,20 @@ dump_section_as_strings (Elf_Internal_Shdr * section, FILE * file)
          new_size -= 12;
        }
 
-      if (uncompressed_size
-         && uncompress_section_contents (& start,
-                                         uncompressed_size, & new_size))
-       num_bytes = new_size;
+      if (uncompressed_size)
+       {
+         if (uncompress_section_contents (& start,
+                                          uncompressed_size, & new_size))
+           num_bytes = new_size;
+         else
+           {
+             error (_("Unable to decompress section %s\n"),
+                    printable_section_name (section));
+             return;
+           }
+       }
+      else
+       start = real_start;
     }
 
   /* If the section being dumped has relocations against it the user might
@@ -12613,7 +12820,7 @@ dump_section_as_bytes (Elf_Internal_Shdr * section,
        {
          Elf_Internal_Chdr chdr;
          unsigned int compression_header_size
-           = get_compression_header (& chdr, start);
+           = get_compression_header (& chdr, start, section_size);
 
          if (chdr.ch_type != ELFCOMPRESS_ZLIB)
            {
@@ -12648,10 +12855,23 @@ dump_section_as_bytes (Elf_Internal_Shdr * section,
          new_size -= 12;
        }
 
-      if (uncompressed_size
-         && uncompress_section_contents (& start, uncompressed_size,
-                                         & new_size))
-       section_size = new_size;
+      if (uncompressed_size)
+       {
+         if (uncompress_section_contents (& start, uncompressed_size,
+                                          & new_size))
+           {
+             section_size = new_size;
+           }
+         else
+           {
+             error (_("Unable to decompress section %s\n"),
+                    printable_section_name (section));
+             /* FIXME: Print the section anyway ?  */
+             return;
+           }
+       }
+      else
+       start = real_start;
     }
 
   if (relocate)
@@ -12766,7 +12986,7 @@ load_specific_debug_section (enum dwarf_section_display_enum debug,
              return 0;
            }
 
-         compression_header_size = get_compression_header (&chdr, start);
+         compression_header_size = get_compression_header (&chdr, start, size);
 
          if (chdr.ch_type != ELFCOMPRESS_ZLIB)
            {
@@ -12801,15 +13021,24 @@ load_specific_debug_section (enum dwarf_section_display_enum debug,
          size -= 12;
        }
 
-      if (uncompressed_size
-         && uncompress_section_contents (&start, uncompressed_size,
-                                         &size))
+      if (uncompressed_size)
        {
-         /* Free the compressed buffer, update the section buffer
-            and the section size if uncompress is successful.  */
-         free (section->start);
-         section->start = start;
+         if (uncompress_section_contents (&start, uncompressed_size,
+                                          &size))
+           {
+             /* Free the compressed buffer, update the section buffer
+                and the section size if uncompress is successful.  */
+             free (section->start);
+             section->start = start;
+           }
+         else
+           {
+             error (_("Unable to decompress section %s\n"),
+                    printable_section_name (sec));
+             return 0;
+           }
        }
+
       section->size = size;
     }
 
@@ -13008,9 +13237,12 @@ process_section_contents (FILE * file)
 
   /* Check to see if the user requested a
      dump of a section that does not exist.  */
-  while (i++ < num_dump_sects)
-    if (dump_sects[i])
-      warn (_("Section %d was not dumped because it does not exist!\n"), i);
+  while (i < num_dump_sects)
+    {
+      if (dump_sects[i])
+       warn (_("Section %d was not dumped because it does not exist!\n"), i);
+      i++;
+    }
 }
 
 static void
@@ -15802,7 +16034,7 @@ print_v850_note (Elf_Internal_Note * pnote)
   return 0;
 }
 
-static int 
+static int
 process_netbsd_elf_note (Elf_Internal_Note * pnote)
 {
   unsigned int version;
@@ -15815,11 +16047,11 @@ process_netbsd_elf_note (Elf_Internal_Note * pnote)
         printf ("  NetBSD\t\t0x%08lx\tIDENT %u (%u.%u%s%c)\n", pnote->descsz,
                version, version / 100000000, (version / 1000000) % 100,
                (version / 10000) % 100 > 26 ? "Z" : "",
-               'A' + (version / 10000) % 26); 
+               'A' + (version / 10000) % 26);
       else
        printf ("  NetBSD\t\t0x%08lx\tIDENT %u (%u.%u.%u)\n", pnote->descsz,
                version, version / 100000000, (version / 1000000) % 100,
-               (version / 100) % 100); 
+               (version / 100) % 100);
       return 1;
 
     case NT_NETBSD_MARCH: