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
decompress(int fd,Elf ** elf)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
what_kind(int fd,Elf ** elfp,Elf_Kind * kind,bool * close_fd)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
__libdw_open_file(int * fdp,Elf ** elfp,bool close_on_fail,bool archive_ok)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