/src/upx/src/packmast.cpp
Line | Count | Source |
1 | | /* packmast.cpp -- |
2 | | |
3 | | This file is part of the UPX executable compressor. |
4 | | |
5 | | Copyright (C) Markus Franz Xaver Johannes Oberhumer |
6 | | Copyright (C) Laszlo Molnar |
7 | | All Rights Reserved. |
8 | | |
9 | | UPX and the UCL library are free software; you can redistribute them |
10 | | and/or modify them under the terms of the GNU General Public License as |
11 | | published by the Free Software Foundation; either version 2 of |
12 | | the License, or (at your option) any later version. |
13 | | |
14 | | This program is distributed in the hope that it will be useful, |
15 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | | GNU General Public License for more details. |
18 | | |
19 | | You should have received a copy of the GNU General Public License |
20 | | along with this program; see the file COPYING. |
21 | | If not, write to the Free Software Foundation, Inc., |
22 | | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
23 | | |
24 | | Markus F.X.J. Oberhumer Laszlo Molnar |
25 | | <markus@oberhumer.com> <ezerotven+github@gmail.com> |
26 | | */ |
27 | | |
28 | | // dispatch to a concrete subclass of class PackerBase; see work.cpp |
29 | | |
30 | | #include "conf.h" |
31 | | #include "file.h" |
32 | | #include "packmast.h" |
33 | | #include "packer.h" |
34 | | |
35 | | #include "lefile.h" |
36 | | #include "pefile.h" |
37 | | #include "p_elf.h" |
38 | | #include "p_unix.h" |
39 | | |
40 | | #include "p_com.h" |
41 | | #include "p_djgpp2.h" |
42 | | #include "p_exe.h" |
43 | | #include "p_lx_elf.h" |
44 | | #include "p_lx_exc.h" |
45 | | #include "p_lx_interp.h" |
46 | | #include "p_lx_sh.h" |
47 | | #include "p_mach.h" |
48 | | #include "p_ps1.h" |
49 | | #include "p_sys.h" |
50 | | #include "p_tmt.h" |
51 | | #include "p_tos.h" |
52 | | #include "p_vmlinx.h" |
53 | | #include "p_vmlinz.h" |
54 | | #include "p_w32pe_i386.h" |
55 | | #include "p_w64pe_amd64.h" |
56 | | #include "p_w64pe_arm64.h" |
57 | | #include "p_wcle.h" |
58 | | #include "p_wince_arm.h" |
59 | | |
60 | | /************************************************************************* |
61 | | // |
62 | | **************************************************************************/ |
63 | | |
64 | 3.84k | PackMaster::PackMaster(InputFile *f, Options *o) noexcept : fi(f) { |
65 | | // replace global options with local options |
66 | 3.84k | if (o != nullptr) { |
67 | | #if WITH_THREADS |
68 | | // TODO later: check for possible "noexcept" violation here |
69 | | std::lock_guard<std::mutex> lock(opt_lock_mutex); |
70 | | #endif |
71 | 3.84k | saved_opt = o; |
72 | 3.84k | memcpy(&this->local_options, o, sizeof(*o)); // struct copy |
73 | 3.84k | opt = &this->local_options; |
74 | 3.84k | } |
75 | 3.84k | } |
76 | | |
77 | 3.84k | PackMaster::~PackMaster() noexcept { |
78 | 3.84k | upx::owner_delete(packer); |
79 | | // restore global options |
80 | 3.84k | if (saved_opt != nullptr) { |
81 | | #if WITH_THREADS |
82 | | // TODO later: check for possible "noexcept" violation here |
83 | | std::lock_guard<std::mutex> lock(opt_lock_mutex); |
84 | | #endif |
85 | 3.84k | opt = saved_opt; |
86 | 3.84k | saved_opt = nullptr; |
87 | 3.84k | } |
88 | 3.84k | } |
89 | | |
90 | | /************************************************************************* |
91 | | // |
92 | | **************************************************************************/ |
93 | | |
94 | 0 | static noinline tribool try_can_pack(PackerBase *pb, void *user) may_throw { |
95 | 0 | InputFile *f = (InputFile *) user; |
96 | 0 | try { |
97 | 0 | pb->initPackHeader(); |
98 | 0 | f->seek(0, SEEK_SET); |
99 | 0 | tribool r = pb->canPack(); |
100 | 0 | if (r) { |
101 | 0 | if (opt->cmd == CMD_COMPRESS) |
102 | 0 | pb->updatePackHeader(); |
103 | 0 | f->seek(0, SEEK_SET); |
104 | 0 | return true; // success |
105 | 0 | } |
106 | 0 | if (r.isThird()) // aka "-1" |
107 | 0 | return r; // canPack() says the format is recognized and we should fail early |
108 | 0 | } catch (const IOException &) { |
109 | | // ignored |
110 | 0 | } |
111 | 0 | return false; |
112 | 0 | } |
113 | | |
114 | 113k | static noinline tribool try_can_unpack(PackerBase *pb, void *user) may_throw { |
115 | 113k | InputFile *f = (InputFile *) user; |
116 | 113k | try { |
117 | 113k | pb->initPackHeader(); |
118 | 113k | f->seek(0, SEEK_SET); |
119 | 113k | tribool r = pb->canUnpack(); |
120 | 113k | if (r) { |
121 | 977 | f->seek(0, SEEK_SET); |
122 | 977 | return true; // success |
123 | 977 | } |
124 | 112k | if (r.isThird()) // aka "-1" |
125 | 29 | return r; // canUnpack() says the format is recognized and we should fail early |
126 | 112k | } catch (const IOException &) { |
127 | | // ignored |
128 | 6.45k | } |
129 | 111k | return false; |
130 | 113k | } |
131 | | |
132 | | /************************************************************************* |
133 | | // |
134 | | **************************************************************************/ |
135 | | |
136 | | /*static*/ |
137 | | PackerBase *PackMaster::visitAllPackers(visit_func_t func, InputFile *f, const Options *o, |
138 | 3.84k | void *user) may_throw { |
139 | 3.84k | #define VISIT(Klass) \ |
140 | 146k | do { \ |
141 | 146k | static_assert(std::is_class_v<Klass>); \ |
142 | 146k | static_assert(std::is_nothrow_destructible_v<Klass>); \ |
143 | 146k | auto pb = std::unique_ptr<PackerBase>(new Klass(f)); \ |
144 | 146k | if (o->debug.debug_level) \ |
145 | 146k | fprintf(stderr, "visitAllPackers: (ver=%d, fmt=%3d) %s\n", pb->getVersion(), \ |
146 | 0 | pb->getFormat(), #Klass); \ |
147 | 146k | pb->assertPacker(); \ |
148 | 146k | tribool r = func(pb.get(), user); \ |
149 | 146k | if (r) \ |
150 | 146k | return pb.release(); /* success */ \ |
151 | 146k | if (r.isThird()) \ |
152 | 145k | return nullptr; /* stop and fail early */ \ |
153 | 145k | } while (0) |
154 | | |
155 | | // NOTE: order of tries is important !!! |
156 | | |
157 | | // |
158 | | // .exe |
159 | | // |
160 | 3.84k | if (!o->dos_exe.force_stub) { |
161 | | // dos32 |
162 | 3.84k | VISIT(PackDjgpp2); |
163 | 3.84k | VISIT(PackTmt); |
164 | 3.83k | VISIT(PackWcle); |
165 | | // Windows |
166 | | // VISIT(PackW64PeArm64EC); // NOT YET IMPLEMENTED |
167 | | // VISIT(PackW64PeArm64); // NOT YET IMPLEMENTED |
168 | 3.81k | VISIT(PackW64PeAmd64); |
169 | 3.80k | VISIT(PackW32PeI386); |
170 | 3.77k | VISIT(PackWinCeArm); |
171 | 3.77k | } |
172 | 3.76k | VISIT(PackExe); // dos/exe |
173 | | |
174 | | // |
175 | | // linux kernel |
176 | | // |
177 | 3.75k | VISIT(PackVmlinuxARMEL); |
178 | 3.75k | VISIT(PackVmlinuxARMEB); |
179 | 3.75k | VISIT(PackVmlinuxPPC32); |
180 | 3.75k | VISIT(PackVmlinuxPPC64LE); |
181 | 3.75k | VISIT(PackVmlinuxAMD64); |
182 | 3.75k | VISIT(PackVmlinuxI386); |
183 | 3.75k | #if (WITH_ZLIB) |
184 | 3.75k | VISIT(PackVmlinuzI386); |
185 | 3.74k | VISIT(PackBvmlinuzI386); |
186 | 3.74k | VISIT(PackVmlinuzARMEL); |
187 | 3.74k | #endif |
188 | | |
189 | | // |
190 | | // linux |
191 | | // |
192 | 3.74k | if (!o->o_unix.force_execve) { |
193 | 3.43k | if (o->o_unix.use_ptinterp) { |
194 | 0 | VISIT(PackLinuxElf32x86interp); |
195 | 0 | } |
196 | 3.43k | VISIT(PackFreeBSDElf32x86); |
197 | 3.43k | VISIT(PackNetBSDElf32x86); |
198 | 3.43k | VISIT(PackOpenBSDElf32x86); |
199 | 3.43k | VISIT(PackLinuxElf32x86); |
200 | 3.28k | VISIT(PackLinuxElf64amd); |
201 | 3.13k | VISIT(PackLinuxElf32armLe); |
202 | 3.11k | VISIT(PackLinuxElf32armBe); |
203 | 3.06k | VISIT(PackLinuxElf64arm); |
204 | 3.02k | VISIT(PackLinuxElf64riscv64); |
205 | 3.02k | VISIT(PackLinuxElf32ppc); |
206 | 2.99k | VISIT(PackLinuxElf64ppc); |
207 | 2.98k | VISIT(PackLinuxElf64ppcle); |
208 | 2.96k | VISIT(PackLinuxElf32mipsel); |
209 | 2.93k | VISIT(PackLinuxElf32mipseb); |
210 | 2.91k | VISIT(PackLinuxI386sh); |
211 | 2.91k | } |
212 | 3.21k | VISIT(PackBSDI386); |
213 | 3.21k | VISIT(PackMachFat); // cafebabe conflict |
214 | 3.21k | VISIT(PackLinuxI386); // cafebabe conflict |
215 | | |
216 | | // |
217 | | // Mach (Darwin / macOS) |
218 | | // |
219 | 3.03k | VISIT(PackDylibAMD64); |
220 | 3.03k | VISIT(PackMachPPC32); // TODO: this works with upx 3.91..3.94 but got broken in 3.95; FIXME |
221 | 3.01k | VISIT(PackMachI386); |
222 | 3.01k | VISIT(PackMachAMD64); |
223 | 2.96k | VISIT(PackMachARMEL); |
224 | 2.95k | VISIT(PackMachARM64EL); |
225 | | |
226 | | // 2010-03-12 omit these because PackMachBase<T>::pack4dylib (p_mach.cpp) |
227 | | // does not understand what the Darwin (Apple Mac OS X) dynamic loader |
228 | | // assumes about .dylib file structure. |
229 | | // VISIT(PackDylibI386); |
230 | | // VISIT(PackDylibPPC32); |
231 | | |
232 | | // |
233 | | // misc |
234 | | // |
235 | 2.86k | VISIT(PackTos); // atari/tos |
236 | 2.86k | VISIT(PackPs1); // ps1/exe |
237 | 2.86k | VISIT(PackSys); // dos/sys |
238 | 2.85k | VISIT(PackCom); // dos/com |
239 | | |
240 | 2.84k | return nullptr; |
241 | 2.85k | #undef VISIT |
242 | 2.85k | } |
243 | | |
244 | 0 | /*static*/ PackerBase *PackMaster::getPacker(InputFile *f) may_throw { |
245 | 0 | PackerBase *pb = visitAllPackers(try_can_pack, f, opt, f); |
246 | 0 | if (!pb) |
247 | 0 | throwUnknownExecutableFormat(); |
248 | 0 | return pb; |
249 | 0 | } |
250 | | |
251 | 3.84k | /*static*/ PackerBase *PackMaster::getUnpacker(InputFile *f) may_throw { |
252 | 3.84k | PackerBase *pb = visitAllPackers(try_can_unpack, f, opt, f); |
253 | 3.84k | if (!pb) |
254 | 968 | throwNotPacked(); |
255 | 2.88k | return pb; |
256 | 3.84k | } |
257 | | |
258 | | /************************************************************************* |
259 | | // delegation from work.cpp |
260 | | **************************************************************************/ |
261 | | |
262 | 0 | void PackMaster::pack(OutputFile *fo) may_throw { |
263 | 0 | assert(packer == nullptr); |
264 | 0 | packer = getPacker(fi); |
265 | 0 | packer->doPack(fo); |
266 | 0 | } |
267 | | |
268 | 0 | void PackMaster::unpack(OutputFile *fo) may_throw { |
269 | 0 | assert(packer == nullptr); |
270 | 0 | packer = getUnpacker(fi); |
271 | 0 | packer->doUnpack(fo); |
272 | 0 | } |
273 | | |
274 | 3.84k | void PackMaster::test() may_throw { |
275 | 3.84k | assert(packer == nullptr); |
276 | 0 | packer = getUnpacker(fi); |
277 | 3.84k | packer->doTest(); |
278 | 3.84k | } |
279 | | |
280 | 0 | void PackMaster::list() may_throw { |
281 | 0 | assert(packer == nullptr); |
282 | 0 | packer = getUnpacker(fi); |
283 | 0 | packer->doList(); |
284 | 0 | } |
285 | | |
286 | 0 | void PackMaster::fileInfo() may_throw { |
287 | 0 | assert(packer == nullptr); |
288 | 0 | packer = visitAllPackers(try_can_unpack, fi, opt, fi); |
289 | 0 | if (!packer) |
290 | 0 | packer = visitAllPackers(try_can_pack, fi, opt, fi); |
291 | 0 | if (!packer) |
292 | 0 | throwUnknownExecutableFormat(nullptr, true); // make a warning here |
293 | 0 | packer->doFileInfo(); |
294 | 0 | } |
295 | | |
296 | | /* vim:set ts=4 sw=4 et: */ |