|  | // Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file | 
|  | // for details. All rights reserved. Use of this source code is governed by a | 
|  | // BSD-style license that can be found in the LICENSE file. | 
|  |  | 
|  | #include "vm/globals.h" | 
|  | #if defined(DART_HOST_OS_FUCHSIA) | 
|  |  | 
|  | #include "platform/memory_sanitizer.h" | 
|  | #include "vm/native_symbol.h" | 
|  |  | 
|  | #include <dlfcn.h>   // NOLINT | 
|  |  | 
|  | namespace dart { | 
|  |  | 
|  | // On Fuchsia, in lieu of the ELF dynamic symbol table consumed through dladdr, | 
|  | // we consumes symbols produced by //topaz/runtime/dart/profiler_symbols and | 
|  | // provided to the VM by the embedder through Dart_AddSymbols. They have the | 
|  | // format | 
|  | // | 
|  | // struct { | 
|  | //    uint32_t num_entries; | 
|  | //    struct { | 
|  | //      uint32_t offset; | 
|  | //      uint32_t size; | 
|  | //      uint32_t string_table_offset; | 
|  | //    } entries[num_entries]; | 
|  | //    const char* string_table; | 
|  | // } | 
|  | // | 
|  | // Entries are sorted by offset. String table entries are NUL-terminated. | 
|  | class NativeSymbols { | 
|  | public: | 
|  | NativeSymbols(const char* dso_name, void* buffer, size_t size) | 
|  | : next_(NULL), dso_name_(dso_name) { | 
|  | num_entries_ = *reinterpret_cast<uint32_t*>(buffer); | 
|  | entries_ = | 
|  | reinterpret_cast<Entry*>(reinterpret_cast<uint32_t*>(buffer) + 1); | 
|  | name_table_ = reinterpret_cast<const char*>(entries_ + num_entries_); | 
|  | } | 
|  |  | 
|  | NativeSymbols* next() const { return next_; } | 
|  | void set_next(NativeSymbols* symbols) { next_ = symbols; } | 
|  |  | 
|  | bool Lookup(const char* dso_name, | 
|  | uword dso_offset, | 
|  | uword* start_offset, | 
|  | const char** name) { | 
|  | if (strcmp(dso_name, dso_name_) != 0) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | intptr_t lo = 0; | 
|  | intptr_t hi = num_entries_ - 1; | 
|  | while (lo <= hi) { | 
|  | intptr_t mid = (hi - lo + 1) / 2 + lo; | 
|  | ASSERT(mid >= lo); | 
|  | ASSERT(mid <= hi); | 
|  | const Entry& entry = entries_[mid]; | 
|  | if (dso_offset < entry.offset) { | 
|  | hi = mid - 1; | 
|  | } else if (dso_offset >= (entry.offset + entry.size)) { | 
|  | lo = mid + 1; | 
|  | } else { | 
|  | *start_offset = entry.offset; | 
|  | *name = &name_table_[entry.name_offset]; | 
|  | return true; | 
|  | } | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | private: | 
|  | struct Entry { | 
|  | uint32_t offset; | 
|  | uint32_t size; | 
|  | uint32_t name_offset; | 
|  | }; | 
|  |  | 
|  | NativeSymbols* next_; | 
|  | const char* const dso_name_; | 
|  | intptr_t num_entries_; | 
|  | Entry* entries_; | 
|  | const char* name_table_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(NativeSymbols); | 
|  | }; | 
|  |  | 
|  | static NativeSymbols* symbols_ = NULL; | 
|  |  | 
|  | void NativeSymbolResolver::Init() {} | 
|  |  | 
|  | void NativeSymbolResolver::Cleanup() { | 
|  | NativeSymbols* symbols = symbols_; | 
|  | symbols_ = NULL; | 
|  | while (symbols != NULL) { | 
|  | NativeSymbols* next = symbols->next(); | 
|  | delete symbols; | 
|  | symbols = next; | 
|  | } | 
|  | } | 
|  |  | 
|  | char* NativeSymbolResolver::LookupSymbolName(uword pc, uword* start) { | 
|  | Dl_info info; | 
|  | int r = dladdr(reinterpret_cast<void*>(pc), &info); | 
|  | if (r == 0) { | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | auto const dso_name = info.dli_fname; | 
|  | const auto dso_base = reinterpret_cast<uword>(info.dli_fbase); | 
|  | const auto dso_offset = pc - dso_base; | 
|  |  | 
|  | for (NativeSymbols* symbols = symbols_; symbols != NULL; | 
|  | symbols = symbols->next()) { | 
|  | uword symbol_start_offset; | 
|  | const char* symbol_name; | 
|  | if (symbols->Lookup(dso_name, dso_offset, &symbol_start_offset, | 
|  | &symbol_name)) { | 
|  | if (start != NULL) { | 
|  | *start = symbol_start_offset + dso_base; | 
|  | } | 
|  | return strdup(symbol_name); | 
|  | } | 
|  | } | 
|  |  | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | void NativeSymbolResolver::FreeSymbolName(char* name) { | 
|  | free(name); | 
|  | } | 
|  |  | 
|  | bool NativeSymbolResolver::LookupSharedObject(uword pc, | 
|  | uword* dso_base, | 
|  | char** dso_name) { | 
|  | Dl_info info; | 
|  | int r = dladdr(reinterpret_cast<void*>(pc), &info); | 
|  | if (r == 0) { | 
|  | return false; | 
|  | } | 
|  | if (dso_base != nullptr) { | 
|  | *dso_base = reinterpret_cast<uword>(info.dli_fbase); | 
|  | } | 
|  | if (dso_name != nullptr) { | 
|  | *dso_name = strdup(info.dli_fname); | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void NativeSymbolResolver::AddSymbols(const char* dso_name, | 
|  | void* buffer, size_t size) { | 
|  | NativeSymbols* symbols = new NativeSymbols(dso_name, buffer, size); | 
|  | symbols->set_next(symbols_); | 
|  | symbols_ = symbols; | 
|  | } | 
|  |  | 
|  | }  // namespace dart | 
|  |  | 
|  | #endif  // defined(DART_HOST_OS_FUCHSIA) |