blob: b7dde5d423080a620c9b38c08b31a85e48829e48 [file] [log] [blame]
Roland McGrathbca43152009-01-05 23:59:32 -08001/* Decompression support for libdwfl: zlib (gzip) and/or bzlib (bzip2).
2 Copyright (C) 2009 Red Hat, Inc.
Mark Wielaardde2ed972012-06-05 17:15:16 +02003 This file is part of elfutils.
Roland McGrathbca43152009-01-05 23:59:32 -08004
Mark Wielaardde2ed972012-06-05 17:15:16 +02005 This file is free software; you can redistribute it and/or modify
6 it under the terms of either
Roland McGrathbca43152009-01-05 23:59:32 -08007
Mark Wielaardde2ed972012-06-05 17:15:16 +02008 * 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
Roland McGrathbca43152009-01-05 23:59:32 -080021 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
Mark Wielaardde2ed972012-06-05 17:15:16 +020025 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/>. */
Roland McGrathbca43152009-01-05 23:59:32 -080028
29#include "libdwflP.h"
Roland McGrathae1d7dc2009-08-26 01:27:59 -070030#include "system.h"
Roland McGrathbca43152009-01-05 23:59:32 -080031
32#include <unistd.h>
33
Roland McGrath24169642009-08-26 02:26:34 -070034#ifdef LZMA
35# define USE_INFLATE 1
36# include <lzma.h>
37# define unzip __libdw_unlzma
38# define DWFL_E_ZLIB DWFL_E_LZMA
Roland McGrath6bb90712009-08-27 12:36:47 -070039# define MAGIC "\xFD" "7zXZ\0" /* XZ file format. */
40# define MAGIC2 "\x5d\0" /* Raw LZMA format. */
Roland McGrath24169642009-08-26 02:26:34 -070041# define Z(what) LZMA_##what
42# define LZMA_ERRNO LZMA_PROG_ERROR
43# define z_stream lzma_stream
44# define inflateInit(z) lzma_auto_decoder (z, 1 << 30, 0)
45# define do_inflate(z) lzma_code (z, LZMA_RUN)
46# define inflateEnd(z) lzma_end (z)
47#elif defined BZLIB
Roland McGrathae1d7dc2009-08-26 01:27:59 -070048# define USE_INFLATE 1
Roland McGrathbca43152009-01-05 23:59:32 -080049# include <bzlib.h>
50# define unzip __libdw_bunzip2
51# define DWFL_E_ZLIB DWFL_E_BZLIB
52# define MAGIC "BZh"
53# define Z(what) BZ_##what
Roland McGrathae1d7dc2009-08-26 01:27:59 -070054# define BZ_ERRNO BZ_IO_ERROR
Roland McGrathbca43152009-01-05 23:59:32 -080055# define z_stream bz_stream
56# define inflateInit(z) BZ2_bzDecompressInit (z, 0, 0)
Roland McGrath24169642009-08-26 02:26:34 -070057# define do_inflate(z) BZ2_bzDecompress (z)
Roland McGrathbca43152009-01-05 23:59:32 -080058# define inflateEnd(z) BZ2_bzDecompressEnd (z)
Roland McGrathbca43152009-01-05 23:59:32 -080059#else
Roland McGrathae1d7dc2009-08-26 01:27:59 -070060# define USE_INFLATE 0
61# define crc32 loser_crc32
Roland McGrathbca43152009-01-05 23:59:32 -080062# include <zlib.h>
63# define unzip __libdw_gunzip
64# define MAGIC "\037\213"
65# define Z(what) Z_##what
Roland McGrathd6ccdc12009-08-26 00:23:01 -070066#endif
Roland McGrathc4ac8612009-01-14 03:01:49 -080067
Roland McGrathae1d7dc2009-08-26 01:27:59 -070068#define READ_SIZE (1 << 20)
69
Roland McGrathbca43152009-01-05 23:59:32 -080070/* If this is not a compressed image, return DWFL_E_BADELF.
71 If we uncompressed it into *WHOLE, *WHOLE_SIZE, return DWFL_E_NOERROR.
Roland McGrath6bb90712009-08-27 12:36:47 -070072 Otherwise return an error for bad compressed data or I/O failure.
73 If we return an error after reading the first part of the file,
74 leave that portion malloc'd in *WHOLE, *WHOLE_SIZE. If *WHOLE
75 is not null on entry, we'll use it in lieu of repeating a read. */
Roland McGrathbca43152009-01-05 23:59:32 -080076
77Dwfl_Error internal_function
78unzip (int fd, off64_t start_offset,
79 void *mapped, size_t mapped_size,
80 void **whole, size_t *whole_size)
81{
82 void *buffer = NULL;
83 size_t size = 0;
84 inline bool bigger_buffer (size_t start)
85 {
86 size_t more = size ? size * 2 : start;
87 char *b = realloc (buffer, more);
88 while (unlikely (b == NULL) && more >= size + 1024)
89 b = realloc (buffer, more -= 1024);
90 if (unlikely (b == NULL))
91 return false;
92 buffer = b;
93 size = more;
94 return true;
95 }
96 inline void smaller_buffer (size_t end)
97 {
Roland McGrath24169642009-08-26 02:26:34 -070098 buffer = realloc (buffer, end) ?: end == 0 ? NULL : buffer;
Roland McGrathbca43152009-01-05 23:59:32 -080099 size = end;
100 }
101
Roland McGrathae1d7dc2009-08-26 01:27:59 -0700102 void *input_buffer = NULL;
Roland McGrath6bb90712009-08-27 12:36:47 -0700103 off_t input_pos = 0;
104
105 inline Dwfl_Error fail (Dwfl_Error failure)
106 {
107 if (input_pos == (off_t) mapped_size)
108 *whole = input_buffer;
109 else
110 {
111 free (input_buffer);
112 *whole = NULL;
113 }
114 free (buffer);
115 return failure;
116 }
Roland McGrathae1d7dc2009-08-26 01:27:59 -0700117
Roland McGrathbca43152009-01-05 23:59:32 -0800118 inline Dwfl_Error zlib_fail (int result)
119 {
Roland McGrathbca43152009-01-05 23:59:32 -0800120 switch (result)
121 {
122 case Z (MEM_ERROR):
Roland McGrath6bb90712009-08-27 12:36:47 -0700123 return fail (DWFL_E_NOMEM);
Roland McGrathae1d7dc2009-08-26 01:27:59 -0700124 case Z (ERRNO):
Roland McGrath6bb90712009-08-27 12:36:47 -0700125 return fail (DWFL_E_ERRNO);
126 default:
127 return fail (DWFL_E_ZLIB);
Roland McGrathbca43152009-01-05 23:59:32 -0800128 }
Roland McGrathbca43152009-01-05 23:59:32 -0800129 }
130
Roland McGrathae1d7dc2009-08-26 01:27:59 -0700131 if (mapped == NULL)
132 {
Roland McGrath6bb90712009-08-27 12:36:47 -0700133 if (*whole == NULL)
134 {
135 input_buffer = malloc (READ_SIZE);
136 if (unlikely (input_buffer == NULL))
137 return DWFL_E_NOMEM;
Roland McGrathae1d7dc2009-08-26 01:27:59 -0700138
Roland McGrath6bb90712009-08-27 12:36:47 -0700139 ssize_t n = pread_retry (fd, input_buffer, READ_SIZE, start_offset);
140 if (unlikely (n < 0))
141 return zlib_fail (Z (ERRNO));
Roland McGrathae1d7dc2009-08-26 01:27:59 -0700142
Roland McGrath6bb90712009-08-27 12:36:47 -0700143 input_pos = n;
144 mapped = input_buffer;
145 mapped_size = n;
146 }
147 else
148 {
149 input_buffer = *whole;
150 input_pos = mapped_size = *whole_size;
151 }
Roland McGrathae1d7dc2009-08-26 01:27:59 -0700152 }
153
Roland McGrath6bb90712009-08-27 12:36:47 -0700154#define NOMAGIC(magic) \
155 (mapped_size <= sizeof magic || memcmp (mapped, magic, sizeof magic - 1))
156
Roland McGrathae1d7dc2009-08-26 01:27:59 -0700157 /* First, look at the header. */
Roland McGrath6bb90712009-08-27 12:36:47 -0700158 if (NOMAGIC (MAGIC)
159#ifdef MAGIC2
160 && NOMAGIC (MAGIC2)
161#endif
162 )
Roland McGratha6ef1dc2009-01-06 00:54:49 -0800163 /* Not a compressed file. */
164 return DWFL_E_BADELF;
165
Roland McGrathae1d7dc2009-08-26 01:27:59 -0700166#if USE_INFLATE
167
168 /* This style actually only works with bzlib and liblzma.
169 The stupid zlib interface has nothing to grok the
170 gzip file headers except the slow gzFile interface. */
171
172 z_stream z = { .next_in = mapped, .avail_in = mapped_size };
173 int result = inflateInit (&z);
174 if (result != Z (OK))
Roland McGrath24169642009-08-26 02:26:34 -0700175 {
176 inflateEnd (&z);
177 return zlib_fail (result);
178 }
Roland McGrathae1d7dc2009-08-26 01:27:59 -0700179
180 do
Roland McGrathbca43152009-01-05 23:59:32 -0800181 {
Roland McGrathae1d7dc2009-08-26 01:27:59 -0700182 if (z.avail_in == 0 && input_buffer != NULL)
183 {
Roland McGrath6bb90712009-08-27 12:36:47 -0700184 ssize_t n = pread_retry (fd, input_buffer, READ_SIZE,
185 start_offset + input_pos);
Roland McGrathae1d7dc2009-08-26 01:27:59 -0700186 if (unlikely (n < 0))
Roland McGrath24169642009-08-26 02:26:34 -0700187 {
188 inflateEnd (&z);
189 return zlib_fail (Z (ERRNO));
190 }
Roland McGrathae1d7dc2009-08-26 01:27:59 -0700191 z.next_in = input_buffer;
192 z.avail_in = n;
193 input_pos += n;
194 }
195 if (z.avail_out == 0)
Roland McGrathbca43152009-01-05 23:59:32 -0800196 {
197 ptrdiff_t pos = (void *) z.next_out - buffer;
198 if (!bigger_buffer (z.avail_in))
199 {
200 result = Z (MEM_ERROR);
201 break;
202 }
203 z.next_out = buffer + pos;
204 z.avail_out = size - pos;
205 }
Roland McGrathae1d7dc2009-08-26 01:27:59 -0700206 }
Roland McGrath24169642009-08-26 02:26:34 -0700207 while ((result = do_inflate (&z)) == Z (OK));
Roland McGrathbca43152009-01-05 23:59:32 -0800208
209#ifdef BZLIB
Roland McGrathae1d7dc2009-08-26 01:27:59 -0700210 uint64_t total_out = (((uint64_t) z.total_out_hi32 << 32)
211 | z.total_out_lo32);
212 smaller_buffer (total_out);
Roland McGrathbca43152009-01-05 23:59:32 -0800213#else
Roland McGrathae1d7dc2009-08-26 01:27:59 -0700214 smaller_buffer (z.total_out);
Roland McGrathbca43152009-01-05 23:59:32 -0800215#endif
216
Roland McGrathae1d7dc2009-08-26 01:27:59 -0700217 inflateEnd (&z);
Roland McGrathbca43152009-01-05 23:59:32 -0800218
Roland McGrathae1d7dc2009-08-26 01:27:59 -0700219 if (result != Z (STREAM_END))
220 return zlib_fail (result);
Roland McGratha6ef1dc2009-01-06 00:54:49 -0800221
Roland McGrathae1d7dc2009-08-26 01:27:59 -0700222#else /* gzip only. */
223
224 /* Let the decompression library read the file directly. */
225
226 gzFile zf;
227 Dwfl_Error open_stream (void)
228 {
229 int d = dup (fd);
230 if (unlikely (d < 0))
231 return DWFL_E_BADELF;
232 if (start_offset != 0)
Roland McGrathc4ac8612009-01-14 03:01:49 -0800233 {
Roland McGrathae1d7dc2009-08-26 01:27:59 -0700234 off64_t off = lseek (d, start_offset, SEEK_SET);
235 if (off != start_offset)
Roland McGrathc4ac8612009-01-14 03:01:49 -0800236 {
237 close (d);
Roland McGrathae1d7dc2009-08-26 01:27:59 -0700238 return DWFL_E_BADELF;
Roland McGrathc4ac8612009-01-14 03:01:49 -0800239 }
Roland McGrathae1d7dc2009-08-26 01:27:59 -0700240 }
241 zf = gzdopen (d, "r");
242 if (unlikely (zf == NULL))
243 {
244 close (d);
245 return zlib_fail (Z (MEM_ERROR));
Roland McGrathc4ac8612009-01-14 03:01:49 -0800246 }
247
Roland McGrathae1d7dc2009-08-26 01:27:59 -0700248 /* From here on, zlib will close D. */
Roland McGrathbca43152009-01-05 23:59:32 -0800249
Roland McGrathae1d7dc2009-08-26 01:27:59 -0700250 return DWFL_E_NOERROR;
251 }
Roland McGrathbca43152009-01-05 23:59:32 -0800252
Roland McGrathae1d7dc2009-08-26 01:27:59 -0700253 Dwfl_Error result = open_stream ();
Roland McGrathc4ac8612009-01-14 03:01:49 -0800254
Roland McGrathae1d7dc2009-08-26 01:27:59 -0700255 if (result == DWFL_E_NOERROR && gzdirect (zf))
256 {
Roland McGrathbca43152009-01-05 23:59:32 -0800257 gzclose (zf);
Roland McGrath6bb90712009-08-27 12:36:47 -0700258 return fail (DWFL_E_BADELF);
Roland McGrathbca43152009-01-05 23:59:32 -0800259 }
260
Roland McGrathae1d7dc2009-08-26 01:27:59 -0700261 if (result != DWFL_E_NOERROR)
Roland McGrath6bb90712009-08-27 12:36:47 -0700262 return fail (result);
Roland McGrathae1d7dc2009-08-26 01:27:59 -0700263
264 ptrdiff_t pos = 0;
265 while (1)
266 {
267 if (!bigger_buffer (1024))
268 {
269 gzclose (zf);
270 return zlib_fail (Z (MEM_ERROR));
271 }
272 int n = gzread (zf, buffer + pos, size - pos);
273 if (n < 0)
274 {
275 int code;
276 gzerror (zf, &code);
277 gzclose (zf);
278 return zlib_fail (code);
279 }
280 if (n == 0)
281 break;
282 pos += n;
283 }
284
285 gzclose (zf);
286 smaller_buffer (pos);
287#endif
288
Roland McGrath6bb90712009-08-27 12:36:47 -0700289 free (input_buffer);
290
Roland McGrathbca43152009-01-05 23:59:32 -0800291 *whole = buffer;
292 *whole_size = size;
293
Roland McGratha6ef1dc2009-01-06 00:54:49 -0800294 return DWFL_E_NOERROR;
Roland McGrathbca43152009-01-05 23:59:32 -0800295}