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