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