Symtab.cpp revision f58438fa7751274b6f4e4b1805940127dce13b00
1//===-- Symtab.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 <map>
11
12#include "lldb/Core/Module.h"
13#include "lldb/Core/RegularExpression.h"
14#include "lldb/Core/Section.h"
15#include "lldb/Core/Timer.h"
16#include "lldb/Symbol/ObjectFile.h"
17#include "lldb/Symbol/SymbolContext.h"
18#include "lldb/Symbol/Symtab.h"
19#include "lldb/Target/CPPLanguageRuntime.h"
20#include "lldb/Target/ObjCLanguageRuntime.h"
21
22using namespace lldb;
23using namespace lldb_private;
24
25
26
27Symtab::Symtab(ObjectFile *objfile) :
28    m_objfile (objfile),
29    m_symbols (),
30    m_addr_indexes (),
31    m_name_to_index (),
32    m_mutex (Mutex::eMutexTypeRecursive),
33    m_addr_indexes_computed (false),
34    m_name_indexes_computed (false)
35{
36}
37
38Symtab::~Symtab()
39{
40}
41
42void
43Symtab::Reserve(size_t count)
44{
45    // Clients should grab the mutex from this symbol table and lock it manually
46    // when calling this function to avoid performance issues.
47    m_symbols.reserve (count);
48}
49
50Symbol *
51Symtab::Resize(size_t count)
52{
53    // Clients should grab the mutex from this symbol table and lock it manually
54    // when calling this function to avoid performance issues.
55    m_symbols.resize (count);
56    return &m_symbols[0];
57}
58
59uint32_t
60Symtab::AddSymbol(const Symbol& symbol)
61{
62    // Clients should grab the mutex from this symbol table and lock it manually
63    // when calling this function to avoid performance issues.
64    uint32_t symbol_idx = m_symbols.size();
65    m_name_to_index.Clear();
66    m_addr_indexes.clear();
67    m_symbols.push_back(symbol);
68    m_addr_indexes_computed = false;
69    m_name_indexes_computed = false;
70    return symbol_idx;
71}
72
73size_t
74Symtab::GetNumSymbols() const
75{
76    Mutex::Locker locker (m_mutex);
77    return m_symbols.size();
78}
79
80void
81Symtab::Dump (Stream *s, Target *target, SortOrder sort_order)
82{
83    Mutex::Locker locker (m_mutex);
84
85//    s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
86    s->Indent();
87    const FileSpec &file_spec = m_objfile->GetFileSpec();
88    const char * object_name = NULL;
89    if (m_objfile->GetModule())
90        object_name = m_objfile->GetModule()->GetObjectName().GetCString();
91
92    if (file_spec)
93        s->Printf("Symtab, file = %s/%s%s%s%s, num_symbols = %lu",
94        file_spec.GetDirectory().AsCString(),
95        file_spec.GetFilename().AsCString(),
96        object_name ? "(" : "",
97        object_name ? object_name : "",
98        object_name ? ")" : "",
99        m_symbols.size());
100    else
101        s->Printf("Symtab, num_symbols = %lu", m_symbols.size());
102
103    if (!m_symbols.empty())
104    {
105        switch (sort_order)
106        {
107        case eSortOrderNone:
108            {
109                s->PutCString (":\n");
110                DumpSymbolHeader (s);
111                const_iterator begin = m_symbols.begin();
112                const_iterator end = m_symbols.end();
113                for (const_iterator pos = m_symbols.begin(); pos != end; ++pos)
114                {
115                    s->Indent();
116                    pos->Dump(s, target, std::distance(begin, pos));
117                }
118            }
119            break;
120
121        case eSortOrderByName:
122            {
123                // Although we maintain a lookup by exact name map, the table
124                // isn't sorted by name. So we must make the ordered symbol list
125                // up ourselves.
126                s->PutCString (" (sorted by name):\n");
127                DumpSymbolHeader (s);
128                typedef std::multimap<const char*, const Symbol *, CStringCompareFunctionObject> CStringToSymbol;
129                CStringToSymbol name_map;
130                for (const_iterator pos = m_symbols.begin(), end = m_symbols.end(); pos != end; ++pos)
131                {
132                    const char *name = pos->GetMangled().GetName(Mangled::ePreferDemangled).AsCString();
133                    if (name && name[0])
134                        name_map.insert (std::make_pair(name, &(*pos)));
135                }
136
137                for (CStringToSymbol::const_iterator pos = name_map.begin(), end = name_map.end(); pos != end; ++pos)
138                {
139                    s->Indent();
140                    pos->second->Dump (s, target, pos->second - &m_symbols[0]);
141                }
142            }
143            break;
144
145        case eSortOrderByAddress:
146            s->PutCString (" (sorted by address):\n");
147            DumpSymbolHeader (s);
148            if (!m_addr_indexes_computed)
149                InitAddressIndexes();
150            const size_t num_symbols = GetNumSymbols();
151            std::vector<uint32_t>::const_iterator pos;
152            std::vector<uint32_t>::const_iterator end = m_addr_indexes.end();
153            for (pos = m_addr_indexes.begin(); pos != end; ++pos)
154            {
155                size_t idx = *pos;
156                if (idx < num_symbols)
157                {
158                    s->Indent();
159                    m_symbols[idx].Dump(s, target, idx);
160                }
161            }
162            break;
163        }
164    }
165}
166
167void
168Symtab::Dump(Stream *s, Target *target, std::vector<uint32_t>& indexes) const
169{
170    Mutex::Locker locker (m_mutex);
171
172    const size_t num_symbols = GetNumSymbols();
173    //s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
174    s->Indent();
175    s->Printf("Symtab %lu symbol indexes (%lu symbols total):\n", indexes.size(), m_symbols.size());
176    s->IndentMore();
177
178    if (!indexes.empty())
179    {
180        std::vector<uint32_t>::const_iterator pos;
181        std::vector<uint32_t>::const_iterator end = indexes.end();
182        DumpSymbolHeader (s);
183        for (pos = indexes.begin(); pos != end; ++pos)
184        {
185            size_t idx = *pos;
186            if (idx < num_symbols)
187            {
188                s->Indent();
189                m_symbols[idx].Dump(s, target, idx);
190            }
191        }
192    }
193    s->IndentLess ();
194}
195
196void
197Symtab::DumpSymbolHeader (Stream *s)
198{
199    s->Indent("               Debug symbol\n");
200    s->Indent("               |Synthetic symbol\n");
201    s->Indent("               ||Externally Visible\n");
202    s->Indent("               |||\n");
203    s->Indent("Index   UserID DSX Type         File Address/Value Load Address       Size               Flags      Name\n");
204    s->Indent("------- ------ --- ------------ ------------------ ------------------ ------------------ ---------- ----------------------------------\n");
205}
206
207
208static int
209CompareSymbolID (const void *key, const void *p)
210{
211    const user_id_t match_uid = *(user_id_t*) key;
212    const user_id_t symbol_uid = ((Symbol *)p)->GetID();
213    if (match_uid < symbol_uid)
214        return -1;
215    if (match_uid > symbol_uid)
216        return 1;
217    return 0;
218}
219
220Symbol *
221Symtab::FindSymbolByID (lldb::user_id_t symbol_uid) const
222{
223    Mutex::Locker locker (m_mutex);
224
225    Symbol *symbol = (Symbol*)::bsearch (&symbol_uid,
226                                         &m_symbols[0],
227                                         m_symbols.size(),
228                                         (uint8_t *)&m_symbols[1] - (uint8_t *)&m_symbols[0],
229                                         CompareSymbolID);
230    return symbol;
231}
232
233
234Symbol *
235Symtab::SymbolAtIndex(size_t idx)
236{
237    // Clients should grab the mutex from this symbol table and lock it manually
238    // when calling this function to avoid performance issues.
239    if (idx < m_symbols.size())
240        return &m_symbols[idx];
241    return NULL;
242}
243
244
245const Symbol *
246Symtab::SymbolAtIndex(size_t idx) const
247{
248    // Clients should grab the mutex from this symbol table and lock it manually
249    // when calling this function to avoid performance issues.
250    if (idx < m_symbols.size())
251        return &m_symbols[idx];
252    return NULL;
253}
254
255//----------------------------------------------------------------------
256// InitNameIndexes
257//----------------------------------------------------------------------
258void
259Symtab::InitNameIndexes()
260{
261    // Protected function, no need to lock mutex...
262    if (!m_name_indexes_computed)
263    {
264        m_name_indexes_computed = true;
265        Timer scoped_timer (__PRETTY_FUNCTION__, "%s", __PRETTY_FUNCTION__);
266        // Create the name index vector to be able to quickly search by name
267        const size_t num_symbols = m_symbols.size();
268#if 1
269        m_name_to_index.Reserve (num_symbols);
270#else
271        // TODO: benchmark this to see if we save any memory. Otherwise we
272        // will always keep the memory reserved in the vector unless we pull
273        // some STL swap magic and then recopy...
274        uint32_t actual_count = 0;
275        for (const_iterator pos = m_symbols.begin(), end = m_symbols.end();
276             pos != end;
277             ++pos)
278        {
279            const Mangled &mangled = pos->GetMangled();
280            if (mangled.GetMangledName())
281                ++actual_count;
282
283            if (mangled.GetDemangledName())
284                ++actual_count;
285        }
286
287        m_name_to_index.Reserve (actual_count);
288#endif
289
290        NameToIndexMap::Entry entry;
291
292        // The "const char *" in "class_contexts" must come from a ConstString::GetCString()
293        std::set<const char *> class_contexts;
294        UniqueCStringMap<uint32_t> mangled_name_to_index;
295        std::vector<const char *> symbol_contexts(num_symbols, NULL);
296
297        for (entry.value = 0; entry.value<num_symbols; ++entry.value)
298        {
299            const Symbol *symbol = &m_symbols[entry.value];
300
301            // Don't let trampolines get into the lookup by name map
302            // If we ever need the trampoline symbols to be searchable by name
303            // we can remove this and then possibly add a new bool to any of the
304            // Symtab functions that lookup symbols by name to indicate if they
305            // want trampolines.
306            if (symbol->IsTrampoline())
307                continue;
308
309            const Mangled &mangled = symbol->GetMangled();
310            entry.cstring = mangled.GetMangledName().GetCString();
311            if (entry.cstring && entry.cstring[0])
312            {
313                m_name_to_index.Append (entry);
314
315                const SymbolType symbol_type = symbol->GetType();
316                if (symbol_type == eSymbolTypeCode || symbol_type == eSymbolTypeResolver)
317                {
318                    if (entry.cstring[0] == '_' && entry.cstring[1] == 'Z' &&
319                        (entry.cstring[2] != 'T' && // avoid virtual table, VTT structure, typeinfo structure, and typeinfo name
320                         entry.cstring[2] != 'G' && // avoid guard variables
321                         entry.cstring[2] != 'Z'))  // named local entities (if we eventually handle eSymbolTypeData, we will want this back)
322                    {
323                        CPPLanguageRuntime::MethodName cxx_method (mangled.GetDemangledName());
324                        entry.cstring = cxx_method.GetBasename ().GetCString();
325                        if (entry.cstring && entry.cstring[0])
326                        {
327                            // ConstString objects permanently store the string in the pool so calling
328                            // GetCString() on the value gets us a const char * that will never go away
329                            const char *const_context = ConstString(cxx_method.GetContext()).GetCString();
330
331                            if (entry.cstring[0] == '~' || !cxx_method.GetQualifiers().empty())
332                            {
333                                // The first character of the demangled basename is '~' which
334                                // means we have a class destructor. We can use this information
335                                // to help us know what is a class and what isn't.
336                                if (class_contexts.find(const_context) == class_contexts.end())
337                                    class_contexts.insert(const_context);
338                                m_method_to_index.Append (entry);
339                            }
340                            else
341                            {
342                                if (const_context && const_context[0])
343                                {
344                                    if (class_contexts.find(const_context) != class_contexts.end())
345                                    {
346                                        // The current decl context is in our "class_contexts" which means
347                                        // this is a method on a class
348                                        m_method_to_index.Append (entry);
349                                    }
350                                    else
351                                    {
352                                        // We don't know if this is a function basename or a method,
353                                        // so put it into a temporary collection so once we are done
354                                        // we can look in class_contexts to see if each entry is a class
355                                        // or just a function and will put any remaining items into
356                                        // m_method_to_index or m_basename_to_index as needed
357                                        mangled_name_to_index.Append (entry);
358                                        symbol_contexts[entry.value] = const_context;
359                                    }
360                                }
361                                else
362                                {
363                                    // No context for this function so this has to be a basename
364                                    m_basename_to_index.Append(entry);
365                                }
366                            }
367                        }
368                    }
369                }
370            }
371
372            entry.cstring = mangled.GetDemangledName().GetCString();
373            if (entry.cstring && entry.cstring[0])
374                m_name_to_index.Append (entry);
375
376            // If the demangled name turns out to be an ObjC name, and
377            // is a category name, add the version without categories to the index too.
378            ObjCLanguageRuntime::MethodName objc_method (entry.cstring, true);
379            if (objc_method.IsValid(true))
380            {
381                entry.cstring = objc_method.GetSelector().GetCString();
382                m_selector_to_index.Append (entry);
383
384                ConstString objc_method_no_category (objc_method.GetFullNameWithoutCategory(true));
385                if (objc_method_no_category)
386                {
387                    entry.cstring = objc_method_no_category.GetCString();
388                    m_name_to_index.Append (entry);
389                }
390            }
391
392        }
393
394        size_t count;
395        if (!mangled_name_to_index.IsEmpty())
396        {
397            count = mangled_name_to_index.GetSize();
398            for (size_t i=0; i<count; ++i)
399            {
400                if (mangled_name_to_index.GetValueAtIndex(i, entry.value))
401                {
402                    entry.cstring = mangled_name_to_index.GetCStringAtIndex(i);
403                    if (symbol_contexts[entry.value] && class_contexts.find(symbol_contexts[entry.value]) != class_contexts.end())
404                    {
405                        m_method_to_index.Append (entry);
406                    }
407                    else
408                    {
409                        // If we got here, we have something that had a context (was inside a namespace or class)
410                        // yet we don't know if the entry
411                        m_method_to_index.Append (entry);
412                        m_basename_to_index.Append (entry);
413                    }
414                }
415            }
416        }
417        m_name_to_index.Sort();
418        m_name_to_index.SizeToFit();
419        m_selector_to_index.Sort();
420        m_selector_to_index.SizeToFit();
421        m_basename_to_index.Sort();
422        m_basename_to_index.SizeToFit();
423        m_method_to_index.Sort();
424        m_method_to_index.SizeToFit();
425
426//        static StreamFile a ("/tmp/a.txt");
427//
428//        count = m_basename_to_index.GetSize();
429//        if (count)
430//        {
431//            for (size_t i=0; i<count; ++i)
432//            {
433//                if (m_basename_to_index.GetValueAtIndex(i, entry.value))
434//                    a.Printf ("%s BASENAME\n", m_symbols[entry.value].GetMangled().GetName().GetCString());
435//            }
436//        }
437//        count = m_method_to_index.GetSize();
438//        if (count)
439//        {
440//            for (size_t i=0; i<count; ++i)
441//            {
442//                if (m_method_to_index.GetValueAtIndex(i, entry.value))
443//                    a.Printf ("%s METHOD\n", m_symbols[entry.value].GetMangled().GetName().GetCString());
444//            }
445//        }
446    }
447}
448
449void
450Symtab::AppendSymbolNamesToMap (const IndexCollection &indexes,
451                                bool add_demangled,
452                                bool add_mangled,
453                                NameToIndexMap &name_to_index_map) const
454{
455    if (add_demangled || add_mangled)
456    {
457        Timer scoped_timer (__PRETTY_FUNCTION__, "%s", __PRETTY_FUNCTION__);
458        Mutex::Locker locker (m_mutex);
459
460        // Create the name index vector to be able to quickly search by name
461        NameToIndexMap::Entry entry;
462        const size_t num_indexes = indexes.size();
463        for (size_t i=0; i<num_indexes; ++i)
464        {
465            entry.value = indexes[i];
466            assert (i < m_symbols.size());
467            const Symbol *symbol = &m_symbols[entry.value];
468
469            const Mangled &mangled = symbol->GetMangled();
470            if (add_demangled)
471            {
472                entry.cstring = mangled.GetDemangledName().GetCString();
473                if (entry.cstring && entry.cstring[0])
474                    name_to_index_map.Append (entry);
475            }
476
477            if (add_mangled)
478            {
479                entry.cstring = mangled.GetMangledName().GetCString();
480                if (entry.cstring && entry.cstring[0])
481                    name_to_index_map.Append (entry);
482            }
483        }
484    }
485}
486
487uint32_t
488Symtab::AppendSymbolIndexesWithType (SymbolType symbol_type, std::vector<uint32_t>& indexes, uint32_t start_idx, uint32_t end_index) const
489{
490    Mutex::Locker locker (m_mutex);
491
492    uint32_t prev_size = indexes.size();
493
494    const uint32_t count = std::min<uint32_t> (m_symbols.size(), end_index);
495
496    for (uint32_t i = start_idx; i < count; ++i)
497    {
498        if (symbol_type == eSymbolTypeAny || m_symbols[i].GetType() == symbol_type)
499            indexes.push_back(i);
500    }
501
502    return indexes.size() - prev_size;
503}
504
505uint32_t
506Symtab::AppendSymbolIndexesWithTypeAndFlagsValue (SymbolType symbol_type, uint32_t flags_value, std::vector<uint32_t>& indexes, uint32_t start_idx, uint32_t end_index) const
507{
508    Mutex::Locker locker (m_mutex);
509
510    uint32_t prev_size = indexes.size();
511
512    const uint32_t count = std::min<uint32_t> (m_symbols.size(), end_index);
513
514    for (uint32_t i = start_idx; i < count; ++i)
515    {
516        if ((symbol_type == eSymbolTypeAny || m_symbols[i].GetType() == symbol_type) && m_symbols[i].GetFlags() == flags_value)
517            indexes.push_back(i);
518    }
519
520    return indexes.size() - prev_size;
521}
522
523uint32_t
524Symtab::AppendSymbolIndexesWithType (SymbolType symbol_type, Debug symbol_debug_type, Visibility symbol_visibility, std::vector<uint32_t>& indexes, uint32_t start_idx, uint32_t end_index) const
525{
526    Mutex::Locker locker (m_mutex);
527
528    uint32_t prev_size = indexes.size();
529
530    const uint32_t count = std::min<uint32_t> (m_symbols.size(), end_index);
531
532    for (uint32_t i = start_idx; i < count; ++i)
533    {
534        if (symbol_type == eSymbolTypeAny || m_symbols[i].GetType() == symbol_type)
535        {
536            if (CheckSymbolAtIndex(i, symbol_debug_type, symbol_visibility))
537                indexes.push_back(i);
538        }
539    }
540
541    return indexes.size() - prev_size;
542}
543
544
545uint32_t
546Symtab::GetIndexForSymbol (const Symbol *symbol) const
547{
548    const Symbol *first_symbol = &m_symbols[0];
549    if (symbol >= first_symbol && symbol < first_symbol + m_symbols.size())
550        return symbol - first_symbol;
551    return UINT32_MAX;
552}
553
554struct SymbolSortInfo
555{
556    const bool sort_by_load_addr;
557    const Symbol *symbols;
558};
559
560namespace {
561    struct SymbolIndexComparator {
562        const std::vector<Symbol>& symbols;
563        std::vector<lldb::addr_t>  &addr_cache;
564
565        // Getting from the symbol to the Address to the File Address involves some work.
566        // Since there are potentially many symbols here, and we're using this for sorting so
567        // we're going to be computing the address many times, cache that in addr_cache.
568        // The array passed in has to be the same size as the symbols array passed into the
569        // member variable symbols, and should be initialized with LLDB_INVALID_ADDRESS.
570        // NOTE: You have to make addr_cache externally and pass it in because std::stable_sort
571        // makes copies of the comparator it is initially passed in, and you end up spending
572        // huge amounts of time copying this array...
573
574        SymbolIndexComparator(const std::vector<Symbol>& s, std::vector<lldb::addr_t> &a) : symbols(s), addr_cache(a)  {
575            assert (symbols.size() == addr_cache.size());
576        }
577        bool operator()(uint32_t index_a, uint32_t index_b) {
578            addr_t value_a = addr_cache[index_a];
579            if (value_a == LLDB_INVALID_ADDRESS)
580            {
581                value_a = symbols[index_a].GetAddress().GetFileAddress();
582                addr_cache[index_a] = value_a;
583            }
584
585            addr_t value_b = addr_cache[index_b];
586            if (value_b == LLDB_INVALID_ADDRESS)
587            {
588                value_b = symbols[index_b].GetAddress().GetFileAddress();
589                addr_cache[index_b] = value_b;
590            }
591
592
593            if (value_a == value_b) {
594                // The if the values are equal, use the original symbol user ID
595                lldb::user_id_t uid_a = symbols[index_a].GetID();
596                lldb::user_id_t uid_b = symbols[index_b].GetID();
597                if (uid_a < uid_b)
598                    return true;
599                if (uid_a > uid_b)
600                    return false;
601                return false;
602            } else if (value_a < value_b)
603                return true;
604
605            return false;
606        }
607    };
608}
609
610void
611Symtab::SortSymbolIndexesByValue (std::vector<uint32_t>& indexes, bool remove_duplicates) const
612{
613    Mutex::Locker locker (m_mutex);
614
615    Timer scoped_timer (__PRETTY_FUNCTION__,__PRETTY_FUNCTION__);
616    // No need to sort if we have zero or one items...
617    if (indexes.size() <= 1)
618        return;
619
620    // Sort the indexes in place using std::stable_sort.
621    // NOTE: The use of std::stable_sort instead of std::sort here is strictly for performance,
622    // not correctness.  The indexes vector tends to be "close" to sorted, which the
623    // stable sort handles better.
624
625    std::vector<lldb::addr_t> addr_cache(m_symbols.size(), LLDB_INVALID_ADDRESS);
626
627    SymbolIndexComparator comparator(m_symbols, addr_cache);
628    std::stable_sort(indexes.begin(), indexes.end(), comparator);
629
630    // Remove any duplicates if requested
631    if (remove_duplicates)
632        std::unique(indexes.begin(), indexes.end());
633}
634
635uint32_t
636Symtab::AppendSymbolIndexesWithName (const ConstString& symbol_name, std::vector<uint32_t>& indexes)
637{
638    Mutex::Locker locker (m_mutex);
639
640    Timer scoped_timer (__PRETTY_FUNCTION__, "%s", __PRETTY_FUNCTION__);
641    if (symbol_name)
642    {
643        const char *symbol_cstr = symbol_name.GetCString();
644        if (!m_name_indexes_computed)
645            InitNameIndexes();
646
647        return m_name_to_index.GetValues (symbol_cstr, indexes);
648    }
649    return 0;
650}
651
652uint32_t
653Symtab::AppendSymbolIndexesWithName (const ConstString& symbol_name, Debug symbol_debug_type, Visibility symbol_visibility, std::vector<uint32_t>& indexes)
654{
655    Mutex::Locker locker (m_mutex);
656
657    Timer scoped_timer (__PRETTY_FUNCTION__, "%s", __PRETTY_FUNCTION__);
658    if (symbol_name)
659    {
660        const size_t old_size = indexes.size();
661        if (!m_name_indexes_computed)
662            InitNameIndexes();
663
664        const char *symbol_cstr = symbol_name.GetCString();
665
666        std::vector<uint32_t> all_name_indexes;
667        const size_t name_match_count = m_name_to_index.GetValues (symbol_cstr, all_name_indexes);
668        for (size_t i=0; i<name_match_count; ++i)
669        {
670            if (CheckSymbolAtIndex(all_name_indexes[i], symbol_debug_type, symbol_visibility))
671                indexes.push_back (all_name_indexes[i]);
672        }
673        return indexes.size() - old_size;
674    }
675    return 0;
676}
677
678uint32_t
679Symtab::AppendSymbolIndexesWithNameAndType (const ConstString& symbol_name, SymbolType symbol_type, std::vector<uint32_t>& indexes)
680{
681    Mutex::Locker locker (m_mutex);
682
683    if (AppendSymbolIndexesWithName(symbol_name, indexes) > 0)
684    {
685        std::vector<uint32_t>::iterator pos = indexes.begin();
686        while (pos != indexes.end())
687        {
688            if (symbol_type == eSymbolTypeAny || m_symbols[*pos].GetType() == symbol_type)
689                ++pos;
690            else
691                indexes.erase(pos);
692        }
693    }
694    return indexes.size();
695}
696
697uint32_t
698Symtab::AppendSymbolIndexesWithNameAndType (const ConstString& symbol_name, SymbolType symbol_type, Debug symbol_debug_type, Visibility symbol_visibility, std::vector<uint32_t>& indexes)
699{
700    Mutex::Locker locker (m_mutex);
701
702    if (AppendSymbolIndexesWithName(symbol_name, symbol_debug_type, symbol_visibility, indexes) > 0)
703    {
704        std::vector<uint32_t>::iterator pos = indexes.begin();
705        while (pos != indexes.end())
706        {
707            if (symbol_type == eSymbolTypeAny || m_symbols[*pos].GetType() == symbol_type)
708                ++pos;
709            else
710                indexes.erase(pos);
711        }
712    }
713    return indexes.size();
714}
715
716
717uint32_t
718Symtab::AppendSymbolIndexesMatchingRegExAndType (const RegularExpression &regexp, SymbolType symbol_type, std::vector<uint32_t>& indexes)
719{
720    Mutex::Locker locker (m_mutex);
721
722    uint32_t prev_size = indexes.size();
723    uint32_t sym_end = m_symbols.size();
724
725    for (int i = 0; i < sym_end; i++)
726    {
727        if (symbol_type == eSymbolTypeAny || m_symbols[i].GetType() == symbol_type)
728        {
729            const char *name = m_symbols[i].GetMangled().GetName().AsCString();
730            if (name)
731            {
732                if (regexp.Execute (name))
733                    indexes.push_back(i);
734            }
735        }
736    }
737    return indexes.size() - prev_size;
738
739}
740
741uint32_t
742Symtab::AppendSymbolIndexesMatchingRegExAndType (const RegularExpression &regexp, SymbolType symbol_type, Debug symbol_debug_type, Visibility symbol_visibility, std::vector<uint32_t>& indexes)
743{
744    Mutex::Locker locker (m_mutex);
745
746    uint32_t prev_size = indexes.size();
747    uint32_t sym_end = m_symbols.size();
748
749    for (int i = 0; i < sym_end; i++)
750    {
751        if (symbol_type == eSymbolTypeAny || m_symbols[i].GetType() == symbol_type)
752        {
753            if (CheckSymbolAtIndex(i, symbol_debug_type, symbol_visibility) == false)
754                continue;
755
756            const char *name = m_symbols[i].GetMangled().GetName().AsCString();
757            if (name)
758            {
759                if (regexp.Execute (name))
760                    indexes.push_back(i);
761            }
762        }
763    }
764    return indexes.size() - prev_size;
765
766}
767
768Symbol *
769Symtab::FindSymbolWithType (SymbolType symbol_type, Debug symbol_debug_type, Visibility symbol_visibility, uint32_t& start_idx)
770{
771    Mutex::Locker locker (m_mutex);
772
773    const size_t count = m_symbols.size();
774    for (size_t idx = start_idx; idx < count; ++idx)
775    {
776        if (symbol_type == eSymbolTypeAny || m_symbols[idx].GetType() == symbol_type)
777        {
778            if (CheckSymbolAtIndex(idx, symbol_debug_type, symbol_visibility))
779            {
780                start_idx = idx;
781                return &m_symbols[idx];
782            }
783        }
784    }
785    return NULL;
786}
787
788size_t
789Symtab::FindAllSymbolsWithNameAndType (const ConstString &name, SymbolType symbol_type, std::vector<uint32_t>& symbol_indexes)
790{
791    Mutex::Locker locker (m_mutex);
792
793    Timer scoped_timer (__PRETTY_FUNCTION__, "%s", __PRETTY_FUNCTION__);
794    // Initialize all of the lookup by name indexes before converting NAME
795    // to a uniqued string NAME_STR below.
796    if (!m_name_indexes_computed)
797        InitNameIndexes();
798
799    if (name)
800    {
801        // The string table did have a string that matched, but we need
802        // to check the symbols and match the symbol_type if any was given.
803        AppendSymbolIndexesWithNameAndType (name, symbol_type, symbol_indexes);
804    }
805    return symbol_indexes.size();
806}
807
808size_t
809Symtab::FindAllSymbolsWithNameAndType (const ConstString &name, SymbolType symbol_type, Debug symbol_debug_type, Visibility symbol_visibility, std::vector<uint32_t>& symbol_indexes)
810{
811    Mutex::Locker locker (m_mutex);
812
813    Timer scoped_timer (__PRETTY_FUNCTION__, "%s", __PRETTY_FUNCTION__);
814    // Initialize all of the lookup by name indexes before converting NAME
815    // to a uniqued string NAME_STR below.
816    if (!m_name_indexes_computed)
817        InitNameIndexes();
818
819    if (name)
820    {
821        // The string table did have a string that matched, but we need
822        // to check the symbols and match the symbol_type if any was given.
823        AppendSymbolIndexesWithNameAndType (name, symbol_type, symbol_debug_type, symbol_visibility, symbol_indexes);
824    }
825    return symbol_indexes.size();
826}
827
828size_t
829Symtab::FindAllSymbolsMatchingRexExAndType (const RegularExpression &regex, SymbolType symbol_type, Debug symbol_debug_type, Visibility symbol_visibility, std::vector<uint32_t>& symbol_indexes)
830{
831    Mutex::Locker locker (m_mutex);
832
833    AppendSymbolIndexesMatchingRegExAndType(regex, symbol_type, symbol_debug_type, symbol_visibility, symbol_indexes);
834    return symbol_indexes.size();
835}
836
837Symbol *
838Symtab::FindFirstSymbolWithNameAndType (const ConstString &name, SymbolType symbol_type, Debug symbol_debug_type, Visibility symbol_visibility)
839{
840    Mutex::Locker locker (m_mutex);
841
842    Timer scoped_timer (__PRETTY_FUNCTION__, "%s", __PRETTY_FUNCTION__);
843    if (!m_name_indexes_computed)
844        InitNameIndexes();
845
846    if (name)
847    {
848        std::vector<uint32_t> matching_indexes;
849        // The string table did have a string that matched, but we need
850        // to check the symbols and match the symbol_type if any was given.
851        if (AppendSymbolIndexesWithNameAndType (name, symbol_type, symbol_debug_type, symbol_visibility, matching_indexes))
852        {
853            std::vector<uint32_t>::const_iterator pos, end = matching_indexes.end();
854            for (pos = matching_indexes.begin(); pos != end; ++pos)
855            {
856                Symbol *symbol = SymbolAtIndex(*pos);
857
858                if (symbol->Compare(name, symbol_type))
859                    return symbol;
860            }
861        }
862    }
863    return NULL;
864}
865
866typedef struct
867{
868    const Symtab *symtab;
869    const addr_t file_addr;
870    Symbol *match_symbol;
871    const uint32_t *match_index_ptr;
872    addr_t match_offset;
873} SymbolSearchInfo;
874
875static int
876SymbolWithFileAddress (SymbolSearchInfo *info, const uint32_t *index_ptr)
877{
878    const Symbol *curr_symbol = info->symtab->SymbolAtIndex (index_ptr[0]);
879    if (curr_symbol == NULL)
880        return -1;
881
882    const addr_t info_file_addr = info->file_addr;
883
884    // lldb::Symbol::GetAddressRangePtr() will only return a non NULL address
885    // range if the symbol has a section!
886    if (curr_symbol->ValueIsAddress())
887    {
888        const addr_t curr_file_addr = curr_symbol->GetAddress().GetFileAddress();
889        if (info_file_addr < curr_file_addr)
890            return -1;
891        if (info_file_addr > curr_file_addr)
892            return +1;
893        info->match_symbol = const_cast<Symbol *>(curr_symbol);
894        info->match_index_ptr = index_ptr;
895        return 0;
896    }
897
898    return -1;
899}
900
901static int
902SymbolWithClosestFileAddress (SymbolSearchInfo *info, const uint32_t *index_ptr)
903{
904    const Symbol *symbol = info->symtab->SymbolAtIndex (index_ptr[0]);
905    if (symbol == NULL)
906        return -1;
907
908    const addr_t info_file_addr = info->file_addr;
909    if (symbol->ValueIsAddress())
910    {
911        const addr_t curr_file_addr = symbol->GetAddress().GetFileAddress();
912        if (info_file_addr < curr_file_addr)
913            return -1;
914
915        // Since we are finding the closest symbol that is greater than or equal
916        // to 'info->file_addr' we set the symbol here. This will get set
917        // multiple times, but after the search is done it will contain the best
918        // symbol match
919        info->match_symbol = const_cast<Symbol *>(symbol);
920        info->match_index_ptr = index_ptr;
921        info->match_offset = info_file_addr - curr_file_addr;
922
923        if (info_file_addr > curr_file_addr)
924            return +1;
925        return 0;
926    }
927    return -1;
928}
929
930static SymbolSearchInfo
931FindIndexPtrForSymbolContainingAddress(Symtab* symtab, addr_t file_addr, const uint32_t* indexes, uint32_t num_indexes)
932{
933    SymbolSearchInfo info = { symtab, file_addr, NULL, NULL, 0 };
934    ::bsearch (&info,
935               indexes,
936               num_indexes,
937               sizeof(uint32_t),
938               (ComparisonFunction)SymbolWithClosestFileAddress);
939    return info;
940}
941
942
943void
944Symtab::InitAddressIndexes()
945{
946    // Protected function, no need to lock mutex...
947    if (!m_addr_indexes_computed && !m_symbols.empty())
948    {
949        m_addr_indexes_computed = true;
950
951        const_iterator begin = m_symbols.begin();
952        const_iterator end = m_symbols.end();
953        for (const_iterator pos = m_symbols.begin(); pos != end; ++pos)
954        {
955            if (pos->ValueIsAddress())
956                m_addr_indexes.push_back (std::distance(begin, pos));
957        }
958
959        SortSymbolIndexesByValue (m_addr_indexes, false);
960        m_addr_indexes.push_back (UINT32_MAX);   // Terminator for bsearch since we might need to look at the next symbol
961    }
962}
963
964size_t
965Symtab::CalculateSymbolSize (Symbol *symbol)
966{
967    Mutex::Locker locker (m_mutex);
968
969    if (m_symbols.empty())
970        return 0;
971
972    // Make sure this symbol is from this symbol table...
973    if (symbol < &m_symbols.front() || symbol > &m_symbols.back())
974        return 0;
975
976    // See if this symbol already has a byte size?
977    size_t byte_size = symbol->GetByteSize();
978
979    if (byte_size)
980    {
981        // It does, just return it
982        return byte_size;
983    }
984
985    // Else if this is an address based symbol, figure out the delta between
986    // it and the next address based symbol
987    if (symbol->ValueIsAddress())
988    {
989        if (!m_addr_indexes_computed)
990            InitAddressIndexes();
991        const size_t num_addr_indexes = m_addr_indexes.size();
992        const lldb::addr_t symbol_file_addr = symbol->GetAddress().GetFileAddress();
993        SymbolSearchInfo info = FindIndexPtrForSymbolContainingAddress (this,
994                                                                        symbol_file_addr,
995                                                                        &m_addr_indexes.front(),
996                                                                        num_addr_indexes);
997        if (info.match_index_ptr != NULL)
998        {
999            // We can figure out the address range of all symbols except the
1000            // last one by taking the delta between the current symbol and
1001            // the next symbol
1002
1003            for (uint32_t addr_index = info.match_index_ptr - &m_addr_indexes.front() + 1;
1004                 addr_index < num_addr_indexes;
1005                 ++addr_index)
1006            {
1007                Symbol *next_symbol = SymbolAtIndex(m_addr_indexes[addr_index]);
1008                if (next_symbol == NULL)
1009                {
1010                    // No next symbol take the size to be the remaining bytes in the section
1011                    // in which the symbol resides
1012                    SectionSP section_sp (m_objfile->GetSectionList()->FindSectionContainingFileAddress (symbol_file_addr));
1013                    if (section_sp)
1014                    {
1015                        const lldb::addr_t end_section_file_addr = section_sp->GetFileAddress() + section_sp->GetByteSize();
1016                        if (end_section_file_addr > symbol_file_addr)
1017                        {
1018                            byte_size = end_section_file_addr - symbol_file_addr;
1019                            symbol->SetByteSize(byte_size);
1020                            symbol->SetSizeIsSynthesized(true);
1021                            break;
1022                        }
1023                    }
1024                }
1025                else
1026                {
1027                    const lldb::addr_t next_file_addr = next_symbol->GetAddress().GetFileAddress();
1028                    if (next_file_addr > symbol_file_addr)
1029                    {
1030                        byte_size = next_file_addr - symbol_file_addr;
1031                        symbol->SetByteSize(byte_size);
1032                        symbol->SetSizeIsSynthesized(true);
1033                        break;
1034                    }
1035                }
1036            }
1037        }
1038    }
1039    return byte_size;
1040}
1041
1042Symbol *
1043Symtab::FindSymbolContainingFileAddress (addr_t file_addr, const uint32_t* indexes, uint32_t num_indexes)
1044{
1045    Mutex::Locker locker (m_mutex);
1046
1047    SymbolSearchInfo info = { this, file_addr, NULL, NULL, 0 };
1048
1049    ::bsearch (&info,
1050               indexes,
1051               num_indexes,
1052               sizeof(uint32_t),
1053               (ComparisonFunction)SymbolWithClosestFileAddress);
1054
1055    if (info.match_symbol)
1056    {
1057        if (info.match_offset == 0)
1058        {
1059            // We found an exact match!
1060            return info.match_symbol;
1061        }
1062
1063        const size_t symbol_byte_size = info.match_symbol->GetByteSize();
1064
1065        if (symbol_byte_size == 0)
1066        {
1067            // We weren't able to find the size of the symbol so lets just go
1068            // with that match we found in our search...
1069            return info.match_symbol;
1070        }
1071
1072        // We were able to figure out a symbol size so lets make sure our
1073        // offset puts "file_addr" in the symbol's address range.
1074        if (info.match_offset < symbol_byte_size)
1075            return info.match_symbol;
1076    }
1077    return NULL;
1078}
1079
1080Symbol *
1081Symtab::FindSymbolContainingFileAddress (addr_t file_addr)
1082{
1083    Mutex::Locker locker (m_mutex);
1084
1085    if (!m_addr_indexes_computed)
1086        InitAddressIndexes();
1087
1088    return FindSymbolContainingFileAddress (file_addr, &m_addr_indexes[0], m_addr_indexes.size());
1089}
1090
1091void
1092Symtab::SymbolIndicesToSymbolContextList (std::vector<uint32_t> &symbol_indexes, SymbolContextList &sc_list)
1093{
1094    // No need to protect this call using m_mutex all other method calls are
1095    // already thread safe.
1096
1097    const bool merge_symbol_into_function = true;
1098    size_t num_indices = symbol_indexes.size();
1099    if (num_indices > 0)
1100    {
1101        SymbolContext sc;
1102        sc.module_sp = m_objfile->GetModule();
1103        for (size_t i = 0; i < num_indices; i++)
1104        {
1105            sc.symbol = SymbolAtIndex (symbol_indexes[i]);
1106            if (sc.symbol)
1107                sc_list.AppendIfUnique(sc, merge_symbol_into_function);
1108        }
1109    }
1110}
1111
1112
1113size_t
1114Symtab::FindFunctionSymbols (const ConstString &name,
1115                             uint32_t name_type_mask,
1116                             SymbolContextList& sc_list)
1117{
1118    size_t count = 0;
1119    std::vector<uint32_t> symbol_indexes;
1120
1121    const char *name_cstr = name.GetCString();
1122
1123    // eFunctionNameTypeAuto should be pre-resolved by a call to Module::PrepareForFunctionNameLookup()
1124    assert ((name_type_mask & eFunctionNameTypeAuto) == 0);
1125
1126    if (name_type_mask & (eFunctionNameTypeBase | eFunctionNameTypeFull))
1127    {
1128        FindAllSymbolsWithNameAndType (name, eSymbolTypeCode, symbol_indexes);
1129    }
1130
1131    if (name_type_mask & eFunctionNameTypeBase)
1132    {
1133        // From mangled names we can't tell what is a basename and what
1134        // is a method name, so we just treat them the same
1135        if (!m_name_indexes_computed)
1136            InitNameIndexes();
1137
1138        if (!m_basename_to_index.IsEmpty())
1139        {
1140            const UniqueCStringMap<uint32_t>::Entry *match;
1141            for (match = m_basename_to_index.FindFirstValueForName(name_cstr);
1142                 match != NULL;
1143                 match = m_basename_to_index.FindNextValueForName(match))
1144            {
1145                symbol_indexes.push_back(match->value);
1146            }
1147        }
1148    }
1149
1150    if (name_type_mask & eFunctionNameTypeMethod)
1151    {
1152        if (!m_name_indexes_computed)
1153            InitNameIndexes();
1154
1155        if (!m_method_to_index.IsEmpty())
1156        {
1157            const UniqueCStringMap<uint32_t>::Entry *match;
1158            for (match = m_method_to_index.FindFirstValueForName(name_cstr);
1159                 match != NULL;
1160                 match = m_method_to_index.FindNextValueForName(match))
1161            {
1162                symbol_indexes.push_back(match->value);
1163            }
1164        }
1165    }
1166
1167    if (name_type_mask & eFunctionNameTypeSelector)
1168    {
1169        if (!m_name_indexes_computed)
1170            InitNameIndexes();
1171
1172        if (!m_selector_to_index.IsEmpty())
1173        {
1174            const UniqueCStringMap<uint32_t>::Entry *match;
1175            for (match = m_selector_to_index.FindFirstValueForName(name_cstr);
1176                 match != NULL;
1177                 match = m_selector_to_index.FindNextValueForName(match))
1178            {
1179                symbol_indexes.push_back(match->value);
1180            }
1181        }
1182    }
1183
1184    if (!symbol_indexes.empty())
1185    {
1186        std::sort(symbol_indexes.begin(), symbol_indexes.end());
1187        symbol_indexes.erase(std::unique(symbol_indexes.begin(), symbol_indexes.end()), symbol_indexes.end());
1188        count = symbol_indexes.size();
1189        SymbolIndicesToSymbolContextList (symbol_indexes, sc_list);
1190    }
1191
1192    return count;
1193}
1194
1195