1 //===-- DYLDRendezvous.cpp --------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 // C Includes 11 // C++ Includes 12 // Other libraries and framework includes 13 #include "lldb/Core/ArchSpec.h" 14 #include "lldb/Core/Error.h" 15 #include "lldb/Core/Log.h" 16 #include "lldb/Core/Module.h" 17 #include "lldb/Symbol/ObjectFile.h" 18 #include "lldb/Symbol/Symbol.h" 19 #include "lldb/Symbol/SymbolContext.h" 20 #include "lldb/Target/Process.h" 21 #include "lldb/Target/Target.h" 22 23 #include "llvm/Support/Path.h" 24 25 #include "DYLDRendezvous.h" 26 27 using namespace lldb; 28 using namespace lldb_private; 29 30 /// Locates the address of the rendezvous structure. Returns the address on 31 /// success and LLDB_INVALID_ADDRESS on failure. 32 static addr_t 33 ResolveRendezvousAddress(Process *process) 34 { 35 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); 36 addr_t info_location; 37 addr_t info_addr; 38 Error error; 39 40 if (!process) 41 { 42 if (log) 43 log->Printf ("%s null process provided", __FUNCTION__); 44 return LLDB_INVALID_ADDRESS; 45 } 46 47 // Try to get it from our process. This might be a remote process and might 48 // grab it via some remote-specific mechanism. 49 info_location = process->GetImageInfoAddress(); 50 if (log) 51 log->Printf ("%s info_location = 0x%" PRIx64, __FUNCTION__, info_location); 52 53 // If the process fails to return an address, fall back to seeing if the local object file can help us find it. 54 if (info_location == LLDB_INVALID_ADDRESS) 55 { 56 Target *target = &process->GetTarget(); 57 if (target) 58 { 59 ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile(); 60 Address addr = obj_file->GetImageInfoAddress(target); 61 62 if (addr.IsValid()) 63 { 64 info_location = addr.GetLoadAddress(target); 65 if (log) 66 log->Printf ("%s resolved via direct object file approach to 0x%" PRIx64, __FUNCTION__, info_location); 67 } 68 else 69 { 70 if (log) 71 log->Printf ("%s FAILED - direct object file approach did not yield a valid address", __FUNCTION__); 72 } 73 } 74 } 75 76 if (info_location == LLDB_INVALID_ADDRESS) 77 { 78 if (log) 79 log->Printf ("%s FAILED - invalid info address", __FUNCTION__); 80 return LLDB_INVALID_ADDRESS; 81 } 82 83 if (log) 84 log->Printf ("%s reading pointer (%" PRIu32 " bytes) from 0x%" PRIx64, __FUNCTION__, process->GetAddressByteSize(), info_location); 85 86 info_addr = process->ReadPointerFromMemory(info_location, error); 87 if (error.Fail()) 88 { 89 if (log) 90 log->Printf ("%s FAILED - could not read from the info location: %s", __FUNCTION__, error.AsCString ()); 91 return LLDB_INVALID_ADDRESS; 92 } 93 94 if (info_addr == 0) 95 { 96 if (log) 97 log->Printf ("%s FAILED - the rendezvous address contained at 0x%" PRIx64 " returned a null value", __FUNCTION__, info_location); 98 return LLDB_INVALID_ADDRESS; 99 } 100 101 return info_addr; 102 } 103 104 DYLDRendezvous::DYLDRendezvous(Process *process) 105 : m_process(process), 106 m_rendezvous_addr(LLDB_INVALID_ADDRESS), 107 m_current(), 108 m_previous(), 109 m_soentries(), 110 m_added_soentries(), 111 m_removed_soentries() 112 { 113 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); 114 115 m_thread_info.valid = false; 116 117 // Cache a copy of the executable path 118 if (m_process) 119 { 120 Module *exe_mod = m_process->GetTarget().GetExecutableModulePointer(); 121 if (exe_mod) 122 { 123 m_exe_file_spec = exe_mod->GetPlatformFileSpec(); 124 if (log) 125 log->Printf ("DYLDRendezvous::%s exe module executable path set: '%s'", 126 __FUNCTION__, m_exe_file_spec.GetCString()); 127 } 128 else 129 { 130 if (log) 131 log->Printf ("DYLDRendezvous::%s cannot cache exe module path: null executable module pointer", __FUNCTION__); 132 } 133 } 134 } 135 136 bool 137 DYLDRendezvous::Resolve() 138 { 139 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); 140 141 const size_t word_size = 4; 142 Rendezvous info; 143 size_t address_size; 144 size_t padding; 145 addr_t info_addr; 146 addr_t cursor; 147 148 address_size = m_process->GetAddressByteSize(); 149 padding = address_size - word_size; 150 if (log) 151 log->Printf ("DYLDRendezvous::%s address size: %" PRIu64 ", padding %" PRIu64, __FUNCTION__, uint64_t(address_size), uint64_t(padding)); 152 153 if (m_rendezvous_addr == LLDB_INVALID_ADDRESS) 154 cursor = info_addr = ResolveRendezvousAddress(m_process); 155 else 156 cursor = info_addr = m_rendezvous_addr; 157 if (log) 158 log->Printf ("DYLDRendezvous::%s cursor = 0x%" PRIx64, __FUNCTION__, cursor); 159 160 if (cursor == LLDB_INVALID_ADDRESS) 161 return false; 162 163 if (!(cursor = ReadWord(cursor, &info.version, word_size))) 164 return false; 165 166 if (!(cursor = ReadPointer(cursor + padding, &info.map_addr))) 167 return false; 168 169 if (!(cursor = ReadPointer(cursor, &info.brk))) 170 return false; 171 172 if (!(cursor = ReadWord(cursor, &info.state, word_size))) 173 return false; 174 175 if (!(cursor = ReadPointer(cursor + padding, &info.ldbase))) 176 return false; 177 178 // The rendezvous was successfully read. Update our internal state. 179 m_rendezvous_addr = info_addr; 180 m_previous = m_current; 181 m_current = info; 182 183 return UpdateSOEntries(); 184 } 185 186 bool 187 DYLDRendezvous::IsValid() 188 { 189 return m_rendezvous_addr != LLDB_INVALID_ADDRESS; 190 } 191 192 bool 193 DYLDRendezvous::UpdateSOEntries() 194 { 195 SOEntry entry; 196 197 if (m_current.map_addr == 0) 198 return false; 199 200 // When the previous and current states are consistent this is the first 201 // time we have been asked to update. Just take a snapshot of the currently 202 // loaded modules. 203 if (m_previous.state == eConsistent && m_current.state == eConsistent) 204 return TakeSnapshot(m_soentries); 205 206 // If we are about to add or remove a shared object clear out the current 207 // state and take a snapshot of the currently loaded images. 208 if (m_current.state == eAdd || m_current.state == eDelete) 209 { 210 // Some versions of the android dynamic linker might send two 211 // notifications with state == eAdd back to back. Ignore them 212 // until we get an eConsistent notification. 213 if (!(m_previous.state == eConsistent || (m_previous.state == eAdd && m_current.state == eDelete))) 214 return false; 215 216 m_soentries.clear(); 217 m_added_soentries.clear(); 218 m_removed_soentries.clear(); 219 return TakeSnapshot(m_soentries); 220 } 221 assert(m_current.state == eConsistent); 222 223 // Otherwise check the previous state to determine what to expect and update 224 // accordingly. 225 if (m_previous.state == eAdd) 226 return UpdateSOEntriesForAddition(); 227 else if (m_previous.state == eDelete) 228 return UpdateSOEntriesForDeletion(); 229 230 return false; 231 } 232 233 bool 234 DYLDRendezvous::UpdateSOEntriesForAddition() 235 { 236 SOEntry entry; 237 iterator pos; 238 239 assert(m_previous.state == eAdd); 240 241 if (m_current.map_addr == 0) 242 return false; 243 244 for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) 245 { 246 if (!ReadSOEntryFromMemory(cursor, entry)) 247 return false; 248 249 // Only add shared libraries and not the executable. 250 if (SOEntryIsMainExecutable(entry)) 251 continue; 252 253 pos = std::find(m_soentries.begin(), m_soentries.end(), entry); 254 if (pos == m_soentries.end()) 255 { 256 m_soentries.push_back(entry); 257 m_added_soentries.push_back(entry); 258 } 259 } 260 261 return true; 262 } 263 264 bool 265 DYLDRendezvous::UpdateSOEntriesForDeletion() 266 { 267 SOEntryList entry_list; 268 iterator pos; 269 270 assert(m_previous.state == eDelete); 271 272 if (!TakeSnapshot(entry_list)) 273 return false; 274 275 for (iterator I = begin(); I != end(); ++I) 276 { 277 pos = std::find(entry_list.begin(), entry_list.end(), *I); 278 if (pos == entry_list.end()) 279 m_removed_soentries.push_back(*I); 280 } 281 282 m_soentries = entry_list; 283 return true; 284 } 285 286 bool 287 DYLDRendezvous::SOEntryIsMainExecutable(const SOEntry &entry) 288 { 289 // On Linux the executable is indicated by an empty path in the entry. On 290 // FreeBSD and on Android it is the full path to the executable. 291 292 auto triple = m_process->GetTarget().GetArchitecture().GetTriple(); 293 auto os_type = triple.getOS(); 294 auto env_type = triple.getEnvironment(); 295 296 switch (os_type) { 297 case llvm::Triple::FreeBSD: 298 return entry.file_spec == m_exe_file_spec; 299 case llvm::Triple::Linux: 300 switch (env_type) { 301 case llvm::Triple::Android: 302 return entry.file_spec == m_exe_file_spec; 303 default: 304 return !entry.file_spec; 305 } 306 default: 307 return false; 308 } 309 } 310 311 bool 312 DYLDRendezvous::TakeSnapshot(SOEntryList &entry_list) 313 { 314 SOEntry entry; 315 316 if (m_current.map_addr == 0) 317 return false; 318 319 // Clear previous entries since we are about to obtain an up to date list. 320 entry_list.clear(); 321 322 for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) 323 { 324 if (!ReadSOEntryFromMemory(cursor, entry)) 325 return false; 326 327 // Only add shared libraries and not the executable. 328 if (SOEntryIsMainExecutable(entry)) 329 continue; 330 331 entry_list.push_back(entry); 332 } 333 334 return true; 335 } 336 337 addr_t 338 DYLDRendezvous::ReadWord(addr_t addr, uint64_t *dst, size_t size) 339 { 340 Error error; 341 342 *dst = m_process->ReadUnsignedIntegerFromMemory(addr, size, 0, error); 343 if (error.Fail()) 344 return 0; 345 346 return addr + size; 347 } 348 349 addr_t 350 DYLDRendezvous::ReadPointer(addr_t addr, addr_t *dst) 351 { 352 Error error; 353 354 *dst = m_process->ReadPointerFromMemory(addr, error); 355 if (error.Fail()) 356 return 0; 357 358 return addr + m_process->GetAddressByteSize(); 359 } 360 361 std::string 362 DYLDRendezvous::ReadStringFromMemory(addr_t addr) 363 { 364 std::string str; 365 Error error; 366 367 if (addr == LLDB_INVALID_ADDRESS) 368 return std::string(); 369 370 m_process->ReadCStringFromMemory(addr, str, error); 371 372 return str; 373 } 374 375 bool 376 DYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry) 377 { 378 entry.clear(); 379 380 entry.link_addr = addr; 381 382 if (!(addr = ReadPointer(addr, &entry.base_addr))) 383 return false; 384 385 // mips adds an extra load offset field to the link map struct on 386 // FreeBSD and NetBSD (need to validate other OSes). 387 // http://svnweb.freebsd.org/base/head/sys/sys/link_elf.h?revision=217153&view=markup#l57 388 const ArchSpec &arch = m_process->GetTarget().GetArchitecture(); 389 if ((arch.GetTriple().getOS() == llvm::Triple::FreeBSD 390 || arch.GetTriple().getOS() == llvm::Triple::NetBSD) && 391 (arch.GetMachine() == llvm::Triple::mips || arch.GetMachine() == llvm::Triple::mipsel 392 || arch.GetMachine() == llvm::Triple::mips64 || arch.GetMachine() == llvm::Triple::mips64el)) 393 { 394 addr_t mips_l_offs; 395 if (!(addr = ReadPointer(addr, &mips_l_offs))) 396 return false; 397 if (mips_l_offs != 0 && mips_l_offs != entry.base_addr) 398 return false; 399 } 400 401 if (!(addr = ReadPointer(addr, &entry.path_addr))) 402 return false; 403 404 if (!(addr = ReadPointer(addr, &entry.dyn_addr))) 405 return false; 406 407 if (!(addr = ReadPointer(addr, &entry.next))) 408 return false; 409 410 if (!(addr = ReadPointer(addr, &entry.prev))) 411 return false; 412 413 std::string file_path = ReadStringFromMemory(entry.path_addr); 414 entry.file_spec.SetFile(file_path, false); 415 416 // On Android L (5.0, 5.1) the load address of the "/system/bin/linker" isn't filled in 417 // correctly. To get the correct load address we fetch the load address of the file from the 418 // proc file system. 419 if (arch.GetTriple().getEnvironment() == llvm::Triple::Android && entry.base_addr == 0 && 420 (file_path == "/system/bin/linker" || file_path == "/system/bin/linker64")) 421 { 422 lldb::addr_t load_addr = LLDB_INVALID_ADDRESS; 423 bool is_loaded = false; 424 Error error = m_process->GetFileLoadAddress(entry.file_spec, is_loaded, load_addr); 425 if (error.Success() && is_loaded) 426 entry.base_addr = load_addr; 427 } 428 429 return true; 430 } 431 432 433 bool 434 DYLDRendezvous::FindMetadata(const char *name, PThreadField field, uint32_t& value) 435 { 436 Target& target = m_process->GetTarget(); 437 438 SymbolContextList list; 439 if (!target.GetImages().FindSymbolsWithNameAndType (ConstString(name), eSymbolTypeAny, list)) 440 return false; 441 442 Address address = list[0].symbol->GetAddress(); 443 addr_t addr = address.GetLoadAddress (&target); 444 if (addr == LLDB_INVALID_ADDRESS) 445 return false; 446 447 Error error; 448 value = (uint32_t)m_process->ReadUnsignedIntegerFromMemory(addr + field*sizeof(uint32_t), sizeof(uint32_t), 0, error); 449 if (error.Fail()) 450 return false; 451 452 if (field == eSize) 453 value /= 8; // convert bits to bytes 454 455 return true; 456 } 457 458 const DYLDRendezvous::ThreadInfo& 459 DYLDRendezvous::GetThreadInfo() 460 { 461 if (!m_thread_info.valid) 462 { 463 bool ok = true; 464 465 ok &= FindMetadata ("_thread_db_pthread_dtvp", eOffset, m_thread_info.dtv_offset); 466 ok &= FindMetadata ("_thread_db_dtv_dtv", eSize, m_thread_info.dtv_slot_size); 467 ok &= FindMetadata ("_thread_db_link_map_l_tls_modid", eOffset, m_thread_info.modid_offset); 468 ok &= FindMetadata ("_thread_db_dtv_t_pointer_val", eOffset, m_thread_info.tls_offset); 469 470 if (ok) 471 m_thread_info.valid = true; 472 } 473 474 return m_thread_info; 475 } 476 477 void 478 DYLDRendezvous::DumpToLog(Log *log) const 479 { 480 int state = GetState(); 481 482 if (!log) 483 return; 484 485 log->PutCString("DYLDRendezvous:"); 486 log->Printf(" Address: %" PRIx64, GetRendezvousAddress()); 487 log->Printf(" Version: %" PRIu64, GetVersion()); 488 log->Printf(" Link : %" PRIx64, GetLinkMapAddress()); 489 log->Printf(" Break : %" PRIx64, GetBreakAddress()); 490 log->Printf(" LDBase : %" PRIx64, GetLDBase()); 491 log->Printf(" State : %s", 492 (state == eConsistent) ? "consistent" : 493 (state == eAdd) ? "add" : 494 (state == eDelete) ? "delete" : "unknown"); 495 496 iterator I = begin(); 497 iterator E = end(); 498 499 if (I != E) 500 log->PutCString("DYLDRendezvous SOEntries:"); 501 502 for (int i = 1; I != E; ++I, ++i) 503 { 504 log->Printf("\n SOEntry [%d] %s", i, I->file_spec.GetCString()); 505 log->Printf(" Base : %" PRIx64, I->base_addr); 506 log->Printf(" Path : %" PRIx64, I->path_addr); 507 log->Printf(" Dyn : %" PRIx64, I->dyn_addr); 508 log->Printf(" Next : %" PRIx64, I->next); 509 log->Printf(" Prev : %" PRIx64, I->prev); 510 } 511 } 512