| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "crazy_linker_rdebug.h" | 5 #include "crazy_linker_rdebug.h" |
| 6 | 6 |
| 7 #include <elf.h> | 7 #include <elf.h> |
| 8 #include <inttypes.h> | 8 #include <inttypes.h> |
| 9 #include <pthread.h> | 9 #include <pthread.h> |
| 10 #include <sys/mman.h> | 10 #include <sys/mman.h> |
| 11 #include <unistd.h> | 11 #include <unistd.h> |
| 12 | 12 |
| 13 #include "crazy_linker_debug.h" | 13 #include "crazy_linker_debug.h" |
| 14 #include "crazy_linker_globals.h" |
| 14 #include "crazy_linker_proc_maps.h" | 15 #include "crazy_linker_proc_maps.h" |
| 15 #include "crazy_linker_util.h" | 16 #include "crazy_linker_util.h" |
| 16 #include "crazy_linker_system.h" | 17 #include "crazy_linker_system.h" |
| 17 #include "elf_traits.h" | 18 #include "elf_traits.h" |
| 18 | 19 |
| 19 namespace crazy { | 20 namespace crazy { |
| 20 | 21 |
| 21 namespace { | 22 namespace { |
| 22 | 23 |
| 23 // Find the full path of the current executable. On success return true | 24 // Find the full path of the current executable. On success return true |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 148 (void*)*dynamic_size); | 149 (void*)*dynamic_size); |
| 149 return true; | 150 return true; |
| 150 } | 151 } |
| 151 | 152 |
| 152 LOG("%s: Executable is not mapped in current process.\n", __FUNCTION__); | 153 LOG("%s: Executable is not mapped in current process.\n", __FUNCTION__); |
| 153 return false; | 154 return false; |
| 154 } | 155 } |
| 155 | 156 |
| 156 // Helper class to temporarily remap a page to readable+writable until | 157 // Helper class to temporarily remap a page to readable+writable until |
| 157 // scope exit. | 158 // scope exit. |
| 158 class ScopedPageMapper { | 159 class ScopedPageReadWriteRemapper { |
| 159 public: | 160 public: |
| 160 ScopedPageMapper() : page_address_(0), page_prot_(0) {} | 161 ScopedPageReadWriteRemapper(void* address); |
| 161 void MapReadWrite(void* address); | 162 ~ScopedPageReadWriteRemapper(); |
| 162 ~ScopedPageMapper(); | 163 |
| 164 // Releases the page so that the destructor does not undo the remapping. |
| 165 void Release(); |
| 163 | 166 |
| 164 private: | 167 private: |
| 165 static const uintptr_t kPageSize = 4096; | 168 static const uintptr_t kPageSize = 4096; |
| 166 uintptr_t page_address_; | 169 uintptr_t page_address_; |
| 167 int page_prot_; | 170 int page_prot_; |
| 168 }; | 171 }; |
| 169 | 172 |
| 170 void ScopedPageMapper::MapReadWrite(void* address) { | 173 ScopedPageReadWriteRemapper::ScopedPageReadWriteRemapper(void* address) { |
| 171 page_address_ = reinterpret_cast<uintptr_t>(address) & ~(kPageSize - 1); | 174 page_address_ = reinterpret_cast<uintptr_t>(address) & ~(kPageSize - 1); |
| 172 page_prot_ = 0; | 175 page_prot_ = 0; |
| 173 if (!FindProtectionFlagsForAddress(address, &page_prot_) || | 176 if (!FindProtectionFlagsForAddress(address, &page_prot_)) { |
| 174 (page_prot_ & (PROT_READ | PROT_WRITE)) == (PROT_READ | PROT_WRITE)) { | 177 LOG("Could not find protection flags for %p\n", address); |
| 175 // If the address is invalid, or if the page is already read+write, | |
| 176 // no need to do anything here. | |
| 177 page_address_ = 0; | 178 page_address_ = 0; |
| 178 return; | 179 return; |
| 179 } | 180 } |
| 181 |
| 182 // Note: page_prot_ may already indicate read/write, but because of |
| 183 // possible races with the system linker we cannot be confident that |
| 184 // this is reliable. So we always set read/write here. |
| 185 // |
| 186 // See commentary in WriteLinkMapField for more. |
| 180 int new_page_prot = page_prot_ | PROT_READ | PROT_WRITE; | 187 int new_page_prot = page_prot_ | PROT_READ | PROT_WRITE; |
| 181 int ret = mprotect( | 188 int ret = mprotect( |
| 182 reinterpret_cast<void*>(page_address_), kPageSize, new_page_prot); | 189 reinterpret_cast<void*>(page_address_), kPageSize, new_page_prot); |
| 183 if (ret < 0) { | 190 if (ret < 0) { |
| 184 LOG_ERRNO("Could not remap page to read/write"); | 191 LOG_ERRNO("Could not remap page to read/write"); |
| 185 page_address_ = 0; | 192 page_address_ = 0; |
| 186 } | 193 } |
| 187 } | 194 } |
| 188 | 195 |
| 189 ScopedPageMapper::~ScopedPageMapper() { | 196 ScopedPageReadWriteRemapper::~ScopedPageReadWriteRemapper() { |
| 190 if (page_address_) { | 197 if (page_address_) { |
| 191 int ret = | 198 int ret = |
| 192 mprotect(reinterpret_cast<void*>(page_address_), kPageSize, page_prot_); | 199 mprotect(reinterpret_cast<void*>(page_address_), kPageSize, page_prot_); |
| 193 if (ret < 0) | 200 if (ret < 0) |
| 194 LOG_ERRNO("Could not remap page to old protection flags"); | 201 LOG_ERRNO("Could not remap page to old protection flags"); |
| 195 } | 202 } |
| 196 } | 203 } |
| 197 | 204 |
| 205 void ScopedPageReadWriteRemapper::Release() { |
| 206 page_address_ = 0; |
| 207 page_prot_ = 0; |
| 208 } |
| 209 |
| 198 } // namespace | 210 } // namespace |
| 199 | 211 |
| 200 bool RDebug::Init() { | 212 bool RDebug::Init() { |
| 201 // The address of '_r_debug' is in the DT_DEBUG entry of the current | 213 // The address of '_r_debug' is in the DT_DEBUG entry of the current |
| 202 // executable. | 214 // executable. |
| 203 init_ = true; | 215 init_ = true; |
| 204 | 216 |
| 205 size_t dynamic_addr = 0; | 217 size_t dynamic_addr = 0; |
| 206 size_t dynamic_size = 0; | 218 size_t dynamic_size = 0; |
| 207 String path; | 219 String path; |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 375 LOG("%s: Posted for later execution, runnable=%p\n", __FUNCTION__, runnable); | 387 LOG("%s: Posted for later execution, runnable=%p\n", __FUNCTION__, runnable); |
| 376 | 388 |
| 377 if (is_blocking) { | 389 if (is_blocking) { |
| 378 RDebugRunnable::WaitForCallback(runnable); | 390 RDebugRunnable::WaitForCallback(runnable); |
| 379 LOG("%s: Completed execution, runnable=%p\n", __FUNCTION__, runnable); | 391 LOG("%s: Completed execution, runnable=%p\n", __FUNCTION__, runnable); |
| 380 } | 392 } |
| 381 | 393 |
| 382 return true; | 394 return true; |
| 383 } | 395 } |
| 384 | 396 |
| 397 // Helper function for AddEntryImpl and DelEntryImpl. |
| 398 // Sets *link_pointer to entry. link_pointer is either an 'l_prev' or an |
| 399 // 'l_next' field in a neighbouring linkmap_t. If link_pointer is in a |
| 400 // page that is mapped readonly, the page is remapped to be writable before |
| 401 // assignment. |
| 402 void RDebug::WriteLinkMapField(link_map_t** link_pointer, link_map_t* entry) { |
| 403 ScopedPageReadWriteRemapper mapper(link_pointer); |
| 404 LOG("%s: Remapped page for %p for read/write\n", __FUNCTION__, link_pointer); |
| 405 |
| 406 *link_pointer = entry; |
| 407 |
| 408 // We always mprotect the page containing link_pointer to read/write, |
| 409 // then write the entry. The page may already be read/write, but on |
| 410 // recent Android release is most likely readonly. Because of the way |
| 411 // the system linker operates we cannot tell with certainty what its |
| 412 // correct setting should be. |
| 413 // |
| 414 // Now, we always leave the page read/write. Here is why. If we set it |
| 415 // back to readonly at the point between where the system linker sets |
| 416 // it to read/write and where it writes to the address, this will cause |
| 417 // the system linker to crash. Clearly that is undesirable. From |
| 418 // observations this occurs most frequently on the gpu process. |
| 419 // |
| 420 // TODO(simonb): Revisit this, details in: |
| 421 // https://code.google.com/p/chromium/issues/detail?id=450659 |
| 422 // https://code.google.com/p/chromium/issues/detail?id=458346 |
| 423 mapper.Release(); |
| 424 LOG("%s: Released mapper, leaving page read/write\n", __FUNCTION__); |
| 425 } |
| 426 |
| 385 void RDebug::AddEntryImpl(link_map_t* entry) { | 427 void RDebug::AddEntryImpl(link_map_t* entry) { |
| 428 ScopedGlobalLock lock; |
| 386 LOG("%s: Adding: %s\n", __FUNCTION__, entry->l_name); | 429 LOG("%s: Adding: %s\n", __FUNCTION__, entry->l_name); |
| 387 if (!init_) | 430 if (!init_) |
| 388 Init(); | 431 Init(); |
| 389 | 432 |
| 390 if (!r_debug_) { | 433 if (!r_debug_) { |
| 391 LOG("%s: Nothing to do\n", __FUNCTION__); | 434 LOG("%s: Nothing to do\n", __FUNCTION__); |
| 392 return; | 435 return; |
| 393 } | 436 } |
| 394 | 437 |
| 395 // Tell GDB the list is going to be modified. | 438 // Tell GDB the list is going to be modified. |
| (...skipping 30 matching lines...) Expand all Loading... |
| 426 link_map_t* after = before->l_next; | 469 link_map_t* after = before->l_next; |
| 427 | 470 |
| 428 // Prepare the new entry. | 471 // Prepare the new entry. |
| 429 entry->l_prev = before; | 472 entry->l_prev = before; |
| 430 entry->l_next = after; | 473 entry->l_next = after; |
| 431 | 474 |
| 432 // IMPORTANT: Before modifying the previous and next entries in the | 475 // IMPORTANT: Before modifying the previous and next entries in the |
| 433 // list, ensure that they are writable. This avoids crashing when | 476 // list, ensure that they are writable. This avoids crashing when |
| 434 // updating the 'l_prev' or 'l_next' fields of a system linker entry, | 477 // updating the 'l_prev' or 'l_next' fields of a system linker entry, |
| 435 // which are mapped read-only. | 478 // which are mapped read-only. |
| 436 { | 479 WriteLinkMapField(&before->l_next, entry); |
| 437 ScopedPageMapper mapper; | 480 WriteLinkMapField(&after->l_prev, entry); |
| 438 if (readonly_entries_) | |
| 439 mapper.MapReadWrite(before); | |
| 440 before->l_next = entry; | |
| 441 } | |
| 442 | |
| 443 { | |
| 444 ScopedPageMapper mapper; | |
| 445 if (readonly_entries_) | |
| 446 mapper.MapReadWrite(after); | |
| 447 after->l_prev = entry; | |
| 448 } | |
| 449 | 481 |
| 450 // Tell GDB that the list modification has completed. | 482 // Tell GDB that the list modification has completed. |
| 451 r_debug_->r_state = RT_CONSISTENT; | 483 r_debug_->r_state = RT_CONSISTENT; |
| 452 r_debug_->r_brk(); | 484 r_debug_->r_brk(); |
| 453 } | 485 } |
| 454 | 486 |
| 455 void RDebug::DelEntryImpl(link_map_t* entry) { | 487 void RDebug::DelEntryImpl(link_map_t* entry) { |
| 488 ScopedGlobalLock lock; |
| 456 LOG("%s: Deleting: %s\n", __FUNCTION__, entry->l_name); | 489 LOG("%s: Deleting: %s\n", __FUNCTION__, entry->l_name); |
| 457 if (!r_debug_) | 490 if (!r_debug_) |
| 458 return; | 491 return; |
| 459 | 492 |
| 460 // Tell GDB the list is going to be modified. | 493 // Tell GDB the list is going to be modified. |
| 461 r_debug_->r_state = RT_DELETE; | 494 r_debug_->r_state = RT_DELETE; |
| 462 r_debug_->r_brk(); | 495 r_debug_->r_brk(); |
| 463 | 496 |
| 464 // IMPORTANT: Before modifying the previous and next entries in the | 497 // IMPORTANT: Before modifying the previous and next entries in the |
| 465 // list, ensure that they are writable. See comment above for more | 498 // list, ensure that they are writable. See comment above for more |
| 466 // details. | 499 // details. |
| 467 if (entry->l_prev) { | 500 if (entry->l_prev) |
| 468 ScopedPageMapper mapper; | 501 WriteLinkMapField(&entry->l_prev->l_next, entry->l_next); |
| 469 if (readonly_entries_) | 502 if (entry->l_next) |
| 470 mapper.MapReadWrite(entry->l_prev); | 503 WriteLinkMapField(&entry->l_next->l_prev, entry->l_prev); |
| 471 entry->l_prev->l_next = entry->l_next; | |
| 472 } | |
| 473 | |
| 474 if (entry->l_next) { | |
| 475 ScopedPageMapper mapper; | |
| 476 if (readonly_entries_) | |
| 477 mapper.MapReadWrite(entry->l_next); | |
| 478 entry->l_next->l_prev = entry->l_prev; | |
| 479 } | |
| 480 | 504 |
| 481 if (r_debug_->r_map == entry) | 505 if (r_debug_->r_map == entry) |
| 482 r_debug_->r_map = entry->l_next; | 506 r_debug_->r_map = entry->l_next; |
| 483 | 507 |
| 484 entry->l_prev = NULL; | 508 entry->l_prev = NULL; |
| 485 entry->l_next = NULL; | 509 entry->l_next = NULL; |
| 486 | 510 |
| 487 // Tell GDB the list modification has completed. | 511 // Tell GDB the list modification has completed. |
| 488 r_debug_->r_state = RT_CONSISTENT; | 512 r_debug_->r_state = RT_CONSISTENT; |
| 489 r_debug_->r_brk(); | 513 r_debug_->r_brk(); |
| 490 } | 514 } |
| 491 | 515 |
| 492 } // namespace crazy | 516 } // namespace crazy |
| OLD | NEW |