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