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
print_usage(bool error)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
print_usage_and_exit(bool error)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
Exception()232402d77f6SIngo Weinhold Exception()
233402d77f6SIngo Weinhold : fError(errno),
234402d77f6SIngo Weinhold fDescription()
235402d77f6SIngo Weinhold {
236402d77f6SIngo Weinhold }
237402d77f6SIngo Weinhold
238402d77f6SIngo Weinhold // constructor
Exception(const char * format,...)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
Exception(int error)250402d77f6SIngo Weinhold Exception(int error)
251402d77f6SIngo Weinhold : fError(error),
252402d77f6SIngo Weinhold fDescription()
253402d77f6SIngo Weinhold {
254402d77f6SIngo Weinhold }
255402d77f6SIngo Weinhold
256402d77f6SIngo Weinhold // constructor
Exception(int error,const char * format,...)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
Exception(const Exception & exception)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
~Exception()275402d77f6SIngo Weinhold ~Exception()
276402d77f6SIngo Weinhold {
277402d77f6SIngo Weinhold }
278402d77f6SIngo Weinhold
279402d77f6SIngo Weinhold // SetTo
SetTo(int error,const char * format,va_list arg)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
Error() const289402d77f6SIngo Weinhold int Error() const
290402d77f6SIngo Weinhold {
291402d77f6SIngo Weinhold return fError;
292402d77f6SIngo Weinhold }
293402d77f6SIngo Weinhold
294402d77f6SIngo Weinhold // Description
Description() const295402d77f6SIngo 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:
ELFObject()319402d77f6SIngo Weinhold ELFObject()
320402d77f6SIngo Weinhold : fFD(-1),
321402d77f6SIngo Weinhold fSectionHeaderStrings(NULL),
322402d77f6SIngo Weinhold fSectionHeaderStringsLength(0)
323402d77f6SIngo Weinhold {
324402d77f6SIngo Weinhold }
325402d77f6SIngo Weinhold
~ELFObject()326402d77f6SIngo Weinhold ~ELFObject()
327402d77f6SIngo Weinhold {
328402d77f6SIngo Weinhold Unset();
329402d77f6SIngo Weinhold }
330402d77f6SIngo Weinhold
Unset()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
SetTo(const char * fileName)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
FindSectionByName(const char * name,SectionInfo & foundInfo)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
Read(off_t position,void * buffer,size_t size,const char * errorMessage=NULL)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) {
409*c1eed5c7SMurai Takashi throw Exception("%s Read too few bytes (%zd/%zu).",
410*c1eed5c7SMurai Takashi errorMessage, bytesRead, size);
411402d77f6SIngo Weinhold } else {
412*c1eed5c7SMurai Takashi throw Exception("Read too few bytes (%zd/%zu).",
413*c1eed5c7SMurai Takashi bytesRead, size);
414402d77f6SIngo Weinhold }
415402d77f6SIngo Weinhold }
416402d77f6SIngo Weinhold }
417402d77f6SIngo Weinhold
Write(off_t position,const void * buffer,size_t size,const char * errorMessage=NULL)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) {
430*c1eed5c7SMurai Takashi throw Exception("%s Wrote too few bytes (%zd/%zu).",
431*c1eed5c7SMurai Takashi errorMessage, bytesWritten, size);
432402d77f6SIngo Weinhold } else {
433*c1eed5c7SMurai Takashi throw Exception("Wrote too few bytes (%zd/%zu).",
434*c1eed5c7SMurai Takashi bytesWritten, size);
435402d77f6SIngo Weinhold }
436402d77f6SIngo Weinhold }
437402d77f6SIngo Weinhold }
438402d77f6SIngo Weinhold
FileSize()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
_SwapUInt16(uint16_t value)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
_SwapUInt32(uint32_t value)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
_SwapUInt64(uint64_t value)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<>
GetValue(int16_t & value)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<>
GetValue(uint16_t & value)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<>
GetValue(int32_t & value)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<>
GetValue(uint32_t & value)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<>
GetValue(int64_t & value)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<>
GetValue(uint64_t & value)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>
_ParseELFHeader()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>
_ReadSectionHeader(int index,SectionInfo & info)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: "
653*c1eed5c7SMurai Takashi "invalid name index: %" PRIu32 ".", 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
main(int argc,const char * const * argv)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
699992ae400SMurai 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