xref: /freebsd/contrib/llvm-project/lldb/source/API/SBModule.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
1  //===-- SBModule.cpp ------------------------------------------------------===//
2  //
3  // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4  // See https://llvm.org/LICENSE.txt for license information.
5  // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6  //
7  //===----------------------------------------------------------------------===//
8  
9  #include "lldb/API/SBModule.h"
10  #include "lldb/API/SBAddress.h"
11  #include "lldb/API/SBFileSpec.h"
12  #include "lldb/API/SBModuleSpec.h"
13  #include "lldb/API/SBProcess.h"
14  #include "lldb/API/SBStream.h"
15  #include "lldb/API/SBSymbolContextList.h"
16  #include "lldb/Core/Module.h"
17  #include "lldb/Core/Section.h"
18  #include "lldb/Core/ValueObjectList.h"
19  #include "lldb/Core/ValueObjectVariable.h"
20  #include "lldb/Symbol/ObjectFile.h"
21  #include "lldb/Symbol/SymbolFile.h"
22  #include "lldb/Symbol/Symtab.h"
23  #include "lldb/Symbol/TypeSystem.h"
24  #include "lldb/Symbol/VariableList.h"
25  #include "lldb/Target/Target.h"
26  #include "lldb/Utility/Instrumentation.h"
27  #include "lldb/Utility/StreamString.h"
28  
29  using namespace lldb;
30  using namespace lldb_private;
31  
32  SBModule::SBModule() { LLDB_INSTRUMENT_VA(this); }
33  
34  SBModule::SBModule(const lldb::ModuleSP &module_sp) : m_opaque_sp(module_sp) {}
35  
36  SBModule::SBModule(const SBModuleSpec &module_spec) {
37    LLDB_INSTRUMENT_VA(this, module_spec);
38  
39    ModuleSP module_sp;
40    Status error = ModuleList::GetSharedModule(
41        *module_spec.m_opaque_up, module_sp, nullptr, nullptr, nullptr);
42    if (module_sp)
43      SetSP(module_sp);
44  }
45  
46  SBModule::SBModule(const SBModule &rhs) : m_opaque_sp(rhs.m_opaque_sp) {
47    LLDB_INSTRUMENT_VA(this, rhs);
48  }
49  
50  SBModule::SBModule(lldb::SBProcess &process, lldb::addr_t header_addr) {
51    LLDB_INSTRUMENT_VA(this, process, header_addr);
52  
53    ProcessSP process_sp(process.GetSP());
54    if (process_sp) {
55      m_opaque_sp = process_sp->ReadModuleFromMemory(FileSpec(), header_addr);
56      if (m_opaque_sp) {
57        Target &target = process_sp->GetTarget();
58        bool changed = false;
59        m_opaque_sp->SetLoadAddress(target, 0, true, changed);
60        target.GetImages().Append(m_opaque_sp);
61      }
62    }
63  }
64  
65  const SBModule &SBModule::operator=(const SBModule &rhs) {
66    LLDB_INSTRUMENT_VA(this, rhs);
67  
68    if (this != &rhs)
69      m_opaque_sp = rhs.m_opaque_sp;
70    return *this;
71  }
72  
73  SBModule::~SBModule() = default;
74  
75  bool SBModule::IsValid() const {
76    LLDB_INSTRUMENT_VA(this);
77    return this->operator bool();
78  }
79  SBModule::operator bool() const {
80    LLDB_INSTRUMENT_VA(this);
81  
82    return m_opaque_sp.get() != nullptr;
83  }
84  
85  void SBModule::Clear() {
86    LLDB_INSTRUMENT_VA(this);
87  
88    m_opaque_sp.reset();
89  }
90  
91  bool SBModule::IsFileBacked() const {
92    LLDB_INSTRUMENT_VA(this);
93  
94    ModuleSP module_sp(GetSP());
95    if (!module_sp)
96      return false;
97  
98    ObjectFile *obj_file = module_sp->GetObjectFile();
99    if (!obj_file)
100      return false;
101  
102    return !obj_file->IsInMemory();
103  }
104  
105  SBFileSpec SBModule::GetFileSpec() const {
106    LLDB_INSTRUMENT_VA(this);
107  
108    SBFileSpec file_spec;
109    ModuleSP module_sp(GetSP());
110    if (module_sp)
111      file_spec.SetFileSpec(module_sp->GetFileSpec());
112  
113    return file_spec;
114  }
115  
116  lldb::SBFileSpec SBModule::GetPlatformFileSpec() const {
117    LLDB_INSTRUMENT_VA(this);
118  
119    SBFileSpec file_spec;
120    ModuleSP module_sp(GetSP());
121    if (module_sp)
122      file_spec.SetFileSpec(module_sp->GetPlatformFileSpec());
123  
124    return file_spec;
125  }
126  
127  bool SBModule::SetPlatformFileSpec(const lldb::SBFileSpec &platform_file) {
128    LLDB_INSTRUMENT_VA(this, platform_file);
129  
130    bool result = false;
131  
132    ModuleSP module_sp(GetSP());
133    if (module_sp) {
134      module_sp->SetPlatformFileSpec(*platform_file);
135      result = true;
136    }
137  
138    return result;
139  }
140  
141  lldb::SBFileSpec SBModule::GetRemoteInstallFileSpec() {
142    LLDB_INSTRUMENT_VA(this);
143  
144    SBFileSpec sb_file_spec;
145    ModuleSP module_sp(GetSP());
146    if (module_sp)
147      sb_file_spec.SetFileSpec(module_sp->GetRemoteInstallFileSpec());
148    return sb_file_spec;
149  }
150  
151  bool SBModule::SetRemoteInstallFileSpec(lldb::SBFileSpec &file) {
152    LLDB_INSTRUMENT_VA(this, file);
153  
154    ModuleSP module_sp(GetSP());
155    if (module_sp) {
156      module_sp->SetRemoteInstallFileSpec(file.ref());
157      return true;
158    }
159    return false;
160  }
161  
162  const uint8_t *SBModule::GetUUIDBytes() const {
163    LLDB_INSTRUMENT_VA(this);
164  
165    const uint8_t *uuid_bytes = nullptr;
166    ModuleSP module_sp(GetSP());
167    if (module_sp)
168      uuid_bytes = module_sp->GetUUID().GetBytes().data();
169  
170    return uuid_bytes;
171  }
172  
173  const char *SBModule::GetUUIDString() const {
174    LLDB_INSTRUMENT_VA(this);
175  
176    ModuleSP module_sp(GetSP());
177    if (!module_sp)
178      return nullptr;
179  
180    // We are going to return a "const char *" value through the public API, so
181    // we need to constify it so it gets added permanently the string pool and
182    // then we don't need to worry about the lifetime of the string as it will
183    // never go away once it has been put into the ConstString string pool
184    const char *uuid_cstr =
185        ConstString(module_sp->GetUUID().GetAsString()).GetCString();
186    // Note: SBModule::GetUUIDString's expected behavior is to return nullptr if
187    // the string we get is empty, so we must perform this check before returning.
188    if (uuid_cstr && uuid_cstr[0])
189      return uuid_cstr;
190    return nullptr;
191  }
192  
193  bool SBModule::operator==(const SBModule &rhs) const {
194    LLDB_INSTRUMENT_VA(this, rhs);
195  
196    if (m_opaque_sp)
197      return m_opaque_sp.get() == rhs.m_opaque_sp.get();
198    return false;
199  }
200  
201  bool SBModule::operator!=(const SBModule &rhs) const {
202    LLDB_INSTRUMENT_VA(this, rhs);
203  
204    if (m_opaque_sp)
205      return m_opaque_sp.get() != rhs.m_opaque_sp.get();
206    return false;
207  }
208  
209  ModuleSP SBModule::GetSP() const { return m_opaque_sp; }
210  
211  void SBModule::SetSP(const ModuleSP &module_sp) { m_opaque_sp = module_sp; }
212  
213  SBAddress SBModule::ResolveFileAddress(lldb::addr_t vm_addr) {
214    LLDB_INSTRUMENT_VA(this, vm_addr);
215  
216    lldb::SBAddress sb_addr;
217    ModuleSP module_sp(GetSP());
218    if (module_sp) {
219      Address addr;
220      if (module_sp->ResolveFileAddress(vm_addr, addr))
221        sb_addr.ref() = addr;
222    }
223    return sb_addr;
224  }
225  
226  SBSymbolContext
227  SBModule::ResolveSymbolContextForAddress(const SBAddress &addr,
228                                           uint32_t resolve_scope) {
229    LLDB_INSTRUMENT_VA(this, addr, resolve_scope);
230  
231    SBSymbolContext sb_sc;
232    ModuleSP module_sp(GetSP());
233    SymbolContextItem scope = static_cast<SymbolContextItem>(resolve_scope);
234    if (module_sp && addr.IsValid())
235      module_sp->ResolveSymbolContextForAddress(addr.ref(), scope, *sb_sc);
236    return sb_sc;
237  }
238  
239  bool SBModule::GetDescription(SBStream &description) {
240    LLDB_INSTRUMENT_VA(this, description);
241  
242    Stream &strm = description.ref();
243  
244    ModuleSP module_sp(GetSP());
245    if (module_sp) {
246      module_sp->GetDescription(strm.AsRawOstream());
247    } else
248      strm.PutCString("No value");
249  
250    return true;
251  }
252  
253  uint32_t SBModule::GetNumCompileUnits() {
254    LLDB_INSTRUMENT_VA(this);
255  
256    ModuleSP module_sp(GetSP());
257    if (module_sp) {
258      return module_sp->GetNumCompileUnits();
259    }
260    return 0;
261  }
262  
263  SBCompileUnit SBModule::GetCompileUnitAtIndex(uint32_t index) {
264    LLDB_INSTRUMENT_VA(this, index);
265  
266    SBCompileUnit sb_cu;
267    ModuleSP module_sp(GetSP());
268    if (module_sp) {
269      CompUnitSP cu_sp = module_sp->GetCompileUnitAtIndex(index);
270      sb_cu.reset(cu_sp.get());
271    }
272    return sb_cu;
273  }
274  
275  SBSymbolContextList SBModule::FindCompileUnits(const SBFileSpec &sb_file_spec) {
276    LLDB_INSTRUMENT_VA(this, sb_file_spec);
277  
278    SBSymbolContextList sb_sc_list;
279    const ModuleSP module_sp(GetSP());
280    if (sb_file_spec.IsValid() && module_sp) {
281      module_sp->FindCompileUnits(*sb_file_spec, *sb_sc_list);
282    }
283    return sb_sc_list;
284  }
285  
286  static Symtab *GetUnifiedSymbolTable(const lldb::ModuleSP &module_sp) {
287    if (module_sp)
288      return module_sp->GetSymtab();
289    return nullptr;
290  }
291  
292  size_t SBModule::GetNumSymbols() {
293    LLDB_INSTRUMENT_VA(this);
294  
295    ModuleSP module_sp(GetSP());
296    if (Symtab *symtab = GetUnifiedSymbolTable(module_sp))
297      return symtab->GetNumSymbols();
298    return 0;
299  }
300  
301  SBSymbol SBModule::GetSymbolAtIndex(size_t idx) {
302    LLDB_INSTRUMENT_VA(this, idx);
303  
304    SBSymbol sb_symbol;
305    ModuleSP module_sp(GetSP());
306    Symtab *symtab = GetUnifiedSymbolTable(module_sp);
307    if (symtab)
308      sb_symbol.SetSymbol(symtab->SymbolAtIndex(idx));
309    return sb_symbol;
310  }
311  
312  lldb::SBSymbol SBModule::FindSymbol(const char *name,
313                                      lldb::SymbolType symbol_type) {
314    LLDB_INSTRUMENT_VA(this, name, symbol_type);
315  
316    SBSymbol sb_symbol;
317    if (name && name[0]) {
318      ModuleSP module_sp(GetSP());
319      Symtab *symtab = GetUnifiedSymbolTable(module_sp);
320      if (symtab)
321        sb_symbol.SetSymbol(symtab->FindFirstSymbolWithNameAndType(
322            ConstString(name), symbol_type, Symtab::eDebugAny,
323            Symtab::eVisibilityAny));
324    }
325    return sb_symbol;
326  }
327  
328  lldb::SBSymbolContextList SBModule::FindSymbols(const char *name,
329                                                  lldb::SymbolType symbol_type) {
330    LLDB_INSTRUMENT_VA(this, name, symbol_type);
331  
332    SBSymbolContextList sb_sc_list;
333    if (name && name[0]) {
334      ModuleSP module_sp(GetSP());
335      Symtab *symtab = GetUnifiedSymbolTable(module_sp);
336      if (symtab) {
337        std::vector<uint32_t> matching_symbol_indexes;
338        symtab->FindAllSymbolsWithNameAndType(ConstString(name), symbol_type,
339                                              matching_symbol_indexes);
340        const size_t num_matches = matching_symbol_indexes.size();
341        if (num_matches) {
342          SymbolContext sc;
343          sc.module_sp = module_sp;
344          SymbolContextList &sc_list = *sb_sc_list;
345          for (size_t i = 0; i < num_matches; ++i) {
346            sc.symbol = symtab->SymbolAtIndex(matching_symbol_indexes[i]);
347            if (sc.symbol)
348              sc_list.Append(sc);
349          }
350        }
351      }
352    }
353    return sb_sc_list;
354  }
355  
356  size_t SBModule::GetNumSections() {
357    LLDB_INSTRUMENT_VA(this);
358  
359    ModuleSP module_sp(GetSP());
360    if (module_sp) {
361      // Give the symbol vendor a chance to add to the unified section list.
362      module_sp->GetSymbolFile();
363      SectionList *section_list = module_sp->GetSectionList();
364      if (section_list)
365        return section_list->GetSize();
366    }
367    return 0;
368  }
369  
370  SBSection SBModule::GetSectionAtIndex(size_t idx) {
371    LLDB_INSTRUMENT_VA(this, idx);
372  
373    SBSection sb_section;
374    ModuleSP module_sp(GetSP());
375    if (module_sp) {
376      // Give the symbol vendor a chance to add to the unified section list.
377      module_sp->GetSymbolFile();
378      SectionList *section_list = module_sp->GetSectionList();
379  
380      if (section_list)
381        sb_section.SetSP(section_list->GetSectionAtIndex(idx));
382    }
383    return sb_section;
384  }
385  
386  lldb::SBSymbolContextList SBModule::FindFunctions(const char *name,
387                                                    uint32_t name_type_mask) {
388    LLDB_INSTRUMENT_VA(this, name, name_type_mask);
389  
390    lldb::SBSymbolContextList sb_sc_list;
391    ModuleSP module_sp(GetSP());
392    if (name && module_sp) {
393  
394      ModuleFunctionSearchOptions function_options;
395      function_options.include_symbols = true;
396      function_options.include_inlines = true;
397      FunctionNameType type = static_cast<FunctionNameType>(name_type_mask);
398      module_sp->FindFunctions(ConstString(name), CompilerDeclContext(), type,
399                               function_options, *sb_sc_list);
400    }
401    return sb_sc_list;
402  }
403  
404  SBValueList SBModule::FindGlobalVariables(SBTarget &target, const char *name,
405                                            uint32_t max_matches) {
406    LLDB_INSTRUMENT_VA(this, target, name, max_matches);
407  
408    SBValueList sb_value_list;
409    ModuleSP module_sp(GetSP());
410    if (name && module_sp) {
411      VariableList variable_list;
412      module_sp->FindGlobalVariables(ConstString(name), CompilerDeclContext(),
413                                     max_matches, variable_list);
414      for (const VariableSP &var_sp : variable_list) {
415        lldb::ValueObjectSP valobj_sp;
416        TargetSP target_sp(target.GetSP());
417        valobj_sp = ValueObjectVariable::Create(target_sp.get(), var_sp);
418        if (valobj_sp)
419          sb_value_list.Append(SBValue(valobj_sp));
420      }
421    }
422  
423    return sb_value_list;
424  }
425  
426  lldb::SBValue SBModule::FindFirstGlobalVariable(lldb::SBTarget &target,
427                                                  const char *name) {
428    LLDB_INSTRUMENT_VA(this, target, name);
429  
430    SBValueList sb_value_list(FindGlobalVariables(target, name, 1));
431    if (sb_value_list.IsValid() && sb_value_list.GetSize() > 0)
432      return sb_value_list.GetValueAtIndex(0);
433    return SBValue();
434  }
435  
436  lldb::SBType SBModule::FindFirstType(const char *name_cstr) {
437    LLDB_INSTRUMENT_VA(this, name_cstr);
438  
439    ModuleSP module_sp(GetSP());
440    if (name_cstr && module_sp) {
441      ConstString name(name_cstr);
442      TypeQuery query(name.GetStringRef(), TypeQueryOptions::e_find_one);
443      TypeResults results;
444      module_sp->FindTypes(query, results);
445      TypeSP type_sp = results.GetFirstType();
446      if (type_sp)
447        return SBType(type_sp);
448  
449      auto type_system_or_err =
450          module_sp->GetTypeSystemForLanguage(eLanguageTypeC);
451      if (auto err = type_system_or_err.takeError()) {
452        llvm::consumeError(std::move(err));
453        return {};
454      }
455  
456      if (auto ts = *type_system_or_err)
457        return SBType(ts->GetBuiltinTypeByName(name));
458    }
459    return {};
460  }
461  
462  lldb::SBType SBModule::GetBasicType(lldb::BasicType type) {
463    LLDB_INSTRUMENT_VA(this, type);
464  
465    ModuleSP module_sp(GetSP());
466    if (module_sp) {
467      auto type_system_or_err =
468          module_sp->GetTypeSystemForLanguage(eLanguageTypeC);
469      if (auto err = type_system_or_err.takeError()) {
470        llvm::consumeError(std::move(err));
471      } else {
472        if (auto ts = *type_system_or_err)
473          return SBType(ts->GetBasicTypeFromAST(type));
474      }
475    }
476    return SBType();
477  }
478  
479  lldb::SBTypeList SBModule::FindTypes(const char *type) {
480    LLDB_INSTRUMENT_VA(this, type);
481  
482    SBTypeList retval;
483  
484    ModuleSP module_sp(GetSP());
485    if (type && module_sp) {
486      TypeList type_list;
487      TypeQuery query(type);
488      TypeResults results;
489      module_sp->FindTypes(query, results);
490      if (results.GetTypeMap().Empty()) {
491        ConstString name(type);
492        auto type_system_or_err =
493            module_sp->GetTypeSystemForLanguage(eLanguageTypeC);
494        if (auto err = type_system_or_err.takeError()) {
495          llvm::consumeError(std::move(err));
496        } else {
497          if (auto ts = *type_system_or_err)
498            if (CompilerType compiler_type = ts->GetBuiltinTypeByName(name))
499              retval.Append(SBType(compiler_type));
500        }
501      } else {
502        for (const TypeSP &type_sp : results.GetTypeMap().Types())
503          retval.Append(SBType(type_sp));
504      }
505    }
506    return retval;
507  }
508  
509  lldb::SBType SBModule::GetTypeByID(lldb::user_id_t uid) {
510    LLDB_INSTRUMENT_VA(this, uid);
511  
512    ModuleSP module_sp(GetSP());
513    if (module_sp) {
514      if (SymbolFile *symfile = module_sp->GetSymbolFile()) {
515        Type *type_ptr = symfile->ResolveTypeUID(uid);
516        if (type_ptr)
517          return SBType(type_ptr->shared_from_this());
518      }
519    }
520    return SBType();
521  }
522  
523  lldb::SBTypeList SBModule::GetTypes(uint32_t type_mask) {
524    LLDB_INSTRUMENT_VA(this, type_mask);
525  
526    SBTypeList sb_type_list;
527  
528    ModuleSP module_sp(GetSP());
529    if (!module_sp)
530      return sb_type_list;
531    SymbolFile *symfile = module_sp->GetSymbolFile();
532    if (!symfile)
533      return sb_type_list;
534  
535    TypeClass type_class = static_cast<TypeClass>(type_mask);
536    TypeList type_list;
537    symfile->GetTypes(nullptr, type_class, type_list);
538    sb_type_list.m_opaque_up->Append(type_list);
539    return sb_type_list;
540  }
541  
542  SBSection SBModule::FindSection(const char *sect_name) {
543    LLDB_INSTRUMENT_VA(this, sect_name);
544  
545    SBSection sb_section;
546  
547    ModuleSP module_sp(GetSP());
548    if (sect_name && module_sp) {
549      // Give the symbol vendor a chance to add to the unified section list.
550      module_sp->GetSymbolFile();
551      SectionList *section_list = module_sp->GetSectionList();
552      if (section_list) {
553        ConstString const_sect_name(sect_name);
554        SectionSP section_sp(section_list->FindSectionByName(const_sect_name));
555        if (section_sp) {
556          sb_section.SetSP(section_sp);
557        }
558      }
559    }
560    return sb_section;
561  }
562  
563  lldb::ByteOrder SBModule::GetByteOrder() {
564    LLDB_INSTRUMENT_VA(this);
565  
566    ModuleSP module_sp(GetSP());
567    if (module_sp)
568      return module_sp->GetArchitecture().GetByteOrder();
569    return eByteOrderInvalid;
570  }
571  
572  const char *SBModule::GetTriple() {
573    LLDB_INSTRUMENT_VA(this);
574  
575    ModuleSP module_sp(GetSP());
576    if (!module_sp)
577      return nullptr;
578  
579    std::string triple(module_sp->GetArchitecture().GetTriple().str());
580    // Unique the string so we don't run into ownership issues since the const
581    // strings put the string into the string pool once and the strings never
582    // comes out
583    ConstString const_triple(triple.c_str());
584    return const_triple.GetCString();
585  }
586  
587  uint32_t SBModule::GetAddressByteSize() {
588    LLDB_INSTRUMENT_VA(this);
589  
590    ModuleSP module_sp(GetSP());
591    if (module_sp)
592      return module_sp->GetArchitecture().GetAddressByteSize();
593    return sizeof(void *);
594  }
595  
596  uint32_t SBModule::GetVersion(uint32_t *versions, uint32_t num_versions) {
597    LLDB_INSTRUMENT_VA(this, versions, num_versions);
598  
599    llvm::VersionTuple version;
600    if (ModuleSP module_sp = GetSP())
601      version = module_sp->GetVersion();
602    uint32_t result = 0;
603    if (!version.empty())
604      ++result;
605    if (version.getMinor())
606      ++result;
607    if (version.getSubminor())
608      ++result;
609  
610    if (!versions)
611      return result;
612  
613    if (num_versions > 0)
614      versions[0] = version.empty() ? UINT32_MAX : version.getMajor();
615    if (num_versions > 1)
616      versions[1] = version.getMinor().value_or(UINT32_MAX);
617    if (num_versions > 2)
618      versions[2] = version.getSubminor().value_or(UINT32_MAX);
619    for (uint32_t i = 3; i < num_versions; ++i)
620      versions[i] = UINT32_MAX;
621    return result;
622  }
623  
624  lldb::SBFileSpec SBModule::GetSymbolFileSpec() const {
625    LLDB_INSTRUMENT_VA(this);
626  
627    lldb::SBFileSpec sb_file_spec;
628    ModuleSP module_sp(GetSP());
629    if (module_sp) {
630      if (SymbolFile *symfile = module_sp->GetSymbolFile())
631        sb_file_spec.SetFileSpec(symfile->GetObjectFile()->GetFileSpec());
632    }
633    return sb_file_spec;
634  }
635  
636  lldb::SBAddress SBModule::GetObjectFileHeaderAddress() const {
637    LLDB_INSTRUMENT_VA(this);
638  
639    lldb::SBAddress sb_addr;
640    ModuleSP module_sp(GetSP());
641    if (module_sp) {
642      ObjectFile *objfile_ptr = module_sp->GetObjectFile();
643      if (objfile_ptr)
644        sb_addr.ref() = objfile_ptr->GetBaseAddress();
645    }
646    return sb_addr;
647  }
648  
649  lldb::SBAddress SBModule::GetObjectFileEntryPointAddress() const {
650    LLDB_INSTRUMENT_VA(this);
651  
652    lldb::SBAddress sb_addr;
653    ModuleSP module_sp(GetSP());
654    if (module_sp) {
655      ObjectFile *objfile_ptr = module_sp->GetObjectFile();
656      if (objfile_ptr)
657        sb_addr.ref() = objfile_ptr->GetEntryPointAddress();
658    }
659    return sb_addr;
660  }
661  
662  uint32_t SBModule::GetNumberAllocatedModules() {
663    LLDB_INSTRUMENT();
664  
665    return Module::GetNumberAllocatedModules();
666  }
667  
668  void SBModule::GarbageCollectAllocatedModules() {
669    LLDB_INSTRUMENT();
670  
671    const bool mandatory = false;
672    ModuleList::RemoveOrphanSharedModules(mandatory);
673  }
674