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#include "lldb/Breakpoint/BreakpointLocation.h"
24
25#include "AuxVector.h"
26#include "DynamicLoaderPOSIXDYLD.h"
27
28using namespace lldb;
29using namespace lldb_private;
30
31void
32DynamicLoaderPOSIXDYLD::Initialize()
33{
34    PluginManager::RegisterPlugin(GetPluginNameStatic(),
35                                  GetPluginDescriptionStatic(),
36                                  CreateInstance);
37}
38
39void
40DynamicLoaderPOSIXDYLD::Terminate()
41{
42}
43
44lldb_private::ConstString
45DynamicLoaderPOSIXDYLD::GetPluginName()
46{
47    return GetPluginNameStatic();
48}
49
50lldb_private::ConstString
51DynamicLoaderPOSIXDYLD::GetPluginNameStatic()
52{
53    static ConstString g_name("linux-dyld");
54    return g_name;
55}
56
57const char *
58DynamicLoaderPOSIXDYLD::GetPluginDescriptionStatic()
59{
60    return "Dynamic loader plug-in that watches for shared library "
61           "loads/unloads in POSIX processes.";
62}
63
64void
65DynamicLoaderPOSIXDYLD::GetPluginCommandHelp(const char *command, Stream *strm)
66{
67}
68
69uint32_t
70DynamicLoaderPOSIXDYLD::GetPluginVersion()
71{
72    return 1;
73}
74
75DynamicLoader *
76DynamicLoaderPOSIXDYLD::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
92DynamicLoaderPOSIXDYLD::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(),
98      m_dyld_bid(LLDB_INVALID_BREAK_ID)
99{
100}
101
102DynamicLoaderPOSIXDYLD::~DynamicLoaderPOSIXDYLD()
103{
104    if (m_dyld_bid != LLDB_INVALID_BREAK_ID)
105    {
106        m_process->GetTarget().RemoveBreakpointByID (m_dyld_bid);
107        m_dyld_bid = LLDB_INVALID_BREAK_ID;
108    }
109}
110
111void
112DynamicLoaderPOSIXDYLD::DidAttach()
113{
114    ModuleSP executable;
115    addr_t load_offset;
116
117    m_auxv.reset(new AuxVector(m_process));
118
119    executable = GetTargetExecutable();
120    load_offset = ComputeLoadOffset();
121
122    if (executable.get() && load_offset != LLDB_INVALID_ADDRESS)
123    {
124        ModuleList module_list;
125        module_list.Append(executable);
126        UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_offset);
127        LoadAllCurrentModules();
128        m_process->GetTarget().ModulesDidLoad(module_list);
129    }
130}
131
132void
133DynamicLoaderPOSIXDYLD::DidLaunch()
134{
135    ModuleSP executable;
136    addr_t load_offset;
137
138    m_auxv.reset(new AuxVector(m_process));
139
140    executable = GetTargetExecutable();
141    load_offset = ComputeLoadOffset();
142
143    if (executable.get() && load_offset != LLDB_INVALID_ADDRESS)
144    {
145        ModuleList module_list;
146        module_list.Append(executable);
147        UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_offset);
148        ProbeEntry();
149        m_process->GetTarget().ModulesDidLoad(module_list);
150    }
151}
152
153Error
154DynamicLoaderPOSIXDYLD::ExecutePluginCommand(Args &command, Stream *strm)
155{
156    return Error();
157}
158
159Log *
160DynamicLoaderPOSIXDYLD::EnablePluginLogging(Stream *strm, Args &command)
161{
162    return NULL;
163}
164
165Error
166DynamicLoaderPOSIXDYLD::CanLoadImage()
167{
168    return Error();
169}
170
171void
172DynamicLoaderPOSIXDYLD::UpdateLoadedSections(ModuleSP module, addr_t link_map_addr, addr_t base_addr)
173{
174    m_loaded_modules[module] = link_map_addr;
175
176    UpdateLoadedSectionsCommon(module, base_addr);
177}
178
179void
180DynamicLoaderPOSIXDYLD::UnloadSections(const ModuleSP module)
181{
182    m_loaded_modules.erase(module);
183
184    UnloadSectionsCommon(module);
185}
186
187void
188DynamicLoaderPOSIXDYLD::ProbeEntry()
189{
190    Breakpoint *entry_break;
191    addr_t entry;
192
193    if ((entry = GetEntryPoint()) == LLDB_INVALID_ADDRESS)
194        return;
195
196    entry_break = m_process->GetTarget().CreateBreakpoint(entry, true, false).get();
197    entry_break->SetCallback(EntryBreakpointHit, this, true);
198    entry_break->SetBreakpointKind("shared-library-event");
199}
200
201// The runtime linker has run and initialized the rendezvous structure once the
202// process has hit its entry point.  When we hit the corresponding breakpoint we
203// interrogate the rendezvous structure to get the load addresses of all
204// dependent modules for the process.  Similarly, we can discover the runtime
205// linker function and setup a breakpoint to notify us of any dynamically loaded
206// modules (via dlopen).
207bool
208DynamicLoaderPOSIXDYLD::EntryBreakpointHit(void *baton,
209                                           StoppointCallbackContext *context,
210                                           user_id_t break_id,
211                                           user_id_t break_loc_id)
212{
213    DynamicLoaderPOSIXDYLD* dyld_instance;
214
215    dyld_instance = static_cast<DynamicLoaderPOSIXDYLD*>(baton);
216    dyld_instance->LoadAllCurrentModules();
217    dyld_instance->SetRendezvousBreakpoint();
218    return false; // Continue running.
219}
220
221void
222DynamicLoaderPOSIXDYLD::SetRendezvousBreakpoint()
223{
224    addr_t break_addr = m_rendezvous.GetBreakAddress();
225    Target &target = m_process->GetTarget();
226
227    if (m_dyld_bid == LLDB_INVALID_BREAK_ID)
228    {
229        Breakpoint *dyld_break = target.CreateBreakpoint (break_addr, true, false).get();
230        dyld_break->SetCallback(RendezvousBreakpointHit, this, true);
231        dyld_break->SetBreakpointKind ("shared-library-event");
232        m_dyld_bid = dyld_break->GetID();
233    }
234
235    // Make sure our breakpoint is at the right address.
236    assert (target.GetBreakpointByID(m_dyld_bid)->FindLocationByAddress(break_addr)->GetBreakpoint().GetID() == m_dyld_bid);
237}
238
239bool
240DynamicLoaderPOSIXDYLD::RendezvousBreakpointHit(void *baton,
241                                                StoppointCallbackContext *context,
242                                                user_id_t break_id,
243                                                user_id_t break_loc_id)
244{
245    DynamicLoaderPOSIXDYLD* dyld_instance;
246
247    dyld_instance = static_cast<DynamicLoaderPOSIXDYLD*>(baton);
248    dyld_instance->RefreshModules();
249
250    // Return true to stop the target, false to just let the target run.
251    return dyld_instance->GetStopWhenImagesChange();
252}
253
254void
255DynamicLoaderPOSIXDYLD::RefreshModules()
256{
257    if (!m_rendezvous.Resolve())
258        return;
259
260    DYLDRendezvous::iterator I;
261    DYLDRendezvous::iterator E;
262
263    ModuleList &loaded_modules = m_process->GetTarget().GetImages();
264
265    if (m_rendezvous.ModulesDidLoad())
266    {
267        ModuleList new_modules;
268
269        E = m_rendezvous.loaded_end();
270        for (I = m_rendezvous.loaded_begin(); I != E; ++I)
271        {
272            FileSpec file(I->path.c_str(), true);
273            ModuleSP module_sp = LoadModuleAtAddress(file, I->link_addr, I->base_addr);
274            if (module_sp.get())
275            {
276                loaded_modules.AppendIfNeeded(module_sp);
277                new_modules.Append(module_sp);
278            }
279        }
280        m_process->GetTarget().ModulesDidLoad(new_modules);
281    }
282
283    if (m_rendezvous.ModulesDidUnload())
284    {
285        ModuleList old_modules;
286
287        E = m_rendezvous.unloaded_end();
288        for (I = m_rendezvous.unloaded_begin(); I != E; ++I)
289        {
290            FileSpec file(I->path.c_str(), true);
291            ModuleSpec module_spec (file);
292            ModuleSP module_sp =
293                loaded_modules.FindFirstModule (module_spec);
294
295            if (module_sp.get())
296            {
297                old_modules.Append(module_sp);
298                UnloadSections(module_sp);
299            }
300        }
301        loaded_modules.Remove(old_modules);
302        m_process->GetTarget().ModulesDidUnload(old_modules, false);
303    }
304}
305
306ThreadPlanSP
307DynamicLoaderPOSIXDYLD::GetStepThroughTrampolinePlan(Thread &thread, bool stop)
308{
309    ThreadPlanSP thread_plan_sp;
310
311    StackFrame *frame = thread.GetStackFrameAtIndex(0).get();
312    const SymbolContext &context = frame->GetSymbolContext(eSymbolContextSymbol);
313    Symbol *sym = context.symbol;
314
315    if (sym == NULL || !sym->IsTrampoline())
316        return thread_plan_sp;
317
318    const ConstString &sym_name = sym->GetMangled().GetName(Mangled::ePreferMangled);
319    if (!sym_name)
320        return thread_plan_sp;
321
322    SymbolContextList target_symbols;
323    Target &target = thread.GetProcess()->GetTarget();
324    const ModuleList &images = target.GetImages();
325
326    images.FindSymbolsWithNameAndType(sym_name, eSymbolTypeCode, target_symbols);
327    size_t num_targets = target_symbols.GetSize();
328    if (!num_targets)
329        return thread_plan_sp;
330
331    typedef std::vector<lldb::addr_t> AddressVector;
332    AddressVector addrs;
333    for (size_t i = 0; i < num_targets; ++i)
334    {
335        SymbolContext context;
336        AddressRange range;
337        if (target_symbols.GetContextAtIndex(i, context))
338        {
339            context.GetAddressRange(eSymbolContextEverything, 0, false, range);
340            lldb::addr_t addr = range.GetBaseAddress().GetLoadAddress(&target);
341            if (addr != LLDB_INVALID_ADDRESS)
342                addrs.push_back(addr);
343        }
344    }
345
346    if (addrs.size() > 0)
347    {
348        AddressVector::iterator start = addrs.begin();
349        AddressVector::iterator end = addrs.end();
350
351        std::sort(start, end);
352        addrs.erase(std::unique(start, end), end);
353        thread_plan_sp.reset(new ThreadPlanRunToAddress(thread, addrs, stop));
354    }
355
356    return thread_plan_sp;
357}
358
359void
360DynamicLoaderPOSIXDYLD::LoadAllCurrentModules()
361{
362    DYLDRendezvous::iterator I;
363    DYLDRendezvous::iterator E;
364    ModuleList module_list;
365
366    if (!m_rendezvous.Resolve())
367    {
368        Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
369        if (log)
370            log->Printf("DynamicLoaderPOSIXDYLD::%s unable to resolve POSIX DYLD rendezvous address",
371                        __FUNCTION__);
372        return;
373    }
374
375    // The rendezvous class doesn't enumerate the main module, so track
376    // that ourselves here.
377    ModuleSP executable = GetTargetExecutable();
378    m_loaded_modules[executable] = m_rendezvous.GetLinkMapAddress();
379
380
381    for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I)
382    {
383        const char *module_path = I->path.c_str();
384        FileSpec file(module_path, false);
385        ModuleSP module_sp = LoadModuleAtAddress(file, I->link_addr, I->base_addr);
386#ifdef __FreeBSD__ // llvm.org/pr17880
387        if (module_sp == executable)
388        {
389            Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
390            if (log)
391                log->Printf("DynamicLoaderPOSIXDYLD::%s reloading main module, ignoring rendezvous base addr %" PRIx64,
392                            __FUNCTION__, I->base_addr);
393            ModuleSP module_sp = LoadModuleAtAddress(file, I->link_addr, 0);
394        }
395#endif
396
397        if (module_sp.get())
398        {
399            module_list.Append(module_sp);
400        }
401        else
402        {
403            Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
404            if (log)
405                log->Printf("DynamicLoaderPOSIXDYLD::%s failed loading module %s at 0x%" PRIx64,
406                            __FUNCTION__, module_path, I->base_addr);
407        }
408    }
409
410    m_process->GetTarget().ModulesDidLoad(module_list);
411}
412
413addr_t
414DynamicLoaderPOSIXDYLD::ComputeLoadOffset()
415{
416    addr_t virt_entry;
417
418    if (m_load_offset != LLDB_INVALID_ADDRESS)
419        return m_load_offset;
420
421    if ((virt_entry = GetEntryPoint()) == LLDB_INVALID_ADDRESS)
422        return LLDB_INVALID_ADDRESS;
423
424    ModuleSP module = m_process->GetTarget().GetExecutableModule();
425    if (!module)
426        return LLDB_INVALID_ADDRESS;
427
428    ObjectFile *exe = module->GetObjectFile();
429    Address file_entry = exe->GetEntryPointAddress();
430
431    if (!file_entry.IsValid())
432        return LLDB_INVALID_ADDRESS;
433
434    m_load_offset = virt_entry - file_entry.GetFileAddress();
435    return m_load_offset;
436}
437
438addr_t
439DynamicLoaderPOSIXDYLD::GetEntryPoint()
440{
441    if (m_entry_point != LLDB_INVALID_ADDRESS)
442        return m_entry_point;
443
444    if (m_auxv.get() == NULL)
445        return LLDB_INVALID_ADDRESS;
446
447    AuxVector::iterator I = m_auxv->FindEntry(AuxVector::AT_ENTRY);
448
449    if (I == m_auxv->end())
450        return LLDB_INVALID_ADDRESS;
451
452    m_entry_point = static_cast<addr_t>(I->value);
453    return m_entry_point;
454}
455
456lldb::addr_t
457DynamicLoaderPOSIXDYLD::GetThreadLocalData (const lldb::ModuleSP module, const lldb::ThreadSP thread)
458{
459    auto it = m_loaded_modules.find (module);
460    if (it == m_loaded_modules.end())
461        return LLDB_INVALID_ADDRESS;
462
463    addr_t link_map = it->second;
464    if (link_map == LLDB_INVALID_ADDRESS)
465        return LLDB_INVALID_ADDRESS;
466
467    const DYLDRendezvous::ThreadInfo &metadata = m_rendezvous.GetThreadInfo();
468    if (!metadata.valid)
469        return LLDB_INVALID_ADDRESS;
470
471    // Get the thread pointer.
472    addr_t tp = thread->GetThreadPointer ();
473    if (tp == LLDB_INVALID_ADDRESS)
474        return LLDB_INVALID_ADDRESS;
475
476    // Find the module's modid.
477    int modid_size = 4;  // FIXME(spucci): This isn't right for big-endian 64-bit
478    int64_t modid = ReadUnsignedIntWithSizeInBytes (link_map + metadata.modid_offset, modid_size);
479    if (modid == -1)
480        return LLDB_INVALID_ADDRESS;
481
482    // Lookup the DTV stucture for this thread.
483    addr_t dtv_ptr = tp + metadata.dtv_offset;
484    addr_t dtv = ReadPointer (dtv_ptr);
485    if (dtv == LLDB_INVALID_ADDRESS)
486        return LLDB_INVALID_ADDRESS;
487
488    // Find the TLS block for this module.
489    addr_t dtv_slot = dtv + metadata.dtv_slot_size*modid;
490    addr_t tls_block = ReadPointer (dtv_slot + metadata.tls_offset);
491
492    Module *mod = module.get();
493    Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
494    if (log)
495        log->Printf("DynamicLoaderPOSIXDYLD::Performed TLS lookup: "
496                    "module=%s, link_map=0x%" PRIx64 ", tp=0x%" PRIx64 ", modid=%" PRId64 ", tls_block=0x%" PRIx64 "\n",
497                    mod->GetObjectName().AsCString(""), link_map, tp, (int64_t)modid, tls_block);
498
499    return tls_block;
500}
501