xref: /haiku/src/tools/set_haiku_revision.cpp (revision 402d77f655d0ae58cc43b7c2c45aa197c681bd6a)
1*402d77f6SIngo Weinhold /*
2*402d77f6SIngo Weinhold  * Copyright 2007, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
3*402d77f6SIngo Weinhold  * All rights reserved. Distributed under the terms of the MIT License.
4*402d77f6SIngo Weinhold  */
5*402d77f6SIngo Weinhold 
6*402d77f6SIngo Weinhold #include <errno.h>
7*402d77f6SIngo Weinhold #include <fcntl.h>
8*402d77f6SIngo Weinhold #include <inttypes.h>
9*402d77f6SIngo Weinhold #include <stdarg.h>
10*402d77f6SIngo Weinhold #include <stdio.h>
11*402d77f6SIngo Weinhold #include <stdlib.h>
12*402d77f6SIngo Weinhold #include <unistd.h>
13*402d77f6SIngo Weinhold 
14*402d77f6SIngo Weinhold #include <algorithm>
15*402d77f6SIngo Weinhold #include <string>
16*402d77f6SIngo Weinhold 
17*402d77f6SIngo Weinhold #include <arpa/inet.h>
18*402d77f6SIngo Weinhold 
19*402d77f6SIngo Weinhold 
20*402d77f6SIngo Weinhold using std::string;
21*402d77f6SIngo Weinhold using std::max;
22*402d77f6SIngo Weinhold using std::min;
23*402d77f6SIngo Weinhold 
24*402d77f6SIngo Weinhold 
25*402d77f6SIngo Weinhold // #pragma mark - ELF definitions
26*402d77f6SIngo Weinhold 
27*402d77f6SIngo Weinhold 
28*402d77f6SIngo Weinhold // types
29*402d77f6SIngo Weinhold typedef uint32_t	Elf32_Addr;
30*402d77f6SIngo Weinhold typedef uint16_t	Elf32_Half;
31*402d77f6SIngo Weinhold typedef uint32_t	Elf32_Off;
32*402d77f6SIngo Weinhold typedef int32_t		Elf32_Sword;
33*402d77f6SIngo Weinhold typedef uint32_t	Elf32_Word;
34*402d77f6SIngo Weinhold 
35*402d77f6SIngo Weinhold // e_ident indices
36*402d77f6SIngo Weinhold #define EI_MAG0		0
37*402d77f6SIngo Weinhold #define EI_MAG1		1
38*402d77f6SIngo Weinhold #define EI_MAG2		2
39*402d77f6SIngo Weinhold #define EI_MAG3		3
40*402d77f6SIngo Weinhold #define EI_CLASS	4
41*402d77f6SIngo Weinhold #define EI_DATA		5
42*402d77f6SIngo Weinhold #define EI_VERSION	6
43*402d77f6SIngo Weinhold #define EI_PAD		7
44*402d77f6SIngo Weinhold #define EI_NIDENT	16
45*402d77f6SIngo Weinhold 
46*402d77f6SIngo Weinhold // object file header
47*402d77f6SIngo Weinhold typedef struct {
48*402d77f6SIngo Weinhold 	unsigned char	e_ident[EI_NIDENT];
49*402d77f6SIngo Weinhold 	Elf32_Half		e_type;
50*402d77f6SIngo Weinhold 	Elf32_Half		e_machine;
51*402d77f6SIngo Weinhold 	Elf32_Word		e_version;
52*402d77f6SIngo Weinhold 	Elf32_Addr		e_entry;
53*402d77f6SIngo Weinhold 	Elf32_Off		e_phoff;
54*402d77f6SIngo Weinhold 	Elf32_Off		e_shoff;
55*402d77f6SIngo Weinhold 	Elf32_Word		e_flags;
56*402d77f6SIngo Weinhold 	Elf32_Half		e_ehsize;
57*402d77f6SIngo Weinhold 	Elf32_Half		e_phentsize;
58*402d77f6SIngo Weinhold 	Elf32_Half		e_phnum;
59*402d77f6SIngo Weinhold 	Elf32_Half		e_shentsize;
60*402d77f6SIngo Weinhold 	Elf32_Half		e_shnum;
61*402d77f6SIngo Weinhold 	Elf32_Half		e_shstrndx;
62*402d77f6SIngo Weinhold } Elf32_Ehdr;
63*402d77f6SIngo Weinhold 
64*402d77f6SIngo Weinhold // e_ident EI_CLASS and EI_DATA values
65*402d77f6SIngo Weinhold #define ELFCLASSNONE	0
66*402d77f6SIngo Weinhold #define ELFCLASS32		1
67*402d77f6SIngo Weinhold #define ELFCLASS64		2
68*402d77f6SIngo Weinhold #define ELFDATANONE		0
69*402d77f6SIngo Weinhold #define ELFDATA2LSB		1
70*402d77f6SIngo Weinhold #define ELFDATA2MSB		2
71*402d77f6SIngo Weinhold 
72*402d77f6SIngo Weinhold // program header
73*402d77f6SIngo Weinhold typedef struct {
74*402d77f6SIngo Weinhold 	Elf32_Word	p_type;
75*402d77f6SIngo Weinhold 	Elf32_Off	p_offset;
76*402d77f6SIngo Weinhold 	Elf32_Addr	p_vaddr;
77*402d77f6SIngo Weinhold 	Elf32_Addr	p_paddr;
78*402d77f6SIngo Weinhold 	Elf32_Word	p_filesz;
79*402d77f6SIngo Weinhold 	Elf32_Word	p_memsz;
80*402d77f6SIngo Weinhold 	Elf32_Word	p_flags;
81*402d77f6SIngo Weinhold 	Elf32_Word	p_align;
82*402d77f6SIngo Weinhold } Elf32_Phdr;
83*402d77f6SIngo Weinhold 
84*402d77f6SIngo Weinhold // p_type
85*402d77f6SIngo Weinhold #define PT_NULL		0
86*402d77f6SIngo Weinhold #define PT_LOAD		1
87*402d77f6SIngo Weinhold #define PT_DYNAMIC	2
88*402d77f6SIngo Weinhold #define PT_INTERP	3
89*402d77f6SIngo Weinhold #define PT_NOTE		4
90*402d77f6SIngo Weinhold #define PT_SHLIB	5
91*402d77f6SIngo Weinhold #define PT_PHDIR	6
92*402d77f6SIngo Weinhold #define PT_LOPROC	0x70000000
93*402d77f6SIngo Weinhold #define PT_HIPROC	0x7fffffff
94*402d77f6SIngo Weinhold 
95*402d77f6SIngo Weinhold // section header
96*402d77f6SIngo Weinhold typedef struct {
97*402d77f6SIngo Weinhold 	Elf32_Word	sh_name;
98*402d77f6SIngo Weinhold 	Elf32_Word	sh_type;
99*402d77f6SIngo Weinhold 	Elf32_Word	sh_flags;
100*402d77f6SIngo Weinhold 	Elf32_Addr	sh_addr;
101*402d77f6SIngo Weinhold 	Elf32_Off	sh_offset;
102*402d77f6SIngo Weinhold 	Elf32_Word	sh_size;
103*402d77f6SIngo Weinhold 	Elf32_Word	sh_link;
104*402d77f6SIngo Weinhold 	Elf32_Word	sh_info;
105*402d77f6SIngo Weinhold 	Elf32_Word	sh_addralign;
106*402d77f6SIngo Weinhold 	Elf32_Word	sh_entsize;
107*402d77f6SIngo Weinhold } Elf32_Shdr;
108*402d77f6SIngo Weinhold 
109*402d77f6SIngo Weinhold // sh_type values
110*402d77f6SIngo Weinhold #define SHT_NULL		0
111*402d77f6SIngo Weinhold #define SHT_PROGBITS	1
112*402d77f6SIngo Weinhold #define SHT_SYMTAB		2
113*402d77f6SIngo Weinhold #define SHT_STRTAB		3
114*402d77f6SIngo Weinhold #define SHT_RELA		4
115*402d77f6SIngo Weinhold #define SHT_HASH		5
116*402d77f6SIngo Weinhold #define SHT_DYNAMIC		6
117*402d77f6SIngo Weinhold #define SHT_NOTE		7
118*402d77f6SIngo Weinhold #define SHT_NOBITS		8
119*402d77f6SIngo Weinhold #define SHT_REL			9
120*402d77f6SIngo Weinhold #define SHT_SHLIB		10
121*402d77f6SIngo Weinhold #define SHT_DYNSYM		11
122*402d77f6SIngo Weinhold #define SHT_LOPROC		0x70000000
123*402d77f6SIngo Weinhold #define SHT_HIPROC		0x7fffffff
124*402d77f6SIngo Weinhold #define SHT_LOUSER		0x80000000
125*402d77f6SIngo Weinhold #define SHT_HIUSER		0xffffffff
126*402d77f6SIngo Weinhold 
127*402d77f6SIngo Weinhold // special section indexes
128*402d77f6SIngo Weinhold #define SHN_UNDEF		0
129*402d77f6SIngo Weinhold 
130*402d77f6SIngo Weinhold static const uint32_t	kMaxELFHeaderSize	= sizeof(Elf32_Ehdr) + 32;
131*402d77f6SIngo Weinhold static const char		kELFFileMagic[4]	= { 0x7f, 'E', 'L', 'F' };
132*402d77f6SIngo Weinhold 
133*402d77f6SIngo Weinhold 
134*402d77f6SIngo Weinhold // #pragma mark - Usage
135*402d77f6SIngo Weinhold 
136*402d77f6SIngo Weinhold // usage
137*402d77f6SIngo Weinhold static const char *kUsage =
138*402d77f6SIngo Weinhold "Usage: %s  <file> <revision>\n"
139*402d77f6SIngo Weinhold "\n"
140*402d77f6SIngo Weinhold "Finds the haiku revision section in ELF object file <file> and replaces the\n"
141*402d77f6SIngo Weinhold "writes the number given by <revision> into the first 32 bits of the\n"
142*402d77f6SIngo Weinhold "section.\n"
143*402d77f6SIngo Weinhold ;
144*402d77f6SIngo Weinhold 
145*402d77f6SIngo Weinhold // command line args
146*402d77f6SIngo Weinhold static int sArgc;
147*402d77f6SIngo Weinhold static const char *const *sArgv;
148*402d77f6SIngo Weinhold 
149*402d77f6SIngo Weinhold // print_usage
150*402d77f6SIngo Weinhold void
151*402d77f6SIngo Weinhold print_usage(bool error)
152*402d77f6SIngo Weinhold {
153*402d77f6SIngo Weinhold 	// get nice program name
154*402d77f6SIngo Weinhold 	const char *programName = (sArgc > 0 ? sArgv[0] : "resattr");
155*402d77f6SIngo Weinhold 	if (const char *lastSlash = strrchr(programName, '/'))
156*402d77f6SIngo Weinhold 		programName = lastSlash + 1;
157*402d77f6SIngo Weinhold 
158*402d77f6SIngo Weinhold 	// print usage
159*402d77f6SIngo Weinhold 	fprintf((error ? stderr : stdout), kUsage, programName);
160*402d77f6SIngo Weinhold }
161*402d77f6SIngo Weinhold 
162*402d77f6SIngo Weinhold // print_usage_and_exit
163*402d77f6SIngo Weinhold static
164*402d77f6SIngo Weinhold void
165*402d77f6SIngo Weinhold print_usage_and_exit(bool error)
166*402d77f6SIngo Weinhold {
167*402d77f6SIngo Weinhold 	print_usage(error);
168*402d77f6SIngo Weinhold 	exit(error ? 1 : 0);
169*402d77f6SIngo Weinhold }
170*402d77f6SIngo Weinhold 
171*402d77f6SIngo Weinhold 
172*402d77f6SIngo Weinhold // #pragma mark - Exception
173*402d77f6SIngo Weinhold 
174*402d77f6SIngo Weinhold 
175*402d77f6SIngo Weinhold class Exception {
176*402d77f6SIngo Weinhold public:
177*402d77f6SIngo Weinhold 	// constructor
178*402d77f6SIngo Weinhold 	Exception()
179*402d77f6SIngo Weinhold 		: fError(errno),
180*402d77f6SIngo Weinhold 		  fDescription()
181*402d77f6SIngo Weinhold 	{
182*402d77f6SIngo Weinhold 	}
183*402d77f6SIngo Weinhold 
184*402d77f6SIngo Weinhold 	// constructor
185*402d77f6SIngo Weinhold 	Exception(const char* format,...)
186*402d77f6SIngo Weinhold 		: fError(errno),
187*402d77f6SIngo Weinhold 		  fDescription()
188*402d77f6SIngo Weinhold 	{
189*402d77f6SIngo Weinhold 		va_list args;
190*402d77f6SIngo Weinhold 		va_start(args, format);
191*402d77f6SIngo Weinhold 		SetTo(errno, format, args);
192*402d77f6SIngo Weinhold 		va_end(args);
193*402d77f6SIngo Weinhold 	}
194*402d77f6SIngo Weinhold 
195*402d77f6SIngo Weinhold 	// constructor
196*402d77f6SIngo Weinhold 	Exception(int error)
197*402d77f6SIngo Weinhold 		: fError(error),
198*402d77f6SIngo Weinhold 		  fDescription()
199*402d77f6SIngo Weinhold 	{
200*402d77f6SIngo Weinhold 	}
201*402d77f6SIngo Weinhold 
202*402d77f6SIngo Weinhold 	// constructor
203*402d77f6SIngo Weinhold 	Exception(int error, const char* format,...)
204*402d77f6SIngo Weinhold 		: fError(error),
205*402d77f6SIngo Weinhold 		  fDescription()
206*402d77f6SIngo Weinhold 	{
207*402d77f6SIngo Weinhold 		va_list args;
208*402d77f6SIngo Weinhold 		va_start(args, format);
209*402d77f6SIngo Weinhold 		SetTo(error, format, args);
210*402d77f6SIngo Weinhold 		va_end(args);
211*402d77f6SIngo Weinhold 	}
212*402d77f6SIngo Weinhold 
213*402d77f6SIngo Weinhold 	// copy constructor
214*402d77f6SIngo Weinhold 	Exception(const Exception& exception)
215*402d77f6SIngo Weinhold 		: fError(exception.fError),
216*402d77f6SIngo Weinhold 		  fDescription(exception.fDescription)
217*402d77f6SIngo Weinhold 	{
218*402d77f6SIngo Weinhold 	}
219*402d77f6SIngo Weinhold 
220*402d77f6SIngo Weinhold 	// destructor
221*402d77f6SIngo Weinhold 	~Exception()
222*402d77f6SIngo Weinhold 	{
223*402d77f6SIngo Weinhold 	}
224*402d77f6SIngo Weinhold 
225*402d77f6SIngo Weinhold 	// SetTo
226*402d77f6SIngo Weinhold 	void SetTo(int error, const char* format, va_list arg)
227*402d77f6SIngo Weinhold 	{
228*402d77f6SIngo Weinhold 		char buffer[2048];
229*402d77f6SIngo Weinhold 		vsprintf(buffer, format, arg);
230*402d77f6SIngo Weinhold 		fError = error;
231*402d77f6SIngo Weinhold 		fDescription = buffer;
232*402d77f6SIngo Weinhold 	}
233*402d77f6SIngo Weinhold 
234*402d77f6SIngo Weinhold 	// Error
235*402d77f6SIngo Weinhold 	int Error() const
236*402d77f6SIngo Weinhold 	{
237*402d77f6SIngo Weinhold 		return fError;
238*402d77f6SIngo Weinhold 	}
239*402d77f6SIngo Weinhold 
240*402d77f6SIngo Weinhold 	// Description
241*402d77f6SIngo Weinhold 	const string& Description() const
242*402d77f6SIngo Weinhold 	{
243*402d77f6SIngo Weinhold 		return fDescription;
244*402d77f6SIngo Weinhold 	}
245*402d77f6SIngo Weinhold 
246*402d77f6SIngo Weinhold private:
247*402d77f6SIngo Weinhold 	int		fError;
248*402d77f6SIngo Weinhold 	string	fDescription;
249*402d77f6SIngo Weinhold };
250*402d77f6SIngo Weinhold 
251*402d77f6SIngo Weinhold 
252*402d77f6SIngo Weinhold // #pragma mark - ELFObject
253*402d77f6SIngo Weinhold 
254*402d77f6SIngo Weinhold 
255*402d77f6SIngo Weinhold struct SectionInfo {
256*402d77f6SIngo Weinhold 	uint32_t	type;
257*402d77f6SIngo Weinhold 	uint32_t	offset;
258*402d77f6SIngo Weinhold 	uint32_t	size;
259*402d77f6SIngo Weinhold 	const char*	name;
260*402d77f6SIngo Weinhold };
261*402d77f6SIngo Weinhold 
262*402d77f6SIngo Weinhold 
263*402d77f6SIngo Weinhold class ELFObject {
264*402d77f6SIngo Weinhold public:
265*402d77f6SIngo Weinhold 	ELFObject()
266*402d77f6SIngo Weinhold 		: fFD(-1),
267*402d77f6SIngo Weinhold 		  fSectionHeaderStrings(NULL),
268*402d77f6SIngo Weinhold 		  fSectionHeaderStringsLength(0)
269*402d77f6SIngo Weinhold 	{
270*402d77f6SIngo Weinhold 	}
271*402d77f6SIngo Weinhold 
272*402d77f6SIngo Weinhold 	~ELFObject()
273*402d77f6SIngo Weinhold 	{
274*402d77f6SIngo Weinhold 		Unset();
275*402d77f6SIngo Weinhold 	}
276*402d77f6SIngo Weinhold 
277*402d77f6SIngo Weinhold 	void Unset()
278*402d77f6SIngo Weinhold 	{
279*402d77f6SIngo Weinhold 		if (fFD >= 0) {
280*402d77f6SIngo Weinhold 			close(fFD);
281*402d77f6SIngo Weinhold 			fFD = -1;
282*402d77f6SIngo Weinhold 		}
283*402d77f6SIngo Weinhold 
284*402d77f6SIngo Weinhold 		delete[] fSectionHeaderStrings;
285*402d77f6SIngo Weinhold 		fSectionHeaderStrings = NULL;
286*402d77f6SIngo Weinhold 	}
287*402d77f6SIngo Weinhold 
288*402d77f6SIngo Weinhold 	void SetTo(const char* fileName)
289*402d77f6SIngo Weinhold 	{
290*402d77f6SIngo Weinhold 		Unset();
291*402d77f6SIngo Weinhold 
292*402d77f6SIngo Weinhold 		// open the file
293*402d77f6SIngo Weinhold 		fFD = open(fileName, O_RDWR);
294*402d77f6SIngo Weinhold 		if (fFD < 0)
295*402d77f6SIngo Weinhold 			throw Exception("Failed to open \"%s\"", fileName);
296*402d77f6SIngo Weinhold 
297*402d77f6SIngo Weinhold 		// get the file size
298*402d77f6SIngo Weinhold 		fFileSize = FileSize();
299*402d77f6SIngo Weinhold 		if (fFileSize < 0)
300*402d77f6SIngo Weinhold 			throw Exception("Failed to get the file size.");
301*402d77f6SIngo Weinhold 
302*402d77f6SIngo Weinhold 		// read ELF header
303*402d77f6SIngo Weinhold 		Elf32_Ehdr fileHeader;
304*402d77f6SIngo Weinhold 		Read(0, &fileHeader, sizeof(Elf32_Ehdr), "Failed to read ELF header.");
305*402d77f6SIngo Weinhold 
306*402d77f6SIngo Weinhold 		// check data encoding (endianess)
307*402d77f6SIngo Weinhold 		switch (fileHeader.e_ident[EI_DATA]) {
308*402d77f6SIngo Weinhold 			case ELFDATA2LSB:
309*402d77f6SIngo Weinhold 				fHostEndianess = (htonl(1) != 1);
310*402d77f6SIngo Weinhold 				break;
311*402d77f6SIngo Weinhold 			case ELFDATA2MSB:
312*402d77f6SIngo Weinhold 				fHostEndianess = (htonl(1) == 1);
313*402d77f6SIngo Weinhold 				break;
314*402d77f6SIngo Weinhold 			default:
315*402d77f6SIngo Weinhold 			case ELFDATANONE:
316*402d77f6SIngo Weinhold 				throw Exception(EIO, "Unsupported ELF data encoding.");
317*402d77f6SIngo Weinhold 				break;
318*402d77f6SIngo Weinhold 		}
319*402d77f6SIngo Weinhold 
320*402d77f6SIngo Weinhold 		// get the header values
321*402d77f6SIngo Weinhold 		fELFHeaderSize	= GetUInt16(fileHeader.e_ehsize);
322*402d77f6SIngo Weinhold 		fSectionHeaderTableOffset = GetUInt32(fileHeader.e_shoff);
323*402d77f6SIngo Weinhold 		fSectionHeaderSize	= GetUInt16(fileHeader.e_shentsize);
324*402d77f6SIngo Weinhold 		fSectionHeaderCount = GetUInt16(fileHeader.e_shnum);
325*402d77f6SIngo Weinhold 		bool hasSectionHeaderTable = (fSectionHeaderTableOffset != 0);
326*402d77f6SIngo Weinhold 
327*402d77f6SIngo Weinhold 		// check the sanity of the header values
328*402d77f6SIngo Weinhold 		// ELF header size
329*402d77f6SIngo Weinhold 		if (fELFHeaderSize < sizeof(Elf32_Ehdr) || fELFHeaderSize > kMaxELFHeaderSize) {
330*402d77f6SIngo Weinhold 			throw Exception(EIO,
331*402d77f6SIngo Weinhold 				"Invalid ELF header: invalid ELF header size: %lu.",
332*402d77f6SIngo Weinhold 				fELFHeaderSize);
333*402d77f6SIngo Weinhold 		}
334*402d77f6SIngo Weinhold 
335*402d77f6SIngo Weinhold 		// section header table offset and entry count/size
336*402d77f6SIngo Weinhold 		uint32_t sectionHeaderTableSize = 0;
337*402d77f6SIngo Weinhold 		if (hasSectionHeaderTable) {
338*402d77f6SIngo Weinhold 			if (fSectionHeaderTableOffset < fELFHeaderSize
339*402d77f6SIngo Weinhold 				|| fSectionHeaderTableOffset > fFileSize) {
340*402d77f6SIngo Weinhold 				throw Exception(EIO, "Invalid ELF header: invalid section "
341*402d77f6SIngo Weinhold 								"header table offset: %lu.",
342*402d77f6SIngo Weinhold 								fSectionHeaderTableOffset);
343*402d77f6SIngo Weinhold 			}
344*402d77f6SIngo Weinhold 			sectionHeaderTableSize = fSectionHeaderSize * fSectionHeaderCount;
345*402d77f6SIngo Weinhold 			if (fSectionHeaderSize < sizeof(Elf32_Shdr)
346*402d77f6SIngo Weinhold 				|| fSectionHeaderTableOffset + sectionHeaderTableSize
347*402d77f6SIngo Weinhold 						> fFileSize) {
348*402d77f6SIngo Weinhold 				throw Exception(EIO, "Invalid ELF header: section header "
349*402d77f6SIngo Weinhold 								"table exceeds file: %lu.",
350*402d77f6SIngo Weinhold 								fSectionHeaderTableOffset
351*402d77f6SIngo Weinhold 									+ sectionHeaderTableSize);
352*402d77f6SIngo Weinhold 			}
353*402d77f6SIngo Weinhold 
354*402d77f6SIngo Weinhold 
355*402d77f6SIngo Weinhold 			// load section header string section
356*402d77f6SIngo Weinhold 			uint16_t sectionHeaderStringSectionIndex
357*402d77f6SIngo Weinhold 				= GetUInt16(fileHeader.e_shstrndx);
358*402d77f6SIngo Weinhold 			if (sectionHeaderStringSectionIndex != SHN_UNDEF) {
359*402d77f6SIngo Weinhold 				if (sectionHeaderStringSectionIndex >= fSectionHeaderCount) {
360*402d77f6SIngo Weinhold 					throw Exception(EIO, "Invalid ELF header: invalid section "
361*402d77f6SIngo Weinhold 									"header string section index: %lu.",
362*402d77f6SIngo Weinhold 									sectionHeaderStringSectionIndex);
363*402d77f6SIngo Weinhold 				}
364*402d77f6SIngo Weinhold 
365*402d77f6SIngo Weinhold 				// get the section info
366*402d77f6SIngo Weinhold 				SectionInfo info;
367*402d77f6SIngo Weinhold 				if (_ReadSectionHeader(sectionHeaderStringSectionIndex,
368*402d77f6SIngo Weinhold 						info)) {
369*402d77f6SIngo Weinhold 					fSectionHeaderStrings = new char[info.size + 1];
370*402d77f6SIngo Weinhold 					Read(info.offset, fSectionHeaderStrings, info.size,
371*402d77f6SIngo Weinhold 						"Failed to read section header string section.");
372*402d77f6SIngo Weinhold 					fSectionHeaderStringsLength = info.size;
373*402d77f6SIngo Weinhold 					// null-terminate to be on the safe side
374*402d77f6SIngo Weinhold 					fSectionHeaderStrings[info.size] = '\0';
375*402d77f6SIngo Weinhold 				}
376*402d77f6SIngo Weinhold 			}
377*402d77f6SIngo Weinhold 		}
378*402d77f6SIngo Weinhold 	}
379*402d77f6SIngo Weinhold 
380*402d77f6SIngo Weinhold 	bool FindSectionByName(const char* name, SectionInfo& foundInfo)
381*402d77f6SIngo Weinhold 	{
382*402d77f6SIngo Weinhold 		// can't find the section by name without section names
383*402d77f6SIngo Weinhold 		if (!fSectionHeaderStrings)
384*402d77f6SIngo Weinhold 			return false;
385*402d77f6SIngo Weinhold 
386*402d77f6SIngo Weinhold 		// iterate through the section headers
387*402d77f6SIngo Weinhold 		for (int32_t i = 0; i < (int32_t)fSectionHeaderCount; i++) {
388*402d77f6SIngo Weinhold 			SectionInfo info;
389*402d77f6SIngo Weinhold 			if (_ReadSectionHeader(i, info)) {
390*402d77f6SIngo Weinhold //printf("section %3d: offset: %7d, size: %7d, name: %s\n", i, info.offset, info.size, info.name);
391*402d77f6SIngo Weinhold 				if (strcmp(info.name, name) == 0) {
392*402d77f6SIngo Weinhold 					foundInfo = info;
393*402d77f6SIngo Weinhold 					return true;
394*402d77f6SIngo Weinhold 				}
395*402d77f6SIngo Weinhold 			}
396*402d77f6SIngo Weinhold 		}
397*402d77f6SIngo Weinhold 
398*402d77f6SIngo Weinhold 		return false;
399*402d77f6SIngo Weinhold 	}
400*402d77f6SIngo Weinhold 
401*402d77f6SIngo Weinhold 	void Read(off_t position, void* buffer, size_t size,
402*402d77f6SIngo Weinhold 		const char *errorMessage = NULL)
403*402d77f6SIngo Weinhold 	{
404*402d77f6SIngo Weinhold 		if (lseek(fFD, position, SEEK_SET) < 0)
405*402d77f6SIngo Weinhold 			throw Exception(errorMessage);
406*402d77f6SIngo Weinhold 
407*402d77f6SIngo Weinhold 		ssize_t bytesRead = read(fFD, buffer, size);
408*402d77f6SIngo Weinhold 		if (bytesRead < 0)
409*402d77f6SIngo Weinhold 			throw Exception(errorMessage);
410*402d77f6SIngo Weinhold 
411*402d77f6SIngo Weinhold 		if ((size_t)bytesRead != size) {
412*402d77f6SIngo Weinhold 			if (errorMessage) {
413*402d77f6SIngo Weinhold 				throw Exception("%s Read too few bytes (%d/%d).",
414*402d77f6SIngo Weinhold 					errorMessage, (int)bytesRead, (int)size);
415*402d77f6SIngo Weinhold 			} else {
416*402d77f6SIngo Weinhold 				throw Exception("Read too few bytes (%ld/%lu).",
417*402d77f6SIngo Weinhold 					(int)bytesRead, (int)size);
418*402d77f6SIngo Weinhold 			}
419*402d77f6SIngo Weinhold 		}
420*402d77f6SIngo Weinhold 	}
421*402d77f6SIngo Weinhold 
422*402d77f6SIngo Weinhold 	void Write(off_t position, const void* buffer, size_t size,
423*402d77f6SIngo Weinhold 		const char *errorMessage = NULL)
424*402d77f6SIngo Weinhold 	{
425*402d77f6SIngo Weinhold 		if (lseek(fFD, position, SEEK_SET) < 0)
426*402d77f6SIngo Weinhold 			throw Exception(errorMessage);
427*402d77f6SIngo Weinhold 
428*402d77f6SIngo Weinhold 		ssize_t bytesWritten = write(fFD, buffer, size);
429*402d77f6SIngo Weinhold 		if (bytesWritten < 0)
430*402d77f6SIngo Weinhold 			throw Exception(errorMessage);
431*402d77f6SIngo Weinhold 
432*402d77f6SIngo Weinhold 		if ((size_t)bytesWritten != size) {
433*402d77f6SIngo Weinhold 			if (errorMessage) {
434*402d77f6SIngo Weinhold 				throw Exception("%s Wrote too few bytes (%d/%d).",
435*402d77f6SIngo Weinhold 					errorMessage, (int)bytesWritten, (int)size);
436*402d77f6SIngo Weinhold 			} else {
437*402d77f6SIngo Weinhold 				throw Exception("Wrote too few bytes (%ld/%lu).",
438*402d77f6SIngo Weinhold 					(int)bytesWritten, (int)size);
439*402d77f6SIngo Weinhold 			}
440*402d77f6SIngo Weinhold 		}
441*402d77f6SIngo Weinhold 	}
442*402d77f6SIngo Weinhold 
443*402d77f6SIngo Weinhold 	off_t FileSize()
444*402d77f6SIngo Weinhold 	{
445*402d77f6SIngo Weinhold 		off_t currentPos = lseek(fFD, 0, SEEK_END);
446*402d77f6SIngo Weinhold 		if (currentPos < 0)
447*402d77f6SIngo Weinhold 			return -1;
448*402d77f6SIngo Weinhold 
449*402d77f6SIngo Weinhold 		return lseek(fFD, currentPos, SEEK_SET);
450*402d77f6SIngo Weinhold 	}
451*402d77f6SIngo Weinhold 
452*402d77f6SIngo Weinhold 	// GetInt16
453*402d77f6SIngo Weinhold 	int16_t GetInt16(int16_t value)
454*402d77f6SIngo Weinhold 	{
455*402d77f6SIngo Weinhold 		return (fHostEndianess ? value : _SwapUInt16(value));
456*402d77f6SIngo Weinhold 	}
457*402d77f6SIngo Weinhold 
458*402d77f6SIngo Weinhold 	// GetUInt16
459*402d77f6SIngo Weinhold 	uint16_t GetUInt16(uint16_t value)
460*402d77f6SIngo Weinhold 	{
461*402d77f6SIngo Weinhold 		return (fHostEndianess ? value : _SwapUInt16(value));
462*402d77f6SIngo Weinhold 	}
463*402d77f6SIngo Weinhold 
464*402d77f6SIngo Weinhold 	// GetInt32
465*402d77f6SIngo Weinhold 	int32_t GetInt32(int32_t value)
466*402d77f6SIngo Weinhold 	{
467*402d77f6SIngo Weinhold 		return (fHostEndianess ? value : _SwapUInt32(value));
468*402d77f6SIngo Weinhold 	}
469*402d77f6SIngo Weinhold 
470*402d77f6SIngo Weinhold 	// GetUInt32
471*402d77f6SIngo Weinhold 	uint32_t GetUInt32(uint32_t value)
472*402d77f6SIngo Weinhold 	{
473*402d77f6SIngo Weinhold 		return (fHostEndianess ? value : _SwapUInt32(value));
474*402d77f6SIngo Weinhold 	}
475*402d77f6SIngo Weinhold 
476*402d77f6SIngo Weinhold private:
477*402d77f6SIngo Weinhold 	bool _ReadSectionHeader(int index, SectionInfo& info)
478*402d77f6SIngo Weinhold 	{
479*402d77f6SIngo Weinhold 		uint32_t shOffset = fSectionHeaderTableOffset
480*402d77f6SIngo Weinhold 			+ index * fSectionHeaderSize;
481*402d77f6SIngo Weinhold 		Elf32_Shdr sectionHeader;
482*402d77f6SIngo Weinhold 		Read(shOffset, &sectionHeader, sizeof(Elf32_Shdr),
483*402d77f6SIngo Weinhold 			"Failed to read ELF section header.");
484*402d77f6SIngo Weinhold 
485*402d77f6SIngo Weinhold 		// get the header values
486*402d77f6SIngo Weinhold 		uint32_t type		= GetUInt32(sectionHeader.sh_type);
487*402d77f6SIngo Weinhold 		uint32_t offset		= GetUInt32(sectionHeader.sh_offset);
488*402d77f6SIngo Weinhold 		uint32_t size		= GetUInt32(sectionHeader.sh_size);
489*402d77f6SIngo Weinhold 		uint32_t nameIndex	= GetUInt32(sectionHeader.sh_name);
490*402d77f6SIngo Weinhold 
491*402d77f6SIngo Weinhold 		// check the values
492*402d77f6SIngo Weinhold 		// SHT_NULL marks the header unused,
493*402d77f6SIngo Weinhold 		if (type == SHT_NULL)
494*402d77f6SIngo Weinhold 			return false;
495*402d77f6SIngo Weinhold 
496*402d77f6SIngo Weinhold 		// SHT_NOBITS sections take no space in the file
497*402d77f6SIngo Weinhold 		if (type != SHT_NOBITS) {
498*402d77f6SIngo Weinhold 			if (offset < fELFHeaderSize || offset > fFileSize) {
499*402d77f6SIngo Weinhold 				throw Exception(EIO, "Invalid ELF section header: "
500*402d77f6SIngo Weinhold 								"invalid section offset: %lu.", offset);
501*402d77f6SIngo Weinhold 			}
502*402d77f6SIngo Weinhold 			uint32_t sectionEnd = offset + size;
503*402d77f6SIngo Weinhold 			if (sectionEnd > fFileSize) {
504*402d77f6SIngo Weinhold 				throw Exception(EIO, "Invalid ELF section header: "
505*402d77f6SIngo Weinhold 								"section exceeds file: %lu.", sectionEnd);
506*402d77f6SIngo Weinhold 			}
507*402d77f6SIngo Weinhold 		}
508*402d77f6SIngo Weinhold 
509*402d77f6SIngo Weinhold 		// get name, if we have a string section
510*402d77f6SIngo Weinhold 		if (fSectionHeaderStrings) {
511*402d77f6SIngo Weinhold 			if (nameIndex >= (uint32_t)fSectionHeaderStringsLength) {
512*402d77f6SIngo Weinhold 				throw Exception(EIO, "Invalid ELF section header: "
513*402d77f6SIngo Weinhold 								"invalid name index: %lu.", nameIndex);
514*402d77f6SIngo Weinhold 			}
515*402d77f6SIngo Weinhold 			info.name = fSectionHeaderStrings + nameIndex;
516*402d77f6SIngo Weinhold 		} else {
517*402d77f6SIngo Weinhold 			info.name = "";
518*402d77f6SIngo Weinhold 		}
519*402d77f6SIngo Weinhold 
520*402d77f6SIngo Weinhold 		info.type = type;
521*402d77f6SIngo Weinhold 		info.offset = offset;
522*402d77f6SIngo Weinhold 		info.size = size;
523*402d77f6SIngo Weinhold 
524*402d77f6SIngo Weinhold 
525*402d77f6SIngo Weinhold 		return true;
526*402d77f6SIngo Weinhold 	}
527*402d77f6SIngo Weinhold 
528*402d77f6SIngo Weinhold 	// _SwapUInt16
529*402d77f6SIngo Weinhold 	static inline uint16_t _SwapUInt16(uint16_t value)
530*402d77f6SIngo Weinhold 	{
531*402d77f6SIngo Weinhold 		return ((value & 0xff) << 8) | (value >> 8);
532*402d77f6SIngo Weinhold 	}
533*402d77f6SIngo Weinhold 
534*402d77f6SIngo Weinhold 	// _SwapUInt32
535*402d77f6SIngo Weinhold 	static inline uint32_t _SwapUInt32(uint32_t value)
536*402d77f6SIngo Weinhold 	{
537*402d77f6SIngo Weinhold 		return ((uint32_t)_SwapUInt16(value & 0xffff) << 16)
538*402d77f6SIngo Weinhold 			| _SwapUInt16(uint16_t(value >> 16));
539*402d77f6SIngo Weinhold 	}
540*402d77f6SIngo Weinhold 
541*402d77f6SIngo Weinhold private:
542*402d77f6SIngo Weinhold 	int			fFD;
543*402d77f6SIngo Weinhold 	bool		fHostEndianess;
544*402d77f6SIngo Weinhold 	off_t		fFileSize;
545*402d77f6SIngo Weinhold 	uint32_t	fELFHeaderSize;
546*402d77f6SIngo Weinhold 	uint32_t	fSectionHeaderTableOffset;
547*402d77f6SIngo Weinhold 	uint32_t	fSectionHeaderSize;
548*402d77f6SIngo Weinhold 	uint32_t	fSectionHeaderCount;
549*402d77f6SIngo Weinhold 	char*		fSectionHeaderStrings;
550*402d77f6SIngo Weinhold 	int			fSectionHeaderStringsLength;
551*402d77f6SIngo Weinhold };
552*402d77f6SIngo Weinhold 
553*402d77f6SIngo Weinhold 
554*402d77f6SIngo Weinhold // main
555*402d77f6SIngo Weinhold int
556*402d77f6SIngo Weinhold main(int argc, const char* const* argv)
557*402d77f6SIngo Weinhold {
558*402d77f6SIngo Weinhold 	sArgc = argc;
559*402d77f6SIngo Weinhold 	sArgv = argv;
560*402d77f6SIngo Weinhold 
561*402d77f6SIngo Weinhold 	if (argc < 3)
562*402d77f6SIngo Weinhold 		print_usage_and_exit(true);
563*402d77f6SIngo Weinhold 
564*402d77f6SIngo Weinhold 	// parameters
565*402d77f6SIngo Weinhold 	const char* fileName = argv[1];
566*402d77f6SIngo Weinhold 	const char* revisionString = argv[2];
567*402d77f6SIngo Weinhold 	uint32_t revision = atol(revisionString);
568*402d77f6SIngo Weinhold 
569*402d77f6SIngo Weinhold 	try {
570*402d77f6SIngo Weinhold 		ELFObject elfObject;
571*402d77f6SIngo Weinhold 		elfObject.SetTo(fileName);
572*402d77f6SIngo Weinhold 
573*402d77f6SIngo Weinhold 		// find haiku revision section
574*402d77f6SIngo Weinhold 		SectionInfo info;
575*402d77f6SIngo Weinhold 		if (!elfObject.FindSectionByName("_haiku_revision", info)) {
576*402d77f6SIngo Weinhold 			fprintf(stderr, "haiku revision section not found\n");
577*402d77f6SIngo Weinhold 			exit(1);
578*402d77f6SIngo Weinhold 		}
579*402d77f6SIngo Weinhold 
580*402d77f6SIngo Weinhold 		// convert revision number to object endianess and write to section
581*402d77f6SIngo Weinhold 		uint32_t revisionBuffer = elfObject.GetUInt32(revision);
582*402d77f6SIngo Weinhold 		elfObject.Write(info.offset, &revisionBuffer, sizeof(revisionBuffer),
583*402d77f6SIngo Weinhold 			"Failed to write revision.");
584*402d77f6SIngo Weinhold 
585*402d77f6SIngo Weinhold 	} catch (Exception exception) {
586*402d77f6SIngo Weinhold 		if (exception.Description() == "") {
587*402d77f6SIngo Weinhold 			fprintf(stderr, "%s\n", strerror(exception.Error()));
588*402d77f6SIngo Weinhold 		} else {
589*402d77f6SIngo Weinhold 			fprintf(stderr, "%s: %s\n", exception.Description().c_str(),
590*402d77f6SIngo Weinhold 				strerror(exception.Error()));
591*402d77f6SIngo Weinhold 		}
592*402d77f6SIngo Weinhold 		exit(1);
593*402d77f6SIngo Weinhold 	}
594*402d77f6SIngo Weinhold 
595*402d77f6SIngo Weinhold 	return 0;
596*402d77f6SIngo Weinhold }
597