1//------------------------------------------------------------------------------
2//	Copyright (c) 2003, Ingo Weinhold
3//
4//	Permission is hereby granted, free of charge, to any person obtaining a
5//	copy of this software and associated documentation files (the "Software"),
6//	to deal in the Software without restriction, including without limitation
7//	the rights to use, copy, modify, merge, publish, distribute, sublicense,
8//	and/or sell copies of the Software, and to permit persons to whom the
9//	Software is furnished to do so, subject to the following conditions:
10//
11//	The above copyright notice and this permission notice shall be included in
12//	all copies or substantial portions of the Software.
13//
14//	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15//	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16//	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17//	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18//	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19//	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20//	DEALINGS IN THE SOFTWARE.
21//
22//	File Name:		ElfSymbolPatcher.cpp
23//	Author:			Ingo Weinhold (bonefish@users.sf.net)
24//	Description:	Interface declaration of classes used for patching ELF
25//					symbols. Central class is ElfSymbolPatcher. It is a kind of
26//					roster, managing all necessary infos (loaded images) and
27//					being able to fill ElfSymbolPatchInfos with life.
28//					An ElfSymbolPatchInfo represents a symbol and is able to
29//					patch/restore it. An ElfSymbolPatchGroup bundles several
30//					ElfSymbolPatchInfos and can update their data, e.g.
31//					when images are loaded/unloaded. It uses a
32//					ElfSymbolPatcher internally and provides a more convenient
33//					API for the user.
34//------------------------------------------------------------------------------
35
36#include <new>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40
41#include "ElfImage.h"
42#include "ElfSymbolPatcher.h"
43
44/////////////////////////////
45// ElfSymbolPatchInfo::Entry
46//
47
48class ElfSymbolPatchInfo::Entry {
49public:
50	static	Entry*				Create(image_id image, void*** targets,
51									   int32 targetCount);
52			void				Delete();
53
54			image_id			GetImage() const	{ return fImage; }
55
56			void				Patch(void* newAddress);
57
58private:
59								Entry();
60								Entry(const Entry&);
61								Entry(image_id image, void*** targets,
62									  int32 targetCount);
63								~Entry();
64
65private:
66			image_id			fImage;
67			int32				fPatchTargetCount;
68			void**				fPatchTargets[1];
69};
70
71// Create
72ElfSymbolPatchInfo::Entry*
73ElfSymbolPatchInfo::Entry::Create(image_id image, void*** targets,
74								  int32 targetCount)
75{
76	if (!targets || targetCount <= 0)
77		return NULL;
78	void* buffer = malloc(sizeof(Entry) + sizeof(void**) * (targetCount - 1));
79	Entry* entry = NULL;
80	if (buffer)
81		entry = new(buffer) Entry(image, targets, targetCount);
82	return entry;
83}
84
85// Delete
86void
87ElfSymbolPatchInfo::Entry::Delete()
88{
89	this->~Entry();
90	free(this);
91}
92
93// Patch
94void
95ElfSymbolPatchInfo::Entry::Patch(void* newAddress)
96{
97//printf("ElfSymbolPatchInfo::Entry::Patch(): patching %ld addresses\n",
98//fPatchTargetCount);
99	for (int i = 0; i < fPatchTargetCount; i++)
100		*fPatchTargets[i] = newAddress;
101}
102
103// constructor
104ElfSymbolPatchInfo::Entry::Entry(image_id image, void*** targets,
105								 int32 targetCount)
106	: fImage(image),
107	  fPatchTargetCount(targetCount)
108{
109	memcpy(fPatchTargets + 0, targets, targetCount * sizeof(void**));
110}
111
112// destructor
113ElfSymbolPatchInfo::Entry::~Entry()
114{
115}
116
117
118//////////////////////
119// ElfSymbolPatchInfo
120//
121
122// constructor
123ElfSymbolPatchInfo::ElfSymbolPatchInfo()
124	: fSymbolName(),
125	  fOriginalAddress(NULL),
126	  fOriginalAddressImage(-1),
127	  fEntries()
128{
129}
130
131// destructor
132ElfSymbolPatchInfo::~ElfSymbolPatchInfo()
133{
134	Unset();
135}
136
137// InitCheck
138status_t
139ElfSymbolPatchInfo::InitCheck() const
140{
141	return (fOriginalAddress && fSymbolName.Length() ? B_OK : B_NO_INIT);
142}
143
144// GetSymbolName
145const char*
146ElfSymbolPatchInfo::GetSymbolName() const
147{
148	return fSymbolName.String();
149}
150
151// GetOriginalAddress
152void*
153ElfSymbolPatchInfo::GetOriginalAddress() const
154{
155	return fOriginalAddress;
156}
157
158// GetOriginalAddressImage
159image_id
160ElfSymbolPatchInfo::GetOriginalAddressImage() const
161{
162	return fOriginalAddressImage;
163}
164
165// Patch
166status_t
167ElfSymbolPatchInfo::Patch(void* newAddress)
168{
169//printf("ElfSymbolPatchInfo::Patch(): patching %ld images\n",
170//fEntries.CountItems());
171	status_t error = InitCheck();
172	if (error == B_OK) {
173		for (int i = 0; Entry* entry = EntryAt(i); i++)
174			entry->Patch(newAddress);
175	}
176	return error;
177}
178
179// Restore
180status_t
181ElfSymbolPatchInfo::Restore()
182{
183	return Patch(fOriginalAddress);
184}
185
186// Unset
187void
188ElfSymbolPatchInfo::Unset()
189{
190	for (int i = 0; Entry* entry = EntryAt(i); i++)
191		entry->Delete();
192	fEntries.MakeEmpty();
193	fSymbolName.SetTo("");
194	fOriginalAddress = NULL;
195	fOriginalAddressImage = -1;
196}
197
198// SetSymbolName
199status_t
200ElfSymbolPatchInfo::SetSymbolName(const char* name)
201{
202	fSymbolName.SetTo(name);
203	if (name && fSymbolName != name)
204		return B_NO_MEMORY;
205	return B_OK;
206}
207
208// SetOriginalAddress
209void
210ElfSymbolPatchInfo::SetOriginalAddress(void* address, image_id image)
211{
212	fOriginalAddress = address;
213	fOriginalAddressImage = image;
214}
215
216// CreateEntry
217status_t
218ElfSymbolPatchInfo::CreateEntry(image_id image, BList* targets)
219{
220	if (!targets || targets->CountItems() == 0)
221		return B_BAD_VALUE;
222	Entry* entry = Entry::Create(image, (void***)targets->Items(),
223								 targets->CountItems());
224	if (!entry)
225		return B_NO_MEMORY;
226	if (!fEntries.AddItem(entry)) {
227		entry->Delete();
228		return B_NO_MEMORY;
229	}
230	return B_OK;
231}
232
233// DeleteEntry
234bool
235ElfSymbolPatchInfo::DeleteEntry(image_id image)
236{
237	for (int i = 0; Entry* entry = EntryAt(i); i++) {
238		if (entry->GetImage() == image) {
239			fEntries.RemoveItem(i);
240			entry->Delete();
241			return true;
242		}
243	}
244	return false;
245}
246
247// EntryAt
248ElfSymbolPatchInfo::Entry*
249ElfSymbolPatchInfo::EntryAt(int32 index)
250{
251	return (Entry*)fEntries.ItemAt(index);
252}
253
254// EntryFor
255ElfSymbolPatchInfo::Entry*
256ElfSymbolPatchInfo::EntryFor(image_id image)
257{
258	for (int i = 0; Entry* entry = EntryAt(i); i++) {
259		if (entry->GetImage() == image)
260			return entry;
261	}
262	return NULL;
263}
264
265
266/////////////////
267// UpdateAdapter
268//
269
270// constructor
271ElfSymbolPatcher::UpdateAdapter::UpdateAdapter()
272{
273}
274
275// destructor
276ElfSymbolPatcher::UpdateAdapter::~UpdateAdapter()
277{
278}
279
280// ImageAdded
281void
282ElfSymbolPatcher::UpdateAdapter::ImageAdded(ElfImage* image)
283{
284}
285
286// ImageRemoved
287void
288ElfSymbolPatcher::UpdateAdapter::ImageRemoved(ElfImage* image)
289{
290}
291
292
293////////////////////
294// ElfSymbolPatcher
295//
296
297// constructor
298ElfSymbolPatcher::ElfSymbolPatcher()
299	: fImages(),
300	  fInitStatus(B_NO_INIT)
301{
302	fInitStatus = _Init();
303	if (fInitStatus != B_OK)
304		_Cleanup();
305}
306
307// destructor
308ElfSymbolPatcher::~ElfSymbolPatcher()
309{
310	_Cleanup();
311}
312
313// InitCheck
314status_t
315ElfSymbolPatcher::InitCheck() const
316{
317	return fInitStatus;
318}
319
320// Update
321status_t
322ElfSymbolPatcher::Update(UpdateAdapter* updateAdapter)
323{
324	if (InitCheck() != B_OK)
325		return B_NO_INIT;
326	// remove obsolete images
327	int32 count = fImages.CountItems();
328	for (int i = count - 1; i >= 0; i--) {
329		ElfImage* image = _ImageAt(i);
330		image_info info;
331		if (get_image_info(image->GetID(), &info) != B_OK) {
332			if (updateAdapter)
333				updateAdapter->ImageRemoved(image);
334			fImages.RemoveItem(i);
335			delete image;
336		}
337	}
338	// add new images
339	status_t error = B_OK;
340	image_info info;
341	int32 cookie = 0;
342	while (get_next_image_info(0, &cookie, &info) == B_OK) {
343		ElfImage* image = _ImageForID(info.id);
344		if (image)
345			continue;
346		image = new(std::nothrow) ElfImage;
347		if (!image)
348			return B_NO_MEMORY;
349		if (!fImages.AddItem(image)) {
350			delete image;
351			return B_NO_MEMORY;
352		}
353		error = image->SetTo(info.id);
354		if (updateAdapter)
355			updateAdapter->ImageAdded(image);
356	}
357	return error;
358}
359
360// Unload
361void
362ElfSymbolPatcher::Unload()
363{
364	for (int i = 0; ElfImage* image = _ImageAt(i); i++)
365		image->Unload();
366}
367
368// GetSymbolPatchInfo
369status_t
370ElfSymbolPatcher::GetSymbolPatchInfo(const char* symbolName,
371									 ElfSymbolPatchInfo* info)
372{
373	// check parameters and intialization
374	if (!symbolName || !info)
375		return B_BAD_VALUE;
376	if (InitCheck() != B_OK)
377		return B_NO_INIT;
378	// set the symbol name
379	info->Unset();
380	status_t error = info->SetSymbolName(symbolName);
381	if (error != B_OK)
382		return error;
383	for (int i = 0; ElfImage* image = _ImageAt(i); i++) {
384//printf("searching in image: %ld\n", image->GetID());
385		// get the symbol's relocations
386		BList patchTargets;
387		error = image->GetSymbolRelocations(symbolName, &patchTargets);
388		if (error != B_OK)
389			break;
390		if (patchTargets.CountItems() > 0) {
391			error = info->CreateEntry(image->GetID(), &patchTargets);
392			if (error != B_OK)
393				break;
394		}
395		// get the symbol's address
396		void* address = NULL;
397		if (image->FindSymbol(symbolName, &address) == B_OK && address) {
398			if (info->GetOriginalAddress()) {
399				// A symbol with that name lives in at least two images.
400				// Better bail out.
401// TODO: That doesn't work so well (on gcc 4). E.g. the libsupc++ symbols might
402// appear in several images.
403//printf("Found the symbol in more than one image!\n");
404				error = B_ERROR;
405				break;
406			} else
407				info->SetOriginalAddress(address, image->GetID());
408		}
409	}
410	// set the symbol address
411	if (!info->GetOriginalAddress())
412{
413//printf("Symbol not found in any image!\n");
414		error = B_ERROR;
415}
416	// cleanup on error
417	if (error != B_OK)
418		info->Unset();
419	return error;
420}
421
422// UpdateSymbolPatchInfo
423status_t
424ElfSymbolPatcher::UpdateSymbolPatchInfo(ElfSymbolPatchInfo* info,
425										ElfImage* image)
426{
427	if (!info || !image || !info->GetSymbolName())
428		return B_BAD_VALUE;
429	// get the symbol's relocations
430	BList patchTargets;
431	status_t error
432		= image->GetSymbolRelocations(info->GetSymbolName(), &patchTargets);
433	if (error == B_OK)
434		error = info->CreateEntry(image->GetID(), &patchTargets);
435	return error;
436}
437
438// _Init
439status_t
440ElfSymbolPatcher::_Init()
441{
442	status_t error = B_OK;
443	image_info info;
444	int32 cookie = 0;
445	while (get_next_image_info(0, &cookie, &info) == B_OK) {
446		ElfImage* image = new(std::nothrow) ElfImage;
447		if (!image)
448			return B_NO_MEMORY;
449		if (!fImages.AddItem(image)) {
450			delete image;
451			return B_NO_MEMORY;
452		}
453		error = image->SetTo(info.id);
454	}
455	return error;
456}
457
458// _Cleanup
459void
460ElfSymbolPatcher::_Cleanup()
461{
462	for (int i = 0; ElfImage* image = _ImageAt(i); i++)
463		delete image;
464	fImages.MakeEmpty();
465}
466
467// _ImageAt
468ElfImage*
469ElfSymbolPatcher::_ImageAt(int32 index) const
470{
471	return (ElfImage*)fImages.ItemAt(index);
472}
473
474// _ImageForID
475ElfImage*
476ElfSymbolPatcher::_ImageForID(image_id id) const
477{
478	for (int i = 0; ElfImage* image = _ImageAt(i); i++) {
479		if (image->GetID() == id)
480			return image;
481	}
482	return NULL;
483}
484
485
486///////////////////////
487// ElfSymbolPatchGroup
488//
489
490// constructor
491ElfSymbolPatchGroup::ElfSymbolPatchGroup(ElfSymbolPatcher* patcher)
492	: fPatcher(patcher),
493	  fPatchInfos(),
494	  fOwnsPatcher(false),
495	  fPatched(false)
496{
497	// create a patcher if none has been supplied
498	if (!fPatcher) {
499		fPatcher = new(std::nothrow) ElfSymbolPatcher;
500		if (fPatcher) {
501			if (fPatcher->InitCheck() == B_OK)
502				fOwnsPatcher = true;
503			else {
504				delete fPatcher;
505				fPatcher = NULL;
506			}
507		}
508	}
509}
510
511// destructor
512ElfSymbolPatchGroup::~ElfSymbolPatchGroup()
513{
514	RemoveAllPatches();
515	if (fPatcher && fOwnsPatcher)
516		delete fPatcher;
517}
518
519// AddPatch
520status_t
521ElfSymbolPatchGroup::AddPatch(const char* symbolName, void* newAddress,
522							  void** originalAddress)
523{
524	// check initialization and parameters
525	if (!fPatcher)
526		return B_NO_INIT;
527	if (!symbolName || !originalAddress)
528		return B_BAD_VALUE;
529	// allocate patch info
530	PatchInfo* patchInfo = new(std::nothrow) PatchInfo;
531	if (!patchInfo)
532		return B_NO_MEMORY;
533	// init and add the patch info
534	status_t error = fPatcher->GetSymbolPatchInfo(symbolName, patchInfo);
535	if (error == B_OK) {
536		if (fPatchInfos.AddItem(patchInfo)) {
537			patchInfo->fNewAddress = newAddress;
538			*originalAddress = patchInfo->GetOriginalAddress();
539		} else
540			error = B_NO_MEMORY;
541	}
542	// cleanup on failure
543	if (error != B_OK && patchInfo) {
544		fPatchInfos.RemoveItem(patchInfo);
545		delete patchInfo;
546	}
547	return error;
548}
549
550// RemoveAllPatches
551void
552ElfSymbolPatchGroup::RemoveAllPatches()
553{
554	for (int i = 0; PatchInfo* info = (PatchInfo*)fPatchInfos.ItemAt(i); i++)
555		delete info;
556	fPatchInfos.MakeEmpty();
557	fPatched = false;
558}
559
560// Patch
561status_t
562ElfSymbolPatchGroup::Patch()
563{
564//printf("ElfSymbolPatchGroup::Patch(): patching %ld symbols\n",
565//fPatchInfos.CountItems());
566	if (!fPatcher)
567		return B_NO_INIT;
568	if (fPatched)
569		return B_OK;
570	for (int i = 0; PatchInfo* info = (PatchInfo*)fPatchInfos.ItemAt(i); i++)
571		info->Patch(info->fNewAddress);
572	fPatched = true;
573	return B_OK;
574}
575
576// Restore
577status_t
578ElfSymbolPatchGroup::Restore()
579{
580	if (!fPatcher)
581		return B_NO_INIT;
582	if (!fPatched)
583		return B_OK;
584	for (int i = 0; PatchInfo* info = (PatchInfo*)fPatchInfos.ItemAt(i); i++)
585		info->Restore();
586	fPatched = false;
587	return B_OK;
588}
589
590// Update
591status_t
592ElfSymbolPatchGroup::Update()
593{
594	if (!fPatcher)
595		return B_NO_INIT;
596	return fPatcher->Update(this);
597}
598
599// ImageAdded
600void
601ElfSymbolPatchGroup::ImageAdded(ElfImage* image)
602{
603	for (int i = 0; PatchInfo* info = (PatchInfo*)fPatchInfos.ItemAt(i); i++) {
604		fPatcher->UpdateSymbolPatchInfo(info, image);
605		if (fPatched) {
606			ElfSymbolPatchInfo::Entry* entry = info->EntryFor(image->GetID());
607			if (entry)
608				info->Patch(info->fNewAddress);
609		}
610	}
611}
612
613// ImageRemoved
614void
615ElfSymbolPatchGroup::ImageRemoved(ElfImage* image)
616{
617	int32 count = fPatchInfos.CountItems();
618	for (int i = count - 1; i >= 0; i--) {
619		PatchInfo* info = (PatchInfo*)fPatchInfos.ItemAt(i);
620		if (info->GetOriginalAddressImage() == image->GetID()) {
621			// the image the symbol lives in, has been removed: remove the
622			// complete patch info
623			fPatchInfos.RemoveItem(i);
624			delete info;
625		} else
626			info->DeleteEntry(image->GetID());
627	}
628}
629
630