diff options
Diffstat (limited to 'CPP/7zip/Archive/ElfHandler.cpp')
-rw-r--r-- | CPP/7zip/Archive/ElfHandler.cpp | 1109 |
1 files changed, 1109 insertions, 0 deletions
diff --git a/CPP/7zip/Archive/ElfHandler.cpp b/CPP/7zip/Archive/ElfHandler.cpp new file mode 100644 index 0000000..efcde95 --- /dev/null +++ b/CPP/7zip/Archive/ElfHandler.cpp | |||
@@ -0,0 +1,1109 @@ | |||
1 | // ElfHandler.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
4 | |||
5 | #include "../../../C/CpuArch.h" | ||
6 | |||
7 | #include "../../Common/ComTry.h" | ||
8 | #include "../../Common/IntToString.h" | ||
9 | #include "../../Common/MyBuffer.h" | ||
10 | |||
11 | #include "../../Windows/PropVariantUtils.h" | ||
12 | |||
13 | #include "../Common/LimitedStreams.h" | ||
14 | #include "../Common/ProgressUtils.h" | ||
15 | #include "../Common/RegisterArc.h" | ||
16 | #include "../Common/StreamUtils.h" | ||
17 | |||
18 | #include "../Compress/CopyCoder.h" | ||
19 | |||
20 | using namespace NWindows; | ||
21 | |||
22 | static UInt16 Get16(const Byte *p, bool be) { if (be) return GetBe16(p); return GetUi16(p); } | ||
23 | static UInt32 Get32(const Byte *p, bool be) { if (be) return GetBe32(p); return GetUi32(p); } | ||
24 | static UInt64 Get64(const Byte *p, bool be) { if (be) return GetBe64(p); return GetUi64(p); } | ||
25 | |||
26 | #define G16(offs, v) v = Get16(p + (offs), be) | ||
27 | #define G32(offs, v) v = Get32(p + (offs), be) | ||
28 | #define G64(offs, v) v = Get64(p + (offs), be) | ||
29 | |||
30 | namespace NArchive { | ||
31 | namespace NElf { | ||
32 | |||
33 | /* | ||
34 | ELF Structure for most files (real order can be different): | ||
35 | Header | ||
36 | Program (segment) header table (used at runtime) | ||
37 | Segment1 (Section ... Section) | ||
38 | Segment2 | ||
39 | ... | ||
40 | SegmentN | ||
41 | Section header table (the data for linking and relocation) | ||
42 | */ | ||
43 | |||
44 | #define ELF_CLASS_32 1 | ||
45 | #define ELF_CLASS_64 2 | ||
46 | |||
47 | #define ELF_DATA_2LSB 1 | ||
48 | #define ELF_DATA_2MSB 2 | ||
49 | |||
50 | static const UInt32 kHeaderSize32 = 0x34; | ||
51 | static const UInt32 kHeaderSize64 = 0x40; | ||
52 | |||
53 | static const UInt32 kSegmentSize32 = 0x20; | ||
54 | static const UInt32 kSegmentSize64 = 0x38; | ||
55 | |||
56 | static const UInt32 kSectionSize32 = 0x28; | ||
57 | static const UInt32 kSectionSize64 = 0x40; | ||
58 | |||
59 | struct CHeader | ||
60 | { | ||
61 | bool Mode64; | ||
62 | bool Be; | ||
63 | Byte Os; | ||
64 | Byte AbiVer; | ||
65 | |||
66 | UInt16 Type; | ||
67 | UInt16 Machine; | ||
68 | // UInt32 Version; | ||
69 | |||
70 | // UInt64 EntryVa; | ||
71 | UInt64 ProgOffset; | ||
72 | UInt64 SectOffset; | ||
73 | UInt32 Flags; | ||
74 | UInt16 HeaderSize; | ||
75 | UInt16 SegmentEntrySize; | ||
76 | UInt16 NumSegments; | ||
77 | UInt16 SectionEntrySize; | ||
78 | UInt16 NumSections; | ||
79 | UInt16 NamesSectIndex; | ||
80 | |||
81 | bool Parse(const Byte *buf); | ||
82 | |||
83 | UInt64 GetHeadersSize() const { return (UInt64)HeaderSize + | ||
84 | (UInt32)NumSegments * SegmentEntrySize + | ||
85 | (UInt32)NumSections * SectionEntrySize; } | ||
86 | }; | ||
87 | |||
88 | bool CHeader::Parse(const Byte *p) | ||
89 | { | ||
90 | switch (p[4]) | ||
91 | { | ||
92 | case ELF_CLASS_32: Mode64 = false; break; | ||
93 | case ELF_CLASS_64: Mode64 = true; break; | ||
94 | default: return false; | ||
95 | } | ||
96 | bool be; | ||
97 | switch (p[5]) | ||
98 | { | ||
99 | case ELF_DATA_2LSB: be = false; break; | ||
100 | case ELF_DATA_2MSB: be = true; break; | ||
101 | default: return false; | ||
102 | } | ||
103 | Be = be; | ||
104 | if (p[6] != 1) // Version | ||
105 | return false; | ||
106 | Os = p[7]; | ||
107 | AbiVer = p[8]; | ||
108 | for (int i = 9; i < 16; i++) | ||
109 | if (p[i] != 0) | ||
110 | return false; | ||
111 | |||
112 | G16(0x10, Type); | ||
113 | G16(0x12, Machine); | ||
114 | if (Get32(p + 0x14, be) != 1) // Version | ||
115 | return false; | ||
116 | |||
117 | if (Mode64) | ||
118 | { | ||
119 | // G64(0x18, EntryVa); | ||
120 | G64(0x20, ProgOffset); | ||
121 | G64(0x28, SectOffset); | ||
122 | p += 0x30; | ||
123 | } | ||
124 | else | ||
125 | { | ||
126 | // G32(0x18, EntryVa); | ||
127 | G32(0x1C, ProgOffset); | ||
128 | G32(0x20, SectOffset); | ||
129 | p += 0x24; | ||
130 | } | ||
131 | |||
132 | G32(0, Flags); | ||
133 | G16(4, HeaderSize); | ||
134 | if (HeaderSize != (Mode64 ? kHeaderSize64 : kHeaderSize32)) | ||
135 | return false; | ||
136 | |||
137 | G16(6, SegmentEntrySize); | ||
138 | G16(8, NumSegments); | ||
139 | G16(10, SectionEntrySize); | ||
140 | G16(12, NumSections); | ||
141 | G16(14, NamesSectIndex); | ||
142 | |||
143 | if (ProgOffset < HeaderSize && (ProgOffset != 0 || NumSegments != 0)) return false; | ||
144 | if (SectOffset < HeaderSize && (SectOffset != 0 || NumSections != 0)) return false; | ||
145 | |||
146 | if (SegmentEntrySize == 0) { if (NumSegments != 0) return false; } | ||
147 | else if (SegmentEntrySize != (Mode64 ? kSegmentSize64 : kSegmentSize32)) return false; | ||
148 | |||
149 | if (SectionEntrySize == 0) { if (NumSections != 0) return false; } | ||
150 | else if (SectionEntrySize != (Mode64 ? kSectionSize64 : kSectionSize32)) return false; | ||
151 | |||
152 | return true; | ||
153 | } | ||
154 | |||
155 | // The program header table itself. | ||
156 | |||
157 | #define PT_PHDR 6 | ||
158 | |||
159 | static const char * const g_SegnmentTypes[] = | ||
160 | { | ||
161 | "Unused" | ||
162 | , "Loadable segment" | ||
163 | , "Dynamic linking tables" | ||
164 | , "Program interpreter path name" | ||
165 | , "Note section" | ||
166 | , "SHLIB" | ||
167 | , "Program header table" | ||
168 | , "TLS" | ||
169 | }; | ||
170 | |||
171 | static const char * const g_SegmentFlags[] = | ||
172 | { | ||
173 | "Execute" | ||
174 | , "Write" | ||
175 | , "Read" | ||
176 | }; | ||
177 | |||
178 | struct CSegment | ||
179 | { | ||
180 | UInt32 Type; | ||
181 | UInt32 Flags; | ||
182 | UInt64 Offset; | ||
183 | UInt64 Va; | ||
184 | // UInt64 Pa; | ||
185 | UInt64 Size; | ||
186 | UInt64 VSize; | ||
187 | UInt64 Align; | ||
188 | |||
189 | void UpdateTotalSize(UInt64 &totalSize) | ||
190 | { | ||
191 | UInt64 t = Offset + Size; | ||
192 | if (totalSize < t) | ||
193 | totalSize = t; | ||
194 | } | ||
195 | void Parse(const Byte *p, bool mode64, bool be); | ||
196 | }; | ||
197 | |||
198 | void CSegment::Parse(const Byte *p, bool mode64, bool be) | ||
199 | { | ||
200 | G32(0, Type); | ||
201 | if (mode64) | ||
202 | { | ||
203 | G32(4, Flags); | ||
204 | G64(8, Offset); | ||
205 | G64(0x10, Va); | ||
206 | // G64(0x18, Pa); | ||
207 | G64(0x20, Size); | ||
208 | G64(0x28, VSize); | ||
209 | G64(0x30, Align); | ||
210 | } | ||
211 | else | ||
212 | { | ||
213 | G32(4, Offset); | ||
214 | G32(8, Va); | ||
215 | // G32(0x0C, Pa); | ||
216 | G32(0x10, Size); | ||
217 | G32(0x14, VSize); | ||
218 | G32(0x18, Flags); | ||
219 | G32(0x1C, Align); | ||
220 | } | ||
221 | } | ||
222 | |||
223 | // Section_index = 0 means NO section | ||
224 | |||
225 | #define SHN_UNDEF 0 | ||
226 | |||
227 | // Section types | ||
228 | |||
229 | /* | ||
230 | #define SHT_NULL 0 | ||
231 | #define SHT_PROGBITS 1 | ||
232 | #define SHT_SYMTAB 2 | ||
233 | #define SHT_STRTAB 3 | ||
234 | #define SHT_RELA 4 | ||
235 | #define SHT_HASH 5 | ||
236 | #define SHT_DYNAMIC 6 | ||
237 | #define SHT_NOTE 7 | ||
238 | */ | ||
239 | #define SHT_NOBITS 8 | ||
240 | /* | ||
241 | #define SHT_REL 9 | ||
242 | #define SHT_SHLIB 10 | ||
243 | #define SHT_DYNSYM 11 | ||
244 | #define SHT_UNKNOWN12 12 | ||
245 | #define SHT_UNKNOWN13 13 | ||
246 | #define SHT_INIT_ARRAY 14 | ||
247 | #define SHT_FINI_ARRAY 15 | ||
248 | #define SHT_PREINIT_ARRAY 16 | ||
249 | #define SHT_GROUP 17 | ||
250 | #define SHT_SYMTAB_SHNDX 18 | ||
251 | */ | ||
252 | |||
253 | static const CUInt32PCharPair g_SectTypes[] = | ||
254 | { | ||
255 | { 0, "NULL" }, | ||
256 | { 1, "PROGBITS" }, | ||
257 | { 2, "SYMTAB" }, | ||
258 | { 3, "STRTAB" }, | ||
259 | { 4, "RELA" }, | ||
260 | { 5, "HASH" }, | ||
261 | { 6, "DYNAMIC" }, | ||
262 | { 7, "NOTE" }, | ||
263 | { 8, "NOBITS" }, | ||
264 | { 9, "REL" }, | ||
265 | { 10, "SHLIB" }, | ||
266 | { 11, "DYNSYM" }, | ||
267 | { 12, "UNKNOWN12" }, | ||
268 | { 13, "UNKNOWN13" }, | ||
269 | { 14, "INIT_ARRAY" }, | ||
270 | { 15, "FINI_ARRAY" }, | ||
271 | { 16, "PREINIT_ARRAY" }, | ||
272 | { 17, "GROUP" }, | ||
273 | { 18, "SYMTAB_SHNDX" }, | ||
274 | { 0x6ffffff5, "GNU_ATTRIBUTES" }, | ||
275 | { 0x6ffffff6, "GNU_HASH" }, | ||
276 | { 0x6ffffffd, "GNU_verdef" }, | ||
277 | { 0x6ffffffe, "GNU_verneed" }, | ||
278 | { 0x6fffffff, "GNU_versym" }, | ||
279 | // { 0x70000001, "X86_64_UNWIND" }, | ||
280 | { 0x70000001, "ARM_EXIDX" }, | ||
281 | { 0x70000002, "ARM_PREEMPTMAP" }, | ||
282 | { 0x70000003, "ARM_ATTRIBUTES" }, | ||
283 | { 0x70000004, "ARM_DEBUGOVERLAY" }, | ||
284 | { 0x70000005, "ARM_OVERLAYSECTION" } | ||
285 | }; | ||
286 | |||
287 | static const CUInt32PCharPair g_SectionFlags[] = | ||
288 | { | ||
289 | { 0, "WRITE" }, | ||
290 | { 1, "ALLOC" }, | ||
291 | { 2, "EXECINSTR" }, | ||
292 | |||
293 | { 4, "MERGE" }, | ||
294 | { 5, "STRINGS" }, | ||
295 | { 6, "INFO_LINK" }, | ||
296 | { 7, "LINK_ORDER" }, | ||
297 | { 8, "OS_NONCONFORMING" }, | ||
298 | { 9, "GROUP" }, | ||
299 | { 10, "TLS" }, | ||
300 | { 11, "CP_SECTION" }, | ||
301 | { 12, "DP_SECTION" }, | ||
302 | { 13, "XCORE_SHF_CP_SECTION" }, | ||
303 | { 28, "64_LARGE" }, | ||
304 | }; | ||
305 | |||
306 | struct CSection | ||
307 | { | ||
308 | UInt32 Name; | ||
309 | UInt32 Type; | ||
310 | UInt64 Flags; | ||
311 | UInt64 Va; | ||
312 | UInt64 Offset; | ||
313 | UInt64 VSize; | ||
314 | UInt32 Link; | ||
315 | UInt32 Info; | ||
316 | UInt64 AddrAlign; | ||
317 | UInt64 EntSize; | ||
318 | |||
319 | UInt64 GetSize() const { return Type == SHT_NOBITS ? 0 : VSize; } | ||
320 | |||
321 | void UpdateTotalSize(UInt64 &totalSize) | ||
322 | { | ||
323 | UInt64 t = Offset + GetSize(); | ||
324 | if (totalSize < t) | ||
325 | totalSize = t; | ||
326 | } | ||
327 | bool Parse(const Byte *p, bool mode64, bool be); | ||
328 | }; | ||
329 | |||
330 | bool CSection::Parse(const Byte *p, bool mode64, bool be) | ||
331 | { | ||
332 | G32(0, Name); | ||
333 | G32(4, Type); | ||
334 | if (mode64) | ||
335 | { | ||
336 | G64(0x08, Flags); | ||
337 | G64(0x10, Va); | ||
338 | G64(0x18, Offset); | ||
339 | G64(0x20, VSize); | ||
340 | G32(0x28, Link); | ||
341 | G32(0x2C, Info); | ||
342 | G64(0x30, AddrAlign); | ||
343 | G64(0x38, EntSize); | ||
344 | } | ||
345 | else | ||
346 | { | ||
347 | G32(0x08, Flags); | ||
348 | G32(0x0C, Va); | ||
349 | G32(0x10, Offset); | ||
350 | G32(0x14, VSize); | ||
351 | G32(0x18, Link); | ||
352 | G32(0x1C, Info); | ||
353 | G32(0x20, AddrAlign); | ||
354 | G32(0x24, EntSize); | ||
355 | } | ||
356 | if (EntSize >= ((UInt32)1 << 31)) | ||
357 | return false; | ||
358 | if (EntSize >= ((UInt32)1 << 10) && | ||
359 | EntSize >= VSize && | ||
360 | VSize != 0) | ||
361 | return false; | ||
362 | return true; | ||
363 | } | ||
364 | |||
365 | |||
366 | static const char * const g_Machines[] = | ||
367 | { | ||
368 | "None" | ||
369 | , "AT&T WE 32100" | ||
370 | , "SPARC" | ||
371 | , "Intel 386" | ||
372 | , "Motorola 68000" | ||
373 | , "Motorola 88000" | ||
374 | , "Intel 486" | ||
375 | , "Intel i860" | ||
376 | , "MIPS" | ||
377 | , "IBM S/370" | ||
378 | , "MIPS RS3000 LE" | ||
379 | , "RS6000" | ||
380 | , NULL | ||
381 | , NULL | ||
382 | , NULL | ||
383 | , "PA-RISC" | ||
384 | , "nCUBE" | ||
385 | , "Fujitsu VPP500" | ||
386 | , "SPARC 32+" | ||
387 | , "Intel i960" | ||
388 | , "PowerPC" | ||
389 | , "PowerPC 64-bit" | ||
390 | , "IBM S/390" | ||
391 | , "SPU" | ||
392 | , NULL | ||
393 | , NULL | ||
394 | , NULL | ||
395 | , NULL | ||
396 | , NULL | ||
397 | , NULL | ||
398 | , NULL | ||
399 | , NULL | ||
400 | , NULL | ||
401 | , NULL | ||
402 | , NULL | ||
403 | , NULL | ||
404 | , "NEX v800" | ||
405 | , "Fujitsu FR20" | ||
406 | , "TRW RH-32" | ||
407 | , "Motorola RCE" | ||
408 | , "ARM" | ||
409 | , "Alpha" | ||
410 | , "Hitachi SH" | ||
411 | , "SPARC-V9" | ||
412 | , "Siemens Tricore" | ||
413 | , "ARC" | ||
414 | , "H8/300" | ||
415 | , "H8/300H" | ||
416 | , "H8S" | ||
417 | , "H8/500" | ||
418 | , "IA-64" | ||
419 | , "Stanford MIPS-X" | ||
420 | , "Motorola ColdFire" | ||
421 | , "M68HC12" | ||
422 | , "Fujitsu MMA" | ||
423 | , "Siemens PCP" | ||
424 | , "Sony nCPU" | ||
425 | , "Denso NDR1" | ||
426 | , "Motorola StarCore" | ||
427 | , "Toyota ME16" | ||
428 | , "ST100" | ||
429 | , "Advanced Logic TinyJ" | ||
430 | , "AMD64" | ||
431 | , "Sony DSP" | ||
432 | , NULL | ||
433 | , NULL | ||
434 | , "Siemens FX66" | ||
435 | , "ST9+" | ||
436 | , "ST7" | ||
437 | , "MC68HC16" | ||
438 | , "MC68HC11" | ||
439 | , "MC68HC08" | ||
440 | , "MC68HC05" | ||
441 | , "Silicon Graphics SVx" | ||
442 | , "ST19" | ||
443 | , "Digital VAX" | ||
444 | , "Axis CRIS" | ||
445 | , "Infineon JAVELIN" | ||
446 | , "Element 14 FirePath" | ||
447 | , "LSI ZSP" | ||
448 | , "MMIX" | ||
449 | , "HUANY" | ||
450 | , "SiTera Prism" | ||
451 | , "Atmel AVR" | ||
452 | , "Fujitsu FR30" | ||
453 | , "Mitsubishi D10V" | ||
454 | , "Mitsubishi D30V" | ||
455 | , "NEC v850" | ||
456 | , "Mitsubishi M32R" | ||
457 | , "Matsushita MN10300" | ||
458 | , "Matsushita MN10200" | ||
459 | , "picoJava" | ||
460 | , "OpenRISC" | ||
461 | , "ARC Tangent-A5" | ||
462 | , "Tensilica Xtensa" | ||
463 | , "Alphamosaic VideoCore" | ||
464 | , "Thompson MM GPP" | ||
465 | , "National Semiconductor 32K" | ||
466 | , "Tenor Network TPC" | ||
467 | , "Trebia SNP 1000" | ||
468 | , "ST200" | ||
469 | , "Ubicom IP2xxx" | ||
470 | , "MAX" | ||
471 | , "NS CompactRISC" | ||
472 | , "Fujitsu F2MC16" | ||
473 | , "TI msp430" | ||
474 | , "Blackfin (DSP)" | ||
475 | , "SE S1C33" | ||
476 | , "Sharp embedded" | ||
477 | , "Arca RISC" | ||
478 | , "Unicore" | ||
479 | , "eXcess" | ||
480 | , "DXP" | ||
481 | , "Altera Nios II" | ||
482 | , "NS CRX" | ||
483 | , "Motorola XGATE" | ||
484 | , "Infineon C16x/XC16x" | ||
485 | , "Renesas M16C" | ||
486 | , "Microchip Technology dsPIC30F" | ||
487 | , "Freescale CE" | ||
488 | , "Renesas M32C" | ||
489 | , NULL | ||
490 | , NULL | ||
491 | , NULL | ||
492 | , NULL | ||
493 | , NULL | ||
494 | , NULL | ||
495 | , NULL | ||
496 | , NULL | ||
497 | , NULL | ||
498 | , NULL | ||
499 | , "Altium TSK3000" | ||
500 | , "Freescale RS08" | ||
501 | , "Analog Devices SHARC" | ||
502 | , "Cyan Technology eCOG2" | ||
503 | , "Sunplus S+core7 RISC" | ||
504 | , "NJR 24-bit DSP" | ||
505 | , "Broadcom VideoCore III" | ||
506 | , "Lattice FPGA" | ||
507 | , "SE C17" | ||
508 | , "TI TMS320C6000" | ||
509 | , "TI TMS320C2000" | ||
510 | , "TI TMS320C55x" | ||
511 | , NULL | ||
512 | , NULL | ||
513 | , NULL | ||
514 | , NULL | ||
515 | , NULL | ||
516 | , NULL | ||
517 | , NULL | ||
518 | , NULL | ||
519 | , NULL | ||
520 | , NULL | ||
521 | , NULL | ||
522 | , NULL | ||
523 | , NULL | ||
524 | , NULL | ||
525 | , NULL | ||
526 | , NULL | ||
527 | , NULL | ||
528 | , "STM 64bit VLIW Data Signal" | ||
529 | , "Cypress M8C" | ||
530 | , "Renesas R32C" | ||
531 | , "NXP TriMedia" | ||
532 | , "Qualcomm Hexagon" | ||
533 | , "Intel 8051" | ||
534 | , "STMicroelectronics STxP7x" | ||
535 | , "Andes" | ||
536 | , "Cyan Technology eCOG1X" | ||
537 | , "Dallas Semiconductor MAXQ30" | ||
538 | , "NJR 16-bit DSP" | ||
539 | , "M2000" | ||
540 | , "Cray NV2" | ||
541 | , "Renesas RX" | ||
542 | , "Imagination Technologies META" | ||
543 | , "MCST Elbrus" | ||
544 | , "Cyan Technology eCOG16" | ||
545 | , "National Semiconductor CR16" | ||
546 | , "Freescale ETPUnit" | ||
547 | , "Infineon SLE9X" | ||
548 | , "Intel L10M" | ||
549 | , "Intel K10M" | ||
550 | , NULL | ||
551 | , "ARM64" | ||
552 | , NULL | ||
553 | , "Atmel AVR32" | ||
554 | , "STM8" | ||
555 | , "Tilera TILE64" | ||
556 | , "Tilera TILEPro" | ||
557 | , "Xilinx MicroBlaze" | ||
558 | , "NVIDIA CUDA" | ||
559 | , "Tilera TILE-Gx" | ||
560 | , "CloudShield" | ||
561 | , "KIPO-KAIST Core-A 1st" | ||
562 | , "KIPO-KAIST Core-A 2nd" | ||
563 | , "Synopsys ARCompact V2" | ||
564 | , "Open8" | ||
565 | , "Renesas RL78" | ||
566 | , "Broadcom VideoCore V" | ||
567 | , "Renesas 78KOR" | ||
568 | , "Freescale 56800EX" // 200 | ||
569 | }; | ||
570 | |||
571 | static const CUInt32PCharPair g_MachinePairs[] = | ||
572 | { | ||
573 | { 243, "RISC-V" }, | ||
574 | { 47787, "Xilinx MicroBlaze" } | ||
575 | // { 0x9026, "Alpha" } | ||
576 | }; | ||
577 | |||
578 | static const CUInt32PCharPair g_OS[] = | ||
579 | { | ||
580 | { 0, "None" }, | ||
581 | { 1, "HP-UX" }, | ||
582 | { 2, "NetBSD" }, | ||
583 | { 3, "Linux" }, | ||
584 | { 4, "Hurd" }, | ||
585 | |||
586 | { 6, "Solaris" }, | ||
587 | { 7, "AIX" }, | ||
588 | { 8, "IRIX" }, | ||
589 | { 9, "FreeBSD" }, | ||
590 | { 10, "TRU64" }, | ||
591 | { 11, "Novell Modesto" }, | ||
592 | { 12, "OpenBSD" }, | ||
593 | { 13, "OpenVMS" }, | ||
594 | { 14, "HP NSK" }, | ||
595 | { 15, "AROS" }, | ||
596 | { 16, "FenixOS" }, | ||
597 | { 64, "Bare-metal TMS320C6000" }, | ||
598 | { 65, "Linux TMS320C6000" }, | ||
599 | { 97, "ARM" }, | ||
600 | { 255, "Standalone" } | ||
601 | }; | ||
602 | |||
603 | #define k_Machine_MIPS 8 | ||
604 | #define k_Machine_ARM 40 | ||
605 | |||
606 | /* | ||
607 | #define EF_ARM_ABIMASK 0xFF000000 | ||
608 | #define EF_ARM_BE8 0x00800000 | ||
609 | #define EF_ARM_GCCMASK 0x00400FFF | ||
610 | #define EF_ARM_ABI_FLOAT_SOFT 0x00000200 | ||
611 | #define EF_ARM_ABI_FLOAT_HARD 0x00000400 | ||
612 | */ | ||
613 | |||
614 | static const CUInt32PCharPair g_ARM_Flags[] = | ||
615 | { | ||
616 | { 1, "HasEntry" }, | ||
617 | { 9, "SF" }, | ||
618 | { 10, "HF" }, | ||
619 | { 23, "BE8" } | ||
620 | }; | ||
621 | |||
622 | |||
623 | static const CUInt32PCharPair g_MIPS_Flags[] = | ||
624 | { | ||
625 | { 0, "NOREORDER" }, | ||
626 | { 1, "PIC" }, | ||
627 | { 2, "CPIC" }, | ||
628 | { 3, "XGOT" }, | ||
629 | { 4, "64BIT_WHIRL" }, | ||
630 | { 5, "ABI2" }, | ||
631 | { 6, "ABI_ON32" }, | ||
632 | { 10, "NAN2008" }, | ||
633 | { 25, "MicroMIPS" }, | ||
634 | { 26, "M16" }, | ||
635 | { 27, "MDMX" } | ||
636 | }; | ||
637 | |||
638 | |||
639 | // #define ET_NONE 0 | ||
640 | #define ET_REL 1 | ||
641 | // #define ET_EXEC 2 | ||
642 | #define ET_DYN 3 | ||
643 | // #define ET_CORE 4 | ||
644 | |||
645 | static const char * const g_Types[] = | ||
646 | { | ||
647 | "None" | ||
648 | , "Relocatable file" | ||
649 | , "Executable file" | ||
650 | , "Shared object file" | ||
651 | , "Core file" | ||
652 | }; | ||
653 | |||
654 | |||
655 | |||
656 | |||
657 | class CHandler: | ||
658 | public IInArchive, | ||
659 | public IArchiveAllowTail, | ||
660 | public CMyUnknownImp | ||
661 | { | ||
662 | CRecordVector<CSegment> _segments; | ||
663 | CRecordVector<CSection> _sections; | ||
664 | CByteBuffer _namesData; | ||
665 | CMyComPtr<IInStream> _inStream; | ||
666 | UInt64 _totalSize; | ||
667 | CHeader _header; | ||
668 | bool _headersError; | ||
669 | bool _allowTail; | ||
670 | |||
671 | void GetSectionName(UInt32 index, NCOM::CPropVariant &prop, bool showNULL) const; | ||
672 | HRESULT Open2(IInStream *stream); | ||
673 | public: | ||
674 | MY_UNKNOWN_IMP2(IInArchive, IArchiveAllowTail) | ||
675 | INTERFACE_IInArchive(;) | ||
676 | STDMETHOD(AllowTail)(Int32 allowTail); | ||
677 | |||
678 | CHandler(): _allowTail(false) {} | ||
679 | }; | ||
680 | |||
681 | void CHandler::GetSectionName(UInt32 index, NCOM::CPropVariant &prop, bool showNULL) const | ||
682 | { | ||
683 | if (index >= _sections.Size()) | ||
684 | return; | ||
685 | const CSection §ion = _sections[index]; | ||
686 | UInt32 offset = section.Name; | ||
687 | if (index == SHN_UNDEF /* && section.Type == SHT_NULL && offset == 0 */) | ||
688 | { | ||
689 | if (showNULL) | ||
690 | prop = "NULL"; | ||
691 | return; | ||
692 | } | ||
693 | const Byte *p = _namesData; | ||
694 | size_t size = _namesData.Size(); | ||
695 | for (size_t i = offset; i < size; i++) | ||
696 | if (p[i] == 0) | ||
697 | { | ||
698 | prop = (const char *)(p + offset); | ||
699 | return; | ||
700 | } | ||
701 | } | ||
702 | |||
703 | static const Byte kArcProps[] = | ||
704 | { | ||
705 | kpidCpu, | ||
706 | kpidBit64, | ||
707 | kpidBigEndian, | ||
708 | kpidHostOS, | ||
709 | kpidCharacts, | ||
710 | kpidHeadersSize | ||
711 | }; | ||
712 | |||
713 | enum | ||
714 | { | ||
715 | kpidLinkSection = kpidUserDefined, | ||
716 | kpidInfoSection | ||
717 | }; | ||
718 | |||
719 | static const CStatProp kProps[] = | ||
720 | { | ||
721 | { NULL, kpidPath, VT_BSTR }, | ||
722 | { NULL, kpidSize, VT_UI8 }, | ||
723 | { NULL, kpidVirtualSize, VT_UI8 }, | ||
724 | { NULL, kpidOffset, VT_UI8 }, | ||
725 | { NULL, kpidVa, VT_UI8 }, | ||
726 | { NULL, kpidType, VT_BSTR }, | ||
727 | { NULL, kpidCharacts, VT_BSTR } | ||
728 | , { "Link Section", kpidLinkSection, VT_BSTR} | ||
729 | , { "Info Section", kpidInfoSection, VT_BSTR} | ||
730 | }; | ||
731 | |||
732 | IMP_IInArchive_Props_WITH_NAME | ||
733 | IMP_IInArchive_ArcProps | ||
734 | |||
735 | STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) | ||
736 | { | ||
737 | COM_TRY_BEGIN | ||
738 | NCOM::CPropVariant prop; | ||
739 | switch (propID) | ||
740 | { | ||
741 | case kpidPhySize: prop = _totalSize; break; | ||
742 | case kpidHeadersSize: prop = _header.GetHeadersSize(); break; | ||
743 | case kpidBit64: if (_header.Mode64) prop = _header.Mode64; break; | ||
744 | case kpidBigEndian: if (_header.Be) prop = _header.Be; break; | ||
745 | case kpidShortComment: | ||
746 | |||
747 | case kpidCpu: | ||
748 | { | ||
749 | AString s; | ||
750 | if (_header.Machine < ARRAY_SIZE(g_Machines)) | ||
751 | { | ||
752 | const char *name = g_Machines[_header.Machine]; | ||
753 | if (name) | ||
754 | s = name; | ||
755 | } | ||
756 | if (s.IsEmpty()) | ||
757 | s = TypePairToString(g_MachinePairs, ARRAY_SIZE(g_MachinePairs), _header.Machine); | ||
758 | UInt32 flags = _header.Flags; | ||
759 | if (flags != 0) | ||
760 | { | ||
761 | s.Add_Space(); | ||
762 | if (_header.Machine == k_Machine_ARM) | ||
763 | { | ||
764 | s += FlagsToString(g_ARM_Flags, ARRAY_SIZE(g_ARM_Flags), flags & (((UInt32)1 << 24) - 1)); | ||
765 | s += " ABI:"; | ||
766 | s.Add_UInt32(flags >> 24); | ||
767 | } | ||
768 | else if (_header.Machine == k_Machine_MIPS) | ||
769 | { | ||
770 | UInt32 ver = flags >> 28; | ||
771 | s += "v"; | ||
772 | s.Add_UInt32(ver); | ||
773 | flags &= (((UInt32)1 << 28) - 1); | ||
774 | |||
775 | UInt32 abi = (flags >> 12) & 7; | ||
776 | if (abi != 0) | ||
777 | { | ||
778 | s += " ABI:"; | ||
779 | s.Add_UInt32(abi); | ||
780 | } | ||
781 | flags &= ~((UInt32)7 << 12); | ||
782 | |||
783 | s.Add_Space(); | ||
784 | s += FlagsToString(g_MIPS_Flags, ARRAY_SIZE(g_MIPS_Flags), flags); | ||
785 | } | ||
786 | else | ||
787 | { | ||
788 | char sz[16]; | ||
789 | ConvertUInt32ToHex(flags, sz); | ||
790 | s += sz; | ||
791 | } | ||
792 | } | ||
793 | prop = s; | ||
794 | break; | ||
795 | } | ||
796 | |||
797 | case kpidHostOS: PAIR_TO_PROP(g_OS, _header.Os, prop); break; | ||
798 | case kpidCharacts: TYPE_TO_PROP(g_Types, _header.Type, prop); break; | ||
799 | case kpidExtension: | ||
800 | { | ||
801 | const char *s = NULL; | ||
802 | if (_header.Type == ET_DYN) | ||
803 | s = "so"; | ||
804 | else if (_header.Type == ET_REL) | ||
805 | s = "o"; | ||
806 | if (s) | ||
807 | prop = s; | ||
808 | break; | ||
809 | } | ||
810 | // case kpidIsSelfExe: prop = (_header.Type != ET_DYN) && (_header.Type == ET_REL); break; | ||
811 | case kpidErrorFlags: | ||
812 | { | ||
813 | UInt32 flags = 0; | ||
814 | if (_headersError) flags |= kpv_ErrorFlags_HeadersError; | ||
815 | if (flags != 0) | ||
816 | prop = flags; | ||
817 | break; | ||
818 | } | ||
819 | } | ||
820 | prop.Detach(value); | ||
821 | return S_OK; | ||
822 | COM_TRY_END | ||
823 | } | ||
824 | |||
825 | STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) | ||
826 | { | ||
827 | COM_TRY_BEGIN | ||
828 | NCOM::CPropVariant prop; | ||
829 | if (index < _segments.Size()) | ||
830 | { | ||
831 | const CSegment &item = _segments[index]; | ||
832 | switch (propID) | ||
833 | { | ||
834 | case kpidPath: | ||
835 | { | ||
836 | char sz[16]; | ||
837 | ConvertUInt32ToString(index, sz); | ||
838 | prop = sz; | ||
839 | break; | ||
840 | } | ||
841 | case kpidOffset: prop = item.Offset; break; | ||
842 | case kpidVa: prop = item.Va; break; | ||
843 | case kpidSize: | ||
844 | case kpidPackSize: prop = (UInt64)item.Size; break; | ||
845 | case kpidVirtualSize: prop = (UInt64)item.VSize; break; | ||
846 | case kpidType: TYPE_TO_PROP(g_SegnmentTypes, item.Type, prop); break; | ||
847 | case kpidCharacts: FLAGS_TO_PROP(g_SegmentFlags, item.Flags, prop); break; | ||
848 | |||
849 | } | ||
850 | } | ||
851 | else | ||
852 | { | ||
853 | index -= _segments.Size(); | ||
854 | const CSection &item = _sections[index]; | ||
855 | switch (propID) | ||
856 | { | ||
857 | case kpidPath: GetSectionName(index, prop, true); break; | ||
858 | case kpidOffset: prop = item.Offset; break; | ||
859 | case kpidVa: prop = item.Va; break; | ||
860 | case kpidSize: | ||
861 | case kpidPackSize: prop = (UInt64)(item.Type == SHT_NOBITS ? 0 : item.VSize); break; | ||
862 | case kpidVirtualSize: prop = item.GetSize(); break; | ||
863 | case kpidType: PAIR_TO_PROP(g_SectTypes, item.Type, prop); break; | ||
864 | case kpidCharacts: FLAGS_TO_PROP(g_SectionFlags, (UInt32)item.Flags, prop); break; | ||
865 | case kpidLinkSection: GetSectionName(item.Link, prop, false); break; | ||
866 | case kpidInfoSection: GetSectionName(item.Info, prop, false); break; | ||
867 | } | ||
868 | } | ||
869 | prop.Detach(value); | ||
870 | return S_OK; | ||
871 | COM_TRY_END | ||
872 | } | ||
873 | |||
874 | HRESULT CHandler::Open2(IInStream *stream) | ||
875 | { | ||
876 | const UInt32 kStartSize = kHeaderSize64; | ||
877 | Byte h[kStartSize]; | ||
878 | RINOK(ReadStream_FALSE(stream, h, kStartSize)); | ||
879 | if (h[0] != 0x7F || h[1] != 'E' || h[2] != 'L' || h[3] != 'F') | ||
880 | return S_FALSE; | ||
881 | if (!_header.Parse(h)) | ||
882 | return S_FALSE; | ||
883 | |||
884 | _totalSize = _header.HeaderSize; | ||
885 | |||
886 | bool addSegments = false; | ||
887 | bool addSections = false; | ||
888 | |||
889 | if (_header.NumSections > 1) | ||
890 | addSections = true; | ||
891 | else | ||
892 | addSegments = true; | ||
893 | |||
894 | if (_header.NumSegments != 0) | ||
895 | { | ||
896 | if (_header.ProgOffset > (UInt64)1 << 60) return S_FALSE; | ||
897 | RINOK(stream->Seek(_header.ProgOffset, STREAM_SEEK_SET, NULL)); | ||
898 | size_t size = (size_t)_header.SegmentEntrySize * _header.NumSegments; | ||
899 | |||
900 | CByteArr buf(size); | ||
901 | |||
902 | RINOK(ReadStream_FALSE(stream, buf, size)); | ||
903 | |||
904 | UInt64 total = _header.ProgOffset + size; | ||
905 | if (_totalSize < total) | ||
906 | _totalSize = total; | ||
907 | |||
908 | const Byte *p = buf; | ||
909 | |||
910 | if (addSegments) | ||
911 | _segments.ClearAndReserve(_header.NumSegments); | ||
912 | for (unsigned i = 0; i < _header.NumSegments; i++, p += _header.SegmentEntrySize) | ||
913 | { | ||
914 | CSegment seg; | ||
915 | seg.Parse(p, _header.Mode64, _header.Be); | ||
916 | seg.UpdateTotalSize(_totalSize); | ||
917 | if (addSegments) | ||
918 | if (seg.Type != PT_PHDR) | ||
919 | _segments.AddInReserved(seg); | ||
920 | } | ||
921 | } | ||
922 | |||
923 | if (_header.NumSections != 0) | ||
924 | { | ||
925 | if (_header.SectOffset > (UInt64)1 << 60) return S_FALSE; | ||
926 | RINOK(stream->Seek(_header.SectOffset, STREAM_SEEK_SET, NULL)); | ||
927 | size_t size = (size_t)_header.SectionEntrySize * _header.NumSections; | ||
928 | |||
929 | CByteArr buf(size); | ||
930 | |||
931 | RINOK(ReadStream_FALSE(stream, buf, size)); | ||
932 | |||
933 | UInt64 total = _header.SectOffset + size; | ||
934 | if (_totalSize < total) | ||
935 | _totalSize = total; | ||
936 | |||
937 | const Byte *p = buf; | ||
938 | |||
939 | if (addSections) | ||
940 | _sections.ClearAndReserve(_header.NumSections); | ||
941 | for (unsigned i = 0; i < _header.NumSections; i++, p += _header.SectionEntrySize) | ||
942 | { | ||
943 | CSection sect; | ||
944 | if (!sect.Parse(p, _header.Mode64, _header.Be)) | ||
945 | { | ||
946 | _headersError = true; | ||
947 | return S_FALSE; | ||
948 | } | ||
949 | sect.UpdateTotalSize(_totalSize); | ||
950 | if (addSections) | ||
951 | _sections.AddInReserved(sect); | ||
952 | } | ||
953 | } | ||
954 | |||
955 | if (addSections) | ||
956 | { | ||
957 | if (_header.NamesSectIndex < _sections.Size()) | ||
958 | { | ||
959 | const CSection § = _sections[_header.NamesSectIndex]; | ||
960 | UInt64 size = sect.GetSize(); | ||
961 | if (size != 0 | ||
962 | && size < ((UInt64)1 << 31) | ||
963 | && (Int64)sect.Offset >= 0) | ||
964 | { | ||
965 | _namesData.Alloc((size_t)size); | ||
966 | RINOK(stream->Seek(sect.Offset, STREAM_SEEK_SET, NULL)); | ||
967 | RINOK(ReadStream_FALSE(stream, _namesData, (size_t)size)); | ||
968 | } | ||
969 | } | ||
970 | |||
971 | /* | ||
972 | // we will not delete NULL sections, since we have links to section via indexes | ||
973 | for (int i = _sections.Size() - 1; i >= 0; i--) | ||
974 | if (_sections[i].Type == SHT_NULL) | ||
975 | _items.Delete(i); | ||
976 | */ | ||
977 | } | ||
978 | |||
979 | if (!_allowTail) | ||
980 | { | ||
981 | UInt64 fileSize; | ||
982 | RINOK(stream->Seek(0, STREAM_SEEK_END, &fileSize)); | ||
983 | if (fileSize > _totalSize) | ||
984 | return S_FALSE; | ||
985 | } | ||
986 | |||
987 | return S_OK; | ||
988 | } | ||
989 | |||
990 | STDMETHODIMP CHandler::Open(IInStream *inStream, | ||
991 | const UInt64 * /* maxCheckStartPosition */, | ||
992 | IArchiveOpenCallback * /* openArchiveCallback */) | ||
993 | { | ||
994 | COM_TRY_BEGIN | ||
995 | Close(); | ||
996 | RINOK(Open2(inStream)); | ||
997 | _inStream = inStream; | ||
998 | return S_OK; | ||
999 | COM_TRY_END | ||
1000 | } | ||
1001 | |||
1002 | STDMETHODIMP CHandler::Close() | ||
1003 | { | ||
1004 | _totalSize = 0; | ||
1005 | _headersError = false; | ||
1006 | |||
1007 | _inStream.Release(); | ||
1008 | _segments.Clear(); | ||
1009 | _sections.Clear(); | ||
1010 | _namesData.Free(); | ||
1011 | return S_OK; | ||
1012 | } | ||
1013 | |||
1014 | STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) | ||
1015 | { | ||
1016 | *numItems = _segments.Size() + _sections.Size(); | ||
1017 | return S_OK; | ||
1018 | } | ||
1019 | |||
1020 | STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, | ||
1021 | Int32 testMode, IArchiveExtractCallback *extractCallback) | ||
1022 | { | ||
1023 | COM_TRY_BEGIN | ||
1024 | bool allFilesMode = (numItems == (UInt32)(Int32)-1); | ||
1025 | if (allFilesMode) | ||
1026 | numItems = _segments.Size() + _sections.Size(); | ||
1027 | if (numItems == 0) | ||
1028 | return S_OK; | ||
1029 | UInt64 totalSize = 0; | ||
1030 | UInt32 i; | ||
1031 | for (i = 0; i < numItems; i++) | ||
1032 | { | ||
1033 | UInt32 index = allFilesMode ? i : indices[i]; | ||
1034 | totalSize += (index < _segments.Size()) ? | ||
1035 | _segments[index].Size : | ||
1036 | _sections[index - _segments.Size()].GetSize(); | ||
1037 | } | ||
1038 | extractCallback->SetTotal(totalSize); | ||
1039 | |||
1040 | UInt64 currentTotalSize = 0; | ||
1041 | UInt64 currentItemSize; | ||
1042 | |||
1043 | NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); | ||
1044 | CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; | ||
1045 | |||
1046 | CLocalProgress *lps = new CLocalProgress; | ||
1047 | CMyComPtr<ICompressProgressInfo> progress = lps; | ||
1048 | lps->Init(extractCallback, false); | ||
1049 | |||
1050 | CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; | ||
1051 | CMyComPtr<ISequentialInStream> inStream(streamSpec); | ||
1052 | streamSpec->SetStream(_inStream); | ||
1053 | |||
1054 | for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) | ||
1055 | { | ||
1056 | lps->InSize = lps->OutSize = currentTotalSize; | ||
1057 | RINOK(lps->SetCur()); | ||
1058 | Int32 askMode = testMode ? | ||
1059 | NExtract::NAskMode::kTest : | ||
1060 | NExtract::NAskMode::kExtract; | ||
1061 | UInt32 index = allFilesMode ? i : indices[i]; | ||
1062 | UInt64 offset; | ||
1063 | if (index < _segments.Size()) | ||
1064 | { | ||
1065 | const CSegment &item = _segments[index]; | ||
1066 | currentItemSize = item.Size; | ||
1067 | offset = item.Offset; | ||
1068 | } | ||
1069 | else | ||
1070 | { | ||
1071 | const CSection &item = _sections[index - _segments.Size()]; | ||
1072 | currentItemSize = item.GetSize(); | ||
1073 | offset = item.Offset; | ||
1074 | } | ||
1075 | |||
1076 | CMyComPtr<ISequentialOutStream> outStream; | ||
1077 | RINOK(extractCallback->GetStream(index, &outStream, askMode)); | ||
1078 | if (!testMode && !outStream) | ||
1079 | continue; | ||
1080 | |||
1081 | RINOK(extractCallback->PrepareOperation(askMode)); | ||
1082 | RINOK(_inStream->Seek(offset, STREAM_SEEK_SET, NULL)); | ||
1083 | streamSpec->Init(currentItemSize); | ||
1084 | RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); | ||
1085 | outStream.Release(); | ||
1086 | RINOK(extractCallback->SetOperationResult(copyCoderSpec->TotalSize == currentItemSize ? | ||
1087 | NExtract::NOperationResult::kOK: | ||
1088 | NExtract::NOperationResult::kDataError)); | ||
1089 | } | ||
1090 | return S_OK; | ||
1091 | COM_TRY_END | ||
1092 | } | ||
1093 | |||
1094 | STDMETHODIMP CHandler::AllowTail(Int32 allowTail) | ||
1095 | { | ||
1096 | _allowTail = IntToBool(allowTail); | ||
1097 | return S_OK; | ||
1098 | } | ||
1099 | |||
1100 | static const Byte k_Signature[] = { 0x7F, 'E', 'L', 'F' }; | ||
1101 | |||
1102 | REGISTER_ARC_I( | ||
1103 | "ELF", "elf", 0, 0xDE, | ||
1104 | k_Signature, | ||
1105 | 0, | ||
1106 | NArcInfoFlags::kPreArc, | ||
1107 | NULL) | ||
1108 | |||
1109 | }} | ||