Module.cpp revision 51b11e06de746667396f56b303d1867f007baf8b
1//===-- Module.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/Module.h"
11#include "lldb/Core/Log.h"
12#include "lldb/Core/ModuleList.h"
13#include "lldb/Core/RegularExpression.h"
14#include "lldb/Core/Timer.h"
15#include "lldb/lldb-private-log.h"
16#include "lldb/Symbol/ObjectFile.h"
17#include "lldb/Symbol/SymbolContext.h"
18#include "lldb/Symbol/SymbolVendor.h"
19
20using namespace lldb;
21using namespace lldb_private;
22
23Module::Module(const FileSpec& file_spec, const ArchSpec& arch, const ConstString *object_name, off_t object_offset) :
24    m_mutex (Mutex::eMutexTypeRecursive),
25    m_mod_time (file_spec.GetModificationTime()),
26    m_arch (arch),
27    m_uuid (),
28    m_file (file_spec),
29    m_platform_file(),
30    m_object_name (),
31    m_object_offset (object_offset),
32    m_objfile_ap (),
33    m_symfile_ap (),
34    m_ast (),
35    m_did_load_objfile (false),
36    m_did_load_symbol_vendor (false),
37    m_did_parse_uuid (false),
38    m_did_init_ast (false),
39    m_is_dynamic_loader_module (false)
40{
41    if (object_name)
42        m_object_name = *object_name;
43    LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
44    if (log)
45        log->Printf ("%p Module::Module((%s) '%s/%s%s%s%s')",
46                     this,
47                     m_arch.GetArchitectureName(),
48                     m_file.GetDirectory().AsCString(""),
49                     m_file.GetFilename().AsCString(""),
50                     m_object_name.IsEmpty() ? "" : "(",
51                     m_object_name.IsEmpty() ? "" : m_object_name.AsCString(""),
52                     m_object_name.IsEmpty() ? "" : ")");
53}
54
55Module::~Module()
56{
57    LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
58    if (log)
59        log->Printf ("%p Module::~Module((%s) '%s/%s%s%s%s')",
60                     this,
61                     m_arch.GetArchitectureName(),
62                     m_file.GetDirectory().AsCString(""),
63                     m_file.GetFilename().AsCString(""),
64                     m_object_name.IsEmpty() ? "" : "(",
65                     m_object_name.IsEmpty() ? "" : m_object_name.AsCString(""),
66                     m_object_name.IsEmpty() ? "" : ")");
67    // Release any auto pointers before we start tearing down our member
68    // variables since the object file and symbol files might need to make
69    // function calls back into this module object. The ordering is important
70    // here because symbol files can require the module object file. So we tear
71    // down the symbol file first, then the object file.
72    m_symfile_ap.reset();
73    m_objfile_ap.reset();
74}
75
76
77ModuleSP
78Module::GetSP () const
79{
80    return ModuleList::GetModuleSP (this);
81}
82
83const lldb_private::UUID&
84Module::GetUUID()
85{
86    Mutex::Locker locker (m_mutex);
87    if (m_did_parse_uuid == false)
88    {
89        ObjectFile * obj_file = GetObjectFile ();
90
91        if (obj_file != NULL)
92        {
93            obj_file->GetUUID(&m_uuid);
94            m_did_parse_uuid = true;
95        }
96    }
97    return m_uuid;
98}
99
100ClangASTContext &
101Module::GetClangASTContext ()
102{
103    Mutex::Locker locker (m_mutex);
104    if (m_did_init_ast == false)
105    {
106        ObjectFile * objfile = GetObjectFile();
107        ArchSpec object_arch;
108        if (objfile && objfile->GetArchitecture(object_arch))
109        {
110            m_did_init_ast = true;
111            m_ast.SetArchitecture (object_arch);
112        }
113    }
114    return m_ast;
115}
116
117void
118Module::ParseAllDebugSymbols()
119{
120    Mutex::Locker locker (m_mutex);
121    uint32_t num_comp_units = GetNumCompileUnits();
122    if (num_comp_units == 0)
123        return;
124
125    TargetSP null_target;
126    SymbolContext sc(null_target, GetSP());
127    uint32_t cu_idx;
128    SymbolVendor *symbols = GetSymbolVendor ();
129
130    for (cu_idx = 0; cu_idx < num_comp_units; cu_idx++)
131    {
132        sc.comp_unit = symbols->GetCompileUnitAtIndex(cu_idx).get();
133        if (sc.comp_unit)
134        {
135            sc.function = NULL;
136            symbols->ParseVariablesForContext(sc);
137
138            symbols->ParseCompileUnitFunctions(sc);
139
140            uint32_t func_idx;
141            for (func_idx = 0; (sc.function = sc.comp_unit->GetFunctionAtIndex(func_idx).get()) != NULL; ++func_idx)
142            {
143                symbols->ParseFunctionBlocks(sc);
144
145                // Parse the variables for this function and all its blocks
146                symbols->ParseVariablesForContext(sc);
147            }
148
149
150            // Parse all types for this compile unit
151            sc.function = NULL;
152            symbols->ParseTypes(sc);
153        }
154    }
155}
156
157void
158Module::CalculateSymbolContext(SymbolContext* sc)
159{
160    sc->module_sp = GetSP();
161}
162
163void
164Module::DumpSymbolContext(Stream *s)
165{
166    s->Printf(", Module{0x%8.8x}", this);
167}
168
169uint32_t
170Module::GetNumCompileUnits()
171{
172    Mutex::Locker locker (m_mutex);
173    Timer scoped_timer(__PRETTY_FUNCTION__, "Module::GetNumCompileUnits (module = %p)", this);
174    SymbolVendor *symbols = GetSymbolVendor ();
175    if (symbols)
176        return symbols->GetNumCompileUnits();
177    return 0;
178}
179
180CompUnitSP
181Module::GetCompileUnitAtIndex (uint32_t index)
182{
183    Mutex::Locker locker (m_mutex);
184    uint32_t num_comp_units = GetNumCompileUnits ();
185    CompUnitSP cu_sp;
186
187    if (index < num_comp_units)
188    {
189        SymbolVendor *symbols = GetSymbolVendor ();
190        if (symbols)
191            cu_sp = symbols->GetCompileUnitAtIndex(index);
192    }
193    return cu_sp;
194}
195
196bool
197Module::ResolveFileAddress (lldb::addr_t vm_addr, Address& so_addr)
198{
199    Mutex::Locker locker (m_mutex);
200    Timer scoped_timer(__PRETTY_FUNCTION__, "Module::ResolveFileAddress (vm_addr = 0x%llx)", vm_addr);
201    ObjectFile* ofile = GetObjectFile();
202    if (ofile)
203        return so_addr.ResolveAddressUsingFileSections(vm_addr, ofile->GetSectionList());
204    return false;
205}
206
207uint32_t
208Module::ResolveSymbolContextForAddress (const Address& so_addr, uint32_t resolve_scope, SymbolContext& sc)
209{
210    Mutex::Locker locker (m_mutex);
211    uint32_t resolved_flags = 0;
212
213    // Clear the result symbol context in case we don't find anything
214    sc.Clear();
215
216    // Get the section from the section/offset address.
217    const Section *section = so_addr.GetSection();
218
219    // Make sure the section matches this module before we try and match anything
220    if (section && section->GetModule() == this)
221    {
222        // If the section offset based address resolved itself, then this
223        // is the right module.
224        sc.module_sp = GetSP();
225        resolved_flags |= eSymbolContextModule;
226
227        // Resolve the compile unit, function, block, line table or line
228        // entry if requested.
229        if (resolve_scope & eSymbolContextCompUnit    ||
230            resolve_scope & eSymbolContextFunction    ||
231            resolve_scope & eSymbolContextBlock       ||
232            resolve_scope & eSymbolContextLineEntry   )
233        {
234            SymbolVendor *symbols = GetSymbolVendor ();
235            if (symbols)
236                resolved_flags |= symbols->ResolveSymbolContext (so_addr, resolve_scope, sc);
237        }
238
239        // Resolve the symbol if requested, but don't re-look it up if we've already found it.
240        if (resolve_scope & eSymbolContextSymbol && !(resolved_flags & eSymbolContextSymbol))
241        {
242            ObjectFile* ofile = GetObjectFile();
243            if (ofile)
244            {
245                Symtab *symtab = ofile->GetSymtab();
246                if (symtab)
247                {
248                    if (so_addr.IsSectionOffset())
249                    {
250                        sc.symbol = symtab->FindSymbolContainingFileAddress(so_addr.GetFileAddress());
251                        if (sc.symbol)
252                            resolved_flags |= eSymbolContextSymbol;
253                    }
254                }
255            }
256        }
257    }
258    return resolved_flags;
259}
260
261uint32_t
262Module::ResolveSymbolContextForFilePath
263(
264    const char *file_path,
265    uint32_t line,
266    bool check_inlines,
267    uint32_t resolve_scope,
268    SymbolContextList& sc_list
269)
270{
271    FileSpec file_spec(file_path, false);
272    return ResolveSymbolContextsForFileSpec (file_spec, line, check_inlines, resolve_scope, sc_list);
273}
274
275uint32_t
276Module::ResolveSymbolContextsForFileSpec (const FileSpec &file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, SymbolContextList& sc_list)
277{
278    Mutex::Locker locker (m_mutex);
279    Timer scoped_timer(__PRETTY_FUNCTION__,
280                       "Module::ResolveSymbolContextForFilePath (%s%s%s:%u, check_inlines = %s, resolve_scope = 0x%8.8x)",
281                       file_spec.GetDirectory().AsCString(""),
282                       file_spec.GetDirectory() ? "/" : "",
283                       file_spec.GetFilename().AsCString(""),
284                       line,
285                       check_inlines ? "yes" : "no",
286                       resolve_scope);
287
288    const uint32_t initial_count = sc_list.GetSize();
289
290    SymbolVendor *symbols = GetSymbolVendor  ();
291    if (symbols)
292        symbols->ResolveSymbolContext (file_spec, line, check_inlines, resolve_scope, sc_list);
293
294    return sc_list.GetSize() - initial_count;
295}
296
297
298uint32_t
299Module::FindGlobalVariables(const ConstString &name, bool append, uint32_t max_matches, VariableList& variables)
300{
301    SymbolVendor *symbols = GetSymbolVendor ();
302    if (symbols)
303        return symbols->FindGlobalVariables(name, append, max_matches, variables);
304    return 0;
305}
306uint32_t
307Module::FindGlobalVariables(const RegularExpression& regex, bool append, uint32_t max_matches, VariableList& variables)
308{
309    SymbolVendor *symbols = GetSymbolVendor ();
310    if (symbols)
311        return symbols->FindGlobalVariables(regex, append, max_matches, variables);
312    return 0;
313}
314
315uint32_t
316Module::FindCompileUnits (const FileSpec &path,
317                          bool append,
318                          SymbolContextList &sc_list)
319{
320    if (!append)
321        sc_list.Clear();
322
323    const uint32_t start_size = sc_list.GetSize();
324    const uint32_t num_compile_units = GetNumCompileUnits();
325    SymbolContext sc;
326    sc.module_sp = GetSP();
327    const bool compare_directory = path.GetDirectory();
328    for (uint32_t i=0; i<num_compile_units; ++i)
329    {
330        sc.comp_unit = GetCompileUnitAtIndex(i).get();
331        if (FileSpec::Equal (*sc.comp_unit, path, compare_directory))
332            sc_list.Append(sc);
333    }
334    return sc_list.GetSize() - start_size;
335}
336
337uint32_t
338Module::FindFunctions (const ConstString &name,
339                       uint32_t name_type_mask,
340                       bool include_symbols,
341                       bool append,
342                       SymbolContextList& sc_list)
343{
344    if (!append)
345        sc_list.Clear();
346
347    const uint32_t start_size = sc_list.GetSize();
348
349    // Find all the functions (not symbols, but debug information functions...
350    SymbolVendor *symbols = GetSymbolVendor ();
351    if (symbols)
352        symbols->FindFunctions(name, name_type_mask, append, sc_list);
353
354    // Now check our symbol table for symbols that are code symbols if requested
355    if (include_symbols)
356    {
357        ObjectFile *objfile = GetObjectFile();
358        if (objfile)
359        {
360            Symtab *symtab = objfile->GetSymtab();
361            if (symtab)
362            {
363                std::vector<uint32_t> symbol_indexes;
364                symtab->FindAllSymbolsWithNameAndType (name, eSymbolTypeCode, Symtab::eDebugAny, Symtab::eVisibilityAny, symbol_indexes);
365                const uint32_t num_matches = symbol_indexes.size();
366                if (num_matches)
367                {
368                    const bool merge_symbol_into_function = true;
369                    SymbolContext sc(this);
370                    for (uint32_t i=0; i<num_matches; i++)
371                    {
372                        sc.symbol = symtab->SymbolAtIndex(symbol_indexes[i]);
373                        sc_list.AppendIfUnique (sc, merge_symbol_into_function);
374                    }
375                }
376            }
377        }
378    }
379    return sc_list.GetSize() - start_size;
380}
381
382uint32_t
383Module::FindFunctions (const RegularExpression& regex,
384                       bool include_symbols,
385                       bool append,
386                       SymbolContextList& sc_list)
387{
388    if (!append)
389        sc_list.Clear();
390
391    const uint32_t start_size = sc_list.GetSize();
392
393    SymbolVendor *symbols = GetSymbolVendor ();
394    if (symbols)
395        symbols->FindFunctions(regex, append, sc_list);
396    // Now check our symbol table for symbols that are code symbols if requested
397    if (include_symbols)
398    {
399        ObjectFile *objfile = GetObjectFile();
400        if (objfile)
401        {
402            Symtab *symtab = objfile->GetSymtab();
403            if (symtab)
404            {
405                std::vector<uint32_t> symbol_indexes;
406                symtab->AppendSymbolIndexesMatchingRegExAndType (regex, eSymbolTypeCode, Symtab::eDebugAny, Symtab::eVisibilityAny, symbol_indexes);
407                const uint32_t num_matches = symbol_indexes.size();
408                if (num_matches)
409                {
410                    const bool merge_symbol_into_function = true;
411                    SymbolContext sc(this);
412                    for (uint32_t i=0; i<num_matches; i++)
413                    {
414                        sc.symbol = symtab->SymbolAtIndex(symbol_indexes[i]);
415                        sc_list.AppendIfUnique (sc, merge_symbol_into_function);
416                    }
417                }
418            }
419        }
420    }
421    return sc_list.GetSize() - start_size;
422}
423
424uint32_t
425Module::FindTypes_Impl (const SymbolContext& sc, const ConstString &name, bool append, uint32_t max_matches, TypeList& types)
426{
427    Timer scoped_timer(__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
428    if (sc.module_sp.get() == NULL || sc.module_sp.get() == this)
429    {
430        SymbolVendor *symbols = GetSymbolVendor ();
431        if (symbols)
432            return symbols->FindTypes(sc, name, append, max_matches, types);
433    }
434    return 0;
435}
436
437// depending on implementation details, type lookup might fail because of
438// embedded spurious namespace:: prefixes. this call strips them, paying
439// attention to the fact that a type might have namespace'd type names as
440// arguments to templates, and those must not be stripped off
441static const char*
442StripTypeName(const char* name_cstr)
443{
444    const char* skip_namespace = strstr(name_cstr, "::");
445    const char* template_arg_char = strchr(name_cstr, '<');
446    while (skip_namespace != NULL)
447    {
448        if (template_arg_char != NULL &&
449            skip_namespace > template_arg_char) // but namespace'd template arguments are still good to go
450            break;
451        name_cstr = skip_namespace+2;
452        skip_namespace = strstr(name_cstr, "::");
453    }
454    return name_cstr;
455}
456
457uint32_t
458Module::FindTypes (const SymbolContext& sc, const ConstString &name, bool append, uint32_t max_matches, TypeList& types)
459{
460    uint32_t retval = FindTypes_Impl(sc, name, append, max_matches, types);
461
462    if (retval == 0)
463    {
464        const char *stripped = StripTypeName(name.GetCString());
465        return FindTypes_Impl(sc, ConstString(stripped), append, max_matches, types);
466    }
467    else
468        return retval;
469
470}
471
472//uint32_t
473//Module::FindTypes(const SymbolContext& sc, const RegularExpression& regex, bool append, uint32_t max_matches, Type::Encoding encoding, const char *udt_name, TypeList& types)
474//{
475//  Timer scoped_timer(__PRETTY_FUNCTION__);
476//  SymbolVendor *symbols = GetSymbolVendor ();
477//  if (symbols)
478//      return symbols->FindTypes(sc, regex, append, max_matches, encoding, udt_name, types);
479//  return 0;
480//
481//}
482
483SymbolVendor*
484Module::GetSymbolVendor (bool can_create)
485{
486    Mutex::Locker locker (m_mutex);
487    if (m_did_load_symbol_vendor == false && can_create)
488    {
489        ObjectFile *obj_file = GetObjectFile ();
490        if (obj_file != NULL)
491        {
492            Timer scoped_timer(__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
493            m_symfile_ap.reset(SymbolVendor::FindPlugin(this));
494            m_did_load_symbol_vendor = true;
495        }
496    }
497    return m_symfile_ap.get();
498}
499
500void
501Module::SetFileSpecAndObjectName (const FileSpec &file, const ConstString &object_name)
502{
503    // Container objects whose paths do not specify a file directly can call
504    // this function to correct the file and object names.
505    m_file = file;
506    m_mod_time = file.GetModificationTime();
507    m_object_name = object_name;
508}
509
510const ArchSpec&
511Module::GetArchitecture () const
512{
513    return m_arch;
514}
515
516void
517Module::GetDescription (Stream *s)
518{
519    Mutex::Locker locker (m_mutex);
520
521    if (m_arch.IsValid())
522        s->Printf("(%s) ", m_arch.GetArchitectureName());
523
524    char path[PATH_MAX];
525    if (m_file.GetPath(path, sizeof(path)))
526        s->PutCString(path);
527
528    const char *object_name = m_object_name.GetCString();
529    if (object_name)
530        s->Printf("(%s)", object_name);
531}
532
533void
534Module::Dump(Stream *s)
535{
536    Mutex::Locker locker (m_mutex);
537    //s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
538    s->Indent();
539    s->Printf("Module %s/%s%s%s%s\n",
540              m_file.GetDirectory().AsCString(),
541              m_file.GetFilename().AsCString(),
542              m_object_name ? "(" : "",
543              m_object_name ? m_object_name.GetCString() : "",
544              m_object_name ? ")" : "");
545
546    s->IndentMore();
547    ObjectFile *objfile = GetObjectFile ();
548
549    if (objfile)
550        objfile->Dump(s);
551
552    SymbolVendor *symbols = GetSymbolVendor ();
553
554    if (symbols)
555        symbols->Dump(s);
556
557    s->IndentLess();
558}
559
560
561TypeList*
562Module::GetTypeList ()
563{
564    SymbolVendor *symbols = GetSymbolVendor ();
565    if (symbols)
566        return &symbols->GetTypeList();
567    return NULL;
568}
569
570const ConstString &
571Module::GetObjectName() const
572{
573    return m_object_name;
574}
575
576ObjectFile *
577Module::GetObjectFile()
578{
579    Mutex::Locker locker (m_mutex);
580    if (m_did_load_objfile == false)
581    {
582        m_did_load_objfile = true;
583        Timer scoped_timer(__PRETTY_FUNCTION__,
584                           "Module::GetObjectFile () module = %s", GetFileSpec().GetFilename().AsCString(""));
585        m_objfile_ap.reset(ObjectFile::FindPlugin(this, &m_file, m_object_offset, m_file.GetByteSize()));
586    }
587    return m_objfile_ap.get();
588}
589
590
591const Symbol *
592Module::FindFirstSymbolWithNameAndType (const ConstString &name, SymbolType symbol_type)
593{
594    Timer scoped_timer(__PRETTY_FUNCTION__,
595                       "Module::FindFirstSymbolWithNameAndType (name = %s, type = %i)",
596                       name.AsCString(),
597                       symbol_type);
598    ObjectFile *objfile = GetObjectFile();
599    if (objfile)
600    {
601        Symtab *symtab = objfile->GetSymtab();
602        if (symtab)
603            return symtab->FindFirstSymbolWithNameAndType (name, symbol_type, Symtab::eDebugAny, Symtab::eVisibilityAny);
604    }
605    return NULL;
606}
607void
608Module::SymbolIndicesToSymbolContextList (Symtab *symtab, std::vector<uint32_t> &symbol_indexes, SymbolContextList &sc_list)
609{
610    // No need to protect this call using m_mutex all other method calls are
611    // already thread safe.
612
613    size_t num_indices = symbol_indexes.size();
614    if (num_indices > 0)
615    {
616        SymbolContext sc;
617        CalculateSymbolContext (&sc);
618        for (size_t i = 0; i < num_indices; i++)
619        {
620            sc.symbol = symtab->SymbolAtIndex (symbol_indexes[i]);
621            if (sc.symbol)
622                sc_list.Append (sc);
623        }
624    }
625}
626
627size_t
628Module::FindSymbolsWithNameAndType (const ConstString &name, SymbolType symbol_type, SymbolContextList &sc_list)
629{
630    // No need to protect this call using m_mutex all other method calls are
631    // already thread safe.
632
633
634    Timer scoped_timer(__PRETTY_FUNCTION__,
635                       "Module::FindSymbolsWithNameAndType (name = %s, type = %i)",
636                       name.AsCString(),
637                       symbol_type);
638    const size_t initial_size = sc_list.GetSize();
639    ObjectFile *objfile = GetObjectFile ();
640    if (objfile)
641    {
642        Symtab *symtab = objfile->GetSymtab();
643        if (symtab)
644        {
645            std::vector<uint32_t> symbol_indexes;
646            symtab->FindAllSymbolsWithNameAndType (name, symbol_type, symbol_indexes);
647            SymbolIndicesToSymbolContextList (symtab, symbol_indexes, sc_list);
648        }
649    }
650    return sc_list.GetSize() - initial_size;
651}
652
653size_t
654Module::FindSymbolsMatchingRegExAndType (const RegularExpression &regex, SymbolType symbol_type, SymbolContextList &sc_list)
655{
656    // No need to protect this call using m_mutex all other method calls are
657    // already thread safe.
658
659    Timer scoped_timer(__PRETTY_FUNCTION__,
660                       "Module::FindSymbolsMatchingRegExAndType (regex = %s, type = %i)",
661                       regex.GetText(),
662                       symbol_type);
663    const size_t initial_size = sc_list.GetSize();
664    ObjectFile *objfile = GetObjectFile ();
665    if (objfile)
666    {
667        Symtab *symtab = objfile->GetSymtab();
668        if (symtab)
669        {
670            std::vector<uint32_t> symbol_indexes;
671            symtab->FindAllSymbolsMatchingRexExAndType (regex, symbol_type, Symtab::eDebugAny, Symtab::eVisibilityAny, symbol_indexes);
672            SymbolIndicesToSymbolContextList (symtab, symbol_indexes, sc_list);
673        }
674    }
675    return sc_list.GetSize() - initial_size;
676}
677
678const TimeValue &
679Module::GetModificationTime () const
680{
681    return m_mod_time;
682}
683
684bool
685Module::IsExecutable ()
686{
687    if (GetObjectFile() == NULL)
688        return false;
689    else
690        return GetObjectFile()->IsExecutable();
691}
692
693bool
694Module::IsLoadedInTarget (Target *target)
695{
696    ObjectFile *obj_file = GetObjectFile();
697    if (obj_file)
698    {
699        SectionList *sections = obj_file->GetSectionList();
700        if (sections != NULL)
701        {
702            size_t num_sections = sections->GetSize();
703            bool loaded = false;
704            for (size_t sect_idx = 0; sect_idx < num_sections; sect_idx++)
705            {
706                SectionSP section_sp = sections->GetSectionAtIndex(sect_idx);
707                if (section_sp->GetLoadBaseAddress(target) != LLDB_INVALID_ADDRESS)
708                {
709                    return true;
710                }
711            }
712        }
713    }
714    return false;
715}
716bool
717Module::SetArchitecture (const ArchSpec &new_arch)
718{
719    if (!m_arch.IsValid())
720    {
721        m_arch = new_arch;
722        return true;
723    }
724    return m_arch == new_arch;
725}
726
727