blob: 4e0461bd2a9e89fae926d44195f49dca95f83789 [file] [log] [blame]
Brian Silverman86497922018-02-10 19:28:39 -05001/* Decompression support for libdwfl: zlib (gzip), bzlib (bzip2) or lzma (xz).
2 Copyright (C) 2009, 2016 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#ifdef HAVE_CONFIG_H
30# include <config.h>
31#endif
32
33#include "../libelf/libelfP.h"
34#undef _
35#include "libdwflP.h"
36
37#include <unistd.h>
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 const off_t offset = (*elf)->start_offset;
56 void *const mapped = ((*elf)->map_address == NULL ? NULL
57 : (*elf)->map_address + offset);
58 const size_t mapped_size = (*elf)->maximum_size;
59 if (mapped_size == 0)
60 return error;
61
62 error = __libdw_gunzip (fd, offset, mapped, mapped_size, &buffer, &size);
63 if (error == DWFL_E_BADELF)
64 error = __libdw_bunzip2 (fd, offset, mapped, mapped_size, &buffer, &size);
65 if (error == DWFL_E_BADELF)
66 error = __libdw_unlzma (fd, offset, mapped, mapped_size, &buffer, &size);
67
68 if (error == DWFL_E_NOERROR)
69 {
70 if (unlikely (size == 0))
71 {
72 error = DWFL_E_BADELF;
73 free (buffer);
74 }
75 else
76 {
77 Elf *memelf = elf_memory (buffer, size);
78 if (memelf == NULL)
79 {
80 error = DWFL_E_LIBELF;
81 free (buffer);
82 }
83 else
84 {
85 memelf->flags |= ELF_F_MALLOCED;
86 elf_end (*elf);
87 *elf = memelf;
88 }
89 }
90 }
91 else
92 free (buffer);
93
94 return error;
95}
96
97static Dwfl_Error
98what_kind (int fd, Elf **elfp, Elf_Kind *kind, bool *close_fd)
99{
100 Dwfl_Error error = DWFL_E_NOERROR;
101 *kind = elf_kind (*elfp);
102 if (unlikely (*kind == ELF_K_NONE))
103 {
104 if (unlikely (*elfp == NULL))
105 error = DWFL_E_LIBELF;
106 else
107 {
108 error = decompress (fd, elfp);
109 if (error == DWFL_E_NOERROR)
110 {
111 *close_fd = true;
112 *kind = elf_kind (*elfp);
113 }
114 }
115 }
116 return error;
117}
118
119Dwfl_Error internal_function
120__libdw_open_file (int *fdp, Elf **elfp, bool close_on_fail, bool archive_ok)
121{
122 bool close_fd = false;
123
124 Elf *elf = elf_begin (*fdp, ELF_C_READ_MMAP_PRIVATE, NULL);
125
126 Elf_Kind kind;
127 Dwfl_Error error = what_kind (*fdp, &elf, &kind, &close_fd);
128 if (error == DWFL_E_BADELF)
129 {
130 /* It's not an ELF file or a compressed file.
131 See if it's an image with a header preceding the real file. */
132
133 off_t offset = elf->start_offset;
134 error = __libdw_image_header (*fdp, &offset,
135 (elf->map_address == NULL ? NULL
136 : elf->map_address + offset),
137 elf->maximum_size);
138 if (error == DWFL_E_NOERROR)
139 {
140 /* Pure evil. libelf needs some better interfaces. */
141 elf->kind = ELF_K_AR;
142 elf->state.ar.elf_ar_hdr.ar_name = "libdwfl is faking you out";
143 elf->state.ar.elf_ar_hdr.ar_size = elf->maximum_size - offset;
144 elf->state.ar.offset = offset - sizeof (struct ar_hdr);
145 Elf *subelf = elf_begin (-1, ELF_C_READ_MMAP_PRIVATE, elf);
146 elf->kind = ELF_K_NONE;
147 if (unlikely (subelf == NULL))
148 error = DWFL_E_LIBELF;
149 else
150 {
151 subelf->parent = NULL;
152 subelf->flags |= elf->flags & (ELF_F_MMAPPED | ELF_F_MALLOCED);
153 elf->flags &= ~(ELF_F_MMAPPED | ELF_F_MALLOCED);
154 elf_end (elf);
155 elf = subelf;
156 error = what_kind (*fdp, &elf, &kind, &close_fd);
157 }
158 }
159 }
160
161 if (error == DWFL_E_NOERROR
162 && kind != ELF_K_ELF
163 && !(archive_ok && kind == ELF_K_AR))
164 error = DWFL_E_BADELF;
165
166 if (error != DWFL_E_NOERROR)
167 {
168 elf_end (elf);
169 elf = NULL;
170 }
171
172 if (error == DWFL_E_NOERROR ? close_fd : close_on_fail)
173 {
174 close (*fdp);
175 *fdp = -1;
176 }
177
178 *elfp = elf;
179 return error;
180}