| Index: third_party/android_crazy_linker/src/src/crazy_linker_rdebug.cpp
|
| diff --git a/third_party/android_crazy_linker/src/src/crazy_linker_rdebug.cpp b/third_party/android_crazy_linker/src/src/crazy_linker_rdebug.cpp
|
| index 60ff8904f5f03009328d89ad58ec4fc1badd3f32..fd410c46f41182c151bebff73171bc9640261848 100644
|
| --- a/third_party/android_crazy_linker/src/src/crazy_linker_rdebug.cpp
|
| +++ b/third_party/android_crazy_linker/src/src/crazy_linker_rdebug.cpp
|
| @@ -11,6 +11,7 @@
|
| #include <unistd.h>
|
|
|
| #include "crazy_linker_debug.h"
|
| +#include "crazy_linker_globals.h"
|
| #include "crazy_linker_proc_maps.h"
|
| #include "crazy_linker_util.h"
|
| #include "crazy_linker_system.h"
|
| @@ -155,11 +156,13 @@ bool FindElfDynamicSection(const char* path,
|
|
|
| // Helper class to temporarily remap a page to readable+writable until
|
| // scope exit.
|
| -class ScopedPageMapper {
|
| +class ScopedPageReadWriteRemapper {
|
| public:
|
| - ScopedPageMapper() : page_address_(0), page_prot_(0) {}
|
| - void MapReadWrite(void* address);
|
| - ~ScopedPageMapper();
|
| + ScopedPageReadWriteRemapper(void* address);
|
| + ~ScopedPageReadWriteRemapper();
|
| +
|
| + // Releases the page so that the destructor does not undo the remapping.
|
| + void Release();
|
|
|
| private:
|
| static const uintptr_t kPageSize = 4096;
|
| @@ -167,16 +170,20 @@ class ScopedPageMapper {
|
| int page_prot_;
|
| };
|
|
|
| -void ScopedPageMapper::MapReadWrite(void* address) {
|
| +ScopedPageReadWriteRemapper::ScopedPageReadWriteRemapper(void* address) {
|
| page_address_ = reinterpret_cast<uintptr_t>(address) & ~(kPageSize - 1);
|
| page_prot_ = 0;
|
| - if (!FindProtectionFlagsForAddress(address, &page_prot_) ||
|
| - (page_prot_ & (PROT_READ | PROT_WRITE)) == (PROT_READ | PROT_WRITE)) {
|
| - // If the address is invalid, or if the page is already read+write,
|
| - // no need to do anything here.
|
| + if (!FindProtectionFlagsForAddress(address, &page_prot_)) {
|
| + LOG("Could not find protection flags for %p\n", address);
|
| page_address_ = 0;
|
| return;
|
| }
|
| +
|
| + // Note: page_prot_ may already indicate read/write, but because of
|
| + // possible races with the system linker we cannot be confident that
|
| + // this is reliable. So we always set read/write here.
|
| + //
|
| + // See commentary in WriteLinkMapField for more.
|
| int new_page_prot = page_prot_ | PROT_READ | PROT_WRITE;
|
| int ret = mprotect(
|
| reinterpret_cast<void*>(page_address_), kPageSize, new_page_prot);
|
| @@ -186,7 +193,7 @@ void ScopedPageMapper::MapReadWrite(void* address) {
|
| }
|
| }
|
|
|
| -ScopedPageMapper::~ScopedPageMapper() {
|
| +ScopedPageReadWriteRemapper::~ScopedPageReadWriteRemapper() {
|
| if (page_address_) {
|
| int ret =
|
| mprotect(reinterpret_cast<void*>(page_address_), kPageSize, page_prot_);
|
| @@ -195,6 +202,11 @@ ScopedPageMapper::~ScopedPageMapper() {
|
| }
|
| }
|
|
|
| +void ScopedPageReadWriteRemapper::Release() {
|
| + page_address_ = 0;
|
| + page_prot_ = 0;
|
| +}
|
| +
|
| } // namespace
|
|
|
| bool RDebug::Init() {
|
| @@ -382,7 +394,38 @@ bool RDebug::PostCallback(rdebug_callback_handler_t handler,
|
| return true;
|
| }
|
|
|
| +// Helper function for AddEntryImpl and DelEntryImpl.
|
| +// Sets *link_pointer to entry. link_pointer is either an 'l_prev' or an
|
| +// 'l_next' field in a neighbouring linkmap_t. If link_pointer is in a
|
| +// page that is mapped readonly, the page is remapped to be writable before
|
| +// assignment.
|
| +void RDebug::WriteLinkMapField(link_map_t** link_pointer, link_map_t* entry) {
|
| + ScopedPageReadWriteRemapper mapper(link_pointer);
|
| + LOG("%s: Remapped page for %p for read/write\n", __FUNCTION__, link_pointer);
|
| +
|
| + *link_pointer = entry;
|
| +
|
| + // We always mprotect the page containing link_pointer to read/write,
|
| + // then write the entry. The page may already be read/write, but on
|
| + // recent Android release is most likely readonly. Because of the way
|
| + // the system linker operates we cannot tell with certainty what its
|
| + // correct setting should be.
|
| + //
|
| + // Now, we always leave the page read/write. Here is why. If we set it
|
| + // back to readonly at the point between where the system linker sets
|
| + // it to read/write and where it writes to the address, this will cause
|
| + // the system linker to crash. Clearly that is undesirable. From
|
| + // observations this occurs most frequently on the gpu process.
|
| + //
|
| + // TODO(simonb): Revisit this, details in:
|
| + // https://code.google.com/p/chromium/issues/detail?id=450659
|
| + // https://code.google.com/p/chromium/issues/detail?id=458346
|
| + mapper.Release();
|
| + LOG("%s: Released mapper, leaving page read/write\n", __FUNCTION__);
|
| +}
|
| +
|
| void RDebug::AddEntryImpl(link_map_t* entry) {
|
| + ScopedGlobalLock lock;
|
| LOG("%s: Adding: %s\n", __FUNCTION__, entry->l_name);
|
| if (!init_)
|
| Init();
|
| @@ -433,19 +476,8 @@ void RDebug::AddEntryImpl(link_map_t* entry) {
|
| // list, ensure that they are writable. This avoids crashing when
|
| // updating the 'l_prev' or 'l_next' fields of a system linker entry,
|
| // which are mapped read-only.
|
| - {
|
| - ScopedPageMapper mapper;
|
| - if (readonly_entries_)
|
| - mapper.MapReadWrite(before);
|
| - before->l_next = entry;
|
| - }
|
| -
|
| - {
|
| - ScopedPageMapper mapper;
|
| - if (readonly_entries_)
|
| - mapper.MapReadWrite(after);
|
| - after->l_prev = entry;
|
| - }
|
| + WriteLinkMapField(&before->l_next, entry);
|
| + WriteLinkMapField(&after->l_prev, entry);
|
|
|
| // Tell GDB that the list modification has completed.
|
| r_debug_->r_state = RT_CONSISTENT;
|
| @@ -453,6 +485,7 @@ void RDebug::AddEntryImpl(link_map_t* entry) {
|
| }
|
|
|
| void RDebug::DelEntryImpl(link_map_t* entry) {
|
| + ScopedGlobalLock lock;
|
| LOG("%s: Deleting: %s\n", __FUNCTION__, entry->l_name);
|
| if (!r_debug_)
|
| return;
|
| @@ -464,19 +497,10 @@ void RDebug::DelEntryImpl(link_map_t* entry) {
|
| // IMPORTANT: Before modifying the previous and next entries in the
|
| // list, ensure that they are writable. See comment above for more
|
| // details.
|
| - if (entry->l_prev) {
|
| - ScopedPageMapper mapper;
|
| - if (readonly_entries_)
|
| - mapper.MapReadWrite(entry->l_prev);
|
| - entry->l_prev->l_next = entry->l_next;
|
| - }
|
| -
|
| - if (entry->l_next) {
|
| - ScopedPageMapper mapper;
|
| - if (readonly_entries_)
|
| - mapper.MapReadWrite(entry->l_next);
|
| - entry->l_next->l_prev = entry->l_prev;
|
| - }
|
| + if (entry->l_prev)
|
| + WriteLinkMapField(&entry->l_prev->l_next, entry->l_next);
|
| + if (entry->l_next)
|
| + WriteLinkMapField(&entry->l_next->l_prev, entry->l_prev);
|
|
|
| if (r_debug_->r_map == entry)
|
| r_debug_->r_map = entry->l_next;
|
|
|