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