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 // C++ Includes
14 // Other libraries and framework includes
15 // Project includes
16 #include "lldb/Core/Log.h"
17 #include "lldb/Core/Module.h"
18 #include "lldb/Host/Host.h"
19 #include "lldb/Host/Symbols.h"
20 #include "lldb/Symbol/ClangNamespaceDecl.h"
21 #include "lldb/Symbol/ObjectFile.h"
22 #include "lldb/Symbol/VariableList.h"
23 
24 using namespace lldb;
25 using namespace lldb_private;
26 
27 //----------------------------------------------------------------------
28 // ModuleList constructor
29 //----------------------------------------------------------------------
30 ModuleList::ModuleList() :
31     m_modules(),
32     m_modules_mutex (Mutex::eMutexTypeRecursive)
33 {
34 }
35 
36 //----------------------------------------------------------------------
37 // Copy constructor
38 //----------------------------------------------------------------------
39 ModuleList::ModuleList(const ModuleList& rhs) :
40     m_modules(rhs.m_modules)
41 {
42 }
43 
44 //----------------------------------------------------------------------
45 // Assignment operator
46 //----------------------------------------------------------------------
47 const ModuleList&
48 ModuleList::operator= (const ModuleList& rhs)
49 {
50     if (this != &rhs)
51     {
52         Mutex::Locker locker(m_modules_mutex);
53         m_modules = rhs.m_modules;
54     }
55     return *this;
56 }
57 
58 //----------------------------------------------------------------------
59 // Destructor
60 //----------------------------------------------------------------------
61 ModuleList::~ModuleList()
62 {
63 }
64 
65 void
66 ModuleList::Append (const ModuleSP &module_sp)
67 {
68     if (module_sp)
69     {
70         Mutex::Locker locker(m_modules_mutex);
71         m_modules.push_back(module_sp);
72     }
73 }
74 
75 bool
76 ModuleList::AppendIfNeeded (const ModuleSP &module_sp)
77 {
78     if (module_sp)
79     {
80         Mutex::Locker locker(m_modules_mutex);
81         collection::iterator pos, end = m_modules.end();
82         for (pos = m_modules.begin(); pos != end; ++pos)
83         {
84             if (pos->get() == module_sp.get())
85                 return false; // Already in the list
86         }
87         // Only push module_sp on the list if it wasn't already in there.
88         m_modules.push_back(module_sp);
89         return true;
90     }
91     return false;
92 }
93 
94 bool
95 ModuleList::Remove (const ModuleSP &module_sp)
96 {
97     if (module_sp)
98     {
99         Mutex::Locker locker(m_modules_mutex);
100         collection::iterator pos, end = m_modules.end();
101         for (pos = m_modules.begin(); pos != end; ++pos)
102         {
103             if (pos->get() == module_sp.get())
104             {
105                 m_modules.erase (pos);
106                 return true;
107             }
108         }
109     }
110     return false;
111 }
112 
113 
114 size_t
115 ModuleList::RemoveOrphans ()
116 {
117     Mutex::Locker locker(m_modules_mutex);
118     collection::iterator pos = m_modules.begin();
119     size_t remove_count = 0;
120     while (pos != m_modules.end())
121     {
122         if (pos->unique())
123         {
124             pos = m_modules.erase (pos);
125             ++remove_count;
126         }
127         else
128         {
129             ++pos;
130         }
131     }
132     return remove_count;
133 }
134 
135 size_t
136 ModuleList::Remove (ModuleList &module_list)
137 {
138     Mutex::Locker locker(m_modules_mutex);
139     size_t num_removed = 0;
140     collection::iterator pos, end = module_list.m_modules.end();
141     for (pos = module_list.m_modules.begin(); pos != end; ++pos)
142     {
143         if (Remove (*pos))
144             ++num_removed;
145     }
146     return num_removed;
147 }
148 
149 
150 
151 void
152 ModuleList::Clear()
153 {
154     Mutex::Locker locker(m_modules_mutex);
155     m_modules.clear();
156 }
157 
158 void
159 ModuleList::Destroy()
160 {
161     Mutex::Locker locker(m_modules_mutex);
162     collection empty;
163     m_modules.swap(empty);
164 }
165 
166 Module*
167 ModuleList::GetModulePointerAtIndex (uint32_t idx) const
168 {
169     Mutex::Locker locker(m_modules_mutex);
170     if (idx < m_modules.size())
171         return m_modules[idx].get();
172     return NULL;
173 }
174 
175 ModuleSP
176 ModuleList::GetModuleAtIndex(uint32_t idx)
177 {
178     Mutex::Locker locker(m_modules_mutex);
179     ModuleSP module_sp;
180     if (idx < m_modules.size())
181         module_sp = m_modules[idx];
182     return module_sp;
183 }
184 
185 uint32_t
186 ModuleList::FindFunctions (const ConstString &name,
187                            uint32_t name_type_mask,
188                            bool include_symbols,
189                            bool include_inlines,
190                            bool append,
191                            SymbolContextList &sc_list)
192 {
193     if (!append)
194         sc_list.Clear();
195 
196     Mutex::Locker locker(m_modules_mutex);
197     collection::const_iterator pos, end = m_modules.end();
198     for (pos = m_modules.begin(); pos != end; ++pos)
199     {
200         (*pos)->FindFunctions (name, NULL, name_type_mask, include_symbols, include_inlines, true, sc_list);
201     }
202 
203     return sc_list.GetSize();
204 }
205 
206 uint32_t
207 ModuleList::FindCompileUnits (const FileSpec &path,
208                               bool append,
209                               SymbolContextList &sc_list)
210 {
211     if (!append)
212         sc_list.Clear();
213 
214     Mutex::Locker locker(m_modules_mutex);
215     collection::const_iterator pos, end = m_modules.end();
216     for (pos = m_modules.begin(); pos != end; ++pos)
217     {
218         (*pos)->FindCompileUnits (path, true, sc_list);
219     }
220 
221     return sc_list.GetSize();
222 }
223 
224 uint32_t
225 ModuleList::FindGlobalVariables (const ConstString &name,
226                                  bool append,
227                                  uint32_t max_matches,
228                                  VariableList& variable_list)
229 {
230     size_t initial_size = variable_list.GetSize();
231     Mutex::Locker locker(m_modules_mutex);
232     collection::iterator pos, end = m_modules.end();
233     for (pos = m_modules.begin(); pos != end; ++pos)
234     {
235         (*pos)->FindGlobalVariables (name, NULL, append, max_matches, variable_list);
236     }
237     return variable_list.GetSize() - initial_size;
238 }
239 
240 
241 uint32_t
242 ModuleList::FindGlobalVariables (const RegularExpression& regex,
243                                  bool append,
244                                  uint32_t max_matches,
245                                  VariableList& variable_list)
246 {
247     size_t initial_size = variable_list.GetSize();
248     Mutex::Locker locker(m_modules_mutex);
249     collection::iterator pos, end = m_modules.end();
250     for (pos = m_modules.begin(); pos != end; ++pos)
251     {
252         (*pos)->FindGlobalVariables (regex, append, max_matches, variable_list);
253     }
254     return variable_list.GetSize() - initial_size;
255 }
256 
257 
258 size_t
259 ModuleList::FindSymbolsWithNameAndType (const ConstString &name,
260                                         SymbolType symbol_type,
261                                         SymbolContextList &sc_list,
262                                         bool append)
263 {
264     Mutex::Locker locker(m_modules_mutex);
265     if (!append)
266         sc_list.Clear();
267     size_t initial_size = sc_list.GetSize();
268 
269     collection::iterator pos, end = m_modules.end();
270     for (pos = m_modules.begin(); pos != end; ++pos)
271         (*pos)->FindSymbolsWithNameAndType (name, symbol_type, sc_list);
272     return sc_list.GetSize() - initial_size;
273 }
274 
275     size_t
276 ModuleList::FindSymbolsMatchingRegExAndType (const RegularExpression &regex,
277                                              lldb::SymbolType symbol_type,
278                                              SymbolContextList &sc_list,
279                                              bool append)
280 {
281     Mutex::Locker locker(m_modules_mutex);
282     if (!append)
283         sc_list.Clear();
284     size_t initial_size = sc_list.GetSize();
285 
286     collection::iterator pos, end = m_modules.end();
287     for (pos = m_modules.begin(); pos != end; ++pos)
288         (*pos)->FindSymbolsMatchingRegExAndType (regex, symbol_type, sc_list);
289     return sc_list.GetSize() - initial_size;
290 }
291 
292 size_t
293 ModuleList::FindModules (const ModuleSpec &module_spec, ModuleList& matching_module_list) const
294 {
295     size_t existing_matches = matching_module_list.GetSize();
296 
297     Mutex::Locker locker(m_modules_mutex);
298     collection::const_iterator pos, end = m_modules.end();
299     for (pos = m_modules.begin(); pos != end; ++pos)
300     {
301         ModuleSP module_sp(*pos);
302         if (module_sp->MatchesModuleSpec (module_spec))
303             matching_module_list.Append(module_sp);
304     }
305     return matching_module_list.GetSize() - existing_matches;
306 }
307 
308 ModuleSP
309 ModuleList::FindModule (const Module *module_ptr)
310 {
311     ModuleSP module_sp;
312 
313     // Scope for "locker"
314     {
315         Mutex::Locker locker(m_modules_mutex);
316         collection::const_iterator pos, end = m_modules.end();
317 
318         for (pos = m_modules.begin(); pos != end; ++pos)
319         {
320             if ((*pos).get() == module_ptr)
321             {
322                 module_sp = (*pos);
323                 break;
324             }
325         }
326     }
327     return module_sp;
328 
329 }
330 
331 ModuleSP
332 ModuleList::FindModule (const UUID &uuid)
333 {
334     ModuleSP module_sp;
335 
336     if (uuid.IsValid())
337     {
338         Mutex::Locker locker(m_modules_mutex);
339         collection::const_iterator pos, end = m_modules.end();
340 
341         for (pos = m_modules.begin(); pos != end; ++pos)
342         {
343             if ((*pos)->GetUUID() == uuid)
344             {
345                 module_sp = (*pos);
346                 break;
347             }
348         }
349     }
350     return module_sp;
351 }
352 
353 
354 uint32_t
355 ModuleList::FindTypes (const SymbolContext& sc, const ConstString &name, bool name_is_fully_qualified, uint32_t max_matches, TypeList& types)
356 {
357     Mutex::Locker locker(m_modules_mutex);
358 
359     uint32_t total_matches = 0;
360     collection::const_iterator pos, end = m_modules.end();
361     if (sc.module_sp)
362     {
363         // The symbol context "sc" contains a module so we want to search that
364         // one first if it is in our list...
365         for (pos = m_modules.begin(); pos != end; ++pos)
366         {
367             if (sc.module_sp.get() == (*pos).get())
368             {
369                 total_matches += (*pos)->FindTypes (sc, name, name_is_fully_qualified, max_matches, types);
370 
371                 if (total_matches >= max_matches)
372                     break;
373             }
374         }
375     }
376 
377     if (total_matches < max_matches)
378     {
379         for (pos = m_modules.begin(); pos != end; ++pos)
380         {
381             // Search the module if the module is not equal to the one in the symbol
382             // context "sc". If "sc" contains a empty module shared pointer, then
383             // the comparisong will always be true (valid_module_ptr != NULL).
384             if (sc.module_sp.get() != (*pos).get())
385                 total_matches += (*pos)->FindTypes (sc, name, name_is_fully_qualified, max_matches, types);
386 
387             if (total_matches >= max_matches)
388                 break;
389         }
390     }
391 
392     return total_matches;
393 }
394 
395 bool
396 ModuleList::FindSourceFile (const FileSpec &orig_spec, FileSpec &new_spec) const
397 {
398     Mutex::Locker locker(m_modules_mutex);
399     collection::const_iterator pos, end = m_modules.end();
400     for (pos = m_modules.begin(); pos != end; ++pos)
401     {
402         if ((*pos)->FindSourceFile (orig_spec, new_spec))
403             return true;
404     }
405     return false;
406 }
407 
408 
409 
410 ModuleSP
411 ModuleList::FindFirstModule (const ModuleSpec &module_spec)
412 {
413     ModuleSP module_sp;
414     Mutex::Locker locker(m_modules_mutex);
415     collection::const_iterator pos, end = m_modules.end();
416     for (pos = m_modules.begin(); pos != end; ++pos)
417     {
418         ModuleSP module_sp(*pos);
419         if (module_sp->MatchesModuleSpec (module_spec))
420             return module_sp;
421     }
422     return module_sp;
423 
424 }
425 
426 size_t
427 ModuleList::GetSize() const
428 {
429     size_t size = 0;
430     {
431         Mutex::Locker locker(m_modules_mutex);
432         size = m_modules.size();
433     }
434     return size;
435 }
436 
437 
438 void
439 ModuleList::Dump(Stream *s) const
440 {
441 //  s.Printf("%.*p: ", (int)sizeof(void*) * 2, this);
442 //  s.Indent();
443 //  s << "ModuleList\n";
444 
445     Mutex::Locker locker(m_modules_mutex);
446     collection::const_iterator pos, end = m_modules.end();
447     for (pos = m_modules.begin(); pos != end; ++pos)
448     {
449         (*pos)->Dump(s);
450     }
451 }
452 
453 void
454 ModuleList::LogUUIDAndPaths (LogSP &log_sp, const char *prefix_cstr)
455 {
456     if (log_sp)
457     {
458         Mutex::Locker locker(m_modules_mutex);
459         char uuid_cstr[256];
460         collection::const_iterator pos, begin = m_modules.begin(), end = m_modules.end();
461         for (pos = begin; pos != end; ++pos)
462         {
463             Module *module = pos->get();
464             module->GetUUID().GetAsCString (uuid_cstr, sizeof(uuid_cstr));
465             const FileSpec &module_file_spec = module->GetFileSpec();
466             log_sp->Printf ("%s[%u] %s (%s) \"%s/%s\"",
467                             prefix_cstr ? prefix_cstr : "",
468                             (uint32_t)std::distance (begin, pos),
469                             uuid_cstr,
470                             module->GetArchitecture().GetArchitectureName(),
471                             module_file_spec.GetDirectory().GetCString(),
472                             module_file_spec.GetFilename().GetCString());
473         }
474     }
475 }
476 
477 bool
478 ModuleList::ResolveFileAddress (lldb::addr_t vm_addr, Address& so_addr)
479 {
480     Mutex::Locker locker(m_modules_mutex);
481     collection::const_iterator pos, end = m_modules.end();
482     for (pos = m_modules.begin(); pos != end; ++pos)
483     {
484         if ((*pos)->ResolveFileAddress (vm_addr, so_addr))
485             return true;
486     }
487 
488     return false;
489 }
490 
491 uint32_t
492 ModuleList::ResolveSymbolContextForAddress (const Address& so_addr, uint32_t resolve_scope, SymbolContext& sc)
493 {
494     // The address is already section offset so it has a module
495     uint32_t resolved_flags = 0;
496     ModuleSP module_sp (so_addr.GetModule());
497     if (module_sp)
498     {
499         resolved_flags = module_sp->ResolveSymbolContextForAddress (so_addr,
500                                                                     resolve_scope,
501                                                                     sc);
502     }
503     else
504     {
505         Mutex::Locker locker(m_modules_mutex);
506         collection::const_iterator pos, end = m_modules.end();
507         for (pos = m_modules.begin(); pos != end; ++pos)
508         {
509             resolved_flags = (*pos)->ResolveSymbolContextForAddress (so_addr,
510                                                                      resolve_scope,
511                                                                      sc);
512             if (resolved_flags != 0)
513                 break;
514         }
515     }
516 
517     return resolved_flags;
518 }
519 
520 uint32_t
521 ModuleList::ResolveSymbolContextForFilePath
522 (
523     const char *file_path,
524     uint32_t line,
525     bool check_inlines,
526     uint32_t resolve_scope,
527     SymbolContextList& sc_list
528 )
529 {
530     FileSpec file_spec(file_path, false);
531     return ResolveSymbolContextsForFileSpec (file_spec, line, check_inlines, resolve_scope, sc_list);
532 }
533 
534 uint32_t
535 ModuleList::ResolveSymbolContextsForFileSpec (const FileSpec &file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, SymbolContextList& sc_list)
536 {
537     Mutex::Locker locker(m_modules_mutex);
538     collection::const_iterator pos, end = m_modules.end();
539     for (pos = m_modules.begin(); pos != end; ++pos)
540     {
541         (*pos)->ResolveSymbolContextsForFileSpec (file_spec, line, check_inlines, resolve_scope, sc_list);
542     }
543 
544     return sc_list.GetSize();
545 }
546 
547 uint32_t
548 ModuleList::GetIndexForModule (const Module *module) const
549 {
550     if (module)
551     {
552         Mutex::Locker locker(m_modules_mutex);
553         collection::const_iterator pos;
554         collection::const_iterator begin = m_modules.begin();
555         collection::const_iterator end = m_modules.end();
556         for (pos = begin; pos != end; ++pos)
557         {
558             if ((*pos).get() == module)
559                 return std::distance (begin, pos);
560         }
561     }
562     return LLDB_INVALID_INDEX32;
563 }
564 
565 static ModuleList &
566 GetSharedModuleList ()
567 {
568     static ModuleList g_shared_module_list;
569     return g_shared_module_list;
570 }
571 
572 bool
573 ModuleList::ModuleIsInCache (const Module *module_ptr)
574 {
575     if (module_ptr)
576     {
577         ModuleList &shared_module_list = GetSharedModuleList ();
578         return shared_module_list.FindModule (module_ptr).get() != NULL;
579     }
580     return false;
581 }
582 
583 size_t
584 ModuleList::FindSharedModules (const ModuleSpec &module_spec, ModuleList &matching_module_list)
585 {
586     return GetSharedModuleList ().FindModules (module_spec, matching_module_list);
587 }
588 
589 uint32_t
590 ModuleList::RemoveOrphanSharedModules ()
591 {
592     return GetSharedModuleList ().RemoveOrphans();
593 }
594 
595 Error
596 ModuleList::GetSharedModule
597 (
598     const ModuleSpec &module_spec,
599     ModuleSP &module_sp,
600     const FileSpecList *module_search_paths_ptr,
601     ModuleSP *old_module_sp_ptr,
602     bool *did_create_ptr,
603     bool always_create
604 )
605 {
606     ModuleList &shared_module_list = GetSharedModuleList ();
607     Mutex::Locker locker(shared_module_list.m_modules_mutex);
608     char path[PATH_MAX];
609     char uuid_cstr[64];
610 
611     Error error;
612 
613     module_sp.reset();
614 
615     if (did_create_ptr)
616         *did_create_ptr = false;
617     if (old_module_sp_ptr)
618         old_module_sp_ptr->reset();
619 
620     const UUID *uuid_ptr = module_spec.GetUUIDPtr();
621     const FileSpec &module_file_spec = module_spec.GetFileSpec();
622     const ArchSpec &arch = module_spec.GetArchitecture();
623 
624     // Make sure no one else can try and get or create a module while this
625     // function is actively working on it by doing an extra lock on the
626     // global mutex list.
627     if (always_create == false)
628     {
629         ModuleList matching_module_list;
630         const size_t num_matching_modules = shared_module_list.FindModules (module_spec, matching_module_list);
631         if (num_matching_modules > 0)
632         {
633             for (uint32_t module_idx = 0; module_idx < num_matching_modules; ++module_idx)
634             {
635                 module_sp = matching_module_list.GetModuleAtIndex(module_idx);
636                 // If we had a UUID and we found a match, then that is good enough for a match
637                 if (uuid_ptr)
638                     break;
639                 if (module_file_spec)
640                 {
641                     // If we didn't have a UUID in mind when looking for the object file,
642                     // then we should make sure the modification time hasn't changed!
643                     TimeValue file_spec_mod_time(module_file_spec.GetModificationTime());
644                     if (file_spec_mod_time.IsValid())
645                     {
646                         if (file_spec_mod_time == module_sp->GetModificationTime())
647                             return error;
648                     }
649                 }
650                 if (old_module_sp_ptr && !old_module_sp_ptr->get())
651                     *old_module_sp_ptr = module_sp;
652                 shared_module_list.Remove (module_sp);
653                 module_sp.reset();
654             }
655         }
656     }
657 
658     if (module_sp)
659         return error;
660     else
661     {
662         module_sp.reset (new Module (module_spec));
663         // Make sure there are a module and an object file since we can specify
664         // a valid file path with an architecture that might not be in that file.
665         // By getting the object file we can guarantee that the architecture matches
666         if (module_sp)
667         {
668             if (module_sp->GetObjectFile())
669             {
670                 // If we get in here we got the correct arch, now we just need
671                 // to verify the UUID if one was given
672                 if (uuid_ptr && *uuid_ptr != module_sp->GetUUID())
673                     module_sp.reset();
674                 else
675                 {
676                     if (did_create_ptr)
677                         *did_create_ptr = true;
678 
679                     shared_module_list.Append(module_sp);
680                     return error;
681                 }
682             }
683             else
684                 module_sp.reset();
685         }
686     }
687 
688     // Either the file didn't exist where at the path, or no path was given, so
689     // we now have to use more extreme measures to try and find the appropriate
690     // module.
691 
692     // Fixup the incoming path in case the path points to a valid file, yet
693     // the arch or UUID (if one was passed in) don't match.
694     FileSpec file_spec = Symbols::LocateExecutableObjectFile (module_spec);
695 
696     // Don't look for the file if it appears to be the same one we already
697     // checked for above...
698     if (file_spec != module_file_spec)
699     {
700         if (!file_spec.Exists())
701         {
702             file_spec.GetPath(path, sizeof(path));
703             if (path[0] == '\0')
704                 module_file_spec.GetPath(path, sizeof(path));
705             if (file_spec.Exists())
706             {
707                 if (uuid_ptr && uuid_ptr->IsValid())
708                     uuid_ptr->GetAsCString(uuid_cstr, sizeof (uuid_cstr));
709                 else
710                     uuid_cstr[0] = '\0';
711 
712 
713                 if (arch.IsValid())
714                 {
715                     if (uuid_cstr[0])
716                         error.SetErrorStringWithFormat("'%s' does not contain the %s architecture and UUID %s", path, arch.GetArchitectureName(), uuid_cstr);
717                     else
718                         error.SetErrorStringWithFormat("'%s' does not contain the %s architecture.", path, arch.GetArchitectureName());
719                 }
720             }
721             else
722             {
723                 error.SetErrorStringWithFormat("'%s' does not exist", path);
724             }
725             if (error.Fail())
726                 module_sp.reset();
727             return error;
728         }
729 
730 
731         // Make sure no one else can try and get or create a module while this
732         // function is actively working on it by doing an extra lock on the
733         // global mutex list.
734         ModuleSpec platform_module_spec(module_spec);
735         platform_module_spec.GetFileSpec() = file_spec;
736         platform_module_spec.GetPlatformFileSpec() = file_spec;
737         ModuleList matching_module_list;
738         if (shared_module_list.FindModules (platform_module_spec, matching_module_list) > 0)
739         {
740             module_sp = matching_module_list.GetModuleAtIndex(0);
741 
742             // If we didn't have a UUID in mind when looking for the object file,
743             // then we should make sure the modification time hasn't changed!
744             if (platform_module_spec.GetUUIDPtr() == NULL)
745             {
746                 TimeValue file_spec_mod_time(file_spec.GetModificationTime());
747                 if (file_spec_mod_time.IsValid())
748                 {
749                     if (file_spec_mod_time != module_sp->GetModificationTime())
750                     {
751                         if (old_module_sp_ptr)
752                             *old_module_sp_ptr = module_sp;
753                         shared_module_list.Remove (module_sp);
754                         module_sp.reset();
755                     }
756                 }
757             }
758         }
759 
760         if (module_sp.get() == NULL)
761         {
762             module_sp.reset (new Module (platform_module_spec));
763             // Make sure there are a module and an object file since we can specify
764             // a valid file path with an architecture that might not be in that file.
765             // By getting the object file we can guarantee that the architecture matches
766             if (module_sp && module_sp->GetObjectFile())
767             {
768                 if (did_create_ptr)
769                     *did_create_ptr = true;
770 
771                 shared_module_list.Append(module_sp);
772             }
773             else
774             {
775                 file_spec.GetPath(path, sizeof(path));
776 
777                 if (file_spec)
778                 {
779                     if (arch.IsValid())
780                         error.SetErrorStringWithFormat("unable to open %s architecture in '%s'", arch.GetArchitectureName(), path);
781                     else
782                         error.SetErrorStringWithFormat("unable to open '%s'", path);
783                 }
784                 else
785                 {
786                     if (uuid_ptr && uuid_ptr->IsValid())
787                         uuid_ptr->GetAsCString(uuid_cstr, sizeof (uuid_cstr));
788                     else
789                         uuid_cstr[0] = '\0';
790 
791                     if (uuid_cstr[0])
792                         error.SetErrorStringWithFormat("cannot locate a module for UUID '%s'", uuid_cstr);
793                     else
794                         error.SetErrorStringWithFormat("cannot locate a module");
795                 }
796             }
797         }
798     }
799 
800     return error;
801 }
802 
803 bool
804 ModuleList::RemoveSharedModule (lldb::ModuleSP &module_sp)
805 {
806     return GetSharedModuleList ().Remove (module_sp);
807 }
808 
809 
810