brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.1 KiB · 62c0fb0 Raw
368 lines · cpp
1//===-- HexagonDYLDRendezvous.cpp -----------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Core/Module.h"10#include "lldb/Symbol/ObjectFile.h"11#include "lldb/Symbol/Symbol.h"12#include "lldb/Symbol/SymbolContext.h"13#include "lldb/Target/Process.h"14#include "lldb/Target/Target.h"15#include "lldb/Utility/Log.h"16#include "lldb/Utility/Status.h"17 18#include "HexagonDYLDRendezvous.h"19 20using namespace lldb;21using namespace lldb_private;22 23/// Locates the address of the rendezvous structure.  Returns the address on24/// success and LLDB_INVALID_ADDRESS on failure.25static addr_t ResolveRendezvousAddress(Process *process) {26  addr_t info_location;27  addr_t info_addr;28  Status error;29 30  info_location = process->GetImageInfoAddress();31 32  if (info_location == LLDB_INVALID_ADDRESS)33    return LLDB_INVALID_ADDRESS;34 35  info_addr = process->ReadPointerFromMemory(info_location, error);36  if (error.Fail())37    return LLDB_INVALID_ADDRESS;38 39  if (info_addr == 0)40    return LLDB_INVALID_ADDRESS;41 42  return info_addr;43}44 45HexagonDYLDRendezvous::HexagonDYLDRendezvous(Process *process)46    : m_process(process), m_rendezvous_addr(LLDB_INVALID_ADDRESS), m_current(),47      m_previous(), m_soentries(), m_added_soentries(), m_removed_soentries() {48  m_thread_info.valid = false;49  m_thread_info.dtv_offset = 0;50  m_thread_info.dtv_slot_size = 0;51  m_thread_info.modid_offset = 0;52  m_thread_info.tls_offset = 0;53 54  // Cache a copy of the executable path55  if (m_process) {56    Module *exe_mod = m_process->GetTarget().GetExecutableModulePointer();57    if (exe_mod)58      exe_mod->GetFileSpec().GetPath(m_exe_path, PATH_MAX);59  }60}61 62bool HexagonDYLDRendezvous::Resolve() {63  const size_t word_size = 4;64  Rendezvous info;65  size_t address_size;66  size_t padding;67  addr_t info_addr;68  addr_t cursor;69 70  address_size = m_process->GetAddressByteSize();71  padding = address_size - word_size;72 73  if (m_rendezvous_addr == LLDB_INVALID_ADDRESS)74    cursor = info_addr = ResolveRendezvousAddress(m_process);75  else76    cursor = info_addr = m_rendezvous_addr;77 78  if (cursor == LLDB_INVALID_ADDRESS)79    return false;80 81  if (!(cursor = ReadWord(cursor, &info.version, word_size)))82    return false;83 84  if (!(cursor = ReadPointer(cursor + padding, &info.map_addr)))85    return false;86 87  if (!(cursor = ReadPointer(cursor, &info.brk)))88    return false;89 90  if (!(cursor = ReadWord(cursor, &info.state, word_size)))91    return false;92 93  if (!(cursor = ReadPointer(cursor + padding, &info.ldbase)))94    return false;95 96  // The rendezvous was successfully read.  Update our internal state.97  m_rendezvous_addr = info_addr;98  m_previous = m_current;99  m_current = info;100 101  return UpdateSOEntries();102}103 104void HexagonDYLDRendezvous::SetRendezvousAddress(lldb::addr_t addr) {105  m_rendezvous_addr = addr;106}107 108bool HexagonDYLDRendezvous::IsValid() {109  return m_rendezvous_addr != LLDB_INVALID_ADDRESS;110}111 112bool HexagonDYLDRendezvous::UpdateSOEntries() {113  SOEntry entry;114 115  if (m_current.map_addr == 0)116    return false;117 118  // When the previous and current states are consistent this is the first time119  // we have been asked to update.  Just take a snapshot of the currently120  // loaded modules.121  if (m_previous.state == eConsistent && m_current.state == eConsistent)122    return TakeSnapshot(m_soentries);123 124  // If we are about to add or remove a shared object clear out the current125  // state and take a snapshot of the currently loaded images.126  if (m_current.state == eAdd || m_current.state == eDelete) {127    // this is a fudge so that we can clear the assert below.128    m_previous.state = eConsistent;129    // We hit this assert on the 2nd run of this function after running the130    // calc example131    assert(m_previous.state == eConsistent);132    m_soentries.clear();133    m_added_soentries.clear();134    m_removed_soentries.clear();135    return TakeSnapshot(m_soentries);136  }137  assert(m_current.state == eConsistent);138 139  // Otherwise check the previous state to determine what to expect and update140  // accordingly.141  if (m_previous.state == eAdd)142    return UpdateSOEntriesForAddition();143  else if (m_previous.state == eDelete)144    return UpdateSOEntriesForDeletion();145 146  return false;147}148 149bool HexagonDYLDRendezvous::UpdateSOEntriesForAddition() {150  SOEntry entry;151  iterator pos;152 153  assert(m_previous.state == eAdd);154 155  if (m_current.map_addr == 0)156    return false;157 158  for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) {159    if (!ReadSOEntryFromMemory(cursor, entry))160      return false;161 162    // Only add shared libraries and not the executable. On Linux this is163    // indicated by an empty path in the entry. On FreeBSD it is the name of164    // the executable.165    if (entry.path.empty() || ::strcmp(entry.path.c_str(), m_exe_path) == 0)166      continue;167 168    if (!llvm::is_contained(m_soentries, entry)) {169      m_soentries.push_back(entry);170      m_added_soentries.push_back(entry);171    }172  }173 174  return true;175}176 177bool HexagonDYLDRendezvous::UpdateSOEntriesForDeletion() {178  SOEntryList entry_list;179  iterator pos;180 181  assert(m_previous.state == eDelete);182 183  if (!TakeSnapshot(entry_list))184    return false;185 186  for (iterator I = begin(); I != end(); ++I) {187    if (!llvm::is_contained(entry_list, *I))188      m_removed_soentries.push_back(*I);189  }190 191  m_soentries = entry_list;192  return true;193}194 195bool HexagonDYLDRendezvous::TakeSnapshot(SOEntryList &entry_list) {196  SOEntry entry;197 198  if (m_current.map_addr == 0)199    return false;200 201  for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) {202    if (!ReadSOEntryFromMemory(cursor, entry))203      return false;204 205    // Only add shared libraries and not the executable. On Linux this is206    // indicated by an empty path in the entry. On FreeBSD it is the name of207    // the executable.208    if (entry.path.empty() || ::strcmp(entry.path.c_str(), m_exe_path) == 0)209      continue;210 211    entry_list.push_back(entry);212  }213 214  return true;215}216 217addr_t HexagonDYLDRendezvous::ReadWord(addr_t addr, uint64_t *dst,218                                       size_t size) {219  Status error;220 221  *dst = m_process->ReadUnsignedIntegerFromMemory(addr, size, 0, error);222  if (error.Fail())223    return 0;224 225  return addr + size;226}227 228addr_t HexagonDYLDRendezvous::ReadPointer(addr_t addr, addr_t *dst) {229  Status error;230 231  *dst = m_process->ReadPointerFromMemory(addr, error);232  if (error.Fail())233    return 0;234 235  return addr + m_process->GetAddressByteSize();236}237 238std::string HexagonDYLDRendezvous::ReadStringFromMemory(addr_t addr) {239  std::string str;240  Status error;241  size_t size;242  char c;243 244  if (addr == LLDB_INVALID_ADDRESS)245    return std::string();246 247  for (;;) {248    size = m_process->ReadMemory(addr, &c, 1, error);249    if (size != 1 || error.Fail())250      return std::string();251    if (c == 0)252      break;253    else {254      str.push_back(c);255      addr++;256    }257  }258 259  return str;260}261 262bool HexagonDYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr,263                                                  SOEntry &entry) {264  entry.clear();265  entry.link_addr = addr;266 267  if (!(addr = ReadPointer(addr, &entry.base_addr)))268    return false;269 270  if (!(addr = ReadPointer(addr, &entry.path_addr)))271    return false;272 273  if (!(addr = ReadPointer(addr, &entry.dyn_addr)))274    return false;275 276  if (!(addr = ReadPointer(addr, &entry.next)))277    return false;278 279  if (!(addr = ReadPointer(addr, &entry.prev)))280    return false;281 282  entry.path = ReadStringFromMemory(entry.path_addr);283 284  return true;285}286 287bool HexagonDYLDRendezvous::FindMetadata(const char *name, PThreadField field,288                                         uint32_t &value) {289  Target &target = m_process->GetTarget();290 291  SymbolContextList list;292  target.GetImages().FindSymbolsWithNameAndType(ConstString(name),293                                                eSymbolTypeAny, list);294  if (list.IsEmpty())295    return false;296 297  Address address = list[0].symbol->GetAddress();298  addr_t addr = address.GetLoadAddress(&target);299  if (addr == LLDB_INVALID_ADDRESS)300    return false;301 302  Status error;303  value = (uint32_t)m_process->ReadUnsignedIntegerFromMemory(304      addr + field * sizeof(uint32_t), sizeof(uint32_t), 0, error);305  if (error.Fail())306    return false;307 308  if (field == eSize)309    value /= 8; // convert bits to bytes310 311  return true;312}313 314const HexagonDYLDRendezvous::ThreadInfo &315HexagonDYLDRendezvous::GetThreadInfo() {316  if (!m_thread_info.valid) {317    bool ok = true;318 319    ok &= FindMetadata("_thread_db_pthread_dtvp", eOffset,320                       m_thread_info.dtv_offset);321    ok &=322        FindMetadata("_thread_db_dtv_dtv", eSize, m_thread_info.dtv_slot_size);323    ok &= FindMetadata("_thread_db_link_map_l_tls_modid", eOffset,324                       m_thread_info.modid_offset);325    ok &= FindMetadata("_thread_db_dtv_t_pointer_val", eOffset,326                       m_thread_info.tls_offset);327 328    if (ok)329      m_thread_info.valid = true;330  }331 332  return m_thread_info;333}334 335void HexagonDYLDRendezvous::DumpToLog(Log *log) const {336  int state = GetState();337 338  if (!log)339    return;340 341  log->PutCString("HexagonDYLDRendezvous:");342  LLDB_LOGF(log, "   Address: %" PRIx64, GetRendezvousAddress());343  LLDB_LOGF(log, "   Version: %" PRIu64, GetVersion());344  LLDB_LOGF(log, "   Link   : %" PRIx64, GetLinkMapAddress());345  LLDB_LOGF(log, "   Break  : %" PRIx64, GetBreakAddress());346  LLDB_LOGF(log, "   LDBase : %" PRIx64, GetLDBase());347  LLDB_LOGF(log, "   State  : %s",348            (state == eConsistent)349                ? "consistent"350                : (state == eAdd) ? "add"351                                  : (state == eDelete) ? "delete" : "unknown");352 353  iterator I = begin();354  iterator E = end();355 356  if (I != E)357    log->PutCString("HexagonDYLDRendezvous SOEntries:");358 359  for (int i = 1; I != E; ++I, ++i) {360    LLDB_LOGF(log, "\n   SOEntry [%d] %s", i, I->path.c_str());361    LLDB_LOGF(log, "      Base : %" PRIx64, I->base_addr);362    LLDB_LOGF(log, "      Path : %" PRIx64, I->path_addr);363    LLDB_LOGF(log, "      Dyn  : %" PRIx64, I->dyn_addr);364    LLDB_LOGF(log, "      Next : %" PRIx64, I->next);365    LLDB_LOGF(log, "      Prev : %" PRIx64, I->prev);366  }367}368