@@ -58,6 +58,12 @@ type SectionHeader struct {
58
58
Info uint32
59
59
Addralign uint64
60
60
Entsize uint64
61
+
62
+ // FileSize is the size of this section in the file in bytes.
63
+ // If a section is compressed, FileSize is the size of the
64
+ // compressed data, while Size (above) is the size of the
65
+ // uncompressed data.
66
+ FileSize uint64
61
67
}
62
68
63
69
// A Section represents a single section in an ELF file.
@@ -70,17 +76,23 @@ type Section struct {
70
76
// If a client wants Read and Seek it must use
71
77
// Open() to avoid fighting over the seek offset
72
78
// with other clients.
79
+ //
80
+ // ReaderAt may be nil if the section is not easily available
81
+ // in a random-access form. For example, a compressed section
82
+ // may have a nil ReaderAt.
73
83
io.ReaderAt
74
84
sr * io.SectionReader
85
+
86
+ compressionType CompressionType
87
+ compressionOffset int64
75
88
}
76
89
77
90
// Data reads and returns the contents of the ELF section.
91
+ // Even if the section is stored compressed in the ELF file,
92
+ // Data returns uncompressed data.
78
93
func (s * Section ) Data () ([]byte , error ) {
79
- dat := make ([]byte , s .sr .Size ())
80
- n , err := s .sr .ReadAt (dat , 0 )
81
- if n == len (dat ) {
82
- err = nil
83
- }
94
+ dat := make ([]byte , s .Size )
95
+ n , err := io .ReadFull (s .Open (), dat )
84
96
return dat [0 :n ], err
85
97
}
86
98
@@ -94,7 +106,24 @@ func (f *File) stringTable(link uint32) ([]byte, error) {
94
106
}
95
107
96
108
// Open returns a new ReadSeeker reading the ELF section.
97
- func (s * Section ) Open () io.ReadSeeker { return io .NewSectionReader (s .sr , 0 , 1 << 63 - 1 ) }
109
+ // Even if the section is stored compressed in the ELF file,
110
+ // the ReadSeeker reads uncompressed data.
111
+ func (s * Section ) Open () io.ReadSeeker {
112
+ if s .Flags & SHF_COMPRESSED == 0 {
113
+ return io .NewSectionReader (s .sr , 0 , 1 << 63 - 1 )
114
+ }
115
+ if s .compressionType == COMPRESS_ZLIB {
116
+ return & readSeekerFromReader {
117
+ reset : func () (io.Reader , error ) {
118
+ fr := io .NewSectionReader (s .sr , s .compressionOffset , int64 (s .FileSize )- s .compressionOffset )
119
+ return zlib .NewReader (fr )
120
+ },
121
+ size : int64 (s .Size ),
122
+ }
123
+ }
124
+ err := & FormatError {int64 (s .Offset ), "unknown compression type" , s .compressionType }
125
+ return errorReader {err }
126
+ }
98
127
99
128
// A ProgHeader represents a single ELF program header.
100
129
type ProgHeader struct {
@@ -344,7 +373,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
344
373
Flags : SectionFlag (sh .Flags ),
345
374
Addr : uint64 (sh .Addr ),
346
375
Offset : uint64 (sh .Off ),
347
- Size : uint64 (sh .Size ),
376
+ FileSize : uint64 (sh .Size ),
348
377
Link : uint32 (sh .Link ),
349
378
Info : uint32 (sh .Info ),
350
379
Addralign : uint64 (sh .Addralign ),
@@ -360,16 +389,43 @@ func NewFile(r io.ReaderAt) (*File, error) {
360
389
Type : SectionType (sh .Type ),
361
390
Flags : SectionFlag (sh .Flags ),
362
391
Offset : uint64 (sh .Off ),
363
- Size : uint64 (sh .Size ),
392
+ FileSize : uint64 (sh .Size ),
364
393
Addr : uint64 (sh .Addr ),
365
394
Link : uint32 (sh .Link ),
366
395
Info : uint32 (sh .Info ),
367
396
Addralign : uint64 (sh .Addralign ),
368
397
Entsize : uint64 (sh .Entsize ),
369
398
}
370
399
}
371
- s .sr = io .NewSectionReader (r , int64 (s .Offset ), int64 (s .Size ))
372
- s .ReaderAt = s .sr
400
+ s .sr = io .NewSectionReader (r , int64 (s .Offset ), int64 (s .FileSize ))
401
+
402
+ if s .Flags & SHF_COMPRESSED == 0 {
403
+ s .ReaderAt = s .sr
404
+ s .Size = s .FileSize
405
+ } else {
406
+ // Read the compression header.
407
+ switch f .Class {
408
+ case ELFCLASS32 :
409
+ ch := new (Chdr32 )
410
+ if err := binary .Read (s .sr , f .ByteOrder , ch ); err != nil {
411
+ return nil , err
412
+ }
413
+ s .compressionType = CompressionType (ch .Type )
414
+ s .Size = uint64 (ch .Size )
415
+ s .Addralign = uint64 (ch .Addralign )
416
+ s .compressionOffset = int64 (binary .Size (ch ))
417
+ case ELFCLASS64 :
418
+ ch := new (Chdr64 )
419
+ if err := binary .Read (s .sr , f .ByteOrder , ch ); err != nil {
420
+ return nil , err
421
+ }
422
+ s .compressionType = CompressionType (ch .Type )
423
+ s .Size = ch .Size
424
+ s .Addralign = ch .Addralign
425
+ s .compressionOffset = int64 (binary .Size (ch ))
426
+ }
427
+ }
428
+
373
429
f .Sections [i ] = s
374
430
}
375
431
0 commit comments