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 §ion = _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 § = _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