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 /*
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
GetSizeNArchive::NElf::CSection319 UInt64 GetSize() const { return Type == SHT_NOBITS ? 0 : VSize; }
320
UpdateTotalSizeNArchive::NElf::CSection321 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
Parse(const Byte * p,bool mode64,bool be)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
CHandler()678 CHandler(): _allowTail(false) {}
679 };
680
GetSectionName(UInt32 index,NCOM::CPropVariant & prop,bool showNULL) const681 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
GetArchiveProperty(PROPID propID,PROPVARIANT * value)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
GetProperty(UInt32 index,PROPID propID,PROPVARIANT * value)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
Open2(IInStream * stream)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
Open(IInStream * inStream,const UInt64 *,IArchiveOpenCallback *)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
Close()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
GetNumberOfItems(UInt32 * numItems)1014 STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
1015 {
1016 *numItems = _segments.Size() + _sections.Size();
1017 return S_OK;
1018 }
1019
Extract(const UInt32 * indices,UInt32 numItems,Int32 testMode,IArchiveExtractCallback * extractCallback)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
AllowTail(Int32 allowTail)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 }}
1110