1402d77f6SIngo Weinhold /* 2402d77f6SIngo Weinhold * Copyright 2007, Ingo Weinhold <bonefish@cs.tu-berlin.de>. 3402d77f6SIngo Weinhold * All rights reserved. Distributed under the terms of the MIT License. 4402d77f6SIngo Weinhold */ 5402d77f6SIngo Weinhold 6402d77f6SIngo Weinhold #include <errno.h> 7402d77f6SIngo Weinhold #include <fcntl.h> 8402d77f6SIngo Weinhold #include <inttypes.h> 9402d77f6SIngo Weinhold #include <stdarg.h> 10402d77f6SIngo Weinhold #include <stdio.h> 11402d77f6SIngo Weinhold #include <stdlib.h> 12cbd4dd19SIngo Weinhold #include <string.h> 13402d77f6SIngo Weinhold #include <unistd.h> 14402d77f6SIngo Weinhold 15402d77f6SIngo Weinhold #include <algorithm> 16402d77f6SIngo Weinhold #include <string> 17402d77f6SIngo Weinhold 18af2da315SOliver Tappe #include <system_revision.h> 19af2da315SOliver Tappe 206b533670SIngo Weinhold // We use htonl(), which is defined in <ByteOrder.h> on BeOS R5. 216b533670SIngo Weinhold #ifdef HAIKU_HOST_PLATFORM_BEOS 226b533670SIngo Weinhold #include <ByteOrder.h> 236b533670SIngo Weinhold #else 24402d77f6SIngo Weinhold #include <arpa/inet.h> 256b533670SIngo Weinhold #endif 26402d77f6SIngo Weinhold 27402d77f6SIngo Weinhold 28402d77f6SIngo Weinhold using std::string; 29402d77f6SIngo Weinhold using std::max; 30402d77f6SIngo Weinhold using std::min; 31402d77f6SIngo Weinhold 32402d77f6SIngo Weinhold 33402d77f6SIngo Weinhold // #pragma mark - ELF definitions 34402d77f6SIngo Weinhold 35402d77f6SIngo Weinhold 36402d77f6SIngo Weinhold // types 37402d77f6SIngo Weinhold typedef uint32_t Elf32_Addr; 38402d77f6SIngo Weinhold typedef uint16_t Elf32_Half; 39402d77f6SIngo Weinhold typedef uint32_t Elf32_Off; 40402d77f6SIngo Weinhold typedef int32_t Elf32_Sword; 41402d77f6SIngo Weinhold typedef uint32_t Elf32_Word; 42d384cac4SAlex Smith typedef uint64_t Elf64_Addr; 43d384cac4SAlex Smith typedef uint64_t Elf64_Off; 44d384cac4SAlex Smith typedef uint16_t Elf64_Half; 45d384cac4SAlex Smith typedef uint32_t Elf64_Word; 46d384cac4SAlex Smith typedef int32_t Elf64_Sword; 47d384cac4SAlex Smith typedef uint64_t Elf64_Xword; 48d384cac4SAlex Smith typedef int64_t Elf64_Sxword; 49402d77f6SIngo Weinhold 50402d77f6SIngo Weinhold // e_ident indices 51402d77f6SIngo Weinhold #define EI_MAG0 0 52402d77f6SIngo Weinhold #define EI_MAG1 1 53402d77f6SIngo Weinhold #define EI_MAG2 2 54402d77f6SIngo Weinhold #define EI_MAG3 3 55402d77f6SIngo Weinhold #define EI_CLASS 4 56402d77f6SIngo Weinhold #define EI_DATA 5 57402d77f6SIngo Weinhold #define EI_VERSION 6 58402d77f6SIngo Weinhold #define EI_PAD 7 59402d77f6SIngo Weinhold #define EI_NIDENT 16 60402d77f6SIngo Weinhold 61402d77f6SIngo Weinhold // object file header 62402d77f6SIngo Weinhold typedef struct { 63402d77f6SIngo Weinhold unsigned char e_ident[EI_NIDENT]; 64402d77f6SIngo Weinhold Elf32_Half e_type; 65402d77f6SIngo Weinhold Elf32_Half e_machine; 66402d77f6SIngo Weinhold Elf32_Word e_version; 67402d77f6SIngo Weinhold Elf32_Addr e_entry; 68402d77f6SIngo Weinhold Elf32_Off e_phoff; 69402d77f6SIngo Weinhold Elf32_Off e_shoff; 70402d77f6SIngo Weinhold Elf32_Word e_flags; 71402d77f6SIngo Weinhold Elf32_Half e_ehsize; 72402d77f6SIngo Weinhold Elf32_Half e_phentsize; 73402d77f6SIngo Weinhold Elf32_Half e_phnum; 74402d77f6SIngo Weinhold Elf32_Half e_shentsize; 75402d77f6SIngo Weinhold Elf32_Half e_shnum; 76402d77f6SIngo Weinhold Elf32_Half e_shstrndx; 77402d77f6SIngo Weinhold } Elf32_Ehdr; 78402d77f6SIngo Weinhold 79d384cac4SAlex Smith typedef struct { 80d384cac4SAlex Smith unsigned char e_ident[EI_NIDENT]; 81d384cac4SAlex Smith Elf64_Half e_type; 82d384cac4SAlex Smith Elf64_Half e_machine; 83d384cac4SAlex Smith Elf64_Word e_version; 84d384cac4SAlex Smith Elf64_Addr e_entry; 85d384cac4SAlex Smith Elf64_Off e_phoff; 86d384cac4SAlex Smith Elf64_Off e_shoff; 87d384cac4SAlex Smith Elf64_Word e_flags; 88d384cac4SAlex Smith Elf64_Half e_ehsize; 89d384cac4SAlex Smith Elf64_Half e_phentsize; 90d384cac4SAlex Smith Elf64_Half e_phnum; 91d384cac4SAlex Smith Elf64_Half e_shentsize; 92d384cac4SAlex Smith Elf64_Half e_shnum; 93d384cac4SAlex Smith Elf64_Half e_shstrndx; 94d384cac4SAlex Smith } Elf64_Ehdr; 95d384cac4SAlex Smith 96402d77f6SIngo Weinhold // e_ident EI_CLASS and EI_DATA values 97402d77f6SIngo Weinhold #define ELFCLASSNONE 0 98402d77f6SIngo Weinhold #define ELFCLASS32 1 99402d77f6SIngo Weinhold #define ELFCLASS64 2 100402d77f6SIngo Weinhold #define ELFDATANONE 0 101402d77f6SIngo Weinhold #define ELFDATA2LSB 1 102402d77f6SIngo Weinhold #define ELFDATA2MSB 2 103402d77f6SIngo Weinhold 104402d77f6SIngo Weinhold // program header 105402d77f6SIngo Weinhold typedef struct { 106402d77f6SIngo Weinhold Elf32_Word p_type; 107402d77f6SIngo Weinhold Elf32_Off p_offset; 108402d77f6SIngo Weinhold Elf32_Addr p_vaddr; 109402d77f6SIngo Weinhold Elf32_Addr p_paddr; 110402d77f6SIngo Weinhold Elf32_Word p_filesz; 111402d77f6SIngo Weinhold Elf32_Word p_memsz; 112402d77f6SIngo Weinhold Elf32_Word p_flags; 113402d77f6SIngo Weinhold Elf32_Word p_align; 114402d77f6SIngo Weinhold } Elf32_Phdr; 115402d77f6SIngo Weinhold 116d384cac4SAlex Smith typedef struct { 117d384cac4SAlex Smith Elf64_Word p_type; 118d384cac4SAlex Smith Elf64_Word p_flags; 119d384cac4SAlex Smith Elf64_Off p_offset; 120d384cac4SAlex Smith Elf64_Addr p_vaddr; 121d384cac4SAlex Smith Elf64_Addr p_paddr; 122d384cac4SAlex Smith Elf64_Xword p_filesz; 123d384cac4SAlex Smith Elf64_Xword p_memsz; 124d384cac4SAlex Smith Elf64_Xword p_align; 125d384cac4SAlex Smith } Elf64_Phdr; 126d384cac4SAlex Smith 127402d77f6SIngo Weinhold // p_type 128402d77f6SIngo Weinhold #define PT_NULL 0 129402d77f6SIngo Weinhold #define PT_LOAD 1 130402d77f6SIngo Weinhold #define PT_DYNAMIC 2 131402d77f6SIngo Weinhold #define PT_INTERP 3 132402d77f6SIngo Weinhold #define PT_NOTE 4 133402d77f6SIngo Weinhold #define PT_SHLIB 5 134402d77f6SIngo Weinhold #define PT_PHDIR 6 135402d77f6SIngo Weinhold #define PT_LOPROC 0x70000000 136402d77f6SIngo Weinhold #define PT_HIPROC 0x7fffffff 137402d77f6SIngo Weinhold 138402d77f6SIngo Weinhold // section header 139402d77f6SIngo Weinhold typedef struct { 140402d77f6SIngo Weinhold Elf32_Word sh_name; 141402d77f6SIngo Weinhold Elf32_Word sh_type; 142402d77f6SIngo Weinhold Elf32_Word sh_flags; 143402d77f6SIngo Weinhold Elf32_Addr sh_addr; 144402d77f6SIngo Weinhold Elf32_Off sh_offset; 145402d77f6SIngo Weinhold Elf32_Word sh_size; 146402d77f6SIngo Weinhold Elf32_Word sh_link; 147402d77f6SIngo Weinhold Elf32_Word sh_info; 148402d77f6SIngo Weinhold Elf32_Word sh_addralign; 149402d77f6SIngo Weinhold Elf32_Word sh_entsize; 150402d77f6SIngo Weinhold } Elf32_Shdr; 151402d77f6SIngo Weinhold 152d384cac4SAlex Smith typedef struct { 153d384cac4SAlex Smith Elf64_Word sh_name; 154d384cac4SAlex Smith Elf64_Word sh_type; 155d384cac4SAlex Smith Elf64_Xword sh_flags; 156d384cac4SAlex Smith Elf64_Addr sh_addr; 157d384cac4SAlex Smith Elf64_Off sh_offset; 158d384cac4SAlex Smith Elf64_Xword sh_size; 159d384cac4SAlex Smith Elf64_Word sh_link; 160d384cac4SAlex Smith Elf64_Word sh_info; 161d384cac4SAlex Smith Elf64_Xword sh_addralign; 162d384cac4SAlex Smith Elf64_Xword sh_entsize; 163d384cac4SAlex Smith } Elf64_Shdr; 164d384cac4SAlex Smith 165402d77f6SIngo Weinhold // sh_type values 166402d77f6SIngo Weinhold #define SHT_NULL 0 167402d77f6SIngo Weinhold #define SHT_PROGBITS 1 168402d77f6SIngo Weinhold #define SHT_SYMTAB 2 169402d77f6SIngo Weinhold #define SHT_STRTAB 3 170402d77f6SIngo Weinhold #define SHT_RELA 4 171402d77f6SIngo Weinhold #define SHT_HASH 5 172402d77f6SIngo Weinhold #define SHT_DYNAMIC 6 173402d77f6SIngo Weinhold #define SHT_NOTE 7 174402d77f6SIngo Weinhold #define SHT_NOBITS 8 175402d77f6SIngo Weinhold #define SHT_REL 9 176402d77f6SIngo Weinhold #define SHT_SHLIB 10 177402d77f6SIngo Weinhold #define SHT_DYNSYM 11 178402d77f6SIngo Weinhold #define SHT_LOPROC 0x70000000 179402d77f6SIngo Weinhold #define SHT_HIPROC 0x7fffffff 180402d77f6SIngo Weinhold #define SHT_LOUSER 0x80000000 181402d77f6SIngo Weinhold #define SHT_HIUSER 0xffffffff 182402d77f6SIngo Weinhold 183402d77f6SIngo Weinhold // special section indexes 184402d77f6SIngo Weinhold #define SHN_UNDEF 0 185402d77f6SIngo Weinhold 186402d77f6SIngo Weinhold static const char kELFFileMagic[4] = { 0x7f, 'E', 'L', 'F' }; 187402d77f6SIngo Weinhold 188402d77f6SIngo Weinhold 189402d77f6SIngo Weinhold // #pragma mark - Usage 190402d77f6SIngo Weinhold 191402d77f6SIngo Weinhold // usage 192402d77f6SIngo Weinhold static const char *kUsage = 193402d77f6SIngo Weinhold "Usage: %s <file> <revision>\n" 194402d77f6SIngo Weinhold "\n" 195402d77f6SIngo Weinhold "Finds the haiku revision section in ELF object file <file> and replaces the\n" 196402d77f6SIngo Weinhold "writes the number given by <revision> into the first 32 bits of the\n" 197402d77f6SIngo Weinhold "section.\n" 198402d77f6SIngo Weinhold ; 199402d77f6SIngo Weinhold 200402d77f6SIngo Weinhold // command line args 201402d77f6SIngo Weinhold static int sArgc; 202402d77f6SIngo Weinhold static const char *const *sArgv; 203402d77f6SIngo Weinhold 204402d77f6SIngo Weinhold // print_usage 205402d77f6SIngo Weinhold void 206402d77f6SIngo Weinhold print_usage(bool error) 207402d77f6SIngo Weinhold { 208402d77f6SIngo Weinhold // get nice program name 209402d77f6SIngo Weinhold const char *programName = (sArgc > 0 ? sArgv[0] : "resattr"); 210402d77f6SIngo Weinhold if (const char *lastSlash = strrchr(programName, '/')) 211402d77f6SIngo Weinhold programName = lastSlash + 1; 212402d77f6SIngo Weinhold 213402d77f6SIngo Weinhold // print usage 214402d77f6SIngo Weinhold fprintf((error ? stderr : stdout), kUsage, programName); 215402d77f6SIngo Weinhold } 216402d77f6SIngo Weinhold 217402d77f6SIngo Weinhold // print_usage_and_exit 218d384cac4SAlex Smith static void 219402d77f6SIngo Weinhold print_usage_and_exit(bool error) 220402d77f6SIngo Weinhold { 221402d77f6SIngo Weinhold print_usage(error); 222402d77f6SIngo Weinhold exit(error ? 1 : 0); 223402d77f6SIngo Weinhold } 224402d77f6SIngo Weinhold 225402d77f6SIngo Weinhold 226402d77f6SIngo Weinhold // #pragma mark - Exception 227402d77f6SIngo Weinhold 228402d77f6SIngo Weinhold 229402d77f6SIngo Weinhold class Exception { 230402d77f6SIngo Weinhold public: 231402d77f6SIngo Weinhold // constructor 232402d77f6SIngo Weinhold Exception() 233402d77f6SIngo Weinhold : fError(errno), 234402d77f6SIngo Weinhold fDescription() 235402d77f6SIngo Weinhold { 236402d77f6SIngo Weinhold } 237402d77f6SIngo Weinhold 238402d77f6SIngo Weinhold // constructor 239402d77f6SIngo Weinhold Exception(const char* format,...) 240402d77f6SIngo Weinhold : fError(errno), 241402d77f6SIngo Weinhold fDescription() 242402d77f6SIngo Weinhold { 243402d77f6SIngo Weinhold va_list args; 244402d77f6SIngo Weinhold va_start(args, format); 245402d77f6SIngo Weinhold SetTo(errno, format, args); 246402d77f6SIngo Weinhold va_end(args); 247402d77f6SIngo Weinhold } 248402d77f6SIngo Weinhold 249402d77f6SIngo Weinhold // constructor 250402d77f6SIngo Weinhold Exception(int error) 251402d77f6SIngo Weinhold : fError(error), 252402d77f6SIngo Weinhold fDescription() 253402d77f6SIngo Weinhold { 254402d77f6SIngo Weinhold } 255402d77f6SIngo Weinhold 256402d77f6SIngo Weinhold // constructor 257402d77f6SIngo Weinhold Exception(int error, const char* format,...) 258402d77f6SIngo Weinhold : fError(error), 259402d77f6SIngo Weinhold fDescription() 260402d77f6SIngo Weinhold { 261402d77f6SIngo Weinhold va_list args; 262402d77f6SIngo Weinhold va_start(args, format); 263402d77f6SIngo Weinhold SetTo(error, format, args); 264402d77f6SIngo Weinhold va_end(args); 265402d77f6SIngo Weinhold } 266402d77f6SIngo Weinhold 267402d77f6SIngo Weinhold // copy constructor 268402d77f6SIngo Weinhold Exception(const Exception& exception) 269402d77f6SIngo Weinhold : fError(exception.fError), 270402d77f6SIngo Weinhold fDescription(exception.fDescription) 271402d77f6SIngo Weinhold { 272402d77f6SIngo Weinhold } 273402d77f6SIngo Weinhold 274402d77f6SIngo Weinhold // destructor 275402d77f6SIngo Weinhold ~Exception() 276402d77f6SIngo Weinhold { 277402d77f6SIngo Weinhold } 278402d77f6SIngo Weinhold 279402d77f6SIngo Weinhold // SetTo 280402d77f6SIngo Weinhold void SetTo(int error, const char* format, va_list arg) 281402d77f6SIngo Weinhold { 282402d77f6SIngo Weinhold char buffer[2048]; 283402d77f6SIngo Weinhold vsprintf(buffer, format, arg); 284402d77f6SIngo Weinhold fError = error; 285402d77f6SIngo Weinhold fDescription = buffer; 286402d77f6SIngo Weinhold } 287402d77f6SIngo Weinhold 288402d77f6SIngo Weinhold // Error 289402d77f6SIngo Weinhold int Error() const 290402d77f6SIngo Weinhold { 291402d77f6SIngo Weinhold return fError; 292402d77f6SIngo Weinhold } 293402d77f6SIngo Weinhold 294402d77f6SIngo Weinhold // Description 295402d77f6SIngo Weinhold const string& Description() const 296402d77f6SIngo Weinhold { 297402d77f6SIngo Weinhold return fDescription; 298402d77f6SIngo Weinhold } 299402d77f6SIngo Weinhold 300402d77f6SIngo Weinhold private: 301402d77f6SIngo Weinhold int fError; 302402d77f6SIngo Weinhold string fDescription; 303402d77f6SIngo Weinhold }; 304402d77f6SIngo Weinhold 305402d77f6SIngo Weinhold 306402d77f6SIngo Weinhold // #pragma mark - ELFObject 307402d77f6SIngo Weinhold 308402d77f6SIngo Weinhold 309402d77f6SIngo Weinhold struct SectionInfo { 310402d77f6SIngo Weinhold uint32_t type; 311d384cac4SAlex Smith off_t offset; 312d384cac4SAlex Smith size_t size; 313402d77f6SIngo Weinhold const char* name; 314402d77f6SIngo Weinhold }; 315402d77f6SIngo Weinhold 316402d77f6SIngo Weinhold 317402d77f6SIngo Weinhold class ELFObject { 318402d77f6SIngo Weinhold public: 319402d77f6SIngo Weinhold ELFObject() 320402d77f6SIngo Weinhold : fFD(-1), 321402d77f6SIngo Weinhold fSectionHeaderStrings(NULL), 322402d77f6SIngo Weinhold fSectionHeaderStringsLength(0) 323402d77f6SIngo Weinhold { 324402d77f6SIngo Weinhold } 325402d77f6SIngo Weinhold 326402d77f6SIngo Weinhold ~ELFObject() 327402d77f6SIngo Weinhold { 328402d77f6SIngo Weinhold Unset(); 329402d77f6SIngo Weinhold } 330402d77f6SIngo Weinhold 331402d77f6SIngo Weinhold void Unset() 332402d77f6SIngo Weinhold { 333402d77f6SIngo Weinhold if (fFD >= 0) { 334402d77f6SIngo Weinhold close(fFD); 335402d77f6SIngo Weinhold fFD = -1; 336402d77f6SIngo Weinhold } 337402d77f6SIngo Weinhold 338402d77f6SIngo Weinhold delete[] fSectionHeaderStrings; 339402d77f6SIngo Weinhold fSectionHeaderStrings = NULL; 340402d77f6SIngo Weinhold } 341402d77f6SIngo Weinhold 342402d77f6SIngo Weinhold void SetTo(const char* fileName) 343402d77f6SIngo Weinhold { 344402d77f6SIngo Weinhold Unset(); 345402d77f6SIngo Weinhold 346402d77f6SIngo Weinhold // open the file 347402d77f6SIngo Weinhold fFD = open(fileName, O_RDWR); 348402d77f6SIngo Weinhold if (fFD < 0) 349402d77f6SIngo Weinhold throw Exception("Failed to open \"%s\"", fileName); 350402d77f6SIngo Weinhold 351402d77f6SIngo Weinhold // get the file size 352402d77f6SIngo Weinhold fFileSize = FileSize(); 353402d77f6SIngo Weinhold if (fFileSize < 0) 354402d77f6SIngo Weinhold throw Exception("Failed to get the file size."); 355402d77f6SIngo Weinhold 356d384cac4SAlex Smith // Read identification information 357d384cac4SAlex Smith unsigned char ident[EI_NIDENT]; 358d384cac4SAlex Smith Read(0, ident, sizeof(ident), "Failed to read ELF identification."); 359d384cac4SAlex Smith if (memcmp(ident, kELFFileMagic, sizeof(kELFFileMagic)) != 0) 360d384cac4SAlex Smith throw Exception("Not a valid ELF file."); 361d384cac4SAlex Smith fELFClass = ident[EI_CLASS]; 362402d77f6SIngo Weinhold 363d384cac4SAlex Smith if (fELFClass == ELFCLASS64) 364d384cac4SAlex Smith _ParseELFHeader<Elf64_Ehdr, Elf64_Shdr>(); 365d384cac4SAlex Smith else 366d384cac4SAlex Smith _ParseELFHeader<Elf32_Ehdr, Elf32_Shdr>(); 367402d77f6SIngo Weinhold } 368402d77f6SIngo Weinhold 369402d77f6SIngo Weinhold bool FindSectionByName(const char* name, SectionInfo& foundInfo) 370402d77f6SIngo Weinhold { 371402d77f6SIngo Weinhold // can't find the section by name without section names 372402d77f6SIngo Weinhold if (!fSectionHeaderStrings) 373402d77f6SIngo Weinhold return false; 374402d77f6SIngo Weinhold 375402d77f6SIngo Weinhold // iterate through the section headers 376d384cac4SAlex Smith for (size_t i = 0; i < fSectionHeaderCount; i++) { 377402d77f6SIngo Weinhold SectionInfo info; 378d384cac4SAlex Smith 379d384cac4SAlex Smith bool result; 380d384cac4SAlex Smith if (fELFClass == ELFCLASS64) 381d384cac4SAlex Smith result = _ReadSectionHeader<Elf64_Shdr>(i, info); 382d384cac4SAlex Smith else 383d384cac4SAlex Smith result = _ReadSectionHeader<Elf32_Shdr>(i, info); 384d384cac4SAlex Smith 385d384cac4SAlex Smith if (result) { 386402d77f6SIngo Weinhold //printf("section %3d: offset: %7d, size: %7d, name: %s\n", i, info.offset, info.size, info.name); 387402d77f6SIngo Weinhold if (strcmp(info.name, name) == 0) { 388402d77f6SIngo Weinhold foundInfo = info; 389402d77f6SIngo Weinhold return true; 390402d77f6SIngo Weinhold } 391402d77f6SIngo Weinhold } 392402d77f6SIngo Weinhold } 393402d77f6SIngo Weinhold 394402d77f6SIngo Weinhold return false; 395402d77f6SIngo Weinhold } 396402d77f6SIngo Weinhold 397402d77f6SIngo Weinhold void Read(off_t position, void* buffer, size_t size, 398402d77f6SIngo Weinhold const char *errorMessage = NULL) 399402d77f6SIngo Weinhold { 400402d77f6SIngo Weinhold if (lseek(fFD, position, SEEK_SET) < 0) 401402d77f6SIngo Weinhold throw Exception(errorMessage); 402402d77f6SIngo Weinhold 403402d77f6SIngo Weinhold ssize_t bytesRead = read(fFD, buffer, size); 404402d77f6SIngo Weinhold if (bytesRead < 0) 405402d77f6SIngo Weinhold throw Exception(errorMessage); 406402d77f6SIngo Weinhold 407402d77f6SIngo Weinhold if ((size_t)bytesRead != size) { 408402d77f6SIngo Weinhold if (errorMessage) { 409402d77f6SIngo Weinhold throw Exception("%s Read too few bytes (%d/%d).", 410402d77f6SIngo Weinhold errorMessage, (int)bytesRead, (int)size); 411402d77f6SIngo Weinhold } else { 412402d77f6SIngo Weinhold throw Exception("Read too few bytes (%ld/%lu).", 413402d77f6SIngo Weinhold (int)bytesRead, (int)size); 414402d77f6SIngo Weinhold } 415402d77f6SIngo Weinhold } 416402d77f6SIngo Weinhold } 417402d77f6SIngo Weinhold 418402d77f6SIngo Weinhold void Write(off_t position, const void* buffer, size_t size, 419402d77f6SIngo Weinhold const char *errorMessage = NULL) 420402d77f6SIngo Weinhold { 421402d77f6SIngo Weinhold if (lseek(fFD, position, SEEK_SET) < 0) 422402d77f6SIngo Weinhold throw Exception(errorMessage); 423402d77f6SIngo Weinhold 424402d77f6SIngo Weinhold ssize_t bytesWritten = write(fFD, buffer, size); 425402d77f6SIngo Weinhold if (bytesWritten < 0) 426402d77f6SIngo Weinhold throw Exception(errorMessage); 427402d77f6SIngo Weinhold 428402d77f6SIngo Weinhold if ((size_t)bytesWritten != size) { 429402d77f6SIngo Weinhold if (errorMessage) { 430402d77f6SIngo Weinhold throw Exception("%s Wrote too few bytes (%d/%d).", 431402d77f6SIngo Weinhold errorMessage, (int)bytesWritten, (int)size); 432402d77f6SIngo Weinhold } else { 433402d77f6SIngo Weinhold throw Exception("Wrote too few bytes (%ld/%lu).", 434402d77f6SIngo Weinhold (int)bytesWritten, (int)size); 435402d77f6SIngo Weinhold } 436402d77f6SIngo Weinhold } 437402d77f6SIngo Weinhold } 438402d77f6SIngo Weinhold 439402d77f6SIngo Weinhold off_t FileSize() 440402d77f6SIngo Weinhold { 441402d77f6SIngo Weinhold off_t currentPos = lseek(fFD, 0, SEEK_END); 442402d77f6SIngo Weinhold if (currentPos < 0) 443402d77f6SIngo Weinhold return -1; 444402d77f6SIngo Weinhold 445402d77f6SIngo Weinhold return lseek(fFD, currentPos, SEEK_SET); 446402d77f6SIngo Weinhold } 447402d77f6SIngo Weinhold 448d384cac4SAlex Smith template<typename Type> 449d384cac4SAlex Smith Type GetValue(Type& value); 450402d77f6SIngo Weinhold 451402d77f6SIngo Weinhold private: 452d384cac4SAlex Smith template<typename EhdrType, typename ShdrType> 4539761f00bSOliver Tappe void _ParseELFHeader(); 4549761f00bSOliver Tappe 4559761f00bSOliver Tappe template<typename ShdrType> 4569761f00bSOliver Tappe bool _ReadSectionHeader(int index, SectionInfo& info); 4579761f00bSOliver Tappe 4589761f00bSOliver Tappe // _SwapUInt16 4599761f00bSOliver Tappe static inline uint16_t _SwapUInt16(uint16_t value) 4609761f00bSOliver Tappe { 4619761f00bSOliver Tappe return ((value & 0xff) << 8) | (value >> 8); 4629761f00bSOliver Tappe } 4639761f00bSOliver Tappe 4649761f00bSOliver Tappe // _SwapUInt32 4659761f00bSOliver Tappe static inline uint32_t _SwapUInt32(uint32_t value) 4669761f00bSOliver Tappe { 4679761f00bSOliver Tappe return ((uint32_t)_SwapUInt16(value & 0xffff) << 16) 4689761f00bSOliver Tappe | _SwapUInt16(uint16_t(value >> 16)); 4699761f00bSOliver Tappe } 4709761f00bSOliver Tappe 4719761f00bSOliver Tappe // _SwapUInt64 4729761f00bSOliver Tappe static inline uint64_t _SwapUInt64(uint64_t value) 4739761f00bSOliver Tappe { 4749761f00bSOliver Tappe return ((uint64_t)_SwapUInt32(value & 0xffffffff) << 32) 4759761f00bSOliver Tappe | _SwapUInt32(uint32_t(value >> 32)); 4769761f00bSOliver Tappe } 4779761f00bSOliver Tappe 4789761f00bSOliver Tappe private: 4799761f00bSOliver Tappe int fFD; 4809761f00bSOliver Tappe uint8_t fELFClass; 4819761f00bSOliver Tappe bool fHostEndianess; 4829761f00bSOliver Tappe off_t fFileSize; 4839761f00bSOliver Tappe size_t fELFHeaderSize; 4849761f00bSOliver Tappe off_t fSectionHeaderTableOffset; 4859761f00bSOliver Tappe size_t fSectionHeaderSize; 4869761f00bSOliver Tappe size_t fSectionHeaderCount; 4879761f00bSOliver Tappe char* fSectionHeaderStrings; 4889761f00bSOliver Tappe uint32_t fSectionHeaderStringsLength; 4899761f00bSOliver Tappe }; 4909761f00bSOliver Tappe 4919761f00bSOliver Tappe 4929761f00bSOliver Tappe template<> 4939761f00bSOliver Tappe int16_t ELFObject::GetValue(int16_t& value) 4949761f00bSOliver Tappe { 4959761f00bSOliver Tappe return (fHostEndianess ? value : _SwapUInt16(value)); 4969761f00bSOliver Tappe } 4979761f00bSOliver Tappe 4989761f00bSOliver Tappe 4999761f00bSOliver Tappe template<> 5009761f00bSOliver Tappe uint16_t ELFObject::GetValue(uint16_t& value) 5019761f00bSOliver Tappe { 5029761f00bSOliver Tappe return (fHostEndianess ? value : _SwapUInt16(value)); 5039761f00bSOliver Tappe } 5049761f00bSOliver Tappe 5059761f00bSOliver Tappe 5069761f00bSOliver Tappe template<> 5079761f00bSOliver Tappe int32_t ELFObject::GetValue(int32_t& value) 5089761f00bSOliver Tappe { 5099761f00bSOliver Tappe return (fHostEndianess ? value : _SwapUInt32(value)); 5109761f00bSOliver Tappe } 5119761f00bSOliver Tappe 5129761f00bSOliver Tappe 5139761f00bSOliver Tappe template<> 5149761f00bSOliver Tappe uint32_t ELFObject::GetValue(uint32_t& value) 5159761f00bSOliver Tappe { 5169761f00bSOliver Tappe return (fHostEndianess ? value : _SwapUInt32(value)); 5179761f00bSOliver Tappe } 5189761f00bSOliver Tappe 5199761f00bSOliver Tappe 5209761f00bSOliver Tappe template<> 5219761f00bSOliver Tappe int64_t ELFObject::GetValue(int64_t& value) 5229761f00bSOliver Tappe { 5239761f00bSOliver Tappe return (fHostEndianess ? value : _SwapUInt64(value)); 5249761f00bSOliver Tappe } 5259761f00bSOliver Tappe 5269761f00bSOliver Tappe 5279761f00bSOliver Tappe template<> 5289761f00bSOliver Tappe uint64_t ELFObject::GetValue(uint64_t& value) 5299761f00bSOliver Tappe { 5309761f00bSOliver Tappe return (fHostEndianess ? value : _SwapUInt64(value)); 5319761f00bSOliver Tappe } 5329761f00bSOliver Tappe 5339761f00bSOliver Tappe 5349761f00bSOliver Tappe template<typename EhdrType, typename ShdrType> 5359761f00bSOliver Tappe void ELFObject::_ParseELFHeader() 536d384cac4SAlex Smith { 537d384cac4SAlex Smith // read ELF header 538d384cac4SAlex Smith EhdrType fileHeader; 539d384cac4SAlex Smith Read(0, &fileHeader, sizeof(EhdrType), "Failed to read ELF header."); 540d384cac4SAlex Smith 541d384cac4SAlex Smith // check data encoding (endianess) 542d384cac4SAlex Smith switch (fileHeader.e_ident[EI_DATA]) { 543d384cac4SAlex Smith case ELFDATA2LSB: 544d384cac4SAlex Smith fHostEndianess = (htonl(1) != 1); 545d384cac4SAlex Smith break; 546d384cac4SAlex Smith case ELFDATA2MSB: 547d384cac4SAlex Smith fHostEndianess = (htonl(1) == 1); 548d384cac4SAlex Smith break; 549d384cac4SAlex Smith default: 550d384cac4SAlex Smith case ELFDATANONE: 551d384cac4SAlex Smith throw Exception(EIO, "Unsupported ELF data encoding."); 552d384cac4SAlex Smith break; 553d384cac4SAlex Smith } 554d384cac4SAlex Smith 555d384cac4SAlex Smith // get the header values 556d384cac4SAlex Smith fELFHeaderSize = GetValue(fileHeader.e_ehsize); 557d384cac4SAlex Smith fSectionHeaderTableOffset = GetValue(fileHeader.e_shoff); 558d384cac4SAlex Smith fSectionHeaderSize = GetValue(fileHeader.e_shentsize); 559d384cac4SAlex Smith fSectionHeaderCount = GetValue(fileHeader.e_shnum); 560d384cac4SAlex Smith bool hasSectionHeaderTable = (fSectionHeaderTableOffset != 0); 561d384cac4SAlex Smith 562d384cac4SAlex Smith // check the sanity of the header values 563d384cac4SAlex Smith // ELF header size 564d384cac4SAlex Smith if (fELFHeaderSize < sizeof(EhdrType)) { 565d384cac4SAlex Smith throw Exception(EIO, 566d384cac4SAlex Smith "Invalid ELF header: invalid ELF header size: %lu.", 567d384cac4SAlex Smith fELFHeaderSize); 568d384cac4SAlex Smith } 569d384cac4SAlex Smith 570d384cac4SAlex Smith // section header table offset and entry count/size 571d384cac4SAlex Smith if (hasSectionHeaderTable) { 572d384cac4SAlex Smith if (fSectionHeaderTableOffset < (off_t)fELFHeaderSize 573d384cac4SAlex Smith || fSectionHeaderTableOffset > fFileSize) { 574d384cac4SAlex Smith throw Exception(EIO, "Invalid ELF header: invalid section " 575d384cac4SAlex Smith "header table offset: %llu.", 576d384cac4SAlex Smith fSectionHeaderTableOffset); 577d384cac4SAlex Smith } 578d384cac4SAlex Smith size_t sectionHeaderTableSize 579d384cac4SAlex Smith = fSectionHeaderSize * fSectionHeaderCount; 580d384cac4SAlex Smith if (fSectionHeaderSize < (off_t)sizeof(ShdrType) 581d384cac4SAlex Smith || fSectionHeaderTableOffset + (off_t)sectionHeaderTableSize 582d384cac4SAlex Smith > fFileSize) { 583d384cac4SAlex Smith throw Exception(EIO, "Invalid ELF header: section header " 584d384cac4SAlex Smith "table exceeds file: %llu.", 585d384cac4SAlex Smith fSectionHeaderTableOffset 586d384cac4SAlex Smith + sectionHeaderTableSize); 587d384cac4SAlex Smith } 588d384cac4SAlex Smith 589d384cac4SAlex Smith 590d384cac4SAlex Smith // load section header string section 591d384cac4SAlex Smith uint16_t sectionHeaderStringSectionIndex 592d384cac4SAlex Smith = GetValue(fileHeader.e_shstrndx); 593d384cac4SAlex Smith if (sectionHeaderStringSectionIndex != SHN_UNDEF) { 594d384cac4SAlex Smith if (sectionHeaderStringSectionIndex >= fSectionHeaderCount) { 595d384cac4SAlex Smith throw Exception(EIO, "Invalid ELF header: invalid section " 596d384cac4SAlex Smith "header string section index: %u.", 597d384cac4SAlex Smith sectionHeaderStringSectionIndex); 598d384cac4SAlex Smith } 599d384cac4SAlex Smith 600d384cac4SAlex Smith // get the section info 601d384cac4SAlex Smith SectionInfo info; 602d384cac4SAlex Smith if (_ReadSectionHeader<ShdrType>(sectionHeaderStringSectionIndex, 603d384cac4SAlex Smith info)) { 604d384cac4SAlex Smith fSectionHeaderStrings = new char[info.size + 1]; 605d384cac4SAlex Smith Read(info.offset, fSectionHeaderStrings, info.size, 606d384cac4SAlex Smith "Failed to read section header string section."); 607d384cac4SAlex Smith fSectionHeaderStringsLength = info.size; 608d384cac4SAlex Smith // null-terminate to be on the safe side 609d384cac4SAlex Smith fSectionHeaderStrings[info.size] = '\0'; 610d384cac4SAlex Smith } 611d384cac4SAlex Smith } 612d384cac4SAlex Smith } 613d384cac4SAlex Smith } 614d384cac4SAlex Smith 6159761f00bSOliver Tappe 616d384cac4SAlex Smith template<typename ShdrType> 6179761f00bSOliver Tappe bool ELFObject::_ReadSectionHeader(int index, SectionInfo& info) 618402d77f6SIngo Weinhold { 619d384cac4SAlex Smith off_t shOffset = fSectionHeaderTableOffset 620402d77f6SIngo Weinhold + index * fSectionHeaderSize; 621d384cac4SAlex Smith ShdrType sectionHeader; 622d384cac4SAlex Smith Read(shOffset, §ionHeader, sizeof(ShdrType), 623402d77f6SIngo Weinhold "Failed to read ELF section header."); 624402d77f6SIngo Weinhold 625402d77f6SIngo Weinhold // get the header values 626d384cac4SAlex Smith uint32_t type = GetValue(sectionHeader.sh_type); 627d384cac4SAlex Smith off_t offset = GetValue(sectionHeader.sh_offset); 628d384cac4SAlex Smith size_t size = GetValue(sectionHeader.sh_size); 629d384cac4SAlex Smith uint32_t nameIndex = GetValue(sectionHeader.sh_name); 630402d77f6SIngo Weinhold 631402d77f6SIngo Weinhold // check the values 632402d77f6SIngo Weinhold // SHT_NULL marks the header unused, 633402d77f6SIngo Weinhold if (type == SHT_NULL) 634402d77f6SIngo Weinhold return false; 635402d77f6SIngo Weinhold 636402d77f6SIngo Weinhold // SHT_NOBITS sections take no space in the file 637402d77f6SIngo Weinhold if (type != SHT_NOBITS) { 638d384cac4SAlex Smith if (offset < (off_t)fELFHeaderSize || offset > fFileSize) { 639402d77f6SIngo Weinhold throw Exception(EIO, "Invalid ELF section header: " 640d384cac4SAlex Smith "invalid section offset: %llu.", offset); 641402d77f6SIngo Weinhold } 642d384cac4SAlex Smith off_t sectionEnd = offset + size; 643402d77f6SIngo Weinhold if (sectionEnd > fFileSize) { 644402d77f6SIngo Weinhold throw Exception(EIO, "Invalid ELF section header: " 645d384cac4SAlex Smith "section exceeds file: %llu.", sectionEnd); 646402d77f6SIngo Weinhold } 647402d77f6SIngo Weinhold } 648402d77f6SIngo Weinhold 649402d77f6SIngo Weinhold // get name, if we have a string section 650402d77f6SIngo Weinhold if (fSectionHeaderStrings) { 651402d77f6SIngo Weinhold if (nameIndex >= (uint32_t)fSectionHeaderStringsLength) { 652402d77f6SIngo Weinhold throw Exception(EIO, "Invalid ELF section header: " 653402d77f6SIngo Weinhold "invalid name index: %lu.", nameIndex); 654402d77f6SIngo Weinhold } 655402d77f6SIngo Weinhold info.name = fSectionHeaderStrings + nameIndex; 656402d77f6SIngo Weinhold } else { 657402d77f6SIngo Weinhold info.name = ""; 658402d77f6SIngo Weinhold } 659402d77f6SIngo Weinhold 660402d77f6SIngo Weinhold info.type = type; 661402d77f6SIngo Weinhold info.offset = offset; 662402d77f6SIngo Weinhold info.size = size; 663402d77f6SIngo Weinhold 664402d77f6SIngo Weinhold 665402d77f6SIngo Weinhold return true; 666402d77f6SIngo Weinhold } 667402d77f6SIngo Weinhold 668d384cac4SAlex Smith 669402d77f6SIngo Weinhold // main 670402d77f6SIngo Weinhold int 671402d77f6SIngo Weinhold main(int argc, const char* const* argv) 672402d77f6SIngo Weinhold { 673402d77f6SIngo Weinhold sArgc = argc; 674402d77f6SIngo Weinhold sArgv = argv; 675402d77f6SIngo Weinhold 676402d77f6SIngo Weinhold if (argc < 3) 677402d77f6SIngo Weinhold print_usage_and_exit(true); 678402d77f6SIngo Weinhold 679402d77f6SIngo Weinhold // parameters 680402d77f6SIngo Weinhold const char* fileName = argv[1]; 681402d77f6SIngo Weinhold const char* revisionString = argv[2]; 682402d77f6SIngo Weinhold 683402d77f6SIngo Weinhold try { 684402d77f6SIngo Weinhold ELFObject elfObject; 685402d77f6SIngo Weinhold elfObject.SetTo(fileName); 686402d77f6SIngo Weinhold 687402d77f6SIngo Weinhold // find haiku revision section 688402d77f6SIngo Weinhold SectionInfo info; 689402d77f6SIngo Weinhold if (!elfObject.FindSectionByName("_haiku_revision", info)) { 690402d77f6SIngo Weinhold fprintf(stderr, "haiku revision section not found\n"); 691402d77f6SIngo Weinhold exit(1); 692402d77f6SIngo Weinhold } 693402d77f6SIngo Weinhold 6946250297aSOliver Tappe // write revision string to section 6956250297aSOliver Tappe elfObject.Write(info.offset, revisionString, 696af2da315SOliver Tappe min((size_t)SYSTEM_REVISION_LENGTH, strlen(revisionString) + 1), 697402d77f6SIngo Weinhold "Failed to write revision."); 698402d77f6SIngo Weinhold 699*992ae400SMurai Takashi } catch (Exception& exception) { 700402d77f6SIngo Weinhold if (exception.Description() == "") { 701402d77f6SIngo Weinhold fprintf(stderr, "%s\n", strerror(exception.Error())); 702402d77f6SIngo Weinhold } else { 703402d77f6SIngo Weinhold fprintf(stderr, "%s: %s\n", exception.Description().c_str(), 704402d77f6SIngo Weinhold strerror(exception.Error())); 705402d77f6SIngo Weinhold } 706402d77f6SIngo Weinhold exit(1); 707402d77f6SIngo Weinhold } 708402d77f6SIngo Weinhold 709402d77f6SIngo Weinhold return 0; 710402d77f6SIngo Weinhold } 711