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