Line data Source code
1 : /* 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. */
48 : static Dwfl_Error
49 6 : decompress (int fd __attribute__ ((unused)), Elf **elf)
50 : {
51 6 : Dwfl_Error error = DWFL_E_BADELF;
52 6 : void *buffer = NULL;
53 6 : size_t size = 0;
54 :
55 6 : const off_t offset = (*elf)->start_offset;
56 12 : void *const mapped = ((*elf)->map_address == NULL ? NULL
57 6 : : (*elf)->map_address + offset);
58 6 : const size_t mapped_size = (*elf)->maximum_size;
59 6 : if (mapped_size == 0)
60 : return error;
61 :
62 6 : error = __libdw_gunzip (fd, offset, mapped, mapped_size, &buffer, &size);
63 6 : if (error == DWFL_E_BADELF)
64 6 : error = __libdw_bunzip2 (fd, offset, mapped, mapped_size, &buffer, &size);
65 6 : if (error == DWFL_E_BADELF)
66 4 : error = __libdw_unlzma (fd, offset, mapped, mapped_size, &buffer, &size);
67 :
68 6 : if (error == DWFL_E_NOERROR)
69 : {
70 6 : if (unlikely (size == 0))
71 : {
72 0 : error = DWFL_E_BADELF;
73 0 : free (buffer);
74 : }
75 : else
76 : {
77 6 : Elf *memelf = elf_memory (buffer, size);
78 6 : if (memelf == NULL)
79 : {
80 0 : error = DWFL_E_LIBELF;
81 0 : free (buffer);
82 : }
83 : else
84 : {
85 6 : memelf->flags |= ELF_F_MALLOCED;
86 6 : elf_end (*elf);
87 6 : *elf = memelf;
88 : }
89 : }
90 : }
91 : else
92 0 : free (buffer);
93 :
94 : return error;
95 : }
96 :
97 : static Dwfl_Error
98 5695 : what_kind (int fd, Elf **elfp, Elf_Kind *kind, bool *may_close_fd)
99 : {
100 5695 : Dwfl_Error error = DWFL_E_NOERROR;
101 5695 : *kind = elf_kind (*elfp);
102 5695 : if (unlikely (*kind == ELF_K_NONE))
103 : {
104 6 : if (unlikely (*elfp == NULL))
105 : error = DWFL_E_LIBELF;
106 : else
107 : {
108 6 : error = decompress (fd, elfp);
109 6 : if (error == DWFL_E_NOERROR)
110 : {
111 6 : *may_close_fd = true;
112 6 : *kind = elf_kind (*elfp);
113 : }
114 : }
115 : }
116 5695 : return error;
117 : }
118 :
119 : static Dwfl_Error
120 5695 : libdw_open_elf (int *fdp, Elf **elfp, bool close_on_fail, bool archive_ok,
121 : bool never_close_fd)
122 : {
123 5695 : bool may_close_fd = false;
124 :
125 5695 : Elf *elf = elf_begin (*fdp, ELF_C_READ_MMAP_PRIVATE, NULL);
126 :
127 : Elf_Kind kind;
128 5695 : Dwfl_Error error = what_kind (*fdp, &elf, &kind, &may_close_fd);
129 5695 : if (error == DWFL_E_BADELF)
130 : {
131 : /* It's not an ELF file or a compressed file.
132 : See if it's an image with a header preceding the real file. */
133 :
134 0 : off_t offset = elf->start_offset;
135 0 : error = __libdw_image_header (*fdp, &offset,
136 0 : (elf->map_address == NULL ? NULL
137 0 : : elf->map_address + offset),
138 : elf->maximum_size);
139 0 : if (error == DWFL_E_NOERROR)
140 : {
141 : /* Pure evil. libelf needs some better interfaces. */
142 0 : elf->kind = ELF_K_AR;
143 0 : elf->state.ar.elf_ar_hdr.ar_name = "libdwfl is faking you out";
144 0 : elf->state.ar.elf_ar_hdr.ar_size = elf->maximum_size - offset;
145 0 : elf->state.ar.offset = offset - sizeof (struct ar_hdr);
146 0 : Elf *subelf = elf_begin (-1, ELF_C_READ_MMAP_PRIVATE, elf);
147 0 : elf->kind = ELF_K_NONE;
148 0 : if (unlikely (subelf == NULL))
149 : error = DWFL_E_LIBELF;
150 : else
151 : {
152 0 : subelf->parent = NULL;
153 0 : subelf->flags |= elf->flags & (ELF_F_MMAPPED | ELF_F_MALLOCED);
154 0 : elf->flags &= ~(ELF_F_MMAPPED | ELF_F_MALLOCED);
155 0 : elf_end (elf);
156 0 : elf = subelf;
157 0 : error = what_kind (*fdp, &elf, &kind, &may_close_fd);
158 : }
159 : }
160 : }
161 :
162 5695 : if (error == DWFL_E_NOERROR
163 5695 : && kind != ELF_K_ELF
164 0 : && !(archive_ok && kind == ELF_K_AR))
165 : error = DWFL_E_BADELF;
166 :
167 5695 : if (error != DWFL_E_NOERROR)
168 : {
169 0 : elf_end (elf);
170 0 : elf = NULL;
171 : }
172 :
173 11390 : if (! never_close_fd
174 5695 : && error == DWFL_E_NOERROR ? may_close_fd : close_on_fail)
175 : {
176 5 : close (*fdp);
177 5 : *fdp = -1;
178 : }
179 :
180 5695 : *elfp = elf;
181 5695 : return error;
182 : }
183 :
184 : Dwfl_Error internal_function
185 5634 : __libdw_open_file (int *fdp, Elf **elfp, bool close_on_fail, bool archive_ok)
186 : {
187 5634 : return libdw_open_elf (fdp, elfp, close_on_fail, archive_ok, false);
188 : }
189 :
190 : Dwfl_Error internal_function
191 61 : __libdw_open_elf (int fd, Elf **elfp)
192 : {
193 61 : return libdw_open_elf (&fd, elfp, false, true, true);
194 : }
|