xref: /haiku/src/tools/set_haiku_revision.cpp (revision c1eed5c7f3295d134760f471bc28c09ce6337726)
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, &sectionHeader, 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