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