SymbolContext.cpp revision f15996eea072cdaa8a092f22d3a1212b3d95f0ec
1//===-- SymbolContext.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/Symbol/SymbolContext.h"
11
12#include "lldb/Core/Module.h"
13#include "lldb/Interpreter/Args.h"
14#include "lldb/Symbol/CompileUnit.h"
15#include "lldb/Symbol/ObjectFile.h"
16#include "lldb/Symbol/Symbol.h"
17#include "lldb/Symbol/SymbolVendor.h"
18#include "lldb/Target/Target.h"
19
20using namespace lldb;
21using namespace lldb_private;
22
23SymbolContext::SymbolContext() :
24    target_sp   (),
25    module_sp   (),
26    comp_unit   (NULL),
27    function    (NULL),
28    block       (NULL),
29    line_entry  (),
30    symbol      (NULL)
31{
32}
33
34SymbolContext::SymbolContext(const ModuleSP& m, CompileUnit *cu, Function *f, Block *b, LineEntry *le, Symbol *s) :
35    target_sp   (),
36    module_sp   (m),
37    comp_unit   (cu),
38    function    (f),
39    block       (b),
40    line_entry  (),
41    symbol      (s)
42{
43    if (le)
44        line_entry = *le;
45}
46
47SymbolContext::SymbolContext(const TargetSP &t, const ModuleSP& m, CompileUnit *cu, Function *f, Block *b, LineEntry *le, Symbol *s) :
48    target_sp   (t),
49    module_sp   (m),
50    comp_unit   (cu),
51    function    (f),
52    block       (b),
53    line_entry  (),
54    symbol      (s)
55{
56    if (le)
57        line_entry = *le;
58}
59
60SymbolContext::SymbolContext(const SymbolContext& rhs) :
61    target_sp   (rhs.target_sp),
62    module_sp   (rhs.module_sp),
63    comp_unit   (rhs.comp_unit),
64    function    (rhs.function),
65    block       (rhs.block),
66    line_entry  (rhs.line_entry),
67    symbol      (rhs.symbol)
68{
69}
70
71
72SymbolContext::SymbolContext (SymbolContextScope *sc_scope) :
73    target_sp   (),
74    module_sp   (),
75    comp_unit   (NULL),
76    function    (NULL),
77    block       (NULL),
78    line_entry  (),
79    symbol      (NULL)
80{
81    sc_scope->CalculateSymbolContext (this);
82}
83
84const SymbolContext&
85SymbolContext::operator= (const SymbolContext& rhs)
86{
87    if (this != &rhs)
88    {
89        target_sp   = rhs.target_sp;
90        module_sp   = rhs.module_sp;
91        comp_unit   = rhs.comp_unit;
92        function    = rhs.function;
93        block       = rhs.block;
94        line_entry  = rhs.line_entry;
95        symbol      = rhs.symbol;
96    }
97    return *this;
98}
99
100void
101SymbolContext::Clear()
102{
103    target_sp.reset();
104    module_sp.reset();
105    comp_unit   = NULL;
106    function    = NULL;
107    block       = NULL;
108    line_entry.Clear();
109    symbol      = NULL;
110}
111
112void
113SymbolContext::DumpStopContext
114(
115    Stream *s,
116    ExecutionContextScope *exe_scope,
117    const Address &addr,
118    bool show_fullpaths,
119    bool show_module,
120    bool show_inlined_frames
121) const
122{
123    if (show_module && module_sp)
124    {
125        if (show_fullpaths)
126            *s << module_sp->GetFileSpec();
127        else
128            *s << module_sp->GetFileSpec().GetFilename();
129        s->PutChar('`');
130    }
131
132    if (function != NULL)
133    {
134        if (function->GetMangled().GetName())
135            function->GetMangled().GetName().Dump(s);
136
137        if (addr.IsValid())
138        {
139            const addr_t function_offset = addr.GetOffset() - function->GetAddressRange().GetBaseAddress().GetOffset();
140            if (function_offset)
141                s->Printf(" + %llu", function_offset);
142        }
143
144        if (block != NULL)
145        {
146            s->IndentMore();
147            block->DumpStopContext (s, this, NULL, show_fullpaths, show_inlined_frames);
148            s->IndentLess();
149        }
150        else
151        {
152            if (line_entry.IsValid())
153            {
154                s->PutCString(" at ");
155                if (line_entry.DumpStopContext(s, show_fullpaths))
156                    return;
157            }
158        }
159    }
160    else if (symbol != NULL)
161    {
162        symbol->GetMangled().GetName().Dump(s);
163
164        if (addr.IsValid() && symbol->GetAddressRangePtr())
165        {
166            const addr_t symbol_offset = addr.GetOffset() - symbol->GetAddressRangePtr()->GetBaseAddress().GetOffset();
167            if (symbol_offset)
168                s->Printf(" + %llu", symbol_offset);
169        }
170    }
171    else if (addr.IsValid())
172    {
173        addr.Dump(s, exe_scope, Address::DumpStyleModuleWithFileAddress);
174    }
175}
176
177void
178SymbolContext::GetDescription(Stream *s, lldb::DescriptionLevel level, Target *target) const
179{
180    if (module_sp)
181    {
182        s->Indent("     Module: file = \"");
183        module_sp->GetFileSpec().Dump(s);
184        *s << '"';
185        if (module_sp->GetArchitecture().IsValid())
186            s->Printf (", arch = \"%s\"", module_sp->GetArchitecture().GetArchitectureName());
187        s->EOL();
188    }
189
190    if (comp_unit != NULL)
191    {
192        s->Indent("CompileUnit: ");
193        comp_unit->GetDescription (s, level);
194        s->EOL();
195    }
196
197    if (function != NULL)
198    {
199        s->Indent("   Function: ");
200        function->GetDescription (s, level, target);
201        s->EOL();
202
203        Type *func_type = function->GetType();
204        if (func_type)
205        {
206            s->Indent("   FuncType: ");
207            func_type->GetDescription (s, level, false);
208            s->EOL();
209        }
210    }
211
212    if (block != NULL)
213    {
214        std::vector<Block *> blocks;
215        blocks.push_back (block);
216        Block *parent_block = block->GetParent();
217
218        while (parent_block)
219        {
220            blocks.push_back (parent_block);
221            parent_block = parent_block->GetParent();
222        }
223        std::vector<Block *>::reverse_iterator pos;
224        std::vector<Block *>::reverse_iterator begin = blocks.rbegin();
225        std::vector<Block *>::reverse_iterator end = blocks.rend();
226        for (pos = begin; pos != end; ++pos)
227        {
228            if (pos == begin)
229                s->Indent("     Blocks: ");
230            else
231                s->Indent("             ");
232            (*pos)->GetDescription(s, function, level, target);
233            s->EOL();
234        }
235    }
236
237    if (line_entry.IsValid())
238    {
239        s->Indent("  LineEntry: ");
240        line_entry.GetDescription (s, level, comp_unit, target, false);
241        s->EOL();
242    }
243
244    if (symbol != NULL)
245    {
246        s->Indent("     Symbol: ");
247        symbol->GetDescription(s, level, target);
248        s->EOL();
249    }
250}
251
252uint32_t
253SymbolContext::GetResolvedMask () const
254{
255    uint32_t resolved_mask = 0;
256    if (target_sp)              resolved_mask |= eSymbolContextTarget;
257    if (module_sp)              resolved_mask |= eSymbolContextModule;
258    if (comp_unit)              resolved_mask |= eSymbolContextCompUnit;
259    if (function)               resolved_mask |= eSymbolContextFunction;
260    if (block)                  resolved_mask |= eSymbolContextBlock;
261    if (line_entry.IsValid())   resolved_mask |= eSymbolContextLineEntry;
262    if (symbol)                 resolved_mask |= eSymbolContextSymbol;
263    return resolved_mask;
264}
265
266
267void
268SymbolContext::Dump(Stream *s, Target *target) const
269{
270    *s << (void *)this << ": ";
271    s->Indent();
272    s->PutCString("SymbolContext");
273    s->IndentMore();
274    s->EOL();
275    s->IndentMore();
276    s->Indent();
277    *s << "Module       = " << (void *)module_sp.get() << ' ';
278    if (module_sp)
279        module_sp->GetFileSpec().Dump(s);
280    s->EOL();
281    s->Indent();
282    *s << "CompileUnit  = " << (void *)comp_unit;
283    if (comp_unit != NULL)
284        *s << " {0x" << comp_unit->GetID() << "} " << *(static_cast<FileSpec*> (comp_unit));
285    s->EOL();
286    s->Indent();
287    *s << "Function     = " << (void *)function;
288    if (function != NULL)
289    {
290        *s << " {0x" << function->GetID() << "} " << function->GetType()->GetName() << ", address-range = ";
291        function->GetAddressRange().Dump(s, target, Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress);
292        s->EOL();
293        s->Indent();
294        Type* func_type = function->GetType();
295        if (func_type)
296        {
297            *s << "        Type = ";
298            func_type->Dump (s, false);
299        }
300    }
301    s->EOL();
302    s->Indent();
303    *s << "Block        = " << (void *)block;
304    if (block != NULL)
305        *s << " {0x" << block->GetID() << '}';
306    // Dump the block and pass it a negative depth to we print all the parent blocks
307    //if (block != NULL)
308    //  block->Dump(s, function->GetFileAddress(), INT_MIN);
309    s->EOL();
310    s->Indent();
311    *s << "LineEntry    = ";
312    line_entry.Dump (s, target, true, Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress, true);
313    s->EOL();
314    s->Indent();
315    *s << "Symbol       = " << (void *)symbol;
316    if (symbol != NULL && symbol->GetMangled())
317        *s << ' ' << symbol->GetMangled().GetName().AsCString();
318    s->EOL();
319    s->IndentLess();
320    s->IndentLess();
321}
322
323bool
324lldb_private::operator== (const SymbolContext& lhs, const SymbolContext& rhs)
325{
326    return  lhs.function == rhs.function
327            && lhs.symbol == rhs.symbol
328            && lhs.module_sp.get() == rhs.module_sp.get()
329            && lhs.comp_unit == rhs.comp_unit
330            && lhs.target_sp.get() == rhs.target_sp.get()
331            && LineEntry::Compare(lhs.line_entry, rhs.line_entry) == 0;
332}
333
334bool
335lldb_private::operator!= (const SymbolContext& lhs, const SymbolContext& rhs)
336{
337    return  lhs.function != rhs.function
338            || lhs.symbol != rhs.symbol
339            || lhs.module_sp.get() != rhs.module_sp.get()
340            || lhs.comp_unit != rhs.comp_unit
341            || lhs.target_sp.get() != rhs.target_sp.get()
342            || LineEntry::Compare(lhs.line_entry, rhs.line_entry) != 0;
343}
344
345bool
346SymbolContext::GetAddressRange (uint32_t scope, AddressRange &range) const
347{
348    if ((scope & eSymbolContextLineEntry) && line_entry.IsValid())
349    {
350        range = line_entry.range;
351        return true;
352    }
353    else if ((scope & eSymbolContextFunction) && function != NULL)
354    {
355        range = function->GetAddressRange();
356        return true;
357    }
358    else if ((scope & eSymbolContextSymbol) && symbol != NULL && symbol->GetAddressRangePtr())
359    {
360        range = *symbol->GetAddressRangePtr();
361
362        if (range.GetByteSize() == 0)
363        {
364            if (module_sp)
365            {
366                ObjectFile *objfile = module_sp->GetObjectFile();
367                if (objfile)
368                {
369                    Symtab *symtab = objfile->GetSymtab();
370                    if (symtab)
371                        range.SetByteSize(symtab->CalculateSymbolSize (symbol));
372                }
373            }
374        }
375        return true;
376    }
377    range.Clear();
378    return false;
379}
380
381ClangNamespaceDecl
382SymbolContext::FindNamespace (const ConstString &name) const
383{
384    ClangNamespaceDecl namespace_decl;
385    if (module_sp)
386        namespace_decl = module_sp->GetSymbolVendor()->FindNamespace (*this, name);
387    return namespace_decl;
388}
389
390size_t
391SymbolContext::FindFunctionsByName (const ConstString &name,
392                                    bool include_symbols,
393                                    bool append,
394                                    SymbolContextList &sc_list) const
395{
396    if (!append)
397        sc_list.Clear();
398
399    if (function != NULL)
400    {
401        // FIXME: Look in the class of the current function, if it exists,
402        // for methods matching name.
403    }
404
405    if (module_sp != NULL)
406        module_sp->FindFunctions (name, eFunctionNameTypeBase | eFunctionNameTypeFull, include_symbols, true, sc_list);
407
408    if (target_sp)
409        target_sp->GetImages().FindFunctions (name, eFunctionNameTypeBase | eFunctionNameTypeFull, include_symbols, true, sc_list);
410
411    return sc_list.GetSize();
412}
413
414//lldb::VariableSP
415//SymbolContext::FindVariableByName (const char *name) const
416//{
417//    lldb::VariableSP return_value;
418//    return return_value;
419//}
420
421lldb::TypeSP
422SymbolContext::FindTypeByName (const ConstString &name) const
423{
424    lldb::TypeSP return_value;
425
426    TypeList types;
427
428    if (module_sp && module_sp->FindTypes (*this, name, false, 1, types))
429        return types.GetTypeAtIndex(0);
430
431    if (!return_value.get() && target_sp && target_sp->GetImages().FindTypes (*this, name, false, 1, types))
432        return types.GetTypeAtIndex(0);
433
434    return return_value;
435}
436
437//----------------------------------------------------------------------
438//
439//  SymbolContextSpecifier
440//
441//----------------------------------------------------------------------
442
443bool
444SymbolContextSpecifier::AddLineSpecification (uint32_t line_no, SpecificationType type)
445{
446    bool return_value = true;
447    switch (type)
448    {
449    case eNothingSpecified:
450        Clear();
451        break;
452    case eLineStartSpecified:
453        m_start_line = line_no;
454        m_type |= eLineStartSpecified;
455        break;
456    case eLineEndSpecified:
457        m_end_line = line_no;
458        m_type |= eLineEndSpecified;
459        break;
460    default:
461        return_value = false;
462        break;
463    }
464    return return_value;
465}
466
467bool
468SymbolContextSpecifier::AddSpecification (const char *spec_string, SpecificationType type)
469{
470    bool return_value = true;
471    switch (type)
472    {
473    case eNothingSpecified:
474        Clear();
475        break;
476    case eModuleSpecified:
477        {
478            // See if we can find the Module, if so stick it in the SymbolContext.
479            FileSpec module_spec(spec_string, false);
480            lldb::ModuleSP module_sp = m_target_sp->GetImages().FindFirstModuleForFileSpec (module_spec, NULL, NULL);
481            m_type |= eModuleSpecified;
482            if (module_sp)
483                m_module_sp = module_sp;
484            else
485                m_module_spec.assign (spec_string);
486        }
487        break;
488    case eFileSpecified:
489        // CompUnits can't necessarily be resolved here, since an inlined function might show up in
490        // a number of CompUnits.  Instead we just convert to a FileSpec and store it away.
491        m_file_spec_ap.reset (new FileSpec (spec_string, false));
492        m_type |= eFileSpecified;
493        break;
494    case eLineStartSpecified:
495        m_start_line = Args::StringToSInt32(spec_string, 0, 0, &return_value);
496        if (return_value)
497            m_type |= eLineStartSpecified;
498        break;
499    case eLineEndSpecified:
500        m_end_line = Args::StringToSInt32(spec_string, 0, 0, &return_value);
501        if (return_value)
502            m_type |= eLineEndSpecified;
503        break;
504    case eFunctionSpecified:
505        m_function_spec.assign(spec_string);
506        m_type |= eFunctionSpecified;
507        break;
508    case eClassOrNamespaceSpecified:
509        Clear();
510        m_class_name.assign (spec_string);
511        m_type = eClassOrNamespaceSpecified;
512        break;
513    case eAddressRangeSpecified:
514        // Not specified yet...
515        break;
516    }
517
518    return return_value;
519}
520
521void
522SymbolContextSpecifier::Clear()
523{
524    m_module_spec.clear();
525    m_file_spec_ap.reset();
526    m_function_spec.clear();
527    m_class_name.clear();
528    m_start_line = 0;
529    m_end_line = 0;
530    m_address_range_ap.reset();
531
532    m_type = eNothingSpecified;
533}
534
535bool
536SymbolContextSpecifier::SymbolContextMatches(SymbolContext &sc)
537{
538    if (m_type == eNothingSpecified)
539        return true;
540
541    if (m_target_sp.get() != sc.target_sp.get())
542        return false;
543
544    if (m_type & eModuleSpecified)
545    {
546        if (sc.module_sp)
547        {
548            if (m_module_sp.get() != NULL)
549            {
550                if (m_module_sp.get() != sc.module_sp.get())
551                    return false;
552            }
553            else
554            {
555                FileSpec module_file_spec (m_module_spec.c_str(), false);
556                if (!FileSpec::Equal (module_file_spec, sc.module_sp->GetFileSpec(), false))
557                    return false;
558            }
559        }
560    }
561    if (m_type & eFileSpecified)
562    {
563        if (m_file_spec_ap.get())
564        {
565            // If we don't have a block or a comp_unit, then we aren't going to match a source file.
566            if (sc.block == NULL && sc.comp_unit == NULL)
567                return false;
568
569            // Check if the block is present, and if so is it inlined:
570            bool was_inlined = false;
571            if (sc.block != NULL)
572            {
573                const InlineFunctionInfo *inline_info = sc.block->GetInlinedFunctionInfo();
574                if (inline_info != NULL)
575                {
576                    was_inlined = true;
577                    if (!FileSpec::Equal (inline_info->GetDeclaration().GetFile(), *(m_file_spec_ap.get()), false))
578                        return false;
579                }
580            }
581
582            // Next check the comp unit, but only if the SymbolContext was not inlined.
583            if (!was_inlined && sc.comp_unit != NULL)
584            {
585                if (!FileSpec::Equal (*(sc.comp_unit), *(m_file_spec_ap.get()), false))
586                    return false;
587            }
588        }
589    }
590    if (m_type & eLineStartSpecified
591        || m_type & eLineEndSpecified)
592    {
593        if (sc.line_entry.line < m_start_line || sc.line_entry.line > m_end_line)
594            return false;
595    }
596
597    if (m_type & eFunctionSpecified)
598    {
599        // First check the current block, and if it is inlined, get the inlined function name:
600        bool was_inlined = false;
601        ConstString func_name(m_function_spec.c_str());
602
603        if (sc.block != NULL)
604        {
605            const InlineFunctionInfo *inline_info = sc.block->GetInlinedFunctionInfo();
606            if (inline_info != NULL)
607            {
608                was_inlined = true;
609                const Mangled &name = inline_info->GetMangled();
610                if (!name.NameMatches (func_name))
611                    return false;
612            }
613        }
614        //  If it wasn't inlined, check the name in the function or symbol:
615        if (!was_inlined)
616        {
617            if (sc.function != NULL)
618            {
619                if (!sc.function->GetMangled().NameMatches(func_name))
620                    return false;
621            }
622            else if (sc.symbol != NULL)
623            {
624                if (!sc.symbol->GetMangled().NameMatches(func_name))
625                    return false;
626            }
627        }
628
629
630    }
631
632    return true;
633}
634
635bool
636SymbolContextSpecifier::AddressMatches(lldb::addr_t addr)
637{
638    if (m_type & eAddressRangeSpecified)
639    {
640
641    }
642    else
643    {
644        Address match_address (addr, NULL);
645        SymbolContext sc;
646        m_target_sp->GetImages().ResolveSymbolContextForAddress(match_address, eSymbolContextEverything, sc);
647        return SymbolContextMatches(sc);
648    }
649    return true;
650}
651
652void
653SymbolContextSpecifier::GetDescription (Stream *s, lldb::DescriptionLevel level) const
654{
655    char path_str[PATH_MAX + 1];
656
657    if (m_type == eNothingSpecified)
658    {
659        s->Printf ("Nothing specified.\n");
660    }
661
662    if (m_type == eModuleSpecified)
663    {
664        s->Indent();
665        if (m_module_sp)
666        {
667            m_module_sp->GetFileSpec().GetPath (path_str, PATH_MAX);
668            s->Printf ("Module: %s\n", path_str);
669        }
670        else
671            s->Printf ("Module: %s\n", m_module_spec.c_str());
672    }
673
674    if (m_type == eFileSpecified  && m_file_spec_ap.get() != NULL)
675    {
676        m_file_spec_ap->GetPath (path_str, PATH_MAX);
677        s->Indent();
678        s->Printf ("File: %s", path_str);
679        if (m_type == eLineStartSpecified)
680        {
681            s->Printf (" from line %d", m_start_line);
682            if (m_type == eLineEndSpecified)
683                s->Printf ("to line %d", m_end_line);
684            else
685                s->Printf ("to end", m_end_line);
686        }
687        else if (m_type == eLineEndSpecified)
688        {
689            s->Printf (" from start to line %d", m_end_line);
690        }
691        s->Printf (".\n");
692    }
693
694    if (m_type == eLineStartSpecified)
695    {
696        s->Indent();
697        s->Printf ("From line %d", m_start_line);
698        if (m_type == eLineEndSpecified)
699            s->Printf ("to line %d", m_end_line);
700        else
701            s->Printf ("to end", m_end_line);
702        s->Printf (".\n");
703    }
704    else if (m_type == eLineEndSpecified)
705    {
706        s->Printf ("From start to line %d.\n", m_end_line);
707    }
708
709    if (m_type == eFunctionSpecified)
710    {
711        s->Indent();
712        s->Printf ("Function: %s.\n", m_function_spec.c_str());
713    }
714
715    if (m_type == eClassOrNamespaceSpecified)
716    {
717        s->Indent();
718        s->Printf ("Class name: %s.\n", m_class_name.c_str());
719    }
720
721    if (m_type == eAddressRangeSpecified && m_address_range_ap.get() != NULL)
722    {
723        s->Indent();
724        s->PutCString ("Address range: ");
725        m_address_range_ap->Dump (s, m_target_sp.get(), Address::DumpStyleLoadAddress, Address::DumpStyleFileAddress);
726        s->PutCString ("\n");
727    }
728}
729
730//----------------------------------------------------------------------
731//
732//  SymbolContextList
733//
734//----------------------------------------------------------------------
735
736
737SymbolContextList::SymbolContextList() :
738    m_symbol_contexts()
739{
740}
741
742SymbolContextList::~SymbolContextList()
743{
744}
745
746void
747SymbolContextList::Append(const SymbolContext& sc)
748{
749    m_symbol_contexts.push_back(sc);
750}
751
752bool
753SymbolContextList::AppendIfUnique (const SymbolContext& sc, bool merge_symbol_into_function)
754{
755    collection::iterator pos, end = m_symbol_contexts.end();
756    for (pos = m_symbol_contexts.begin(); pos != end; ++pos)
757    {
758        if (*pos == sc)
759            return false;
760    }
761    if (merge_symbol_into_function
762        && sc.symbol    != NULL
763        && sc.comp_unit == NULL
764        && sc.function  == NULL
765        && sc.block     == NULL
766        && sc.line_entry.IsValid() == false)
767    {
768        const AddressRange *symbol_range = sc.symbol->GetAddressRangePtr();
769        if (symbol_range)
770        {
771            for (pos = m_symbol_contexts.begin(); pos != end; ++pos)
772            {
773                if (pos->function)
774                {
775                    if (pos->function->GetAddressRange().GetBaseAddress() == symbol_range->GetBaseAddress())
776                    {
777                        // Do we already have a function with this symbol?
778                        if (pos->symbol == sc.symbol)
779                            return false;
780                        if (pos->symbol == NULL)
781                        {
782                            pos->symbol = sc.symbol;
783                            return false;
784                        }
785                    }
786                }
787            }
788        }
789    }
790    m_symbol_contexts.push_back(sc);
791    return true;
792}
793
794void
795SymbolContextList::Clear()
796{
797    m_symbol_contexts.clear();
798}
799
800void
801SymbolContextList::Dump(Stream *s, Target *target) const
802{
803
804    *s << (void *)this << ": ";
805    s->Indent();
806    s->PutCString("SymbolContextList");
807    s->EOL();
808    s->IndentMore();
809
810    collection::const_iterator pos, end = m_symbol_contexts.end();
811    for (pos = m_symbol_contexts.begin(); pos != end; ++pos)
812    {
813        pos->Dump(s, target);
814    }
815    s->IndentLess();
816}
817
818bool
819SymbolContextList::GetContextAtIndex(uint32_t idx, SymbolContext& sc) const
820{
821    if (idx < m_symbol_contexts.size())
822    {
823        sc = m_symbol_contexts[idx];
824        return true;
825    }
826    return false;
827}
828
829bool
830SymbolContextList::RemoveContextAtIndex (uint32_t idx)
831{
832    if (idx < m_symbol_contexts.size())
833    {
834        m_symbol_contexts.erase(m_symbol_contexts.begin() + idx);
835        return true;
836    }
837    return false;
838}
839
840uint32_t
841SymbolContextList::GetSize() const
842{
843    return m_symbol_contexts.size();
844}
845