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