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