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