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