1 //===-- HexagonDYLDRendezvous.cpp -------------------------------*- C++ -*-===// 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 23 using namespace lldb; 24 using namespace lldb_private; 25 26 /// Locates the address of the rendezvous structure. Returns the address on 27 /// success and LLDB_INVALID_ADDRESS on failure. 28 static 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 48 HexagonDYLDRendezvous::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 53 // Cache a copy of the executable path 54 if (m_process) { 55 Module *exe_mod = m_process->GetTarget().GetExecutableModulePointer(); 56 if (exe_mod) 57 exe_mod->GetFileSpec().GetPath(m_exe_path, PATH_MAX); 58 } 59 } 60 61 bool HexagonDYLDRendezvous::Resolve() { 62 const size_t word_size = 4; 63 Rendezvous info; 64 size_t address_size; 65 size_t padding; 66 addr_t info_addr; 67 addr_t cursor; 68 69 address_size = m_process->GetAddressByteSize(); 70 padding = address_size - word_size; 71 72 if (m_rendezvous_addr == LLDB_INVALID_ADDRESS) 73 cursor = info_addr = ResolveRendezvousAddress(m_process); 74 else 75 cursor = info_addr = m_rendezvous_addr; 76 77 if (cursor == LLDB_INVALID_ADDRESS) 78 return false; 79 80 if (!(cursor = ReadWord(cursor, &info.version, word_size))) 81 return false; 82 83 if (!(cursor = ReadPointer(cursor + padding, &info.map_addr))) 84 return false; 85 86 if (!(cursor = ReadPointer(cursor, &info.brk))) 87 return false; 88 89 if (!(cursor = ReadWord(cursor, &info.state, word_size))) 90 return false; 91 92 if (!(cursor = ReadPointer(cursor + padding, &info.ldbase))) 93 return false; 94 95 // The rendezvous was successfully read. Update our internal state. 96 m_rendezvous_addr = info_addr; 97 m_previous = m_current; 98 m_current = info; 99 100 return UpdateSOEntries(); 101 } 102 103 void HexagonDYLDRendezvous::SetRendezvousAddress(lldb::addr_t addr) { 104 m_rendezvous_addr = addr; 105 } 106 107 bool HexagonDYLDRendezvous::IsValid() { 108 return m_rendezvous_addr != LLDB_INVALID_ADDRESS; 109 } 110 111 bool HexagonDYLDRendezvous::UpdateSOEntries() { 112 SOEntry entry; 113 114 if (m_current.map_addr == 0) 115 return false; 116 117 // When the previous and current states are consistent this is the first time 118 // we have been asked to update. Just take a snapshot of the currently 119 // loaded modules. 120 if (m_previous.state == eConsistent && m_current.state == eConsistent) 121 return TakeSnapshot(m_soentries); 122 123 // If we are about to add or remove a shared object clear out the current 124 // state and take a snapshot of the currently loaded images. 125 if (m_current.state == eAdd || m_current.state == eDelete) { 126 // this is a fudge so that we can clear the assert below. 127 m_previous.state = eConsistent; 128 // We hit this assert on the 2nd run of this function after running the 129 // calc example 130 assert(m_previous.state == eConsistent); 131 m_soentries.clear(); 132 m_added_soentries.clear(); 133 m_removed_soentries.clear(); 134 return TakeSnapshot(m_soentries); 135 } 136 assert(m_current.state == eConsistent); 137 138 // Otherwise check the previous state to determine what to expect and update 139 // accordingly. 140 if (m_previous.state == eAdd) 141 return UpdateSOEntriesForAddition(); 142 else if (m_previous.state == eDelete) 143 return UpdateSOEntriesForDeletion(); 144 145 return false; 146 } 147 148 bool HexagonDYLDRendezvous::UpdateSOEntriesForAddition() { 149 SOEntry entry; 150 iterator pos; 151 152 assert(m_previous.state == eAdd); 153 154 if (m_current.map_addr == 0) 155 return false; 156 157 for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) { 158 if (!ReadSOEntryFromMemory(cursor, entry)) 159 return false; 160 161 // Only add shared libraries and not the executable. On Linux this is 162 // indicated by an empty path in the entry. On FreeBSD it is the name of 163 // the executable. 164 if (entry.path.empty() || ::strcmp(entry.path.c_str(), m_exe_path) == 0) 165 continue; 166 167 pos = std::find(m_soentries.begin(), m_soentries.end(), entry); 168 if (pos == m_soentries.end()) { 169 m_soentries.push_back(entry); 170 m_added_soentries.push_back(entry); 171 } 172 } 173 174 return true; 175 } 176 177 bool 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 pos = std::find(entry_list.begin(), entry_list.end(), *I); 188 if (pos == entry_list.end()) 189 m_removed_soentries.push_back(*I); 190 } 191 192 m_soentries = entry_list; 193 return true; 194 } 195 196 bool HexagonDYLDRendezvous::TakeSnapshot(SOEntryList &entry_list) { 197 SOEntry entry; 198 199 if (m_current.map_addr == 0) 200 return false; 201 202 for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) { 203 if (!ReadSOEntryFromMemory(cursor, entry)) 204 return false; 205 206 // Only add shared libraries and not the executable. On Linux this is 207 // indicated by an empty path in the entry. On FreeBSD it is the name of 208 // the executable. 209 if (entry.path.empty() || ::strcmp(entry.path.c_str(), m_exe_path) == 0) 210 continue; 211 212 entry_list.push_back(entry); 213 } 214 215 return true; 216 } 217 218 addr_t HexagonDYLDRendezvous::ReadWord(addr_t addr, uint64_t *dst, 219 size_t size) { 220 Status error; 221 222 *dst = m_process->ReadUnsignedIntegerFromMemory(addr, size, 0, error); 223 if (error.Fail()) 224 return 0; 225 226 return addr + size; 227 } 228 229 addr_t HexagonDYLDRendezvous::ReadPointer(addr_t addr, addr_t *dst) { 230 Status error; 231 232 *dst = m_process->ReadPointerFromMemory(addr, error); 233 if (error.Fail()) 234 return 0; 235 236 return addr + m_process->GetAddressByteSize(); 237 } 238 239 std::string HexagonDYLDRendezvous::ReadStringFromMemory(addr_t addr) { 240 std::string str; 241 Status error; 242 size_t size; 243 char c; 244 245 if (addr == LLDB_INVALID_ADDRESS) 246 return std::string(); 247 248 for (;;) { 249 size = m_process->DoReadMemory(addr, &c, 1, error); 250 if (size != 1 || error.Fail()) 251 return std::string(); 252 if (c == 0) 253 break; 254 else { 255 str.push_back(c); 256 addr++; 257 } 258 } 259 260 return str; 261 } 262 263 bool HexagonDYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, 264 SOEntry &entry) { 265 entry.clear(); 266 entry.link_addr = addr; 267 268 if (!(addr = ReadPointer(addr, &entry.base_addr))) 269 return false; 270 271 if (!(addr = ReadPointer(addr, &entry.path_addr))) 272 return false; 273 274 if (!(addr = ReadPointer(addr, &entry.dyn_addr))) 275 return false; 276 277 if (!(addr = ReadPointer(addr, &entry.next))) 278 return false; 279 280 if (!(addr = ReadPointer(addr, &entry.prev))) 281 return false; 282 283 entry.path = ReadStringFromMemory(entry.path_addr); 284 285 return true; 286 } 287 288 bool HexagonDYLDRendezvous::FindMetadata(const char *name, PThreadField field, 289 uint32_t &value) { 290 Target &target = m_process->GetTarget(); 291 292 SymbolContextList list; 293 if (!target.GetImages().FindSymbolsWithNameAndType(ConstString(name), 294 eSymbolTypeAny, list)) 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 bytes 310 311 return true; 312 } 313 314 const HexagonDYLDRendezvous::ThreadInfo & 315 HexagonDYLDRendezvous::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 335 void HexagonDYLDRendezvous::DumpToLog(Log *log) const { 336 int state = GetState(); 337 338 if (!log) 339 return; 340 341 log->PutCString("HexagonDYLDRendezvous:"); 342 log->Printf(" Address: %" PRIx64, GetRendezvousAddress()); 343 log->Printf(" Version: %" PRIu64, GetVersion()); 344 log->Printf(" Link : %" PRIx64, GetLinkMapAddress()); 345 log->Printf(" Break : %" PRIx64, GetBreakAddress()); 346 log->Printf(" LDBase : %" PRIx64, GetLDBase()); 347 log->Printf(" State : %s", 348 (state == eConsistent) 349 ? "consistent" 350 : (state == eAdd) ? "add" : (state == eDelete) ? "delete" 351 : "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 log->Printf("\n SOEntry [%d] %s", i, I->path.c_str()); 361 log->Printf(" Base : %" PRIx64, I->base_addr); 362 log->Printf(" Path : %" PRIx64, I->path_addr); 363 log->Printf(" Dyn : %" PRIx64, I->dyn_addr); 364 log->Printf(" Next : %" PRIx64, I->next); 365 log->Printf(" Prev : %" PRIx64, I->prev); 366 } 367 } 368