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