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