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, 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, load_offset);
148        ProbeEntry();
149        m_process->GetTarget().ModulesDidLoad(module_list);
150    }
151}
152
153ModuleSP
154DynamicLoaderPOSIXDYLD::GetTargetExecutable()
155{
156    Target &target = m_process->GetTarget();
157    ModuleSP executable = target.GetExecutableModule();
158
159    if (executable.get())
160    {
161        if (executable->GetFileSpec().Exists())
162        {
163            ModuleSpec module_spec (executable->GetFileSpec(), executable->GetArchitecture());
164            ModuleSP module_sp (new Module (module_spec));
165
166            // Check if the executable has changed and set it to the target executable if they differ.
167            if (module_sp.get() && module_sp->GetUUID().IsValid() && executable->GetUUID().IsValid())
168            {
169                if (module_sp->GetUUID() != executable->GetUUID())
170                    executable.reset();
171            }
172            else if (executable->FileHasChanged())
173            {
174                executable.reset();
175            }
176
177            if (!executable.get())
178            {
179                executable = target.GetSharedModule(module_spec);
180                if (executable.get() != target.GetExecutableModulePointer())
181                {
182                    // Don't load dependent images since we are in dyld where we will know
183                    // and find out about all images that are loaded
184                    const bool get_dependent_images = false;
185                    target.SetExecutableModule(executable, get_dependent_images);
186                }
187            }
188        }
189    }
190    return executable;
191}
192
193Error
194DynamicLoaderPOSIXDYLD::ExecutePluginCommand(Args &command, Stream *strm)
195{
196    return Error();
197}
198
199Log *
200DynamicLoaderPOSIXDYLD::EnablePluginLogging(Stream *strm, Args &command)
201{
202    return NULL;
203}
204
205Error
206DynamicLoaderPOSIXDYLD::CanLoadImage()
207{
208    return Error();
209}
210
211void
212DynamicLoaderPOSIXDYLD::UpdateLoadedSections(ModuleSP module, addr_t base_addr)
213{
214    ObjectFile *obj_file = module->GetObjectFile();
215    SectionList *sections = obj_file->GetSectionList();
216    SectionLoadList &load_list = m_process->GetTarget().GetSectionLoadList();
217    const size_t num_sections = sections->GetSize();
218
219    for (unsigned i = 0; i < num_sections; ++i)
220    {
221        SectionSP section_sp (sections->GetSectionAtIndex(i));
222        lldb::addr_t new_load_addr = section_sp->GetFileAddress() + base_addr;
223        lldb::addr_t old_load_addr = load_list.GetSectionLoadAddress(section_sp);
224
225        // If the file address of the section is zero then this is not an
226        // allocatable/loadable section (property of ELF sh_addr).  Skip it.
227        if (new_load_addr == base_addr)
228            continue;
229
230        if (old_load_addr == LLDB_INVALID_ADDRESS ||
231            old_load_addr != new_load_addr)
232            load_list.SetSectionLoadAddress(section_sp, new_load_addr);
233    }
234}
235
236void
237DynamicLoaderPOSIXDYLD::ProbeEntry()
238{
239    Breakpoint *entry_break;
240    addr_t entry;
241
242    if ((entry = GetEntryPoint()) == LLDB_INVALID_ADDRESS)
243        return;
244
245    entry_break = m_process->GetTarget().CreateBreakpoint(entry, true).get();
246    entry_break->SetCallback(EntryBreakpointHit, this, true);
247    entry_break->SetBreakpointKind("shared-library-event");
248}
249
250// The runtime linker has run and initialized the rendezvous structure once the
251// process has hit its entry point.  When we hit the corresponding breakpoint we
252// interrogate the rendezvous structure to get the load addresses of all
253// dependent modules for the process.  Similarly, we can discover the runtime
254// linker function and setup a breakpoint to notify us of any dynamically loaded
255// modules (via dlopen).
256bool
257DynamicLoaderPOSIXDYLD::EntryBreakpointHit(void *baton,
258                                           StoppointCallbackContext *context,
259                                           user_id_t break_id,
260                                           user_id_t break_loc_id)
261{
262    DynamicLoaderPOSIXDYLD* dyld_instance;
263
264    dyld_instance = static_cast<DynamicLoaderPOSIXDYLD*>(baton);
265    dyld_instance->LoadAllCurrentModules();
266    dyld_instance->SetRendezvousBreakpoint();
267    return false; // Continue running.
268}
269
270void
271DynamicLoaderPOSIXDYLD::SetRendezvousBreakpoint()
272{
273    addr_t break_addr = m_rendezvous.GetBreakAddress();
274    Target &target = m_process->GetTarget();
275
276    if (m_dyld_bid == LLDB_INVALID_BREAK_ID)
277    {
278        Breakpoint *dyld_break = target.CreateBreakpoint (break_addr, true).get();
279        dyld_break->SetCallback(RendezvousBreakpointHit, this, true);
280        dyld_break->SetBreakpointKind ("shared-library-event");
281        m_dyld_bid = dyld_break->GetID();
282    }
283
284    // Make sure our breakpoint is at the right address.
285    assert (target.GetBreakpointByID(m_dyld_bid)->FindLocationByAddress(break_addr)->GetBreakpoint().GetID() == m_dyld_bid);
286}
287
288bool
289DynamicLoaderPOSIXDYLD::RendezvousBreakpointHit(void *baton,
290                                                StoppointCallbackContext *context,
291                                                user_id_t break_id,
292                                                user_id_t break_loc_id)
293{
294    DynamicLoaderPOSIXDYLD* dyld_instance;
295
296    dyld_instance = static_cast<DynamicLoaderPOSIXDYLD*>(baton);
297    dyld_instance->RefreshModules();
298
299    // Return true to stop the target, false to just let the target run.
300    return dyld_instance->GetStopWhenImagesChange();
301}
302
303void
304DynamicLoaderPOSIXDYLD::RefreshModules()
305{
306    if (!m_rendezvous.Resolve())
307        return;
308
309    DYLDRendezvous::iterator I;
310    DYLDRendezvous::iterator E;
311
312    ModuleList &loaded_modules = m_process->GetTarget().GetImages();
313
314    if (m_rendezvous.ModulesDidLoad())
315    {
316        ModuleList new_modules;
317
318        E = m_rendezvous.loaded_end();
319        for (I = m_rendezvous.loaded_begin(); I != E; ++I)
320        {
321            FileSpec file(I->path.c_str(), true);
322            ModuleSP module_sp = LoadModuleAtAddress(file, I->base_addr);
323            if (module_sp.get())
324                loaded_modules.AppendIfNeeded(module_sp);
325        }
326    }
327
328    if (m_rendezvous.ModulesDidUnload())
329    {
330        ModuleList old_modules;
331
332        E = m_rendezvous.unloaded_end();
333        for (I = m_rendezvous.unloaded_begin(); I != E; ++I)
334        {
335            FileSpec file(I->path.c_str(), true);
336            ModuleSpec module_spec (file);
337            ModuleSP module_sp =
338                loaded_modules.FindFirstModule (module_spec);
339            if (module_sp.get())
340                old_modules.Append(module_sp);
341        }
342        loaded_modules.Remove(old_modules);
343    }
344}
345
346ThreadPlanSP
347DynamicLoaderPOSIXDYLD::GetStepThroughTrampolinePlan(Thread &thread, bool stop)
348{
349    ThreadPlanSP thread_plan_sp;
350
351    StackFrame *frame = thread.GetStackFrameAtIndex(0).get();
352    const SymbolContext &context = frame->GetSymbolContext(eSymbolContextSymbol);
353    Symbol *sym = context.symbol;
354
355    if (sym == NULL || !sym->IsTrampoline())
356        return thread_plan_sp;
357
358    const ConstString &sym_name = sym->GetMangled().GetName(Mangled::ePreferMangled);
359    if (!sym_name)
360        return thread_plan_sp;
361
362    SymbolContextList target_symbols;
363    Target &target = thread.GetProcess()->GetTarget();
364    const ModuleList &images = target.GetImages();
365
366    images.FindSymbolsWithNameAndType(sym_name, eSymbolTypeCode, target_symbols);
367    size_t num_targets = target_symbols.GetSize();
368    if (!num_targets)
369        return thread_plan_sp;
370
371    typedef std::vector<lldb::addr_t> AddressVector;
372    AddressVector addrs;
373    for (size_t i = 0; i < num_targets; ++i)
374    {
375        SymbolContext context;
376        AddressRange range;
377        if (target_symbols.GetContextAtIndex(i, context))
378        {
379            context.GetAddressRange(eSymbolContextEverything, 0, false, range);
380            lldb::addr_t addr = range.GetBaseAddress().GetLoadAddress(&target);
381            if (addr != LLDB_INVALID_ADDRESS)
382                addrs.push_back(addr);
383        }
384    }
385
386    if (addrs.size() > 0)
387    {
388        AddressVector::iterator start = addrs.begin();
389        AddressVector::iterator end = addrs.end();
390
391        std::sort(start, end);
392        addrs.erase(std::unique(start, end), end);
393        thread_plan_sp.reset(new ThreadPlanRunToAddress(thread, addrs, stop));
394    }
395
396    return thread_plan_sp;
397}
398
399void
400DynamicLoaderPOSIXDYLD::LoadAllCurrentModules()
401{
402    DYLDRendezvous::iterator I;
403    DYLDRendezvous::iterator E;
404    ModuleList module_list;
405
406    if (!m_rendezvous.Resolve())
407        return;
408
409    for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I)
410    {
411        FileSpec file(I->path.c_str(), false);
412        ModuleSP module_sp = LoadModuleAtAddress(file, I->base_addr);
413        if (module_sp.get())
414            module_list.Append(module_sp);
415    }
416
417    m_process->GetTarget().ModulesDidLoad(module_list);
418}
419
420ModuleSP
421DynamicLoaderPOSIXDYLD::LoadModuleAtAddress(const FileSpec &file, addr_t base_addr)
422{
423    Target &target = m_process->GetTarget();
424    ModuleList &modules = target.GetImages();
425    ModuleSP module_sp;
426
427    ModuleSpec module_spec (file, target.GetArchitecture());
428    if ((module_sp = modules.FindFirstModule (module_spec)))
429    {
430        UpdateLoadedSections(module_sp, base_addr);
431    }
432    else if ((module_sp = target.GetSharedModule(module_spec)))
433    {
434        UpdateLoadedSections(module_sp, base_addr);
435    }
436
437    return module_sp;
438}
439
440addr_t
441DynamicLoaderPOSIXDYLD::ComputeLoadOffset()
442{
443    addr_t virt_entry;
444
445    if (m_load_offset != LLDB_INVALID_ADDRESS)
446        return m_load_offset;
447
448    if ((virt_entry = GetEntryPoint()) == LLDB_INVALID_ADDRESS)
449        return LLDB_INVALID_ADDRESS;
450
451    ModuleSP module = m_process->GetTarget().GetExecutableModule();
452    ObjectFile *exe = module->GetObjectFile();
453    Address file_entry = exe->GetEntryPointAddress();
454
455    if (!file_entry.IsValid())
456        return LLDB_INVALID_ADDRESS;
457
458    m_load_offset = virt_entry - file_entry.GetFileAddress();
459    return m_load_offset;
460}
461
462addr_t
463DynamicLoaderPOSIXDYLD::GetEntryPoint()
464{
465    if (m_entry_point != LLDB_INVALID_ADDRESS)
466        return m_entry_point;
467
468    if (m_auxv.get() == NULL)
469        return LLDB_INVALID_ADDRESS;
470
471    AuxVector::iterator I = m_auxv->FindEntry(AuxVector::AT_ENTRY);
472
473    if (I == m_auxv->end())
474        return LLDB_INVALID_ADDRESS;
475
476    m_entry_point = static_cast<addr_t>(I->value);
477    return m_entry_point;
478}
479