HaikuDepot: notify work status from main window
[haiku.git] / src / tools / elfsymbolpatcher / ElfSymbolPatcher.cpp
blob89e20010fc960615955b4c693e867592e2d5b5d8
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:
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
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.
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 //------------------------------------------------------------------------------
36 #include <new>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
41 #include "ElfImage.h"
42 #include "ElfSymbolPatcher.h"
44 /////////////////////////////
45 // ElfSymbolPatchInfo::Entry
48 class ElfSymbolPatchInfo::Entry {
49 public:
50 static Entry* Create(image_id image, void*** targets,
51 int32 targetCount);
52 void Delete();
54 image_id GetImage() const { return fImage; }
56 void Patch(void* newAddress);
58 private:
59 Entry();
60 Entry(const Entry&);
61 Entry(image_id image, void*** targets,
62 int32 targetCount);
63 ~Entry();
65 private:
66 image_id fImage;
67 int32 fPatchTargetCount;
68 void** fPatchTargets[1];
71 // Create
72 ElfSymbolPatchInfo::Entry*
73 ElfSymbolPatchInfo::Entry::Create(image_id image, void*** targets,
74 int32 targetCount)
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;
85 // Delete
86 void
87 ElfSymbolPatchInfo::Entry::Delete()
89 this->~Entry();
90 free(this);
93 // Patch
94 void
95 ElfSymbolPatchInfo::Entry::Patch(void* newAddress)
97 //printf("ElfSymbolPatchInfo::Entry::Patch(): patching %ld addresses\n",
98 //fPatchTargetCount);
99 for (int i = 0; i < fPatchTargetCount; i++)
100 *fPatchTargets[i] = newAddress;
103 // constructor
104 ElfSymbolPatchInfo::Entry::Entry(image_id image, void*** targets,
105 int32 targetCount)
106 : fImage(image),
107 fPatchTargetCount(targetCount)
109 memcpy(fPatchTargets + 0, targets, targetCount * sizeof(void**));
112 // destructor
113 ElfSymbolPatchInfo::Entry::~Entry()
118 //////////////////////
119 // ElfSymbolPatchInfo
122 // constructor
123 ElfSymbolPatchInfo::ElfSymbolPatchInfo()
124 : fSymbolName(),
125 fOriginalAddress(NULL),
126 fOriginalAddressImage(-1),
127 fEntries()
131 // destructor
132 ElfSymbolPatchInfo::~ElfSymbolPatchInfo()
134 Unset();
137 // InitCheck
138 status_t
139 ElfSymbolPatchInfo::InitCheck() const
141 return (fOriginalAddress && fSymbolName.Length() ? B_OK : B_NO_INIT);
144 // GetSymbolName
145 const char*
146 ElfSymbolPatchInfo::GetSymbolName() const
148 return fSymbolName.String();
151 // GetOriginalAddress
152 void*
153 ElfSymbolPatchInfo::GetOriginalAddress() const
155 return fOriginalAddress;
158 // GetOriginalAddressImage
159 image_id
160 ElfSymbolPatchInfo::GetOriginalAddressImage() const
162 return fOriginalAddressImage;
165 // Patch
166 status_t
167 ElfSymbolPatchInfo::Patch(void* newAddress)
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);
176 return error;
179 // Restore
180 status_t
181 ElfSymbolPatchInfo::Restore()
183 return Patch(fOriginalAddress);
186 // Unset
187 void
188 ElfSymbolPatchInfo::Unset()
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;
198 // SetSymbolName
199 status_t
200 ElfSymbolPatchInfo::SetSymbolName(const char* name)
202 fSymbolName.SetTo(name);
203 if (name && fSymbolName != name)
204 return B_NO_MEMORY;
205 return B_OK;
208 // SetOriginalAddress
209 void
210 ElfSymbolPatchInfo::SetOriginalAddress(void* address, image_id image)
212 fOriginalAddress = address;
213 fOriginalAddressImage = image;
216 // CreateEntry
217 status_t
218 ElfSymbolPatchInfo::CreateEntry(image_id image, BList* targets)
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;
230 return B_OK;
233 // DeleteEntry
234 bool
235 ElfSymbolPatchInfo::DeleteEntry(image_id image)
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;
244 return false;
247 // EntryAt
248 ElfSymbolPatchInfo::Entry*
249 ElfSymbolPatchInfo::EntryAt(int32 index)
251 return (Entry*)fEntries.ItemAt(index);
254 // EntryFor
255 ElfSymbolPatchInfo::Entry*
256 ElfSymbolPatchInfo::EntryFor(image_id image)
258 for (int i = 0; Entry* entry = EntryAt(i); i++) {
259 if (entry->GetImage() == image)
260 return entry;
262 return NULL;
266 /////////////////
267 // UpdateAdapter
270 // constructor
271 ElfSymbolPatcher::UpdateAdapter::UpdateAdapter()
275 // destructor
276 ElfSymbolPatcher::UpdateAdapter::~UpdateAdapter()
280 // ImageAdded
281 void
282 ElfSymbolPatcher::UpdateAdapter::ImageAdded(ElfImage* image)
286 // ImageRemoved
287 void
288 ElfSymbolPatcher::UpdateAdapter::ImageRemoved(ElfImage* image)
293 ////////////////////
294 // ElfSymbolPatcher
297 // constructor
298 ElfSymbolPatcher::ElfSymbolPatcher()
299 : fImages(),
300 fInitStatus(B_NO_INIT)
302 fInitStatus = _Init();
303 if (fInitStatus != B_OK)
304 _Cleanup();
307 // destructor
308 ElfSymbolPatcher::~ElfSymbolPatcher()
310 _Cleanup();
313 // InitCheck
314 status_t
315 ElfSymbolPatcher::InitCheck() const
317 return fInitStatus;
320 // Update
321 status_t
322 ElfSymbolPatcher::Update(UpdateAdapter* updateAdapter)
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;
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;
353 error = image->SetTo(info.id);
354 if (updateAdapter)
355 updateAdapter->ImageAdded(image);
357 return error;
360 // Unload
361 void
362 ElfSymbolPatcher::Unload()
364 for (int i = 0; ElfImage* image = _ImageAt(i); i++)
365 image->Unload();
368 // GetSymbolPatchInfo
369 status_t
370 ElfSymbolPatcher::GetSymbolPatchInfo(const char* symbolName,
371 ElfSymbolPatchInfo* info)
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;
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());
410 // set the symbol address
411 if (!info->GetOriginalAddress())
413 //printf("Symbol not found in any image!\n");
414 error = B_ERROR;
416 // cleanup on error
417 if (error != B_OK)
418 info->Unset();
419 return error;
422 // UpdateSymbolPatchInfo
423 status_t
424 ElfSymbolPatcher::UpdateSymbolPatchInfo(ElfSymbolPatchInfo* info,
425 ElfImage* image)
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;
438 // _Init
439 status_t
440 ElfSymbolPatcher::_Init()
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;
453 error = image->SetTo(info.id);
455 return error;
458 // _Cleanup
459 void
460 ElfSymbolPatcher::_Cleanup()
462 for (int i = 0; ElfImage* image = _ImageAt(i); i++)
463 delete image;
464 fImages.MakeEmpty();
467 // _ImageAt
468 ElfImage*
469 ElfSymbolPatcher::_ImageAt(int32 index) const
471 return (ElfImage*)fImages.ItemAt(index);
474 // _ImageForID
475 ElfImage*
476 ElfSymbolPatcher::_ImageForID(image_id id) const
478 for (int i = 0; ElfImage* image = _ImageAt(i); i++) {
479 if (image->GetID() == id)
480 return image;
482 return NULL;
486 ///////////////////////
487 // ElfSymbolPatchGroup
490 // constructor
491 ElfSymbolPatchGroup::ElfSymbolPatchGroup(ElfSymbolPatcher* patcher)
492 : fPatcher(patcher),
493 fPatchInfos(),
494 fOwnsPatcher(false),
495 fPatched(false)
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;
511 // destructor
512 ElfSymbolPatchGroup::~ElfSymbolPatchGroup()
514 RemoveAllPatches();
515 if (fPatcher && fOwnsPatcher)
516 delete fPatcher;
519 // AddPatch
520 status_t
521 ElfSymbolPatchGroup::AddPatch(const char* symbolName, void* newAddress,
522 void** originalAddress)
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;
542 // cleanup on failure
543 if (error != B_OK && patchInfo) {
544 fPatchInfos.RemoveItem(patchInfo);
545 delete patchInfo;
547 return error;
550 // RemoveAllPatches
551 void
552 ElfSymbolPatchGroup::RemoveAllPatches()
554 for (int i = 0; PatchInfo* info = (PatchInfo*)fPatchInfos.ItemAt(i); i++)
555 delete info;
556 fPatchInfos.MakeEmpty();
557 fPatched = false;
560 // Patch
561 status_t
562 ElfSymbolPatchGroup::Patch()
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;
576 // Restore
577 status_t
578 ElfSymbolPatchGroup::Restore()
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;
590 // Update
591 status_t
592 ElfSymbolPatchGroup::Update()
594 if (!fPatcher)
595 return B_NO_INIT;
596 return fPatcher->Update(this);
599 // ImageAdded
600 void
601 ElfSymbolPatchGroup::ImageAdded(ElfImage* image)
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);
613 // ImageRemoved
614 void
615 ElfSymbolPatchGroup::ImageRemoved(ElfImage* image)
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());