Home | History | Annotate | Download | only in libdwfl
      1 /* Decompression support for libdwfl: zlib (gzip) and/or bzlib (bzip2).
      2    Copyright (C) 2009 Red Hat, Inc.
      3    This file is part of elfutils.
      4 
      5    This file is free software; you can redistribute it and/or modify
      6    it under the terms of either
      7 
      8      * the GNU Lesser General Public License as published by the Free
      9        Software Foundation; either version 3 of the License, or (at
     10        your option) any later version
     11 
     12    or
     13 
     14      * the GNU General Public License as published by the Free
     15        Software Foundation; either version 2 of the License, or (at
     16        your option) any later version
     17 
     18    or both in parallel, as here.
     19 
     20    elfutils is distributed in the hope that it will be useful, but
     21    WITHOUT ANY WARRANTY; without even the implied warranty of
     22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     23    General Public License for more details.
     24 
     25    You should have received copies of the GNU General Public License and
     26    the GNU Lesser General Public License along with this program.  If
     27    not, see <http://www.gnu.org/licenses/>.  */
     28 
     29 #include "../libelf/libelfP.h"
     30 #undef	_
     31 #include "libdwflP.h"
     32 
     33 #include <unistd.h>
     34 
     35 #if !USE_ZLIB
     36 # define __libdw_gunzip(...)	DWFL_E_BADELF
     37 #endif
     38 
     39 #if !USE_BZLIB
     40 # define __libdw_bunzip2(...)	DWFL_E_BADELF
     41 #endif
     42 
     43 #if !USE_LZMA
     44 # define __libdw_unlzma(...)	DWFL_E_BADELF
     45 #endif
     46 
     47 /* Consumes and replaces *ELF only on success.  */
     48 static Dwfl_Error
     49 decompress (int fd __attribute__ ((unused)), Elf **elf)
     50 {
     51   Dwfl_Error error = DWFL_E_BADELF;
     52   void *buffer = NULL;
     53   size_t size = 0;
     54 
     55 #if USE_ZLIB || USE_BZLIB || USE_LZMA
     56   const off64_t offset = (*elf)->start_offset;
     57   void *const mapped = ((*elf)->map_address == NULL ? NULL
     58 			: (*elf)->map_address + offset);
     59   const size_t mapped_size = (*elf)->maximum_size;
     60   if (mapped_size == 0)
     61     return error;
     62 
     63   error = __libdw_gunzip (fd, offset, mapped, mapped_size, &buffer, &size);
     64   if (error == DWFL_E_BADELF)
     65     error = __libdw_bunzip2 (fd, offset, mapped, mapped_size, &buffer, &size);
     66   if (error == DWFL_E_BADELF)
     67     error = __libdw_unlzma (fd, offset, mapped, mapped_size, &buffer, &size);
     68 #endif
     69 
     70   if (error == DWFL_E_NOERROR)
     71     {
     72       if (unlikely (size == 0))
     73 	{
     74 	  error = DWFL_E_BADELF;
     75 	  free (buffer);
     76 	}
     77       else
     78 	{
     79 	  Elf *memelf = elf_memory (buffer, size);
     80 	  if (memelf == NULL)
     81 	    {
     82 	      error = DWFL_E_LIBELF;
     83 	      free (buffer);
     84 	    }
     85 	  else
     86 	    {
     87 	      memelf->flags |= ELF_F_MALLOCED;
     88 	      elf_end (*elf);
     89 	      *elf = memelf;
     90 	    }
     91 	}
     92     }
     93   else
     94     free (buffer);
     95 
     96   return error;
     97 }
     98 
     99 static Dwfl_Error
    100 what_kind (int fd, Elf **elfp, Elf_Kind *kind, bool *close_fd)
    101 {
    102   Dwfl_Error error = DWFL_E_NOERROR;
    103   *kind = elf_kind (*elfp);
    104   if (unlikely (*kind == ELF_K_NONE))
    105     {
    106       if (unlikely (*elfp == NULL))
    107 	error = DWFL_E_LIBELF;
    108       else
    109 	{
    110 	  error = decompress (fd, elfp);
    111 	  if (error == DWFL_E_NOERROR)
    112 	    {
    113 	      *close_fd = true;
    114 	      *kind = elf_kind (*elfp);
    115 	    }
    116 	}
    117     }
    118   return error;
    119 }
    120 
    121 Dwfl_Error internal_function
    122 __libdw_open_file (int *fdp, Elf **elfp, bool close_on_fail, bool archive_ok)
    123 {
    124   bool close_fd = false;
    125 
    126   Elf *elf = elf_begin (*fdp, ELF_C_READ_MMAP_PRIVATE, NULL);
    127 
    128   Elf_Kind kind;
    129   Dwfl_Error error = what_kind (*fdp, &elf, &kind, &close_fd);
    130   if (error == DWFL_E_BADELF)
    131     {
    132       /* It's not an ELF file or a compressed file.
    133 	 See if it's an image with a header preceding the real file.  */
    134 
    135       off64_t offset = elf->start_offset;
    136       error = __libdw_image_header (*fdp, &offset,
    137 				    (elf->map_address == NULL ? NULL
    138 				     : elf->map_address + offset),
    139 				    elf->maximum_size);
    140       if (error == DWFL_E_NOERROR)
    141 	{
    142 	  /* Pure evil.  libelf needs some better interfaces.  */
    143 	  elf->kind = ELF_K_AR;
    144 	  elf->state.ar.elf_ar_hdr.ar_name = "libdwfl is faking you out";
    145 	  elf->state.ar.elf_ar_hdr.ar_size = elf->maximum_size - offset;
    146 	  elf->state.ar.offset = offset - sizeof (struct ar_hdr);
    147 	  Elf *subelf = elf_begin (-1, ELF_C_READ_MMAP_PRIVATE, elf);
    148 	  elf->kind = ELF_K_NONE;
    149 	  if (unlikely (subelf == NULL))
    150 	    error = DWFL_E_LIBELF;
    151 	  else
    152 	    {
    153 	      subelf->parent = NULL;
    154 	      subelf->flags |= elf->flags & (ELF_F_MMAPPED | ELF_F_MALLOCED);
    155 	      elf->flags &= ~(ELF_F_MMAPPED | ELF_F_MALLOCED);
    156 	      elf_end (elf);
    157 	      elf = subelf;
    158 	      error = what_kind (*fdp, &elf, &kind, &close_fd);
    159 	    }
    160 	}
    161     }
    162 
    163   if (error == DWFL_E_NOERROR
    164       && kind != ELF_K_ELF
    165       && !(archive_ok && kind == ELF_K_AR))
    166     error = DWFL_E_BADELF;
    167 
    168   if (error != DWFL_E_NOERROR)
    169     {
    170       elf_end (elf);
    171       elf = NULL;
    172     }
    173 
    174   if (error == DWFL_E_NOERROR ? close_fd : close_on_fail)
    175     {
    176       close (*fdp);
    177       *fdp = -1;
    178     }
    179 
    180   *elfp = elf;
    181   return error;
    182 }
    183