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