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/Target/Process.h" 18 #include "lldb/Target/Target.h" 19 20 #include "DYLDRendezvous.h" 21 22 using namespace lldb; 23 using namespace lldb_private; 24 25 /// Locates the address of the rendezvous structure. Returns the address on 26 /// success and LLDB_INVALID_ADDRESS on failure. 27 static addr_t 28 ResolveRendezvousAddress(Process *process) 29 { 30 addr_t info_location; 31 addr_t info_addr; 32 Error error; 33 size_t size; 34 35 info_location = process->GetImageInfoAddress(); 36 37 if (info_location == LLDB_INVALID_ADDRESS) 38 return LLDB_INVALID_ADDRESS; 39 40 info_addr = 0; 41 size = process->DoReadMemory(info_location, &info_addr, 42 process->GetAddressByteSize(), error); 43 if (size != process->GetAddressByteSize() || error.Fail()) 44 return LLDB_INVALID_ADDRESS; 45 46 if (info_addr == 0) 47 return LLDB_INVALID_ADDRESS; 48 49 return info_addr; 50 } 51 52 DYLDRendezvous::DYLDRendezvous(Process *process) 53 : m_process(process), 54 m_rendezvous_addr(LLDB_INVALID_ADDRESS), 55 m_current(), 56 m_previous(), 57 m_soentries(), 58 m_added_soentries(), 59 m_removed_soentries() 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 70 bool 71 DYLDRendezvous::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 = ReadMemory(cursor, &info.version, word_size))) 92 return false; 93 94 if (!(cursor = ReadMemory(cursor + padding, &info.map_addr, address_size))) 95 return false; 96 97 if (!(cursor = ReadMemory(cursor, &info.brk, address_size))) 98 return false; 99 100 if (!(cursor = ReadMemory(cursor, &info.state, word_size))) 101 return false; 102 103 if (!(cursor = ReadMemory(cursor + padding, &info.ldbase, address_size))) 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 114 bool 115 DYLDRendezvous::IsValid() 116 { 117 return m_rendezvous_addr != LLDB_INVALID_ADDRESS; 118 } 119 120 bool 121 DYLDRendezvous::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 156 bool 157 DYLDRendezvous::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 189 bool 190 DYLDRendezvous::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 211 bool 212 DYLDRendezvous::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 236 addr_t 237 DYLDRendezvous::ReadMemory(addr_t addr, void *dst, size_t size) 238 { 239 size_t bytes_read; 240 Error error; 241 242 bytes_read = m_process->DoReadMemory(addr, dst, size, error); 243 if (bytes_read != size || error.Fail()) 244 return 0; 245 246 return addr + bytes_read; 247 } 248 249 std::string 250 DYLDRendezvous::ReadStringFromMemory(addr_t addr) 251 { 252 std::string str; 253 Error error; 254 size_t size; 255 char c; 256 257 if (addr == LLDB_INVALID_ADDRESS) 258 return std::string(); 259 260 for (;;) { 261 size = m_process->DoReadMemory(addr, &c, 1, error); 262 if (size != 1 || error.Fail()) 263 return std::string(); 264 if (c == 0) 265 break; 266 else { 267 str.push_back(c); 268 addr++; 269 } 270 } 271 272 return str; 273 } 274 275 bool 276 DYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry) 277 { 278 size_t address_size = m_process->GetAddressByteSize(); 279 280 entry.clear(); 281 282 if (!(addr = ReadMemory(addr, &entry.base_addr, address_size))) 283 return false; 284 285 if (!(addr = ReadMemory(addr, &entry.path_addr, address_size))) 286 return false; 287 288 if (!(addr = ReadMemory(addr, &entry.dyn_addr, address_size))) 289 return false; 290 291 if (!(addr = ReadMemory(addr, &entry.next, address_size))) 292 return false; 293 294 if (!(addr = ReadMemory(addr, &entry.prev, address_size))) 295 return false; 296 297 entry.path = ReadStringFromMemory(entry.path_addr); 298 299 return true; 300 } 301 302 void 303 DYLDRendezvous::DumpToLog(Log *log) const 304 { 305 int state = GetState(); 306 307 if (!log) 308 return; 309 310 log->PutCString("DYLDRendezvous:"); 311 log->Printf(" Address: %" PRIx64, GetRendezvousAddress()); 312 log->Printf(" Version: %" PRIu64, GetVersion()); 313 log->Printf(" Link : %" PRIx64, GetLinkMapAddress()); 314 log->Printf(" Break : %" PRIx64, GetBreakAddress()); 315 log->Printf(" LDBase : %" PRIx64, GetLDBase()); 316 log->Printf(" State : %s", 317 (state == eConsistent) ? "consistent" : 318 (state == eAdd) ? "add" : 319 (state == eDelete) ? "delete" : "unknown"); 320 321 iterator I = begin(); 322 iterator E = end(); 323 324 if (I != E) 325 log->PutCString("DYLDRendezvous SOEntries:"); 326 327 for (int i = 1; I != E; ++I, ++i) 328 { 329 log->Printf("\n SOEntry [%d] %s", i, I->path.c_str()); 330 log->Printf(" Base : %" PRIx64, I->base_addr); 331 log->Printf(" Path : %" PRIx64, I->path_addr); 332 log->Printf(" Dyn : %" PRIx64, I->dyn_addr); 333 log->Printf(" Next : %" PRIx64, I->next); 334 log->Printf(" Prev : %" PRIx64, I->prev); 335 } 336 } 337