ModuleList.cpp revision 280031
1//===-- ModuleList.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#include "lldb/Core/ModuleList.h"
11
12// C Includes
13#include <stdint.h>
14
15// C++ Includes
16#include <mutex> // std::once
17
18// Other libraries and framework includes
19// Project includes
20#include "lldb/Core/Log.h"
21#include "lldb/Core/Module.h"
22#include "lldb/Core/ModuleSpec.h"
23#include "lldb/Host/Host.h"
24#include "lldb/Host/Symbols.h"
25#include "lldb/Symbol/ClangNamespaceDecl.h"
26#include "lldb/Symbol/ObjectFile.h"
27#include "lldb/Symbol/VariableList.h"
28
29using namespace lldb;
30using namespace lldb_private;
31
32//----------------------------------------------------------------------
33// ModuleList constructor
34//----------------------------------------------------------------------
35ModuleList::ModuleList() :
36    m_modules(),
37    m_modules_mutex (Mutex::eMutexTypeRecursive),
38    m_notifier(NULL)
39{
40}
41
42//----------------------------------------------------------------------
43// Copy constructor
44//----------------------------------------------------------------------
45ModuleList::ModuleList(const ModuleList& rhs) :
46    m_modules(),
47    m_modules_mutex (Mutex::eMutexTypeRecursive),
48    m_notifier(NULL)
49{
50    Mutex::Locker lhs_locker(m_modules_mutex);
51    Mutex::Locker rhs_locker(rhs.m_modules_mutex);
52    m_modules = rhs.m_modules;
53}
54
55ModuleList::ModuleList (ModuleList::Notifier* notifier) :
56    m_modules(),
57    m_modules_mutex (Mutex::eMutexTypeRecursive),
58    m_notifier(notifier)
59{
60}
61
62//----------------------------------------------------------------------
63// Assignment operator
64//----------------------------------------------------------------------
65const ModuleList&
66ModuleList::operator= (const ModuleList& rhs)
67{
68    if (this != &rhs)
69    {
70        // That's probably me nit-picking, but in theoretical situation:
71        //
72        // * that two threads A B and
73        // * two ModuleList's x y do opposite assignemnts ie.:
74        //
75        //  in thread A: | in thread B:
76        //    x = y;     |   y = x;
77        //
78        // This establishes correct(same) lock taking order and thus
79        // avoids priority inversion.
80        if (uintptr_t(this) > uintptr_t(&rhs))
81        {
82            Mutex::Locker lhs_locker(m_modules_mutex);
83            Mutex::Locker rhs_locker(rhs.m_modules_mutex);
84            m_modules = rhs.m_modules;
85        }
86        else
87        {
88            Mutex::Locker rhs_locker(rhs.m_modules_mutex);
89            Mutex::Locker lhs_locker(m_modules_mutex);
90            m_modules = rhs.m_modules;
91        }
92    }
93    return *this;
94}
95
96//----------------------------------------------------------------------
97// Destructor
98//----------------------------------------------------------------------
99ModuleList::~ModuleList()
100{
101}
102
103void
104ModuleList::AppendImpl (const ModuleSP &module_sp, bool use_notifier)
105{
106    if (module_sp)
107    {
108        Mutex::Locker locker(m_modules_mutex);
109        m_modules.push_back(module_sp);
110        if (use_notifier && m_notifier)
111            m_notifier->ModuleAdded(*this, module_sp);
112    }
113}
114
115void
116ModuleList::Append (const ModuleSP &module_sp)
117{
118    AppendImpl (module_sp);
119}
120
121void
122ModuleList::ReplaceEquivalent (const ModuleSP &module_sp)
123{
124    if (module_sp)
125    {
126        Mutex::Locker locker(m_modules_mutex);
127
128        // First remove any equivalent modules. Equivalent modules are modules
129        // whose path, platform path and architecture match.
130        ModuleSpec equivalent_module_spec (module_sp->GetFileSpec(), module_sp->GetArchitecture());
131        equivalent_module_spec.GetPlatformFileSpec() = module_sp->GetPlatformFileSpec();
132
133        size_t idx = 0;
134        while (idx < m_modules.size())
135        {
136            ModuleSP module_sp (m_modules[idx]);
137            if (module_sp->MatchesModuleSpec (equivalent_module_spec))
138                RemoveImpl(m_modules.begin() + idx);
139            else
140                ++idx;
141        }
142        // Now add the new module to the list
143        Append(module_sp);
144    }
145}
146
147bool
148ModuleList::AppendIfNeeded (const ModuleSP &module_sp)
149{
150    if (module_sp)
151    {
152        Mutex::Locker locker(m_modules_mutex);
153        collection::iterator pos, end = m_modules.end();
154        for (pos = m_modules.begin(); pos != end; ++pos)
155        {
156            if (pos->get() == module_sp.get())
157                return false; // Already in the list
158        }
159        // Only push module_sp on the list if it wasn't already in there.
160        Append(module_sp);
161        return true;
162    }
163    return false;
164}
165
166void
167ModuleList::Append (const ModuleList& module_list)
168{
169    for (auto pos : module_list.m_modules)
170        Append(pos);
171}
172
173bool
174ModuleList::AppendIfNeeded (const ModuleList& module_list)
175{
176    bool any_in = false;
177    for (auto pos : module_list.m_modules)
178    {
179        if (AppendIfNeeded(pos))
180            any_in = true;
181    }
182    return any_in;
183}
184
185bool
186ModuleList::RemoveImpl (const ModuleSP &module_sp, bool use_notifier)
187{
188    if (module_sp)
189    {
190        Mutex::Locker locker(m_modules_mutex);
191        collection::iterator pos, end = m_modules.end();
192        for (pos = m_modules.begin(); pos != end; ++pos)
193        {
194            if (pos->get() == module_sp.get())
195            {
196                m_modules.erase (pos);
197                if (use_notifier && m_notifier)
198                    m_notifier->ModuleRemoved(*this, module_sp);
199                return true;
200            }
201        }
202    }
203    return false;
204}
205
206ModuleList::collection::iterator
207ModuleList::RemoveImpl (ModuleList::collection::iterator pos, bool use_notifier)
208{
209    ModuleSP module_sp(*pos);
210    collection::iterator retval = m_modules.erase(pos);
211    if (use_notifier && m_notifier)
212        m_notifier->ModuleRemoved(*this, module_sp);
213    return retval;
214}
215
216bool
217ModuleList::Remove (const ModuleSP &module_sp)
218{
219    return RemoveImpl (module_sp);
220}
221
222bool
223ModuleList::ReplaceModule (const lldb::ModuleSP &old_module_sp, const lldb::ModuleSP &new_module_sp)
224{
225    if (!RemoveImpl(old_module_sp, false))
226        return false;
227    AppendImpl (new_module_sp, false);
228    if (m_notifier)
229        m_notifier->ModuleUpdated(*this, old_module_sp,new_module_sp);
230    return true;
231}
232
233bool
234ModuleList::RemoveIfOrphaned (const Module *module_ptr)
235{
236    if (module_ptr)
237    {
238        Mutex::Locker locker(m_modules_mutex);
239        collection::iterator pos, end = m_modules.end();
240        for (pos = m_modules.begin(); pos != end; ++pos)
241        {
242            if (pos->get() == module_ptr)
243            {
244                if (pos->unique())
245                {
246                    pos = RemoveImpl(pos);
247                    return true;
248                }
249                else
250                    return false;
251            }
252        }
253    }
254    return false;
255}
256
257size_t
258ModuleList::RemoveOrphans (bool mandatory)
259{
260    Mutex::Locker locker;
261
262    if (mandatory)
263    {
264        locker.Lock (m_modules_mutex);
265    }
266    else
267    {
268        // Not mandatory, remove orphans if we can get the mutex
269        if (!locker.TryLock(m_modules_mutex))
270            return 0;
271    }
272    collection::iterator pos = m_modules.begin();
273    size_t remove_count = 0;
274    while (pos != m_modules.end())
275    {
276        if (pos->unique())
277        {
278            pos = RemoveImpl(pos);
279            ++remove_count;
280        }
281        else
282        {
283            ++pos;
284        }
285    }
286    return remove_count;
287}
288
289size_t
290ModuleList::Remove (ModuleList &module_list)
291{
292    Mutex::Locker locker(m_modules_mutex);
293    size_t num_removed = 0;
294    collection::iterator pos, end = module_list.m_modules.end();
295    for (pos = module_list.m_modules.begin(); pos != end; ++pos)
296    {
297        if (Remove (*pos))
298            ++num_removed;
299    }
300    return num_removed;
301}
302
303
304void
305ModuleList::Clear()
306{
307    ClearImpl();
308}
309
310void
311ModuleList::Destroy()
312{
313    ClearImpl();
314}
315
316void
317ModuleList::ClearImpl (bool use_notifier)
318{
319    Mutex::Locker locker(m_modules_mutex);
320    if (use_notifier && m_notifier)
321        m_notifier->WillClearList(*this);
322    m_modules.clear();
323}
324
325Module*
326ModuleList::GetModulePointerAtIndex (size_t idx) const
327{
328    Mutex::Locker locker(m_modules_mutex);
329    return GetModulePointerAtIndexUnlocked(idx);
330}
331
332Module*
333ModuleList::GetModulePointerAtIndexUnlocked (size_t idx) const
334{
335    if (idx < m_modules.size())
336        return m_modules[idx].get();
337    return NULL;
338}
339
340ModuleSP
341ModuleList::GetModuleAtIndex(size_t idx) const
342{
343    Mutex::Locker locker(m_modules_mutex);
344    return GetModuleAtIndexUnlocked(idx);
345}
346
347ModuleSP
348ModuleList::GetModuleAtIndexUnlocked(size_t idx) const
349{
350    ModuleSP module_sp;
351    if (idx < m_modules.size())
352        module_sp = m_modules[idx];
353    return module_sp;
354}
355
356size_t
357ModuleList::FindFunctions (const ConstString &name,
358                           uint32_t name_type_mask,
359                           bool include_symbols,
360                           bool include_inlines,
361                           bool append,
362                           SymbolContextList &sc_list) const
363{
364    if (!append)
365        sc_list.Clear();
366
367    const size_t old_size = sc_list.GetSize();
368
369    if (name_type_mask & eFunctionNameTypeAuto)
370    {
371        ConstString lookup_name;
372        uint32_t lookup_name_type_mask = 0;
373        bool match_name_after_lookup = false;
374        Module::PrepareForFunctionNameLookup (name, name_type_mask,
375                                              lookup_name,
376                                              lookup_name_type_mask,
377                                              match_name_after_lookup);
378
379        Mutex::Locker locker(m_modules_mutex);
380        collection::const_iterator pos, end = m_modules.end();
381        for (pos = m_modules.begin(); pos != end; ++pos)
382        {
383            (*pos)->FindFunctions (lookup_name,
384                                   NULL,
385                                   lookup_name_type_mask,
386                                   include_symbols,
387                                   include_inlines,
388                                   true,
389                                   sc_list);
390        }
391
392        if (match_name_after_lookup)
393        {
394            SymbolContext sc;
395            size_t i = old_size;
396            while (i<sc_list.GetSize())
397            {
398                if (sc_list.GetContextAtIndex(i, sc))
399                {
400                    const char *func_name = sc.GetFunctionName().GetCString();
401                    if (func_name && strstr (func_name, name.GetCString()) == NULL)
402                    {
403                        // Remove the current context
404                        sc_list.RemoveContextAtIndex(i);
405                        // Don't increment i and continue in the loop
406                        continue;
407                    }
408                }
409                ++i;
410            }
411        }
412
413    }
414    else
415    {
416        Mutex::Locker locker(m_modules_mutex);
417        collection::const_iterator pos, end = m_modules.end();
418        for (pos = m_modules.begin(); pos != end; ++pos)
419        {
420            (*pos)->FindFunctions (name, NULL, name_type_mask, include_symbols, include_inlines, true, sc_list);
421        }
422    }
423    return sc_list.GetSize() - old_size;
424}
425
426size_t
427ModuleList::FindFunctionSymbols (const ConstString &name,
428                                 uint32_t name_type_mask,
429                                 SymbolContextList& sc_list)
430{
431    const size_t old_size = sc_list.GetSize();
432
433    if (name_type_mask & eFunctionNameTypeAuto)
434    {
435        ConstString lookup_name;
436        uint32_t lookup_name_type_mask = 0;
437        bool match_name_after_lookup = false;
438        Module::PrepareForFunctionNameLookup (name, name_type_mask,
439                                              lookup_name,
440                                              lookup_name_type_mask,
441                                              match_name_after_lookup);
442
443        Mutex::Locker locker(m_modules_mutex);
444        collection::const_iterator pos, end = m_modules.end();
445        for (pos = m_modules.begin(); pos != end; ++pos)
446        {
447            (*pos)->FindFunctionSymbols (lookup_name,
448                                   lookup_name_type_mask,
449                                   sc_list);
450        }
451
452        if (match_name_after_lookup)
453        {
454            SymbolContext sc;
455            size_t i = old_size;
456            while (i<sc_list.GetSize())
457            {
458                if (sc_list.GetContextAtIndex(i, sc))
459                {
460                    const char *func_name = sc.GetFunctionName().GetCString();
461                    if (func_name && strstr (func_name, name.GetCString()) == NULL)
462                    {
463                        // Remove the current context
464                        sc_list.RemoveContextAtIndex(i);
465                        // Don't increment i and continue in the loop
466                        continue;
467                    }
468                }
469                ++i;
470            }
471        }
472
473    }
474    else
475    {
476        Mutex::Locker locker(m_modules_mutex);
477        collection::const_iterator pos, end = m_modules.end();
478        for (pos = m_modules.begin(); pos != end; ++pos)
479        {
480            (*pos)->FindFunctionSymbols (name, name_type_mask, sc_list);
481        }
482    }
483
484    return sc_list.GetSize() - old_size;
485}
486
487
488size_t
489ModuleList::FindFunctions(const RegularExpression &name,
490                          bool include_symbols,
491                          bool include_inlines,
492                          bool append,
493                          SymbolContextList& sc_list)
494{
495    const size_t old_size = sc_list.GetSize();
496
497    Mutex::Locker locker(m_modules_mutex);
498    collection::const_iterator pos, end = m_modules.end();
499    for (pos = m_modules.begin(); pos != end; ++pos)
500    {
501        (*pos)->FindFunctions (name, include_symbols, include_inlines, append, sc_list);
502    }
503
504    return sc_list.GetSize() - old_size;
505}
506
507size_t
508ModuleList::FindCompileUnits (const FileSpec &path,
509                              bool append,
510                              SymbolContextList &sc_list) const
511{
512    if (!append)
513        sc_list.Clear();
514
515    Mutex::Locker locker(m_modules_mutex);
516    collection::const_iterator pos, end = m_modules.end();
517    for (pos = m_modules.begin(); pos != end; ++pos)
518    {
519        (*pos)->FindCompileUnits (path, true, sc_list);
520    }
521
522    return sc_list.GetSize();
523}
524
525size_t
526ModuleList::FindGlobalVariables (const ConstString &name,
527                                 bool append,
528                                 size_t max_matches,
529                                 VariableList& variable_list) const
530{
531    size_t initial_size = variable_list.GetSize();
532    Mutex::Locker locker(m_modules_mutex);
533    collection::const_iterator pos, end = m_modules.end();
534    for (pos = m_modules.begin(); pos != end; ++pos)
535    {
536        (*pos)->FindGlobalVariables (name, NULL, append, max_matches, variable_list);
537    }
538    return variable_list.GetSize() - initial_size;
539}
540
541
542size_t
543ModuleList::FindGlobalVariables (const RegularExpression& regex,
544                                 bool append,
545                                 size_t max_matches,
546                                 VariableList& variable_list) const
547{
548    size_t initial_size = variable_list.GetSize();
549    Mutex::Locker locker(m_modules_mutex);
550    collection::const_iterator pos, end = m_modules.end();
551    for (pos = m_modules.begin(); pos != end; ++pos)
552    {
553        (*pos)->FindGlobalVariables (regex, append, max_matches, variable_list);
554    }
555    return variable_list.GetSize() - initial_size;
556}
557
558
559size_t
560ModuleList::FindSymbolsWithNameAndType (const ConstString &name,
561                                        SymbolType symbol_type,
562                                        SymbolContextList &sc_list,
563                                        bool append) const
564{
565    Mutex::Locker locker(m_modules_mutex);
566    if (!append)
567        sc_list.Clear();
568    size_t initial_size = sc_list.GetSize();
569
570    collection::const_iterator pos, end = m_modules.end();
571    for (pos = m_modules.begin(); pos != end; ++pos)
572        (*pos)->FindSymbolsWithNameAndType (name, symbol_type, sc_list);
573    return sc_list.GetSize() - initial_size;
574}
575
576size_t
577ModuleList::FindSymbolsMatchingRegExAndType (const RegularExpression &regex,
578                                             lldb::SymbolType symbol_type,
579                                             SymbolContextList &sc_list,
580                                             bool append) const
581{
582    Mutex::Locker locker(m_modules_mutex);
583    if (!append)
584        sc_list.Clear();
585    size_t initial_size = sc_list.GetSize();
586
587    collection::const_iterator pos, end = m_modules.end();
588    for (pos = m_modules.begin(); pos != end; ++pos)
589        (*pos)->FindSymbolsMatchingRegExAndType (regex, symbol_type, sc_list);
590    return sc_list.GetSize() - initial_size;
591}
592
593size_t
594ModuleList::FindModules (const ModuleSpec &module_spec, ModuleList& matching_module_list) const
595{
596    size_t existing_matches = matching_module_list.GetSize();
597
598    Mutex::Locker locker(m_modules_mutex);
599    collection::const_iterator pos, end = m_modules.end();
600    for (pos = m_modules.begin(); pos != end; ++pos)
601    {
602        ModuleSP module_sp(*pos);
603        if (module_sp->MatchesModuleSpec (module_spec))
604            matching_module_list.Append(module_sp);
605    }
606    return matching_module_list.GetSize() - existing_matches;
607}
608
609ModuleSP
610ModuleList::FindModule (const Module *module_ptr) const
611{
612    ModuleSP module_sp;
613
614    // Scope for "locker"
615    {
616        Mutex::Locker locker(m_modules_mutex);
617        collection::const_iterator pos, end = m_modules.end();
618
619        for (pos = m_modules.begin(); pos != end; ++pos)
620        {
621            if ((*pos).get() == module_ptr)
622            {
623                module_sp = (*pos);
624                break;
625            }
626        }
627    }
628    return module_sp;
629
630}
631
632ModuleSP
633ModuleList::FindModule (const UUID &uuid) const
634{
635    ModuleSP module_sp;
636
637    if (uuid.IsValid())
638    {
639        Mutex::Locker locker(m_modules_mutex);
640        collection::const_iterator pos, end = m_modules.end();
641
642        for (pos = m_modules.begin(); pos != end; ++pos)
643        {
644            if ((*pos)->GetUUID() == uuid)
645            {
646                module_sp = (*pos);
647                break;
648            }
649        }
650    }
651    return module_sp;
652}
653
654
655size_t
656ModuleList::FindTypes (const SymbolContext& sc, const ConstString &name, bool name_is_fully_qualified, size_t max_matches, TypeList& types) const
657{
658    Mutex::Locker locker(m_modules_mutex);
659
660    size_t total_matches = 0;
661    collection::const_iterator pos, end = m_modules.end();
662    if (sc.module_sp)
663    {
664        // The symbol context "sc" contains a module so we want to search that
665        // one first if it is in our list...
666        for (pos = m_modules.begin(); pos != end; ++pos)
667        {
668            if (sc.module_sp.get() == (*pos).get())
669            {
670                total_matches += (*pos)->FindTypes (sc, name, name_is_fully_qualified, max_matches, types);
671
672                if (total_matches >= max_matches)
673                    break;
674            }
675        }
676    }
677
678    if (total_matches < max_matches)
679    {
680        SymbolContext world_sc;
681        for (pos = m_modules.begin(); pos != end; ++pos)
682        {
683            // Search the module if the module is not equal to the one in the symbol
684            // context "sc". If "sc" contains a empty module shared pointer, then
685            // the comparisong will always be true (valid_module_ptr != NULL).
686            if (sc.module_sp.get() != (*pos).get())
687                total_matches += (*pos)->FindTypes (world_sc, name, name_is_fully_qualified, max_matches, types);
688
689            if (total_matches >= max_matches)
690                break;
691        }
692    }
693
694    return total_matches;
695}
696
697bool
698ModuleList::FindSourceFile (const FileSpec &orig_spec, FileSpec &new_spec) const
699{
700    Mutex::Locker locker(m_modules_mutex);
701    collection::const_iterator pos, end = m_modules.end();
702    for (pos = m_modules.begin(); pos != end; ++pos)
703    {
704        if ((*pos)->FindSourceFile (orig_spec, new_spec))
705            return true;
706    }
707    return false;
708}
709
710void
711ModuleList::FindAddressesForLine (const lldb::TargetSP target_sp,
712                                  const FileSpec &file, uint32_t line,
713                                  Function *function,
714                                  std::vector<Address> &output_local, std::vector<Address> &output_extern)
715{
716    Mutex::Locker locker(m_modules_mutex);
717    collection::const_iterator pos, end = m_modules.end();
718    for (pos = m_modules.begin(); pos != end; ++pos)
719    {
720        (*pos)->FindAddressesForLine(target_sp, file, line, function, output_local, output_extern);
721    }
722}
723
724ModuleSP
725ModuleList::FindFirstModule (const ModuleSpec &module_spec) const
726{
727    ModuleSP module_sp;
728    Mutex::Locker locker(m_modules_mutex);
729    collection::const_iterator pos, end = m_modules.end();
730    for (pos = m_modules.begin(); pos != end; ++pos)
731    {
732        ModuleSP module_sp(*pos);
733        if (module_sp->MatchesModuleSpec (module_spec))
734            return module_sp;
735    }
736    return module_sp;
737
738}
739
740size_t
741ModuleList::GetSize() const
742{
743    size_t size = 0;
744    {
745        Mutex::Locker locker(m_modules_mutex);
746        size = m_modules.size();
747    }
748    return size;
749}
750
751
752void
753ModuleList::Dump(Stream *s) const
754{
755//  s.Printf("%.*p: ", (int)sizeof(void*) * 2, this);
756//  s.Indent();
757//  s << "ModuleList\n";
758
759    Mutex::Locker locker(m_modules_mutex);
760    collection::const_iterator pos, end = m_modules.end();
761    for (pos = m_modules.begin(); pos != end; ++pos)
762    {
763        (*pos)->Dump(s);
764    }
765}
766
767void
768ModuleList::LogUUIDAndPaths (Log *log, const char *prefix_cstr)
769{
770    if (log)
771    {
772        Mutex::Locker locker(m_modules_mutex);
773        collection::const_iterator pos, begin = m_modules.begin(), end = m_modules.end();
774        for (pos = begin; pos != end; ++pos)
775        {
776            Module *module = pos->get();
777            const FileSpec &module_file_spec = module->GetFileSpec();
778            log->Printf ("%s[%u] %s (%s) \"%s\"",
779                         prefix_cstr ? prefix_cstr : "",
780                         (uint32_t)std::distance (begin, pos),
781                         module->GetUUID().GetAsString().c_str(),
782                         module->GetArchitecture().GetArchitectureName(),
783                         module_file_spec.GetPath().c_str());
784        }
785    }
786}
787
788bool
789ModuleList::ResolveFileAddress (lldb::addr_t vm_addr, Address& so_addr) const
790{
791    Mutex::Locker locker(m_modules_mutex);
792    collection::const_iterator pos, end = m_modules.end();
793    for (pos = m_modules.begin(); pos != end; ++pos)
794    {
795        if ((*pos)->ResolveFileAddress (vm_addr, so_addr))
796            return true;
797    }
798
799    return false;
800}
801
802uint32_t
803ModuleList::ResolveSymbolContextForAddress (const Address& so_addr, uint32_t resolve_scope, SymbolContext& sc) const
804{
805    // The address is already section offset so it has a module
806    uint32_t resolved_flags = 0;
807    ModuleSP module_sp (so_addr.GetModule());
808    if (module_sp)
809    {
810        resolved_flags = module_sp->ResolveSymbolContextForAddress (so_addr,
811                                                                    resolve_scope,
812                                                                    sc);
813    }
814    else
815    {
816        Mutex::Locker locker(m_modules_mutex);
817        collection::const_iterator pos, end = m_modules.end();
818        for (pos = m_modules.begin(); pos != end; ++pos)
819        {
820            resolved_flags = (*pos)->ResolveSymbolContextForAddress (so_addr,
821                                                                     resolve_scope,
822                                                                     sc);
823            if (resolved_flags != 0)
824                break;
825        }
826    }
827
828    return resolved_flags;
829}
830
831uint32_t
832ModuleList::ResolveSymbolContextForFilePath
833(
834    const char *file_path,
835    uint32_t line,
836    bool check_inlines,
837    uint32_t resolve_scope,
838    SymbolContextList& sc_list
839)  const
840{
841    FileSpec file_spec(file_path, false);
842    return ResolveSymbolContextsForFileSpec (file_spec, line, check_inlines, resolve_scope, sc_list);
843}
844
845uint32_t
846ModuleList::ResolveSymbolContextsForFileSpec (const FileSpec &file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, SymbolContextList& sc_list) const
847{
848    Mutex::Locker locker(m_modules_mutex);
849    collection::const_iterator pos, end = m_modules.end();
850    for (pos = m_modules.begin(); pos != end; ++pos)
851    {
852        (*pos)->ResolveSymbolContextsForFileSpec (file_spec, line, check_inlines, resolve_scope, sc_list);
853    }
854
855    return sc_list.GetSize();
856}
857
858size_t
859ModuleList::GetIndexForModule (const Module *module) const
860{
861    if (module)
862    {
863        Mutex::Locker locker(m_modules_mutex);
864        collection::const_iterator pos;
865        collection::const_iterator begin = m_modules.begin();
866        collection::const_iterator end = m_modules.end();
867        for (pos = begin; pos != end; ++pos)
868        {
869            if ((*pos).get() == module)
870                return std::distance (begin, pos);
871        }
872    }
873    return LLDB_INVALID_INDEX32;
874}
875
876static ModuleList &
877GetSharedModuleList ()
878{
879    static ModuleList *g_shared_module_list = NULL;
880    static std::once_flag g_once_flag;
881    std::call_once(g_once_flag, [](){
882        // NOTE: Intentionally leak the module list so a program doesn't have to
883        // cleanup all modules and object files as it exits. This just wastes time
884        // doing a bunch of cleanup that isn't required.
885        if (g_shared_module_list == NULL)
886            g_shared_module_list = new ModuleList(); // <--- Intentional leak!!!
887    });
888    return *g_shared_module_list;
889}
890
891bool
892ModuleList::ModuleIsInCache (const Module *module_ptr)
893{
894    if (module_ptr)
895    {
896        ModuleList &shared_module_list = GetSharedModuleList ();
897        return shared_module_list.FindModule (module_ptr).get() != NULL;
898    }
899    return false;
900}
901
902size_t
903ModuleList::FindSharedModules (const ModuleSpec &module_spec, ModuleList &matching_module_list)
904{
905    return GetSharedModuleList ().FindModules (module_spec, matching_module_list);
906}
907
908size_t
909ModuleList::RemoveOrphanSharedModules (bool mandatory)
910{
911    return GetSharedModuleList ().RemoveOrphans(mandatory);
912}
913
914Error
915ModuleList::GetSharedModule
916(
917    const ModuleSpec &module_spec,
918    ModuleSP &module_sp,
919    const FileSpecList *module_search_paths_ptr,
920    ModuleSP *old_module_sp_ptr,
921    bool *did_create_ptr,
922    bool always_create
923)
924{
925    ModuleList &shared_module_list = GetSharedModuleList ();
926    Mutex::Locker locker(shared_module_list.m_modules_mutex);
927    char path[PATH_MAX];
928
929    Error error;
930
931    module_sp.reset();
932
933    if (did_create_ptr)
934        *did_create_ptr = false;
935    if (old_module_sp_ptr)
936        old_module_sp_ptr->reset();
937
938    const UUID *uuid_ptr = module_spec.GetUUIDPtr();
939    const FileSpec &module_file_spec = module_spec.GetFileSpec();
940    const ArchSpec &arch = module_spec.GetArchitecture();
941
942    // Make sure no one else can try and get or create a module while this
943    // function is actively working on it by doing an extra lock on the
944    // global mutex list.
945    if (always_create == false)
946    {
947        ModuleList matching_module_list;
948        const size_t num_matching_modules = shared_module_list.FindModules (module_spec, matching_module_list);
949        if (num_matching_modules > 0)
950        {
951            for (size_t module_idx = 0; module_idx < num_matching_modules; ++module_idx)
952            {
953                module_sp = matching_module_list.GetModuleAtIndex(module_idx);
954
955                // Make sure the file for the module hasn't been modified
956                if (module_sp->FileHasChanged())
957                {
958                    if (old_module_sp_ptr && !old_module_sp_ptr->get())
959                        *old_module_sp_ptr = module_sp;
960
961                    Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_MODULES));
962                    if (log)
963                        log->Printf("module changed: %p, removing from global module list",
964                                    static_cast<void*>(module_sp.get()));
965
966                    shared_module_list.Remove (module_sp);
967                    module_sp.reset();
968                }
969                else
970                {
971                    // The module matches and the module was not modified from
972                    // when it was last loaded.
973                    return error;
974                }
975            }
976        }
977    }
978
979    if (module_sp)
980        return error;
981    else
982    {
983        module_sp.reset (new Module (module_spec));
984        // Make sure there are a module and an object file since we can specify
985        // a valid file path with an architecture that might not be in that file.
986        // By getting the object file we can guarantee that the architecture matches
987        if (module_sp)
988        {
989            if (module_sp->GetObjectFile())
990            {
991                // If we get in here we got the correct arch, now we just need
992                // to verify the UUID if one was given
993                if (uuid_ptr && *uuid_ptr != module_sp->GetUUID())
994                    module_sp.reset();
995                else
996                {
997                    if (did_create_ptr)
998                        *did_create_ptr = true;
999
1000                    shared_module_list.ReplaceEquivalent(module_sp);
1001                    return error;
1002                }
1003            }
1004            else
1005                module_sp.reset();
1006        }
1007    }
1008
1009    // Either the file didn't exist where at the path, or no path was given, so
1010    // we now have to use more extreme measures to try and find the appropriate
1011    // module.
1012
1013    // Fixup the incoming path in case the path points to a valid file, yet
1014    // the arch or UUID (if one was passed in) don't match.
1015    FileSpec file_spec = Symbols::LocateExecutableObjectFile (module_spec);
1016
1017    // Don't look for the file if it appears to be the same one we already
1018    // checked for above...
1019    if (file_spec != module_file_spec)
1020    {
1021        if (!file_spec.Exists())
1022        {
1023            file_spec.GetPath(path, sizeof(path));
1024            if (path[0] == '\0')
1025                module_file_spec.GetPath(path, sizeof(path));
1026            // How can this check ever be true? This branch it is false, and we haven't modified file_spec.
1027            if (file_spec.Exists())
1028            {
1029                std::string uuid_str;
1030                if (uuid_ptr && uuid_ptr->IsValid())
1031                    uuid_str = uuid_ptr->GetAsString();
1032
1033                if (arch.IsValid())
1034                {
1035                    if (!uuid_str.empty())
1036                        error.SetErrorStringWithFormat("'%s' does not contain the %s architecture and UUID %s", path, arch.GetArchitectureName(), uuid_str.c_str());
1037                    else
1038                        error.SetErrorStringWithFormat("'%s' does not contain the %s architecture.", path, arch.GetArchitectureName());
1039                }
1040            }
1041            else
1042            {
1043                error.SetErrorStringWithFormat("'%s' does not exist", path);
1044            }
1045            if (error.Fail())
1046                module_sp.reset();
1047            return error;
1048        }
1049
1050
1051        // Make sure no one else can try and get or create a module while this
1052        // function is actively working on it by doing an extra lock on the
1053        // global mutex list.
1054        ModuleSpec platform_module_spec(module_spec);
1055        platform_module_spec.GetFileSpec() = file_spec;
1056        platform_module_spec.GetPlatformFileSpec() = file_spec;
1057        ModuleList matching_module_list;
1058        if (shared_module_list.FindModules (platform_module_spec, matching_module_list) > 0)
1059        {
1060            module_sp = matching_module_list.GetModuleAtIndex(0);
1061
1062            // If we didn't have a UUID in mind when looking for the object file,
1063            // then we should make sure the modification time hasn't changed!
1064            if (platform_module_spec.GetUUIDPtr() == NULL)
1065            {
1066                TimeValue file_spec_mod_time(file_spec.GetModificationTime());
1067                if (file_spec_mod_time.IsValid())
1068                {
1069                    if (file_spec_mod_time != module_sp->GetModificationTime())
1070                    {
1071                        if (old_module_sp_ptr)
1072                            *old_module_sp_ptr = module_sp;
1073                        shared_module_list.Remove (module_sp);
1074                        module_sp.reset();
1075                    }
1076                }
1077            }
1078        }
1079
1080        if (module_sp.get() == NULL)
1081        {
1082            module_sp.reset (new Module (platform_module_spec));
1083            // Make sure there are a module and an object file since we can specify
1084            // a valid file path with an architecture that might not be in that file.
1085            // By getting the object file we can guarantee that the architecture matches
1086            if (module_sp && module_sp->GetObjectFile())
1087            {
1088                if (did_create_ptr)
1089                    *did_create_ptr = true;
1090
1091                shared_module_list.ReplaceEquivalent(module_sp);
1092            }
1093            else
1094            {
1095                file_spec.GetPath(path, sizeof(path));
1096
1097                if (file_spec)
1098                {
1099                    if (arch.IsValid())
1100                        error.SetErrorStringWithFormat("unable to open %s architecture in '%s'", arch.GetArchitectureName(), path);
1101                    else
1102                        error.SetErrorStringWithFormat("unable to open '%s'", path);
1103                }
1104                else
1105                {
1106                    std::string uuid_str;
1107                    if (uuid_ptr && uuid_ptr->IsValid())
1108                        uuid_str = uuid_ptr->GetAsString();
1109
1110                    if (!uuid_str.empty())
1111                        error.SetErrorStringWithFormat("cannot locate a module for UUID '%s'", uuid_str.c_str());
1112                    else
1113                        error.SetErrorStringWithFormat("cannot locate a module");
1114                }
1115            }
1116        }
1117    }
1118
1119    return error;
1120}
1121
1122bool
1123ModuleList::RemoveSharedModule (lldb::ModuleSP &module_sp)
1124{
1125    return GetSharedModuleList ().Remove (module_sp);
1126}
1127
1128bool
1129ModuleList::RemoveSharedModuleIfOrphaned (const Module *module_ptr)
1130{
1131    return GetSharedModuleList ().RemoveIfOrphaned (module_ptr);
1132}
1133
1134bool
1135ModuleList::LoadScriptingResourcesInTarget (Target *target,
1136                                            std::list<Error>& errors,
1137                                            Stream *feedback_stream,
1138                                            bool continue_on_error)
1139{
1140    if (!target)
1141        return false;
1142    Mutex::Locker locker(m_modules_mutex);
1143    for (auto module : m_modules)
1144    {
1145        Error error;
1146        if (module)
1147        {
1148            if (!module->LoadScriptingResourceInTarget(target, error, feedback_stream))
1149            {
1150                if (error.Fail() && error.AsCString())
1151                {
1152                    error.SetErrorStringWithFormat("unable to load scripting data for module %s - error reported was %s",
1153                                                   module->GetFileSpec().GetFileNameStrippingExtension().GetCString(),
1154                                                   error.AsCString());
1155                    errors.push_back(error);
1156
1157                    if (!continue_on_error)
1158                        return false;
1159                }
1160            }
1161        }
1162    }
1163    return errors.size() == 0;
1164}
1165