1 //===-- DynamicLoaderPOSIX.h ------------------------------------*- 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/PluginManager.h" 14 #include "lldb/Core/Log.h" 15 #include "lldb/Core/Module.h" 16 #include "lldb/Core/ModuleSpec.h" 17 #include "lldb/Core/Section.h" 18 #include "lldb/Symbol/ObjectFile.h" 19 #include "lldb/Target/Process.h" 20 #include "lldb/Target/Target.h" 21 #include "lldb/Target/Thread.h" 22 #include "lldb/Target/ThreadPlanRunToAddress.h" 23 24 #include "AuxVector.h" 25 #include "DynamicLoaderPOSIXDYLD.h" 26 27 using namespace lldb; 28 using namespace lldb_private; 29 30 void 31 DynamicLoaderPOSIXDYLD::Initialize() 32 { 33 PluginManager::RegisterPlugin(GetPluginNameStatic(), 34 GetPluginDescriptionStatic(), 35 CreateInstance); 36 } 37 38 void 39 DynamicLoaderPOSIXDYLD::Terminate() 40 { 41 } 42 43 const char * 44 DynamicLoaderPOSIXDYLD::GetPluginName() 45 { 46 return "DynamicLoaderPOSIXDYLD"; 47 } 48 49 const char * 50 DynamicLoaderPOSIXDYLD::GetShortPluginName() 51 { 52 return "linux-dyld"; 53 } 54 55 const char * 56 DynamicLoaderPOSIXDYLD::GetPluginNameStatic() 57 { 58 return "dynamic-loader.linux-dyld"; 59 } 60 61 const char * 62 DynamicLoaderPOSIXDYLD::GetPluginDescriptionStatic() 63 { 64 return "Dynamic loader plug-in that watches for shared library " 65 "loads/unloads in POSIX processes."; 66 } 67 68 void 69 DynamicLoaderPOSIXDYLD::GetPluginCommandHelp(const char *command, Stream *strm) 70 { 71 } 72 73 uint32_t 74 DynamicLoaderPOSIXDYLD::GetPluginVersion() 75 { 76 return 1; 77 } 78 79 DynamicLoader * 80 DynamicLoaderPOSIXDYLD::CreateInstance(Process *process, bool force) 81 { 82 bool create = force; 83 if (!create) 84 { 85 const llvm::Triple &triple_ref = process->GetTarget().GetArchitecture().GetTriple(); 86 if (triple_ref.getOS() == llvm::Triple::Linux || 87 triple_ref.getOS() == llvm::Triple::FreeBSD) 88 create = true; 89 } 90 91 if (create) 92 return new DynamicLoaderPOSIXDYLD (process); 93 return NULL; 94 } 95 96 DynamicLoaderPOSIXDYLD::DynamicLoaderPOSIXDYLD(Process *process) 97 : DynamicLoader(process), 98 m_rendezvous(process), 99 m_load_offset(LLDB_INVALID_ADDRESS), 100 m_entry_point(LLDB_INVALID_ADDRESS), 101 m_auxv() 102 { 103 } 104 105 DynamicLoaderPOSIXDYLD::~DynamicLoaderPOSIXDYLD() 106 { 107 } 108 109 void 110 DynamicLoaderPOSIXDYLD::DidAttach() 111 { 112 ModuleSP executable; 113 addr_t load_offset; 114 115 m_auxv.reset(new AuxVector(m_process)); 116 117 executable = GetTargetExecutable(); 118 load_offset = ComputeLoadOffset(); 119 120 if (executable.get() && load_offset != LLDB_INVALID_ADDRESS) 121 { 122 ModuleList module_list; 123 module_list.Append(executable); 124 UpdateLoadedSections(executable, load_offset); 125 LoadAllCurrentModules(); 126 m_process->GetTarget().ModulesDidLoad(module_list); 127 } 128 } 129 130 void 131 DynamicLoaderPOSIXDYLD::DidLaunch() 132 { 133 ModuleSP executable; 134 addr_t load_offset; 135 136 m_auxv.reset(new AuxVector(m_process)); 137 138 executable = GetTargetExecutable(); 139 load_offset = ComputeLoadOffset(); 140 141 if (executable.get() && load_offset != LLDB_INVALID_ADDRESS) 142 { 143 ModuleList module_list; 144 module_list.Append(executable); 145 UpdateLoadedSections(executable, load_offset); 146 ProbeEntry(); 147 m_process->GetTarget().ModulesDidLoad(module_list); 148 } 149 } 150 151 ModuleSP 152 DynamicLoaderPOSIXDYLD::GetTargetExecutable() 153 { 154 Target &target = m_process->GetTarget(); 155 ModuleSP executable = target.GetExecutableModule(); 156 157 if (executable.get()) 158 { 159 if (executable->GetFileSpec().Exists()) 160 { 161 ModuleSpec module_spec (executable->GetFileSpec(), executable->GetArchitecture()); 162 ModuleSP module_sp (new Module (module_spec)); 163 164 // Check if the executable has changed and set it to the target executable if they differ. 165 if (module_sp.get() && module_sp->GetUUID().IsValid() && executable->GetUUID().IsValid()) 166 { 167 if (module_sp->GetUUID() != executable->GetUUID()) 168 executable.reset(); 169 } 170 else if (executable->FileHasChanged()) 171 { 172 executable.reset(); 173 } 174 175 if (!executable.get()) 176 { 177 executable = target.GetSharedModule(module_spec); 178 if (executable.get() != target.GetExecutableModulePointer()) 179 { 180 // Don't load dependent images since we are in dyld where we will know 181 // and find out about all images that are loaded 182 const bool get_dependent_images = false; 183 target.SetExecutableModule(executable, get_dependent_images); 184 } 185 } 186 } 187 } 188 return executable; 189 } 190 191 Error 192 DynamicLoaderPOSIXDYLD::ExecutePluginCommand(Args &command, Stream *strm) 193 { 194 return Error(); 195 } 196 197 Log * 198 DynamicLoaderPOSIXDYLD::EnablePluginLogging(Stream *strm, Args &command) 199 { 200 return NULL; 201 } 202 203 Error 204 DynamicLoaderPOSIXDYLD::CanLoadImage() 205 { 206 return Error(); 207 } 208 209 void 210 DynamicLoaderPOSIXDYLD::UpdateLoadedSections(ModuleSP module, addr_t base_addr) 211 { 212 ObjectFile *obj_file = module->GetObjectFile(); 213 SectionList *sections = obj_file->GetSectionList(); 214 SectionLoadList &load_list = m_process->GetTarget().GetSectionLoadList(); 215 const size_t num_sections = sections->GetSize(); 216 217 for (unsigned i = 0; i < num_sections; ++i) 218 { 219 SectionSP section_sp (sections->GetSectionAtIndex(i)); 220 lldb::addr_t new_load_addr = section_sp->GetFileAddress() + base_addr; 221 lldb::addr_t old_load_addr = load_list.GetSectionLoadAddress(section_sp); 222 223 // If the file address of the section is zero then this is not an 224 // allocatable/loadable section (property of ELF sh_addr). Skip it. 225 if (new_load_addr == base_addr) 226 continue; 227 228 if (old_load_addr == LLDB_INVALID_ADDRESS || 229 old_load_addr != new_load_addr) 230 load_list.SetSectionLoadAddress(section_sp, new_load_addr); 231 } 232 } 233 234 void 235 DynamicLoaderPOSIXDYLD::ProbeEntry() 236 { 237 Breakpoint *entry_break; 238 addr_t entry; 239 240 if ((entry = GetEntryPoint()) == LLDB_INVALID_ADDRESS) 241 return; 242 243 entry_break = m_process->GetTarget().CreateBreakpoint(entry, true).get(); 244 entry_break->SetCallback(EntryBreakpointHit, this, true); 245 entry_break->SetBreakpointKind("shared-library-event"); 246 } 247 248 // The runtime linker has run and initialized the rendezvous structure once the 249 // process has hit its entry point. When we hit the corresponding breakpoint we 250 // interrogate the rendezvous structure to get the load addresses of all 251 // dependent modules for the process. Similarly, we can discover the runtime 252 // linker function and setup a breakpoint to notify us of any dynamically loaded 253 // modules (via dlopen). 254 bool 255 DynamicLoaderPOSIXDYLD::EntryBreakpointHit(void *baton, 256 StoppointCallbackContext *context, 257 user_id_t break_id, 258 user_id_t break_loc_id) 259 { 260 DynamicLoaderPOSIXDYLD* dyld_instance; 261 262 dyld_instance = static_cast<DynamicLoaderPOSIXDYLD*>(baton); 263 dyld_instance->LoadAllCurrentModules(); 264 dyld_instance->SetRendezvousBreakpoint(); 265 return false; // Continue running. 266 } 267 268 void 269 DynamicLoaderPOSIXDYLD::SetRendezvousBreakpoint() 270 { 271 Breakpoint *dyld_break; 272 addr_t break_addr; 273 274 break_addr = m_rendezvous.GetBreakAddress(); 275 dyld_break = m_process->GetTarget().CreateBreakpoint(break_addr, true).get(); 276 dyld_break->SetCallback(RendezvousBreakpointHit, this, true); 277 dyld_break->SetBreakpointKind ("shared-library-event"); 278 } 279 280 bool 281 DynamicLoaderPOSIXDYLD::RendezvousBreakpointHit(void *baton, 282 StoppointCallbackContext *context, 283 user_id_t break_id, 284 user_id_t break_loc_id) 285 { 286 DynamicLoaderPOSIXDYLD* dyld_instance; 287 288 dyld_instance = static_cast<DynamicLoaderPOSIXDYLD*>(baton); 289 dyld_instance->RefreshModules(); 290 291 // Return true to stop the target, false to just let the target run. 292 return dyld_instance->GetStopWhenImagesChange(); 293 } 294 295 void 296 DynamicLoaderPOSIXDYLD::RefreshModules() 297 { 298 if (!m_rendezvous.Resolve()) 299 return; 300 301 DYLDRendezvous::iterator I; 302 DYLDRendezvous::iterator E; 303 304 ModuleList &loaded_modules = m_process->GetTarget().GetImages(); 305 306 if (m_rendezvous.ModulesDidLoad()) 307 { 308 ModuleList new_modules; 309 310 E = m_rendezvous.loaded_end(); 311 for (I = m_rendezvous.loaded_begin(); I != E; ++I) 312 { 313 FileSpec file(I->path.c_str(), true); 314 ModuleSP module_sp = LoadModuleAtAddress(file, I->base_addr); 315 if (module_sp.get()) 316 loaded_modules.AppendIfNeeded(module_sp); 317 } 318 } 319 320 if (m_rendezvous.ModulesDidUnload()) 321 { 322 ModuleList old_modules; 323 324 E = m_rendezvous.unloaded_end(); 325 for (I = m_rendezvous.unloaded_begin(); I != E; ++I) 326 { 327 FileSpec file(I->path.c_str(), true); 328 ModuleSpec module_spec (file); 329 ModuleSP module_sp = 330 loaded_modules.FindFirstModule (module_spec); 331 if (module_sp.get()) 332 old_modules.Append(module_sp); 333 } 334 loaded_modules.Remove(old_modules); 335 } 336 } 337 338 ThreadPlanSP 339 DynamicLoaderPOSIXDYLD::GetStepThroughTrampolinePlan(Thread &thread, bool stop) 340 { 341 ThreadPlanSP thread_plan_sp; 342 343 StackFrame *frame = thread.GetStackFrameAtIndex(0).get(); 344 const SymbolContext &context = frame->GetSymbolContext(eSymbolContextSymbol); 345 Symbol *sym = context.symbol; 346 347 if (sym == NULL || !sym->IsTrampoline()) 348 return thread_plan_sp; 349 350 const ConstString &sym_name = sym->GetMangled().GetName(Mangled::ePreferMangled); 351 if (!sym_name) 352 return thread_plan_sp; 353 354 SymbolContextList target_symbols; 355 Target &target = thread.GetProcess()->GetTarget(); 356 const ModuleList &images = target.GetImages(); 357 358 images.FindSymbolsWithNameAndType(sym_name, eSymbolTypeCode, target_symbols); 359 size_t num_targets = target_symbols.GetSize(); 360 if (!num_targets) 361 return thread_plan_sp; 362 363 typedef std::vector<lldb::addr_t> AddressVector; 364 AddressVector addrs; 365 for (size_t i = 0; i < num_targets; ++i) 366 { 367 SymbolContext context; 368 AddressRange range; 369 if (target_symbols.GetContextAtIndex(i, context)) 370 { 371 context.GetAddressRange(eSymbolContextEverything, 0, false, range); 372 lldb::addr_t addr = range.GetBaseAddress().GetLoadAddress(&target); 373 if (addr != LLDB_INVALID_ADDRESS) 374 addrs.push_back(addr); 375 } 376 } 377 378 if (addrs.size() > 0) 379 { 380 AddressVector::iterator start = addrs.begin(); 381 AddressVector::iterator end = addrs.end(); 382 383 std::sort(start, end); 384 addrs.erase(std::unique(start, end), end); 385 thread_plan_sp.reset(new ThreadPlanRunToAddress(thread, addrs, stop)); 386 } 387 388 return thread_plan_sp; 389 } 390 391 void 392 DynamicLoaderPOSIXDYLD::LoadAllCurrentModules() 393 { 394 DYLDRendezvous::iterator I; 395 DYLDRendezvous::iterator E; 396 ModuleList module_list; 397 398 if (!m_rendezvous.Resolve()) 399 return; 400 401 for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I) 402 { 403 FileSpec file(I->path.c_str(), false); 404 ModuleSP module_sp = LoadModuleAtAddress(file, I->base_addr); 405 if (module_sp.get()) 406 module_list.Append(module_sp); 407 } 408 409 m_process->GetTarget().ModulesDidLoad(module_list); 410 } 411 412 ModuleSP 413 DynamicLoaderPOSIXDYLD::LoadModuleAtAddress(const FileSpec &file, addr_t base_addr) 414 { 415 Target &target = m_process->GetTarget(); 416 ModuleList &modules = target.GetImages(); 417 ModuleSP module_sp; 418 419 ModuleSpec module_spec (file, target.GetArchitecture()); 420 if ((module_sp = modules.FindFirstModule (module_spec))) 421 { 422 UpdateLoadedSections(module_sp, base_addr); 423 } 424 else if ((module_sp = target.GetSharedModule(module_spec))) 425 { 426 UpdateLoadedSections(module_sp, base_addr); 427 modules.Append(module_sp); 428 } 429 430 return module_sp; 431 } 432 433 addr_t 434 DynamicLoaderPOSIXDYLD::ComputeLoadOffset() 435 { 436 addr_t virt_entry; 437 438 if (m_load_offset != LLDB_INVALID_ADDRESS) 439 return m_load_offset; 440 441 if ((virt_entry = GetEntryPoint()) == LLDB_INVALID_ADDRESS) 442 return LLDB_INVALID_ADDRESS; 443 444 ModuleSP module = m_process->GetTarget().GetExecutableModule(); 445 ObjectFile *exe = module->GetObjectFile(); 446 Address file_entry = exe->GetEntryPointAddress(); 447 448 if (!file_entry.IsValid()) 449 return LLDB_INVALID_ADDRESS; 450 451 m_load_offset = virt_entry - file_entry.GetFileAddress(); 452 return m_load_offset; 453 } 454 455 addr_t 456 DynamicLoaderPOSIXDYLD::GetEntryPoint() 457 { 458 if (m_entry_point != LLDB_INVALID_ADDRESS) 459 return m_entry_point; 460 461 if (m_auxv.get() == NULL) 462 return LLDB_INVALID_ADDRESS; 463 464 AuxVector::iterator I = m_auxv->FindEntry(AuxVector::AT_ENTRY); 465 466 if (I == m_auxv->end()) 467 return LLDB_INVALID_ADDRESS; 468 469 m_entry_point = static_cast<addr_t>(I->value); 470 return m_entry_point; 471 } 472