xref: /haiku/src/tools/elfsymbolpatcher/ElfSymbolPatcher.cpp (revision 820dca4df6c7bf955c46e8f6521b9408f50b2900)
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 
48 class ElfSymbolPatchInfo::Entry {
49 public:
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 
58 private:
59 								Entry();
60 								Entry(const Entry&);
61 								Entry(image_id image, void*** targets,
62 									  int32 targetCount);
63 								~Entry();
64 
65 private:
66 			image_id			fImage;
67 			int32				fPatchTargetCount;
68 			void**				fPatchTargets[1];
69 };
70 
71 // Create
72 ElfSymbolPatchInfo::Entry*
73 ElfSymbolPatchInfo::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
86 void
87 ElfSymbolPatchInfo::Entry::Delete()
88 {
89 	this->~Entry();
90 	free(this);
91 }
92 
93 // Patch
94 void
95 ElfSymbolPatchInfo::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
104 ElfSymbolPatchInfo::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
113 ElfSymbolPatchInfo::Entry::~Entry()
114 {
115 }
116 
117 
118 //////////////////////
119 // ElfSymbolPatchInfo
120 //
121 
122 // constructor
123 ElfSymbolPatchInfo::ElfSymbolPatchInfo()
124 	: fSymbolName(),
125 	  fOriginalAddress(NULL),
126 	  fOriginalAddressImage(-1),
127 	  fEntries()
128 {
129 }
130 
131 // destructor
132 ElfSymbolPatchInfo::~ElfSymbolPatchInfo()
133 {
134 	Unset();
135 }
136 
137 // InitCheck
138 status_t
139 ElfSymbolPatchInfo::InitCheck() const
140 {
141 	return (fOriginalAddress && fSymbolName.Length() ? B_OK : B_NO_INIT);
142 }
143 
144 // GetSymbolName
145 const char*
146 ElfSymbolPatchInfo::GetSymbolName() const
147 {
148 	return fSymbolName.String();
149 }
150 
151 // GetOriginalAddress
152 void*
153 ElfSymbolPatchInfo::GetOriginalAddress() const
154 {
155 	return fOriginalAddress;
156 }
157 
158 // GetOriginalAddressImage
159 image_id
160 ElfSymbolPatchInfo::GetOriginalAddressImage() const
161 {
162 	return fOriginalAddressImage;
163 }
164 
165 // Patch
166 status_t
167 ElfSymbolPatchInfo::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
180 status_t
181 ElfSymbolPatchInfo::Restore()
182 {
183 	return Patch(fOriginalAddress);
184 }
185 
186 // Unset
187 void
188 ElfSymbolPatchInfo::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
199 status_t
200 ElfSymbolPatchInfo::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
209 void
210 ElfSymbolPatchInfo::SetOriginalAddress(void* address, image_id image)
211 {
212 	fOriginalAddress = address;
213 	fOriginalAddressImage = image;
214 }
215 
216 // CreateEntry
217 status_t
218 ElfSymbolPatchInfo::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
234 bool
235 ElfSymbolPatchInfo::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
248 ElfSymbolPatchInfo::Entry*
249 ElfSymbolPatchInfo::EntryAt(int32 index)
250 {
251 	return (Entry*)fEntries.ItemAt(index);
252 }
253 
254 // EntryFor
255 ElfSymbolPatchInfo::Entry*
256 ElfSymbolPatchInfo::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
271 ElfSymbolPatcher::UpdateAdapter::UpdateAdapter()
272 {
273 }
274 
275 // destructor
276 ElfSymbolPatcher::UpdateAdapter::~UpdateAdapter()
277 {
278 }
279 
280 // ImageAdded
281 void
282 ElfSymbolPatcher::UpdateAdapter::ImageAdded(ElfImage* image)
283 {
284 }
285 
286 // ImageRemoved
287 void
288 ElfSymbolPatcher::UpdateAdapter::ImageRemoved(ElfImage* image)
289 {
290 }
291 
292 
293 ////////////////////
294 // ElfSymbolPatcher
295 //
296 
297 // constructor
298 ElfSymbolPatcher::ElfSymbolPatcher()
299 	: fImages(),
300 	  fInitStatus(B_NO_INIT)
301 {
302 	fInitStatus = _Init();
303 	if (fInitStatus != B_OK)
304 		_Cleanup();
305 }
306 
307 // destructor
308 ElfSymbolPatcher::~ElfSymbolPatcher()
309 {
310 	_Cleanup();
311 }
312 
313 // InitCheck
314 status_t
315 ElfSymbolPatcher::InitCheck() const
316 {
317 	return fInitStatus;
318 }
319 
320 // Update
321 status_t
322 ElfSymbolPatcher::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
361 void
362 ElfSymbolPatcher::Unload()
363 {
364 	for (int i = 0; ElfImage* image = _ImageAt(i); i++)
365 		image->Unload();
366 }
367 
368 // GetSymbolPatchInfo
369 status_t
370 ElfSymbolPatcher::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
423 status_t
424 ElfSymbolPatcher::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
439 status_t
440 ElfSymbolPatcher::_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
459 void
460 ElfSymbolPatcher::_Cleanup()
461 {
462 	for (int i = 0; ElfImage* image = _ImageAt(i); i++)
463 		delete image;
464 	fImages.MakeEmpty();
465 }
466 
467 // _ImageAt
468 ElfImage*
469 ElfSymbolPatcher::_ImageAt(int32 index) const
470 {
471 	return (ElfImage*)fImages.ItemAt(index);
472 }
473 
474 // _ImageForID
475 ElfImage*
476 ElfSymbolPatcher::_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
491 ElfSymbolPatchGroup::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
512 ElfSymbolPatchGroup::~ElfSymbolPatchGroup()
513 {
514 	RemoveAllPatches();
515 	if (fPatcher && fOwnsPatcher)
516 		delete fPatcher;
517 }
518 
519 // AddPatch
520 status_t
521 ElfSymbolPatchGroup::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
551 void
552 ElfSymbolPatchGroup::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
561 status_t
562 ElfSymbolPatchGroup::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
577 status_t
578 ElfSymbolPatchGroup::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
591 status_t
592 ElfSymbolPatchGroup::Update()
593 {
594 	if (!fPatcher)
595 		return B_NO_INIT;
596 	return fPatcher->Update(this);
597 }
598 
599 // ImageAdded
600 void
601 ElfSymbolPatchGroup::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
614 void
615 ElfSymbolPatchGroup::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