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