// 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 // 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(buffer); entries_ = reinterpret_cast(reinterpret_cast(buffer) + 1); name_table_ = reinterpret_cast(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(pc), &info); if (r == 0) { return NULL; } auto const dso_name = info.dli_fname; const auto dso_base = reinterpret_cast(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(pc), &info); if (r == 0) { return false; } if (dso_base != nullptr) { *dso_base = reinterpret_cast(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)