1 //------------------------------------------------------------------------------
2 // Copyright (c) 2003, Ingo Weinhold
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
34 //------------------------------------------------------------------------------
42 #include "ElfSymbolPatcher.h"
44 /////////////////////////////
45 // ElfSymbolPatchInfo::Entry
48 class ElfSymbolPatchInfo::Entry
{
50 static Entry
* Create(image_id image
, void*** targets
,
54 image_id
GetImage() const { return fImage
; }
56 void Patch(void* newAddress
);
61 Entry(image_id image
, void*** targets
,
67 int32 fPatchTargetCount
;
68 void** fPatchTargets
[1];
72 ElfSymbolPatchInfo::Entry
*
73 ElfSymbolPatchInfo::Entry::Create(image_id image
, void*** targets
,
76 if (!targets
|| targetCount
<= 0)
78 void* buffer
= malloc(sizeof(Entry
) + sizeof(void**) * (targetCount
- 1));
81 entry
= new(buffer
) Entry(image
, targets
, targetCount
);
87 ElfSymbolPatchInfo::Entry::Delete()
95 ElfSymbolPatchInfo::Entry::Patch(void* newAddress
)
97 //printf("ElfSymbolPatchInfo::Entry::Patch(): patching %ld addresses\n",
99 for (int i
= 0; i
< fPatchTargetCount
; i
++)
100 *fPatchTargets
[i
] = newAddress
;
104 ElfSymbolPatchInfo::Entry::Entry(image_id image
, void*** targets
,
107 fPatchTargetCount(targetCount
)
109 memcpy(fPatchTargets
+ 0, targets
, targetCount
* sizeof(void**));
113 ElfSymbolPatchInfo::Entry::~Entry()
118 //////////////////////
119 // ElfSymbolPatchInfo
123 ElfSymbolPatchInfo::ElfSymbolPatchInfo()
125 fOriginalAddress(NULL
),
126 fOriginalAddressImage(-1),
132 ElfSymbolPatchInfo::~ElfSymbolPatchInfo()
139 ElfSymbolPatchInfo::InitCheck() const
141 return (fOriginalAddress
&& fSymbolName
.Length() ? B_OK
: B_NO_INIT
);
146 ElfSymbolPatchInfo::GetSymbolName() const
148 return fSymbolName
.String();
151 // GetOriginalAddress
153 ElfSymbolPatchInfo::GetOriginalAddress() const
155 return fOriginalAddress
;
158 // GetOriginalAddressImage
160 ElfSymbolPatchInfo::GetOriginalAddressImage() const
162 return fOriginalAddressImage
;
167 ElfSymbolPatchInfo::Patch(void* newAddress
)
169 //printf("ElfSymbolPatchInfo::Patch(): patching %ld images\n",
170 //fEntries.CountItems());
171 status_t error
= InitCheck();
173 for (int i
= 0; Entry
* entry
= EntryAt(i
); i
++)
174 entry
->Patch(newAddress
);
181 ElfSymbolPatchInfo::Restore()
183 return Patch(fOriginalAddress
);
188 ElfSymbolPatchInfo::Unset()
190 for (int i
= 0; Entry
* entry
= EntryAt(i
); i
++)
192 fEntries
.MakeEmpty();
193 fSymbolName
.SetTo("");
194 fOriginalAddress
= NULL
;
195 fOriginalAddressImage
= -1;
200 ElfSymbolPatchInfo::SetSymbolName(const char* name
)
202 fSymbolName
.SetTo(name
);
203 if (name
&& fSymbolName
!= name
)
208 // SetOriginalAddress
210 ElfSymbolPatchInfo::SetOriginalAddress(void* address
, image_id image
)
212 fOriginalAddress
= address
;
213 fOriginalAddressImage
= image
;
218 ElfSymbolPatchInfo::CreateEntry(image_id image
, BList
* targets
)
220 if (!targets
|| targets
->CountItems() == 0)
222 Entry
* entry
= Entry::Create(image
, (void***)targets
->Items(),
223 targets
->CountItems());
226 if (!fEntries
.AddItem(entry
)) {
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
);
248 ElfSymbolPatchInfo::Entry
*
249 ElfSymbolPatchInfo::EntryAt(int32 index
)
251 return (Entry
*)fEntries
.ItemAt(index
);
255 ElfSymbolPatchInfo::Entry
*
256 ElfSymbolPatchInfo::EntryFor(image_id image
)
258 for (int i
= 0; Entry
* entry
= EntryAt(i
); i
++) {
259 if (entry
->GetImage() == image
)
271 ElfSymbolPatcher::UpdateAdapter::UpdateAdapter()
276 ElfSymbolPatcher::UpdateAdapter::~UpdateAdapter()
282 ElfSymbolPatcher::UpdateAdapter::ImageAdded(ElfImage
* image
)
288 ElfSymbolPatcher::UpdateAdapter::ImageRemoved(ElfImage
* image
)
298 ElfSymbolPatcher::ElfSymbolPatcher()
300 fInitStatus(B_NO_INIT
)
302 fInitStatus
= _Init();
303 if (fInitStatus
!= B_OK
)
308 ElfSymbolPatcher::~ElfSymbolPatcher()
315 ElfSymbolPatcher::InitCheck() const
322 ElfSymbolPatcher::Update(UpdateAdapter
* updateAdapter
)
324 if (InitCheck() != B_OK
)
326 // remove obsolete images
327 int32 count
= fImages
.CountItems();
328 for (int i
= count
- 1; i
>= 0; i
--) {
329 ElfImage
* image
= _ImageAt(i
);
331 if (get_image_info(image
->GetID(), &info
) != B_OK
) {
333 updateAdapter
->ImageRemoved(image
);
334 fImages
.RemoveItem(i
);
339 status_t error
= B_OK
;
342 while (get_next_image_info(0, &cookie
, &info
) == B_OK
) {
343 ElfImage
* image
= _ImageForID(info
.id
);
346 image
= new(std::nothrow
) ElfImage
;
349 if (!fImages
.AddItem(image
)) {
353 error
= image
->SetTo(info
.id
);
355 updateAdapter
->ImageAdded(image
);
362 ElfSymbolPatcher::Unload()
364 for (int i
= 0; ElfImage
* image
= _ImageAt(i
); i
++)
368 // GetSymbolPatchInfo
370 ElfSymbolPatcher::GetSymbolPatchInfo(const char* symbolName
,
371 ElfSymbolPatchInfo
* info
)
373 // check parameters and intialization
374 if (!symbolName
|| !info
)
376 if (InitCheck() != B_OK
)
378 // set the symbol name
380 status_t error
= info
->SetSymbolName(symbolName
);
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
387 error
= image
->GetSymbolRelocations(symbolName
, &patchTargets
);
390 if (patchTargets
.CountItems() > 0) {
391 error
= info
->CreateEntry(image
->GetID(), &patchTargets
);
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.
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");
407 info
->SetOriginalAddress(address
, image
->GetID());
410 // set the symbol address
411 if (!info
->GetOriginalAddress())
413 //printf("Symbol not found in any image!\n");
422 // UpdateSymbolPatchInfo
424 ElfSymbolPatcher::UpdateSymbolPatchInfo(ElfSymbolPatchInfo
* info
,
427 if (!info
|| !image
|| !info
->GetSymbolName())
429 // get the symbol's relocations
432 = image
->GetSymbolRelocations(info
->GetSymbolName(), &patchTargets
);
434 error
= info
->CreateEntry(image
->GetID(), &patchTargets
);
440 ElfSymbolPatcher::_Init()
442 status_t error
= B_OK
;
445 while (get_next_image_info(0, &cookie
, &info
) == B_OK
) {
446 ElfImage
* image
= new(std::nothrow
) ElfImage
;
449 if (!fImages
.AddItem(image
)) {
453 error
= image
->SetTo(info
.id
);
460 ElfSymbolPatcher::_Cleanup()
462 for (int i
= 0; ElfImage
* image
= _ImageAt(i
); i
++)
469 ElfSymbolPatcher::_ImageAt(int32 index
) const
471 return (ElfImage
*)fImages
.ItemAt(index
);
476 ElfSymbolPatcher::_ImageForID(image_id id
) const
478 for (int i
= 0; ElfImage
* image
= _ImageAt(i
); i
++) {
479 if (image
->GetID() == id
)
486 ///////////////////////
487 // ElfSymbolPatchGroup
491 ElfSymbolPatchGroup::ElfSymbolPatchGroup(ElfSymbolPatcher
* patcher
)
497 // create a patcher if none has been supplied
499 fPatcher
= new(std::nothrow
) ElfSymbolPatcher
;
501 if (fPatcher
->InitCheck() == B_OK
)
512 ElfSymbolPatchGroup::~ElfSymbolPatchGroup()
515 if (fPatcher
&& fOwnsPatcher
)
521 ElfSymbolPatchGroup::AddPatch(const char* symbolName
, void* newAddress
,
522 void** originalAddress
)
524 // check initialization and parameters
527 if (!symbolName
|| !originalAddress
)
529 // allocate patch info
530 PatchInfo
* patchInfo
= new(std::nothrow
) PatchInfo
;
533 // init and add the patch info
534 status_t error
= fPatcher
->GetSymbolPatchInfo(symbolName
, patchInfo
);
536 if (fPatchInfos
.AddItem(patchInfo
)) {
537 patchInfo
->fNewAddress
= newAddress
;
538 *originalAddress
= patchInfo
->GetOriginalAddress();
542 // cleanup on failure
543 if (error
!= B_OK
&& patchInfo
) {
544 fPatchInfos
.RemoveItem(patchInfo
);
552 ElfSymbolPatchGroup::RemoveAllPatches()
554 for (int i
= 0; PatchInfo
* info
= (PatchInfo
*)fPatchInfos
.ItemAt(i
); i
++)
556 fPatchInfos
.MakeEmpty();
562 ElfSymbolPatchGroup::Patch()
564 //printf("ElfSymbolPatchGroup::Patch(): patching %ld symbols\n",
565 //fPatchInfos.CountItems());
570 for (int i
= 0; PatchInfo
* info
= (PatchInfo
*)fPatchInfos
.ItemAt(i
); i
++)
571 info
->Patch(info
->fNewAddress
);
578 ElfSymbolPatchGroup::Restore()
584 for (int i
= 0; PatchInfo
* info
= (PatchInfo
*)fPatchInfos
.ItemAt(i
); i
++)
592 ElfSymbolPatchGroup::Update()
596 return fPatcher
->Update(this);
601 ElfSymbolPatchGroup::ImageAdded(ElfImage
* image
)
603 for (int i
= 0; PatchInfo
* info
= (PatchInfo
*)fPatchInfos
.ItemAt(i
); i
++) {
604 fPatcher
->UpdateSymbolPatchInfo(info
, image
);
606 ElfSymbolPatchInfo::Entry
* entry
= info
->EntryFor(image
->GetID());
608 info
->Patch(info
->fNewAddress
);
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
);
626 info
->DeleteEntry(image
->GetID());