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