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 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 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 65 bool 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 107 void HexagonDYLDRendezvous::SetRendezvousAddress(lldb::addr_t addr) { 108 m_rendezvous_addr = addr; 109 } 110 111 bool HexagonDYLDRendezvous::IsValid() { 112 return m_rendezvous_addr != LLDB_INVALID_ADDRESS; 113 } 114 115 bool 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 152 bool 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 pos = std::find(m_soentries.begin(), m_soentries.end(), entry); 172 if (pos == m_soentries.end()) { 173 m_soentries.push_back(entry); 174 m_added_soentries.push_back(entry); 175 } 176 } 177 178 return true; 179 } 180 181 bool HexagonDYLDRendezvous::UpdateSOEntriesForDeletion() { 182 SOEntryList entry_list; 183 iterator pos; 184 185 assert(m_previous.state == eDelete); 186 187 if (!TakeSnapshot(entry_list)) 188 return false; 189 190 for (iterator I = begin(); I != end(); ++I) { 191 pos = std::find(entry_list.begin(), entry_list.end(), *I); 192 if (pos == entry_list.end()) 193 m_removed_soentries.push_back(*I); 194 } 195 196 m_soentries = entry_list; 197 return true; 198 } 199 200 bool HexagonDYLDRendezvous::TakeSnapshot(SOEntryList &entry_list) { 201 SOEntry entry; 202 203 if (m_current.map_addr == 0) 204 return false; 205 206 for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) { 207 if (!ReadSOEntryFromMemory(cursor, entry)) 208 return false; 209 210 // Only add shared libraries and not the executable. On Linux this is 211 // indicated by an empty path in the entry. On FreeBSD it is the name of 212 // the executable. 213 if (entry.path.empty() || ::strcmp(entry.path.c_str(), m_exe_path) == 0) 214 continue; 215 216 entry_list.push_back(entry); 217 } 218 219 return true; 220 } 221 222 addr_t HexagonDYLDRendezvous::ReadWord(addr_t addr, uint64_t *dst, 223 size_t size) { 224 Status error; 225 226 *dst = m_process->ReadUnsignedIntegerFromMemory(addr, size, 0, error); 227 if (error.Fail()) 228 return 0; 229 230 return addr + size; 231 } 232 233 addr_t HexagonDYLDRendezvous::ReadPointer(addr_t addr, addr_t *dst) { 234 Status error; 235 236 *dst = m_process->ReadPointerFromMemory(addr, error); 237 if (error.Fail()) 238 return 0; 239 240 return addr + m_process->GetAddressByteSize(); 241 } 242 243 std::string HexagonDYLDRendezvous::ReadStringFromMemory(addr_t addr) { 244 std::string str; 245 Status error; 246 size_t size; 247 char c; 248 249 if (addr == LLDB_INVALID_ADDRESS) 250 return std::string(); 251 252 for (;;) { 253 size = m_process->ReadMemory(addr, &c, 1, error); 254 if (size != 1 || error.Fail()) 255 return std::string(); 256 if (c == 0) 257 break; 258 else { 259 str.push_back(c); 260 addr++; 261 } 262 } 263 264 return str; 265 } 266 267 bool HexagonDYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, 268 SOEntry &entry) { 269 entry.clear(); 270 entry.link_addr = addr; 271 272 if (!(addr = ReadPointer(addr, &entry.base_addr))) 273 return false; 274 275 if (!(addr = ReadPointer(addr, &entry.path_addr))) 276 return false; 277 278 if (!(addr = ReadPointer(addr, &entry.dyn_addr))) 279 return false; 280 281 if (!(addr = ReadPointer(addr, &entry.next))) 282 return false; 283 284 if (!(addr = ReadPointer(addr, &entry.prev))) 285 return false; 286 287 entry.path = ReadStringFromMemory(entry.path_addr); 288 289 return true; 290 } 291 292 bool HexagonDYLDRendezvous::FindMetadata(const char *name, PThreadField field, 293 uint32_t &value) { 294 Target &target = m_process->GetTarget(); 295 296 SymbolContextList list; 297 target.GetImages().FindSymbolsWithNameAndType(ConstString(name), 298 eSymbolTypeAny, list); 299 if (list.IsEmpty()) 300 return false; 301 302 Address address = list[0].symbol->GetAddress(); 303 addr_t addr = address.GetLoadAddress(&target); 304 if (addr == LLDB_INVALID_ADDRESS) 305 return false; 306 307 Status error; 308 value = (uint32_t)m_process->ReadUnsignedIntegerFromMemory( 309 addr + field * sizeof(uint32_t), sizeof(uint32_t), 0, error); 310 if (error.Fail()) 311 return false; 312 313 if (field == eSize) 314 value /= 8; // convert bits to bytes 315 316 return true; 317 } 318 319 const HexagonDYLDRendezvous::ThreadInfo & 320 HexagonDYLDRendezvous::GetThreadInfo() { 321 if (!m_thread_info.valid) { 322 bool ok = true; 323 324 ok &= FindMetadata("_thread_db_pthread_dtvp", eOffset, 325 m_thread_info.dtv_offset); 326 ok &= 327 FindMetadata("_thread_db_dtv_dtv", eSize, m_thread_info.dtv_slot_size); 328 ok &= FindMetadata("_thread_db_link_map_l_tls_modid", eOffset, 329 m_thread_info.modid_offset); 330 ok &= FindMetadata("_thread_db_dtv_t_pointer_val", eOffset, 331 m_thread_info.tls_offset); 332 333 if (ok) 334 m_thread_info.valid = true; 335 } 336 337 return m_thread_info; 338 } 339 340 void HexagonDYLDRendezvous::DumpToLog(Log *log) const { 341 int state = GetState(); 342 343 if (!log) 344 return; 345 346 log->PutCString("HexagonDYLDRendezvous:"); 347 LLDB_LOGF(log, " Address: %" PRIx64, GetRendezvousAddress()); 348 LLDB_LOGF(log, " Version: %" PRIu64, GetVersion()); 349 LLDB_LOGF(log, " Link : %" PRIx64, GetLinkMapAddress()); 350 LLDB_LOGF(log, " Break : %" PRIx64, GetBreakAddress()); 351 LLDB_LOGF(log, " LDBase : %" PRIx64, GetLDBase()); 352 LLDB_LOGF(log, " State : %s", 353 (state == eConsistent) 354 ? "consistent" 355 : (state == eAdd) ? "add" 356 : (state == eDelete) ? "delete" : "unknown"); 357 358 iterator I = begin(); 359 iterator E = end(); 360 361 if (I != E) 362 log->PutCString("HexagonDYLDRendezvous SOEntries:"); 363 364 for (int i = 1; I != E; ++I, ++i) { 365 LLDB_LOGF(log, "\n SOEntry [%d] %s", i, I->path.c_str()); 366 LLDB_LOGF(log, " Base : %" PRIx64, I->base_addr); 367 LLDB_LOGF(log, " Path : %" PRIx64, I->path_addr); 368 LLDB_LOGF(log, " Dyn : %" PRIx64, I->dyn_addr); 369 LLDB_LOGF(log, " Next : %" PRIx64, I->next); 370 LLDB_LOGF(log, " Prev : %" PRIx64, I->prev); 371 } 372 } 373