2 * Copyright 2007, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
3 * All rights reserved. Distributed under the terms of the MIT License.
18 #include <system_revision.h>
20 // We use htonl(), which is defined in <ByteOrder.h> on BeOS R5.
21 #ifdef HAIKU_HOST_PLATFORM_BEOS
22 #include <ByteOrder.h>
24 #include <arpa/inet.h>
33 // #pragma mark - ELF definitions
37 typedef uint32_t Elf32_Addr
;
38 typedef uint16_t Elf32_Half
;
39 typedef uint32_t Elf32_Off
;
40 typedef int32_t Elf32_Sword
;
41 typedef uint32_t Elf32_Word
;
42 typedef uint64_t Elf64_Addr
;
43 typedef uint64_t Elf64_Off
;
44 typedef uint16_t Elf64_Half
;
45 typedef uint32_t Elf64_Word
;
46 typedef int32_t Elf64_Sword
;
47 typedef uint64_t Elf64_Xword
;
48 typedef int64_t Elf64_Sxword
;
63 unsigned char e_ident
[EI_NIDENT
];
72 Elf32_Half e_phentsize
;
74 Elf32_Half e_shentsize
;
76 Elf32_Half e_shstrndx
;
80 unsigned char e_ident
[EI_NIDENT
];
89 Elf64_Half e_phentsize
;
91 Elf64_Half e_shentsize
;
93 Elf64_Half e_shstrndx
;
96 // e_ident EI_CLASS and EI_DATA values
97 #define ELFCLASSNONE 0
100 #define ELFDATANONE 0
101 #define ELFDATA2LSB 1
102 #define ELFDATA2MSB 2
122 Elf64_Xword p_filesz
;
135 #define PT_LOPROC 0x70000000
136 #define PT_HIPROC 0x7fffffff
148 Elf32_Word sh_addralign
;
149 Elf32_Word sh_entsize
;
155 Elf64_Xword sh_flags
;
161 Elf64_Xword sh_addralign
;
162 Elf64_Xword sh_entsize
;
167 #define SHT_PROGBITS 1
172 #define SHT_DYNAMIC 6
177 #define SHT_DYNSYM 11
178 #define SHT_LOPROC 0x70000000
179 #define SHT_HIPROC 0x7fffffff
180 #define SHT_LOUSER 0x80000000
181 #define SHT_HIUSER 0xffffffff
183 // special section indexes
186 static const char kELFFileMagic
[4] = { 0x7f, 'E', 'L', 'F' };
189 // #pragma mark - Usage
192 static const char *kUsage
=
193 "Usage: %s <file> <revision>\n"
195 "Finds the haiku revision section in ELF object file <file> and replaces the\n"
196 "writes the number given by <revision> into the first 32 bits of the\n"
202 static const char *const *sArgv
;
206 print_usage(bool error
)
208 // get nice program name
209 const char *programName
= (sArgc
> 0 ? sArgv
[0] : "resattr");
210 if (const char *lastSlash
= strrchr(programName
, '/'))
211 programName
= lastSlash
+ 1;
214 fprintf((error
? stderr
: stdout
), kUsage
, programName
);
217 // print_usage_and_exit
219 print_usage_and_exit(bool error
)
226 // #pragma mark - Exception
239 Exception(const char* format
,...)
244 va_start(args
, format
);
245 SetTo(errno
, format
, args
);
257 Exception(int error
, const char* format
,...)
262 va_start(args
, format
);
263 SetTo(error
, format
, args
);
268 Exception(const Exception
& exception
)
269 : fError(exception
.fError
),
270 fDescription(exception
.fDescription
)
280 void SetTo(int error
, const char* format
, va_list arg
)
283 vsprintf(buffer
, format
, arg
);
285 fDescription
= buffer
;
295 const string
& Description() const
306 // #pragma mark - ELFObject
321 fSectionHeaderStrings(NULL
),
322 fSectionHeaderStringsLength(0)
338 delete[] fSectionHeaderStrings
;
339 fSectionHeaderStrings
= NULL
;
342 void SetTo(const char* fileName
)
347 fFD
= open(fileName
, O_RDWR
);
349 throw Exception("Failed to open \"%s\"", fileName
);
352 fFileSize
= FileSize();
354 throw Exception("Failed to get the file size.");
356 // Read identification information
357 unsigned char ident
[EI_NIDENT
];
358 Read(0, ident
, sizeof(ident
), "Failed to read ELF identification.");
359 if (memcmp(ident
, kELFFileMagic
, sizeof(kELFFileMagic
)) != 0)
360 throw Exception("Not a valid ELF file.");
361 fELFClass
= ident
[EI_CLASS
];
363 if (fELFClass
== ELFCLASS64
)
364 _ParseELFHeader
<Elf64_Ehdr
, Elf64_Shdr
>();
366 _ParseELFHeader
<Elf32_Ehdr
, Elf32_Shdr
>();
369 bool FindSectionByName(const char* name
, SectionInfo
& foundInfo
)
371 // can't find the section by name without section names
372 if (!fSectionHeaderStrings
)
375 // iterate through the section headers
376 for (size_t i
= 0; i
< fSectionHeaderCount
; i
++) {
380 if (fELFClass
== ELFCLASS64
)
381 result
= _ReadSectionHeader
<Elf64_Shdr
>(i
, info
);
383 result
= _ReadSectionHeader
<Elf32_Shdr
>(i
, info
);
386 //printf("section %3d: offset: %7d, size: %7d, name: %s\n", i, info.offset, info.size, info.name);
387 if (strcmp(info
.name
, name
) == 0) {
397 void Read(off_t position
, void* buffer
, size_t size
,
398 const char *errorMessage
= NULL
)
400 if (lseek(fFD
, position
, SEEK_SET
) < 0)
401 throw Exception(errorMessage
);
403 ssize_t bytesRead
= read(fFD
, buffer
, size
);
405 throw Exception(errorMessage
);
407 if ((size_t)bytesRead
!= size
) {
409 throw Exception("%s Read too few bytes (%d/%d).",
410 errorMessage
, (int)bytesRead
, (int)size
);
412 throw Exception("Read too few bytes (%ld/%lu).",
413 (int)bytesRead
, (int)size
);
418 void Write(off_t position
, const void* buffer
, size_t size
,
419 const char *errorMessage
= NULL
)
421 if (lseek(fFD
, position
, SEEK_SET
) < 0)
422 throw Exception(errorMessage
);
424 ssize_t bytesWritten
= write(fFD
, buffer
, size
);
425 if (bytesWritten
< 0)
426 throw Exception(errorMessage
);
428 if ((size_t)bytesWritten
!= size
) {
430 throw Exception("%s Wrote too few bytes (%d/%d).",
431 errorMessage
, (int)bytesWritten
, (int)size
);
433 throw Exception("Wrote too few bytes (%ld/%lu).",
434 (int)bytesWritten
, (int)size
);
441 off_t currentPos
= lseek(fFD
, 0, SEEK_END
);
445 return lseek(fFD
, currentPos
, SEEK_SET
);
448 template<typename Type
>
449 Type
GetValue(Type
& value
);
452 template<typename EhdrType
, typename ShdrType
>
453 void _ParseELFHeader();
455 template<typename ShdrType
>
456 bool _ReadSectionHeader(int index
, SectionInfo
& info
);
459 static inline uint16_t _SwapUInt16(uint16_t value
)
461 return ((value
& 0xff) << 8) | (value
>> 8);
465 static inline uint32_t _SwapUInt32(uint32_t value
)
467 return ((uint32_t)_SwapUInt16(value
& 0xffff) << 16)
468 | _SwapUInt16(uint16_t(value
>> 16));
472 static inline uint64_t _SwapUInt64(uint64_t value
)
474 return ((uint64_t)_SwapUInt32(value
& 0xffffffff) << 32)
475 | _SwapUInt32(uint32_t(value
>> 32));
483 size_t fELFHeaderSize
;
484 off_t fSectionHeaderTableOffset
;
485 size_t fSectionHeaderSize
;
486 size_t fSectionHeaderCount
;
487 char* fSectionHeaderStrings
;
488 uint32_t fSectionHeaderStringsLength
;
493 int16_t ELFObject::GetValue(int16_t& value
)
495 return (fHostEndianess
? value
: _SwapUInt16(value
));
500 uint16_t ELFObject::GetValue(uint16_t& value
)
502 return (fHostEndianess
? value
: _SwapUInt16(value
));
507 int32_t ELFObject::GetValue(int32_t& value
)
509 return (fHostEndianess
? value
: _SwapUInt32(value
));
514 uint32_t ELFObject::GetValue(uint32_t& value
)
516 return (fHostEndianess
? value
: _SwapUInt32(value
));
521 int64_t ELFObject::GetValue(int64_t& value
)
523 return (fHostEndianess
? value
: _SwapUInt64(value
));
528 uint64_t ELFObject::GetValue(uint64_t& value
)
530 return (fHostEndianess
? value
: _SwapUInt64(value
));
534 template<typename EhdrType
, typename ShdrType
>
535 void ELFObject::_ParseELFHeader()
539 Read(0, &fileHeader
, sizeof(EhdrType
), "Failed to read ELF header.");
541 // check data encoding (endianess)
542 switch (fileHeader
.e_ident
[EI_DATA
]) {
544 fHostEndianess
= (htonl(1) != 1);
547 fHostEndianess
= (htonl(1) == 1);
551 throw Exception(EIO
, "Unsupported ELF data encoding.");
555 // get the header values
556 fELFHeaderSize
= GetValue(fileHeader
.e_ehsize
);
557 fSectionHeaderTableOffset
= GetValue(fileHeader
.e_shoff
);
558 fSectionHeaderSize
= GetValue(fileHeader
.e_shentsize
);
559 fSectionHeaderCount
= GetValue(fileHeader
.e_shnum
);
560 bool hasSectionHeaderTable
= (fSectionHeaderTableOffset
!= 0);
562 // check the sanity of the header values
564 if (fELFHeaderSize
< sizeof(EhdrType
)) {
566 "Invalid ELF header: invalid ELF header size: %lu.",
570 // section header table offset and entry count/size
571 if (hasSectionHeaderTable
) {
572 if (fSectionHeaderTableOffset
< (off_t
)fELFHeaderSize
573 || fSectionHeaderTableOffset
> fFileSize
) {
574 throw Exception(EIO
, "Invalid ELF header: invalid section "
575 "header table offset: %llu.",
576 fSectionHeaderTableOffset
);
578 size_t sectionHeaderTableSize
579 = fSectionHeaderSize
* fSectionHeaderCount
;
580 if (fSectionHeaderSize
< (off_t
)sizeof(ShdrType
)
581 || fSectionHeaderTableOffset
+ (off_t
)sectionHeaderTableSize
583 throw Exception(EIO
, "Invalid ELF header: section header "
584 "table exceeds file: %llu.",
585 fSectionHeaderTableOffset
586 + sectionHeaderTableSize
);
590 // load section header string section
591 uint16_t sectionHeaderStringSectionIndex
592 = GetValue(fileHeader
.e_shstrndx
);
593 if (sectionHeaderStringSectionIndex
!= SHN_UNDEF
) {
594 if (sectionHeaderStringSectionIndex
>= fSectionHeaderCount
) {
595 throw Exception(EIO
, "Invalid ELF header: invalid section "
596 "header string section index: %u.",
597 sectionHeaderStringSectionIndex
);
600 // get the section info
602 if (_ReadSectionHeader
<ShdrType
>(sectionHeaderStringSectionIndex
,
604 fSectionHeaderStrings
= new char[info
.size
+ 1];
605 Read(info
.offset
, fSectionHeaderStrings
, info
.size
,
606 "Failed to read section header string section.");
607 fSectionHeaderStringsLength
= info
.size
;
608 // null-terminate to be on the safe side
609 fSectionHeaderStrings
[info
.size
] = '\0';
616 template<typename ShdrType
>
617 bool ELFObject::_ReadSectionHeader(int index
, SectionInfo
& info
)
619 off_t shOffset
= fSectionHeaderTableOffset
620 + index
* fSectionHeaderSize
;
621 ShdrType sectionHeader
;
622 Read(shOffset
, §ionHeader
, sizeof(ShdrType
),
623 "Failed to read ELF section header.");
625 // get the header values
626 uint32_t type
= GetValue(sectionHeader
.sh_type
);
627 off_t offset
= GetValue(sectionHeader
.sh_offset
);
628 size_t size
= GetValue(sectionHeader
.sh_size
);
629 uint32_t nameIndex
= GetValue(sectionHeader
.sh_name
);
632 // SHT_NULL marks the header unused,
633 if (type
== SHT_NULL
)
636 // SHT_NOBITS sections take no space in the file
637 if (type
!= SHT_NOBITS
) {
638 if (offset
< (off_t
)fELFHeaderSize
|| offset
> fFileSize
) {
639 throw Exception(EIO
, "Invalid ELF section header: "
640 "invalid section offset: %llu.", offset
);
642 off_t sectionEnd
= offset
+ size
;
643 if (sectionEnd
> fFileSize
) {
644 throw Exception(EIO
, "Invalid ELF section header: "
645 "section exceeds file: %llu.", sectionEnd
);
649 // get name, if we have a string section
650 if (fSectionHeaderStrings
) {
651 if (nameIndex
>= (uint32_t)fSectionHeaderStringsLength
) {
652 throw Exception(EIO
, "Invalid ELF section header: "
653 "invalid name index: %lu.", nameIndex
);
655 info
.name
= fSectionHeaderStrings
+ nameIndex
;
661 info
.offset
= offset
;
671 main(int argc
, const char* const* argv
)
677 print_usage_and_exit(true);
680 const char* fileName
= argv
[1];
681 const char* revisionString
= argv
[2];
685 elfObject
.SetTo(fileName
);
687 // find haiku revision section
689 if (!elfObject
.FindSectionByName("_haiku_revision", info
)) {
690 fprintf(stderr
, "haiku revision section not found\n");
694 // write revision string to section
695 elfObject
.Write(info
.offset
, revisionString
,
696 min((size_t)SYSTEM_REVISION_LENGTH
, strlen(revisionString
) + 1),
697 "Failed to write revision.");
699 } catch (Exception exception
) {
700 if (exception
.Description() == "") {
701 fprintf(stderr
, "%s\n", strerror(exception
.Error()));
703 fprintf(stderr
, "%s: %s\n", exception
.Description().c_str(),
704 strerror(exception
.Error()));