Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(530)

Unified Diff: third_party/crazy_linker/crazy_linker/src/crazy_linker_proc_maps.cpp

Issue 23717023: Android: Add chrome-specific dynamic linker. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Remove findbugs issues. Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/crazy_linker/crazy_linker/src/crazy_linker_proc_maps.cpp
diff --git a/third_party/crazy_linker/crazy_linker/src/crazy_linker_proc_maps.cpp b/third_party/crazy_linker/crazy_linker/src/crazy_linker_proc_maps.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9597d70e0005829b2c687ab57d9da629cd5c23d9
--- /dev/null
+++ b/third_party/crazy_linker/crazy_linker/src/crazy_linker_proc_maps.cpp
@@ -0,0 +1,301 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "crazy_linker_proc_maps.h"
+
+#include <inttypes.h>
+#include <limits.h>
+
+#include "elf_traits.h"
+#include "crazy_linker_debug.h"
+#include "crazy_linker_line_reader.h"
+#include "crazy_linker_util.h"
+#include "crazy_linker_system.h"
+
+namespace crazy {
+
+namespace {
+
+// Decompose the components of a /proc/$PID/maps file into multiple
+// components. |line| should be the address of a zero-terminated line
+// of input. On success, returns true and sets |*entry|, false otherwise.
+//
+// IMPORTANT: On success, |entry->path| will point into the input line,
+// the caller will have to copy the string into a different location if
+// it needs to persist it.
+bool ParseProcMapsLine(const char* line,
+ const char* line_end,
+ ProcMaps::Entry* entry) {
+ // Example input lines on a 64-bit system, one cannot assume that
+ // everything is properly sized.
+ //
+ // 00400000-0040b000 r-xp 00000000 08:01 6570708 /bin/cat
+ // 0060a000-0060b000 r--p 0000a000 08:01 6570708 /bin/cat
+ // 0060b000-0060c000 rw-p 0000b000 08:01 6570708 /bin/cat
+ // 01dd0000-01df1000 rw-p 00000000 00:00 0 [heap]
+ // 7f4b8d4d7000-7f4b8e22a000 r--p 00000000 08:01 38666648 /usr/lib/locale/locale-archive
+ // 7f4b8e22a000-7f4b8e3df000 r-xp 00000000 08:01 28836281 /lib/x86_64-linux-gnu/libc-2.15.so
+ // 7f4b8e3df000-7f4b8e5de000 ---p 001b5000 08:01 28836281 /lib/x86_64-linux-gnu/libc-2.15.so
+ // 7f4b8e5de000-7f4b8e5e2000 r--p 001b4000 08:01 28836281 /lib/x86_64-linux-gnu/libc-2.15.so
+ // 7f4b8e5e2000-7f4b8e5e4000 rw-p 001b8000 08:01 28836281 /lib/x86_64-linux-gnu/libc-2.15.so
+ const char* p = line;
+ for (int token = 0; token < 7; ++token) {
+ char separator = (token == 0) ? '-' : ' ';
+ // skip leading token separators first.
+ while (p < line_end && *p == separator)
+ p++;
+
+ // find start and end of current token, and compute start of
+ // next search.
+ const char* tok_start = p;
+ const char* tok_end = static_cast<const char*>(
+ memchr(p, separator, line_end - p));
+ if (!tok_end) {
+ tok_end = line_end;
+ p = line_end;
+ } else {
+ p = tok_end + 1;
+ }
+
+ if (tok_end == tok_start) {
+ if (token == 6) {
+ // empty token can happen for index 6, when there is no path
+ // element on the line. This corresponds to anonymous memory
+ // mapped segments.
+ entry->path = NULL;
+ entry->path_len = 0;
+ break;
+ }
+ return false;
+ }
+
+ switch (token) {
+ case 0: // vma_start
+ entry->vma_start = static_cast<size_t>(
+ strtoumax(tok_start, NULL, 16));
+ break;
+
+ case 1: // vma_end
+ entry->vma_end = static_cast<size_t>(
+ strtoumax(tok_start, NULL, 16));
+ break;
+
+ case 2: // protection bits
+ {
+ int flags = 0;
+ for (const char* t = tok_start; t < tok_end; ++t) {
+ if (*t == 'r')
+ flags |= PROT_READ;
+ if (*t == 'w')
+ flags |= PROT_WRITE;
+ if (*t == 'x')
+ flags |= PROT_EXEC;
+ }
+ entry->prot_flags = flags;
+ }
+ break;
+
+ case 3: // page offset
+ entry->load_offset = static_cast<size_t>(
+ strtoumax(tok_start, NULL, 16)) * PAGE_SIZE;
+ break;
+
+ case 6: // path
+ // Get rid of trailing newlines, if any.
+ while (tok_end > tok_start && tok_end[-1] == '\n')
+ tok_end--;
+ entry->path = tok_start;
+ entry->path_len = tok_end - tok_start;
+ break;
+
+ default: // ignore all other tokens.
+ ;
+ }
+ }
+ return true;
+}
+
+} // namespace
+
+// Internal implementation of ProcMaps class.
+class ProcMapsInternal {
+public:
+ ProcMapsInternal()
+ : index_(0), entries_() {
+ }
+
+ ~ProcMapsInternal() {
+ Reset();
+ }
+
+ bool Open(const char* path) {
+ Reset();
+ LineReader reader(path);
+ index_ = 0;
+ while (reader.GetNextLine()) {
+ ProcMaps::Entry entry;
+ memset(&entry, 0, sizeof(entry));
+ if (!ParseProcMapsLine(reader.line(),
+ reader.line() + reader.length(),
+ &entry)) {
+ // Ignore broken lines.
+ continue;
+ }
+
+ // Reallocate path.
+ const char* old_path = entry.path;
+ if (old_path) {
+ char* new_path = static_cast<char*>(::malloc(entry.path_len + 1));
+ ::memcpy(new_path, old_path, entry.path_len);
+ new_path[entry.path_len] = '\0';
+ entry.path = const_cast<const char*>(new_path);
+ }
+
+ entries_.PushBack(entry);
+ }
+ return true;
+ }
+
+ void Rewind() {
+ index_ = 0;
+ }
+
+ bool GetNextEntry(ProcMaps::Entry* entry) {
+ if (index_ >= entries_.GetCount())
+ return false;
+
+ *entry = entries_[index_++];
+ return true;
+ }
+
+private:
+ void Reset() {
+ for (size_t n = 0; n < entries_.GetCount(); ++n) {
+ ProcMaps::Entry& entry = entries_[n];
+ ::free(const_cast<char*>(entry.path));
+ }
+ entries_.Resize(0);
+ }
+
+ size_t index_;
+ Vector<ProcMaps::Entry> entries_;
+};
+
+ProcMaps::ProcMaps() {
+ internal_ = new ProcMapsInternal();
+ (void) internal_->Open("/proc/self/maps");
+}
+
+ProcMaps::ProcMaps(pid_t pid) {
+ internal_ = new ProcMapsInternal();
+ char maps_file[32];
+ snprintf(maps_file, sizeof maps_file, "/proc/%u/maps", pid);
+ (void) internal_->Open(maps_file);
+}
+
+ProcMaps::~ProcMaps() {
+ delete internal_;
+}
+
+void ProcMaps::Rewind() {
+ internal_->Rewind();
+}
+
+bool ProcMaps::GetNextEntry(Entry* entry) {
+ return internal_->GetNextEntry(entry);
+}
+
+int ProcMaps::GetProtectionFlagsForAddress(void* address) {
+ size_t vma_addr = reinterpret_cast<size_t>(address);
+ internal_->Rewind();
+ ProcMaps::Entry entry;
+ while (internal_->GetNextEntry(&entry)) {
+ if (entry.vma_start <= vma_addr && vma_addr < entry.vma_end)
+ return entry.prot_flags;
+ }
+ return 0;
+}
+
+bool FindElfBinaryForAddress(void* address,
+ uintptr_t* load_address,
+ char* path_buffer,
+ size_t path_buffer_len) {
+ ProcMaps self_maps;
+ ProcMaps::Entry entry;
+
+ uintptr_t addr = reinterpret_cast<uintptr_t>(address);
+
+ while (self_maps.GetNextEntry(&entry)) {
+ if (entry.vma_start <= addr && addr < entry.vma_end) {
+ *load_address = entry.vma_start;
+ if (!entry.path) {
+ LOG("Could not find ELF binary path!?\n");
+ return false;
+ }
+ if (entry.path_len >= path_buffer_len) {
+ LOG("ELF binary path too long: '%s'\n", entry.path);
+ return false;
+ }
+ memcpy(path_buffer, entry.path, entry.path_len);
+ path_buffer[entry.path_len] = '\0';
+ return true;
+ }
+ }
+ return false;
+}
+
+// Returns the current protection bit flags for the page holding a given
+// address. Returns true on success, or false if the address is not mapped.
+bool FindProtectionFlagsForAddress(void* address, int* prot_flags) {
+ ProcMaps self_maps;
+ ProcMaps::Entry entry;
+
+ uintptr_t addr = reinterpret_cast<uintptr_t>(address);
+
+ while (self_maps.GetNextEntry(&entry)) {
+ if (entry.vma_start <= addr && addr < entry.vma_end) {
+ *prot_flags = entry.prot_flags;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool FindLoadAddressForFile(const char* file_name,
+ uintptr_t* load_address,
+ uintptr_t* load_offset) {
+ size_t file_name_len = strlen(file_name);
+ bool is_base_name = (strchr(file_name, '/') == NULL);
+ ProcMaps self_maps;
+ ProcMaps::Entry entry;
+
+ while (self_maps.GetNextEntry(&entry)) {
+ // Skip vDSO et al.
+ if (entry.path_len == 0 || entry.path[0] == '[')
+ continue;
+
+ const char* entry_name = entry.path;
+ size_t entry_len = entry.path_len;
+
+ if (is_base_name) {
+ const char* p = reinterpret_cast<const char*>(
+ ::memrchr(entry.path, '/', entry.path_len));
+ if (p) {
+ entry_name = p + 1;
+ entry_len = entry.path_len - (p - entry.path) - 1;
+ }
+ }
+
+ if (file_name_len == entry_len &&
+ !memcmp(file_name, entry_name, entry_len)) {
+ *load_address = entry.vma_start;
+ *load_offset = entry.load_offset;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+} // namespace crazy

Powered by Google App Engine
This is Rietveld 408576698