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/Module.h"
17 #include "lldb/Host/Symbols.h"
18 #include "lldb/Symbol/ObjectFile.h"
19 #include "lldb/Symbol/VariableList.h"
20 
21 using namespace lldb;
22 using namespace lldb_private;
23 
24 //----------------------------------------------------------------------
25 // ModuleList constructor
26 //----------------------------------------------------------------------
27 ModuleList::ModuleList() :
28     m_modules(),
29     m_modules_mutex (Mutex::eMutexTypeRecursive)
30 {
31 }
32 
33 //----------------------------------------------------------------------
34 // Copy constructor
35 //----------------------------------------------------------------------
36 ModuleList::ModuleList(const ModuleList& rhs) :
37     m_modules(rhs.m_modules)
38 {
39 }
40 
41 //----------------------------------------------------------------------
42 // Assignment operator
43 //----------------------------------------------------------------------
44 const ModuleList&
45 ModuleList::operator= (const ModuleList& rhs)
46 {
47     if (this != &rhs)
48     {
49         Mutex::Locker locker(m_modules_mutex);
50         m_modules = rhs.m_modules;
51     }
52     return *this;
53 }
54 
55 //----------------------------------------------------------------------
56 // Destructor
57 //----------------------------------------------------------------------
58 ModuleList::~ModuleList()
59 {
60 }
61 
62 void
63 ModuleList::Append (ModuleSP &module_sp)
64 {
65     Mutex::Locker locker(m_modules_mutex);
66     m_modules.push_back(module_sp);
67 }
68 
69 bool
70 ModuleList::AppendInNeeded (ModuleSP &module_sp)
71 {
72     Mutex::Locker locker(m_modules_mutex);
73     collection::iterator pos, end = m_modules.end();
74     for (pos = m_modules.begin(); pos != end; ++pos)
75     {
76         if (pos->get() == module_sp.get())
77             return false; // Already in the list
78     }
79     // Only push module_sp on the list if it wasn't already in there.
80     m_modules.push_back(module_sp);
81     return true;
82 }
83 
84 bool
85 ModuleList::Remove (ModuleSP &module_sp)
86 {
87     Mutex::Locker locker(m_modules_mutex);
88     collection::iterator pos, end = m_modules.end();
89     for (pos = m_modules.begin(); pos != end; ++pos)
90     {
91         if (pos->get() == module_sp.get())
92         {
93             m_modules.erase (pos);
94             return true;
95         }
96     }
97     return false;
98 }
99 
100 
101 
102 void
103 ModuleList::Clear()
104 {
105     Mutex::Locker locker(m_modules_mutex);
106     m_modules.clear();
107 }
108 
109 Module*
110 ModuleList::GetModulePointerAtIndex (uint32_t idx) const
111 {
112     Mutex::Locker locker(m_modules_mutex);
113     if (idx < m_modules.size())
114         return m_modules[idx].get();
115     return NULL;
116 }
117 
118 ModuleSP
119 ModuleList::GetModuleAtIndex(uint32_t idx)
120 {
121     Mutex::Locker locker(m_modules_mutex);
122     ModuleSP module_sp;
123     if (idx < m_modules.size())
124         module_sp = m_modules[idx];
125     return module_sp;
126 }
127 
128 size_t
129 ModuleList::FindFunctions (const ConstString &name, uint32_t name_type_mask, bool append, SymbolContextList &sc_list)
130 {
131     if (!append)
132         sc_list.Clear();
133 
134     Mutex::Locker locker(m_modules_mutex);
135     collection::const_iterator pos, end = m_modules.end();
136     for (pos = m_modules.begin(); pos != end; ++pos)
137     {
138         (*pos)->FindFunctions (name, name_type_mask, true, sc_list);
139     }
140 
141     return sc_list.GetSize();
142 }
143 
144 uint32_t
145 ModuleList::FindGlobalVariables (const ConstString &name, bool append, uint32_t max_matches, VariableList& variable_list)
146 {
147     size_t initial_size = variable_list.GetSize();
148     Mutex::Locker locker(m_modules_mutex);
149     collection::iterator pos, end = m_modules.end();
150     for (pos = m_modules.begin(); pos != end; ++pos)
151     {
152         (*pos)->FindGlobalVariables (name, append, max_matches, variable_list);
153     }
154     return variable_list.GetSize() - initial_size;
155 }
156 
157 
158 uint32_t
159 ModuleList::FindGlobalVariables (const RegularExpression& regex, bool append, uint32_t max_matches, VariableList& variable_list)
160 {
161     size_t initial_size = variable_list.GetSize();
162     Mutex::Locker locker(m_modules_mutex);
163     collection::iterator pos, end = m_modules.end();
164     for (pos = m_modules.begin(); pos != end; ++pos)
165     {
166         (*pos)->FindGlobalVariables (regex, append, max_matches, variable_list);
167     }
168     return variable_list.GetSize() - initial_size;
169 }
170 
171 
172 size_t
173 ModuleList::FindSymbolsWithNameAndType (const ConstString &name, SymbolType symbol_type, SymbolContextList &sc_list)
174 {
175     Mutex::Locker locker(m_modules_mutex);
176     sc_list.Clear();
177     collection::iterator pos, end = m_modules.end();
178     for (pos = m_modules.begin(); pos != end; ++pos)
179         (*pos)->FindSymbolsWithNameAndType (name, symbol_type, sc_list);
180     return sc_list.GetSize();
181 }
182 
183 class ModuleMatches
184 {
185 public:
186     //--------------------------------------------------------------
187     /// Construct with the user ID to look for.
188     //--------------------------------------------------------------
189     ModuleMatches (const FileSpec *file_spec_ptr,
190                    const ArchSpec *arch_ptr,
191                    const UUID *uuid_ptr,
192                    const ConstString *object_name) :
193         m_file_spec_ptr (file_spec_ptr),
194         m_arch_ptr (arch_ptr),
195         m_uuid_ptr (uuid_ptr),
196         m_object_name (object_name)
197     {
198     }
199 
200     //--------------------------------------------------------------
201     /// Unary predicate function object callback.
202     //--------------------------------------------------------------
203     bool
204     operator () (const ModuleSP& module_sp) const
205     {
206         if (m_file_spec_ptr)
207         {
208             if (!FileSpec::Equal (*m_file_spec_ptr, module_sp->GetFileSpec(), m_file_spec_ptr->GetDirectory()))
209                 return false;
210         }
211 
212         if (m_arch_ptr)
213         {
214             if (module_sp->GetArchitecture() != *m_arch_ptr)
215                 return false;
216         }
217 
218         if (m_uuid_ptr)
219         {
220             if (module_sp->GetUUID() != *m_uuid_ptr)
221                 return false;
222         }
223 
224         if (m_object_name)
225         {
226             if (module_sp->GetObjectName() != *m_object_name)
227                 return false;
228         }
229         return true;
230     }
231 
232 private:
233     //--------------------------------------------------------------
234     // Member variables.
235     //--------------------------------------------------------------
236     const FileSpec *    m_file_spec_ptr;
237     const ArchSpec *    m_arch_ptr;
238     const UUID *        m_uuid_ptr;
239     const ConstString * m_object_name;
240 };
241 
242 size_t
243 ModuleList::FindModules
244 (
245     const FileSpec *file_spec_ptr,
246     const ArchSpec *arch_ptr,
247     const UUID *uuid_ptr,
248     const ConstString *object_name,
249     ModuleList& matching_module_list
250 ) const
251 {
252     size_t existing_matches = matching_module_list.GetSize();
253     ModuleMatches matcher (file_spec_ptr, arch_ptr, uuid_ptr, object_name);
254 
255     Mutex::Locker locker(m_modules_mutex);
256     collection::const_iterator end = m_modules.end();
257     collection::const_iterator pos;
258 
259     for (pos = std::find_if (m_modules.begin(), end, matcher);
260          pos != end;
261          pos = std::find_if (++pos, end, matcher))
262     {
263         ModuleSP module_sp(*pos);
264         matching_module_list.Append(module_sp);
265     }
266     return matching_module_list.GetSize() - existing_matches;
267 }
268 
269 ModuleSP
270 ModuleList::FindModule (const Module *module_ptr)
271 {
272     ModuleSP module_sp;
273 
274     // Scope for "locker"
275     {
276         Mutex::Locker locker(m_modules_mutex);
277         collection::const_iterator pos, end = m_modules.end();
278 
279         for (pos = m_modules.begin(); pos != end; ++pos)
280         {
281             if ((*pos).get() == module_ptr)
282             {
283                 module_sp = (*pos);
284                 break;
285             }
286         }
287     }
288     return module_sp;
289 
290 }
291 
292 
293 uint32_t
294 ModuleList::FindTypes (const SymbolContext& sc, const ConstString &name, bool append, uint32_t max_matches, TypeList& types)
295 {
296     Mutex::Locker locker(m_modules_mutex);
297 
298     if (!append)
299         types.Clear();
300 
301     uint32_t total_matches = 0;
302     collection::const_iterator pos, end = m_modules.end();
303     for (pos = m_modules.begin(); pos != end; ++pos)
304     {
305         if (sc.module_sp.get() == NULL || sc.module_sp.get() == (*pos).get())
306             total_matches += (*pos)->FindTypes (sc, name, true, max_matches, types);
307 
308         if (total_matches >= max_matches)
309             break;
310     }
311     return total_matches;
312 }
313 
314 
315 ModuleSP
316 ModuleList::FindFirstModuleForFileSpec (const FileSpec &file_spec, const ConstString *object_name)
317 {
318     ModuleSP module_sp;
319     ModuleMatches matcher (&file_spec, NULL, NULL, NULL);
320 
321     // Scope for "locker"
322     {
323         Mutex::Locker locker(m_modules_mutex);
324         collection::const_iterator end = m_modules.end();
325         collection::const_iterator pos = m_modules.begin();
326 
327         pos = std::find_if (pos, end, matcher);
328         if (pos != end)
329             module_sp = (*pos);
330     }
331     return module_sp;
332 
333 }
334 
335 
336 size_t
337 ModuleList::GetSize() const
338 {
339     size_t size = 0;
340     {
341         Mutex::Locker locker(m_modules_mutex);
342         size = m_modules.size();
343     }
344     return size;
345 }
346 
347 
348 void
349 ModuleList::Dump(Stream *s) const
350 {
351 //  s.Printf("%.*p: ", (int)sizeof(void*) * 2, this);
352 //  s.Indent();
353 //  s << "ModuleList\n";
354 
355     Mutex::Locker locker(m_modules_mutex);
356     collection::const_iterator pos, end = m_modules.end();
357     for (pos = m_modules.begin(); pos != end; ++pos)
358     {
359         (*pos)->Dump(s);
360     }
361 }
362 
363 
364 bool
365 ModuleList::ResolveFileAddress (lldb::addr_t vm_addr, Address& so_addr)
366 {
367     Mutex::Locker locker(m_modules_mutex);
368     collection::const_iterator pos, end = m_modules.end();
369     for (pos = m_modules.begin(); pos != end; ++pos)
370     {
371         if ((*pos)->ResolveFileAddress (vm_addr, so_addr))
372             return true;
373     }
374 
375     return false;
376 }
377 
378 uint32_t
379 ModuleList::ResolveSymbolContextForAddress (const Address& so_addr, uint32_t resolve_scope, SymbolContext& sc)
380 {
381     // The address is already section offset so it has a module
382     uint32_t resolved_flags = 0;
383     Module *module = so_addr.GetModule();
384     if (module)
385     {
386         resolved_flags = module->ResolveSymbolContextForAddress (so_addr,
387                                                                  resolve_scope,
388                                                                  sc);
389     }
390     else
391     {
392         Mutex::Locker locker(m_modules_mutex);
393         collection::const_iterator pos, end = m_modules.end();
394         for (pos = m_modules.begin(); pos != end; ++pos)
395         {
396             resolved_flags = (*pos)->ResolveSymbolContextForAddress (so_addr,
397                                                                      resolve_scope,
398                                                                      sc);
399             if (resolved_flags != 0)
400                 break;
401         }
402     }
403 
404     return resolved_flags;
405 }
406 
407 uint32_t
408 ModuleList::ResolveSymbolContextForFilePath
409 (
410     const char *file_path,
411     uint32_t line,
412     bool check_inlines,
413     uint32_t resolve_scope,
414     SymbolContextList& sc_list
415 )
416 {
417     FileSpec file_spec(file_path, false);
418     return ResolveSymbolContextsForFileSpec (file_spec, line, check_inlines, resolve_scope, sc_list);
419 }
420 
421 uint32_t
422 ModuleList::ResolveSymbolContextsForFileSpec (const FileSpec &file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, SymbolContextList& sc_list)
423 {
424     Mutex::Locker locker(m_modules_mutex);
425     collection::const_iterator pos, end = m_modules.end();
426     for (pos = m_modules.begin(); pos != end; ++pos)
427     {
428         (*pos)->ResolveSymbolContextsForFileSpec (file_spec, line, check_inlines, resolve_scope, sc_list);
429     }
430 
431     return sc_list.GetSize();
432 }
433 
434 uint32_t
435 ModuleList::GetIndexForModule (const Module *module) const
436 {
437     if (module)
438     {
439         Mutex::Locker locker(m_modules_mutex);
440         collection::const_iterator pos;
441         collection::const_iterator begin = m_modules.begin();
442         collection::const_iterator end = m_modules.end();
443         for (pos = begin; pos != end; ++pos)
444         {
445             if ((*pos).get() == module)
446                 return std::distance (begin, pos);
447         }
448     }
449     return LLDB_INVALID_INDEX32;
450 }
451 
452 static ModuleList &
453 GetSharedModuleList ()
454 {
455     static ModuleList g_shared_module_list;
456     return g_shared_module_list;
457 }
458 
459 const lldb::ModuleSP
460 ModuleList::GetModuleSP (const Module *module_ptr)
461 {
462     lldb::ModuleSP module_sp;
463     if (module_ptr)
464     {
465         ModuleList &shared_module_list = GetSharedModuleList ();
466         module_sp = shared_module_list.FindModule (module_ptr);
467         assert (module_sp.get());   // This might fire off a few times and we need to make sure it never fires...
468     }
469     return module_sp;
470 }
471 
472 size_t
473 ModuleList::FindSharedModules
474 (
475     const FileSpec& in_file_spec,
476     const ArchSpec& arch,
477     const UUID *uuid_ptr,
478     const ConstString *object_name_ptr,
479     ModuleList &matching_module_list
480 )
481 {
482     ModuleList &shared_module_list = GetSharedModuleList ();
483     Mutex::Locker locker(shared_module_list.m_modules_mutex);
484     return shared_module_list.FindModules (&in_file_spec, &arch, uuid_ptr, object_name_ptr, matching_module_list);
485 }
486 
487 Error
488 ModuleList::GetSharedModule
489 (
490     const FileSpec& in_file_spec,
491     const ArchSpec& arch,
492     const UUID *uuid_ptr,
493     const ConstString *object_name_ptr,
494     off_t object_offset,
495     ModuleSP &module_sp,
496     ModuleSP *old_module_sp_ptr,
497     bool *did_create_ptr
498 )
499 {
500     ModuleList &shared_module_list = GetSharedModuleList ();
501     char path[PATH_MAX];
502     char uuid_cstr[64];
503 
504     Error error;
505 
506     module_sp.reset();
507 
508     if (did_create_ptr)
509         *did_create_ptr = false;
510     if (old_module_sp_ptr)
511         old_module_sp_ptr->reset();
512 
513 
514     // First just try and get the file where it purports to be (path in
515     // in_file_spec), then check and uuid.
516 
517     if (in_file_spec)
518     {
519         // Make sure no one else can try and get or create a module while this
520         // function is actively working on it by doing an extra lock on the
521         // global mutex list.
522         ModuleList matching_module_list;
523         Mutex::Locker locker(shared_module_list.m_modules_mutex);
524         if (shared_module_list.FindModules (&in_file_spec, &arch, uuid_ptr, object_name_ptr, matching_module_list) > 0)
525         {
526             module_sp = matching_module_list.GetModuleAtIndex(0);
527 
528             // If we didn't have a UUID in mind when looking for the object file,
529             // then we should make sure the modification time hasn't changed!
530             if (uuid_ptr == NULL)
531             {
532                 TimeValue file_spec_mod_time(in_file_spec.GetModificationTime());
533                 if (file_spec_mod_time.IsValid())
534                 {
535                     if (file_spec_mod_time != module_sp->GetModificationTime())
536                     {
537                         if (old_module_sp_ptr)
538                             *old_module_sp_ptr = module_sp;
539                         shared_module_list.Remove (module_sp);
540                         module_sp.reset();
541                     }
542                 }
543             }
544         }
545 
546         if (module_sp.get() == NULL)
547         {
548             module_sp.reset (new Module (in_file_spec, arch, object_name_ptr, object_offset));
549             if (module_sp)
550             {
551                 // If we get in here we got the correct arch, now we just need
552                 // to verify the UUID if one was given
553                 if (uuid_ptr && *uuid_ptr != module_sp->GetUUID())
554                     module_sp.reset();
555                 else
556                 {
557                     if (did_create_ptr)
558                         *did_create_ptr = true;
559 
560                     shared_module_list.Append(module_sp);
561                     return error;
562                 }
563             }
564         }
565     }
566 
567     // Either the file didn't exist where at the path, or no path was given, so
568     // we now have to use more extreme measures to try and find the appropriate
569     // module.
570 
571     // Fixup the incoming path in case the path points to a valid file, yet
572     // the arch or UUID (if one was passed in) don't match.
573     FileSpec file_spec = Symbols::LocateExecutableObjectFile (&in_file_spec, arch.IsValid() ? &arch : NULL, uuid_ptr);
574 
575     // Don't look for the file if it appears to be the same one we already
576     // checked for above...
577     if (file_spec != in_file_spec)
578     {
579         if (!file_spec.Exists())
580         {
581             file_spec.GetPath(path, sizeof(path));
582             if (file_spec.Exists())
583             {
584                 if (uuid_ptr && uuid_ptr->IsValid())
585                     uuid_ptr->GetAsCString(uuid_cstr, sizeof (uuid_cstr));
586                 else
587                     uuid_cstr[0] = '\0';
588 
589 
590                 if (arch.IsValid())
591                 {
592                     if (uuid_cstr[0])
593                         error.SetErrorStringWithFormat("'%s' does not contain the %s architecture and UUID %s.\n", path, arch.AsCString(), uuid_cstr[0]);
594                     else
595                         error.SetErrorStringWithFormat("'%s' does not contain the %s architecture.\n", path, arch.AsCString());
596                 }
597             }
598             else
599             {
600                 error.SetErrorStringWithFormat("'%s' does not exist.\n", path);
601             }
602             return error;
603         }
604 
605 
606         // Make sure no one else can try and get or create a module while this
607         // function is actively working on it by doing an extra lock on the
608         // global mutex list.
609         Mutex::Locker locker(shared_module_list.m_modules_mutex);
610         ModuleList matching_module_list;
611         if (shared_module_list.FindModules (&file_spec, &arch, uuid_ptr, object_name_ptr, matching_module_list) > 0)
612         {
613             module_sp = matching_module_list.GetModuleAtIndex(0);
614 
615             // If we didn't have a UUID in mind when looking for the object file,
616             // then we should make sure the modification time hasn't changed!
617             if (uuid_ptr == NULL)
618             {
619                 TimeValue file_spec_mod_time(file_spec.GetModificationTime());
620                 if (file_spec_mod_time.IsValid())
621                 {
622                     if (file_spec_mod_time != module_sp->GetModificationTime())
623                     {
624                         if (old_module_sp_ptr)
625                             *old_module_sp_ptr = module_sp;
626                         shared_module_list.Remove (module_sp);
627                         module_sp.reset();
628                     }
629                 }
630             }
631         }
632 
633         if (module_sp.get() == NULL)
634         {
635             module_sp.reset (new Module (file_spec, arch, object_name_ptr, object_offset));
636             if (module_sp)
637             {
638                 if (did_create_ptr)
639                     *did_create_ptr = true;
640 
641                 shared_module_list.Append(module_sp);
642             }
643             else
644             {
645                 file_spec.GetPath(path, sizeof(path));
646 
647                 if (file_spec)
648                 {
649                     if (arch.IsValid())
650                         error.SetErrorStringWithFormat("Unable to open %s architecture in '%s'.\n", arch.AsCString(), path);
651                     else
652                         error.SetErrorStringWithFormat("Unable to open '%s'.\n", path);
653                 }
654                 else
655                 {
656                     if (uuid_ptr && uuid_ptr->IsValid())
657                         uuid_ptr->GetAsCString(uuid_cstr, sizeof (uuid_cstr));
658                     else
659                         uuid_cstr[0] = '\0';
660 
661                     if (uuid_cstr[0])
662                         error.SetErrorStringWithFormat("Cannot locate a module for UUID '%s'.\n", uuid_cstr[0]);
663                     else
664                         error.SetErrorStringWithFormat("Cannot locate a module.\n", path, arch.AsCString());
665                 }
666             }
667         }
668     }
669 
670     return error;
671 }
672 
673