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. */ 48static Dwfl_Error 49decompress (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 99static Dwfl_Error 100what_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 121Dwfl_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