Symtab.cpp revision 8d3802d9d6c1be4c0d37c4d269b18bcb865823e6
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/Timer.h"
15#include "lldb/Symbol/ObjectFile.h"
16#include "lldb/Symbol/Symtab.h"
17
18using namespace lldb;
19using namespace lldb_private;
20
21
22
23Symtab::Symtab(ObjectFile *objfile) :
24    m_objfile (objfile),
25    m_symbols (),
26    m_addr_indexes (),
27    m_name_to_index (),
28    m_mutex (Mutex::eMutexTypeRecursive),
29    m_addr_indexes_computed (false),
30    m_name_indexes_computed (false)
31{
32}
33
34Symtab::~Symtab()
35{
36}
37
38void
39Symtab::Reserve(uint32_t count)
40{
41    // Clients should grab the mutex from this symbol table and lock it manually
42    // when calling this function to avoid performance issues.
43    m_symbols.reserve (count);
44}
45
46Symbol *
47Symtab::Resize(uint32_t count)
48{
49    // Clients should grab the mutex from this symbol table and lock it manually
50    // when calling this function to avoid performance issues.
51    m_symbols.resize (count);
52    return &m_symbols[0];
53}
54
55uint32_t
56Symtab::AddSymbol(const Symbol& symbol)
57{
58    // Clients should grab the mutex from this symbol table and lock it manually
59    // when calling this function to avoid performance issues.
60    uint32_t symbol_idx = m_symbols.size();
61    m_name_to_index.Clear();
62    m_addr_indexes.clear();
63    m_symbols.push_back(symbol);
64    m_addr_indexes_computed = false;
65    m_name_indexes_computed = false;
66    return symbol_idx;
67}
68
69size_t
70Symtab::GetNumSymbols() const
71{
72    Mutex::Locker locker (m_mutex);
73    return m_symbols.size();
74}
75
76void
77Symtab::Dump (Stream *s, Target *target, lldb::SortOrder sort_order)
78{
79    Mutex::Locker locker (m_mutex);
80
81//    s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
82    s->Indent();
83    const FileSpec &file_spec = m_objfile->GetFileSpec();
84    const char * object_name = NULL;
85    if (m_objfile->GetModule())
86        object_name = m_objfile->GetModule()->GetObjectName().GetCString();
87
88    if (file_spec)
89        s->Printf("Symtab, file = %s/%s%s%s%s, num_symbols = %u",
90        file_spec.GetDirectory().AsCString(),
91        file_spec.GetFilename().AsCString(),
92        object_name ? "(" : "",
93        object_name ? object_name : "",
94        object_name ? ")" : "",
95        m_symbols.size());
96    else
97        s->Printf("Symtab, num_symbols = %u", m_symbols.size());
98
99    if (!m_symbols.empty())
100    {
101        switch (sort_order)
102        {
103        case eSortOrderNone:
104            {
105                s->PutCString (":\n");
106                DumpSymbolHeader (s);
107                const_iterator begin = m_symbols.begin();
108                const_iterator end = m_symbols.end();
109                for (const_iterator pos = m_symbols.begin(); pos != end; ++pos)
110                {
111                    s->Indent();
112                    pos->Dump(s, target, std::distance(begin, pos));
113                }
114            }
115            break;
116
117        case eSortOrderByName:
118            {
119                // Although we maintain a lookup by exact name map, the table
120                // isn't sorted by name. So we must make the ordered symbol list
121                // up ourselves.
122                s->PutCString (" (sorted by name):\n");
123                DumpSymbolHeader (s);
124                typedef std::multimap<const char*, const Symbol *, CStringCompareFunctionObject> CStringToSymbol;
125                CStringToSymbol name_map;
126                for (const_iterator pos = m_symbols.begin(), end = m_symbols.end(); pos != end; ++pos)
127                {
128                    const char *name = pos->GetMangled().GetName(Mangled::ePreferDemangled).AsCString();
129                    if (name && name[0])
130                        name_map.insert (std::make_pair(name, &(*pos)));
131                }
132
133                for (CStringToSymbol::const_iterator pos = name_map.begin(), end = name_map.end(); pos != end; ++pos)
134                {
135                    s->Indent();
136                    pos->second->Dump (s, target, pos->second - &m_symbols[0]);
137                }
138            }
139            break;
140
141        case eSortOrderByAddress:
142            s->PutCString (" (sorted by address):\n");
143            DumpSymbolHeader (s);
144            if (!m_addr_indexes_computed)
145                InitAddressIndexes();
146            const size_t num_symbols = GetNumSymbols();
147            std::vector<uint32_t>::const_iterator pos;
148            std::vector<uint32_t>::const_iterator end = m_addr_indexes.end();
149            for (pos = m_addr_indexes.begin(); pos != end; ++pos)
150            {
151                uint32_t idx = *pos;
152                if (idx < num_symbols)
153                {
154                    s->Indent();
155                    m_symbols[idx].Dump(s, target, idx);
156                }
157            }
158            break;
159        }
160    }
161}
162
163void
164Symtab::Dump(Stream *s, Target *target, std::vector<uint32_t>& indexes) const
165{
166    Mutex::Locker locker (m_mutex);
167
168    const size_t num_symbols = GetNumSymbols();
169    //s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
170    s->Indent();
171    s->Printf("Symtab %u symbol indexes (%u symbols total):\n", indexes.size(), m_symbols.size());
172    s->IndentMore();
173
174    if (!indexes.empty())
175    {
176        std::vector<uint32_t>::const_iterator pos;
177        std::vector<uint32_t>::const_iterator end = indexes.end();
178        DumpSymbolHeader (s);
179        for (pos = indexes.begin(); pos != end; ++pos)
180        {
181            uint32_t idx = *pos;
182            if (idx < num_symbols)
183            {
184                s->Indent();
185                m_symbols[idx].Dump(s, target, idx);
186            }
187        }
188    }
189    s->IndentLess ();
190}
191
192void
193Symtab::DumpSymbolHeader (Stream *s)
194{
195    s->Indent("               Debug symbol\n");
196    s->Indent("               |Synthetic symbol\n");
197    s->Indent("               ||Externally Visible\n");
198    s->Indent("               |||\n");
199    s->Indent("Index   UserID DSX Type         File Address/Value Load Address       Size               Flags      Name\n");
200    s->Indent("------- ------ --- ------------ ------------------ ------------------ ------------------ ---------- ----------------------------------\n");
201}
202
203
204static int
205CompareSymbolID (const void *key, const void *p)
206{
207    const user_id_t match_uid = *(user_id_t*) key;
208    const user_id_t symbol_uid = ((Symbol *)p)->GetID();
209    if (match_uid < symbol_uid)
210        return -1;
211    if (match_uid > symbol_uid)
212        return 1;
213    return 0;
214}
215
216Symbol *
217Symtab::FindSymbolByID (lldb::user_id_t symbol_uid) const
218{
219    Mutex::Locker locker (m_mutex);
220
221    Symbol *symbol = (Symbol*)::bsearch (&symbol_uid,
222                                         &m_symbols[0],
223                                         m_symbols.size(),
224                                         (uint8_t *)&m_symbols[1] - (uint8_t *)&m_symbols[0],
225                                         CompareSymbolID);
226    return symbol;
227}
228
229
230Symbol *
231Symtab::SymbolAtIndex(uint32_t idx)
232{
233    // Clients should grab the mutex from this symbol table and lock it manually
234    // when calling this function to avoid performance issues.
235    if (idx < m_symbols.size())
236        return &m_symbols[idx];
237    return NULL;
238}
239
240
241const Symbol *
242Symtab::SymbolAtIndex(uint32_t idx) const
243{
244    // Clients should grab the mutex from this symbol table and lock it manually
245    // when calling this function to avoid performance issues.
246    if (idx < m_symbols.size())
247        return &m_symbols[idx];
248    return NULL;
249}
250
251//----------------------------------------------------------------------
252// InitNameIndexes
253//----------------------------------------------------------------------
254void
255Symtab::InitNameIndexes()
256{
257    // Protected function, no need to lock mutex...
258    if (!m_name_indexes_computed)
259    {
260        m_name_indexes_computed = true;
261        Timer scoped_timer (__PRETTY_FUNCTION__, "%s", __PRETTY_FUNCTION__);
262        // Create the name index vector to be able to quickly search by name
263        const size_t count = m_symbols.size();
264        assert(m_objfile != NULL);
265        assert(m_objfile->GetModule() != NULL);
266
267#if 1
268        m_name_to_index.Reserve (count);
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        UniqueCStringMap<uint32_t>::Entry entry;
290
291        for (entry.value = 0; entry.value < count; ++entry.value)
292        {
293            const Symbol *symbol = &m_symbols[entry.value];
294
295            // Don't let trampolines get into the lookup by name map
296            // If we ever need the trampoline symbols to be searchable by name
297            // we can remove this and then possibly add a new bool to any of the
298            // Symtab functions that lookup symbols by name to indicate if they
299            // want trampolines.
300            if (symbol->IsTrampoline())
301                continue;
302
303            const Mangled &mangled = symbol->GetMangled();
304            entry.cstring = mangled.GetMangledName().GetCString();
305            if (entry.cstring && entry.cstring[0])
306                m_name_to_index.Append (entry);
307
308            entry.cstring = mangled.GetDemangledName().GetCString();
309            if (entry.cstring && entry.cstring[0])
310                m_name_to_index.Append (entry);
311        }
312        m_name_to_index.Sort();
313    }
314}
315
316uint32_t
317Symtab::AppendSymbolIndexesWithType (SymbolType symbol_type, std::vector<uint32_t>& indexes, uint32_t start_idx, uint32_t end_index) const
318{
319    Mutex::Locker locker (m_mutex);
320
321    uint32_t prev_size = indexes.size();
322
323    const uint32_t count = std::min<uint32_t> (m_symbols.size(), end_index);
324
325    for (uint32_t i = start_idx; i < count; ++i)
326    {
327        if (symbol_type == eSymbolTypeAny || m_symbols[i].GetType() == symbol_type)
328            indexes.push_back(i);
329    }
330
331    return indexes.size() - prev_size;
332}
333
334uint32_t
335Symtab::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
336{
337    Mutex::Locker locker (m_mutex);
338
339    uint32_t prev_size = indexes.size();
340
341    const uint32_t count = std::min<uint32_t> (m_symbols.size(), end_index);
342
343    for (uint32_t i = start_idx; i < count; ++i)
344    {
345        if (symbol_type == eSymbolTypeAny || m_symbols[i].GetType() == symbol_type)
346        {
347            if (CheckSymbolAtIndex(i, symbol_debug_type, symbol_visibility))
348                indexes.push_back(i);
349        }
350    }
351
352    return indexes.size() - prev_size;
353}
354
355
356uint32_t
357Symtab::GetIndexForSymbol (const Symbol *symbol) const
358{
359    const Symbol *first_symbol = &m_symbols[0];
360    if (symbol >= first_symbol && symbol < first_symbol + m_symbols.size())
361        return symbol - first_symbol;
362    return UINT32_MAX;
363}
364
365struct SymbolSortInfo
366{
367    const bool sort_by_load_addr;
368    const Symbol *symbols;
369};
370
371namespace {
372    struct SymbolIndexComparator {
373        const std::vector<Symbol>& symbols;
374        SymbolIndexComparator(const std::vector<Symbol>& s) : symbols(s) { }
375        bool operator()(uint32_t index_a, uint32_t index_b) {
376            addr_t value_a;
377            addr_t value_b;
378            if (symbols[index_a].GetValue().GetSection() == symbols[index_b].GetValue().GetSection()) {
379                value_a = symbols[index_a].GetValue ().GetOffset();
380                value_b = symbols[index_b].GetValue ().GetOffset();
381            } else {
382                value_a = symbols[index_a].GetValue ().GetFileAddress();
383                value_b = symbols[index_b].GetValue ().GetFileAddress();
384            }
385
386            if (value_a == value_b) {
387                // The if the values are equal, use the original symbol user ID
388                lldb::user_id_t uid_a = symbols[index_a].GetID();
389                lldb::user_id_t uid_b = symbols[index_b].GetID();
390                if (uid_a < uid_b)
391                    return true;
392                if (uid_a > uid_b)
393                    return false;
394                return false;
395            } else if (value_a < value_b)
396                return true;
397
398            return false;
399        }
400    };
401}
402
403void
404Symtab::SortSymbolIndexesByValue (std::vector<uint32_t>& indexes, bool remove_duplicates) const
405{
406    Mutex::Locker locker (m_mutex);
407
408    Timer scoped_timer (__PRETTY_FUNCTION__,__PRETTY_FUNCTION__);
409    // No need to sort if we have zero or one items...
410    if (indexes.size() <= 1)
411        return;
412
413    // Sort the indexes in place using std::stable_sort.
414    // NOTE: The use of std::stable_sort instead of std::sort here is strictly for performance,
415    // not correctness.  The indexes vector tends to be "close" to sorted, which the
416    // stable sort handles better.
417    std::stable_sort(indexes.begin(), indexes.end(), SymbolIndexComparator(m_symbols));
418
419    // Remove any duplicates if requested
420    if (remove_duplicates)
421        std::unique(indexes.begin(), indexes.end());
422}
423
424uint32_t
425Symtab::AppendSymbolIndexesWithName (const ConstString& symbol_name, std::vector<uint32_t>& indexes)
426{
427    Mutex::Locker locker (m_mutex);
428
429    Timer scoped_timer (__PRETTY_FUNCTION__, "%s", __PRETTY_FUNCTION__);
430    if (symbol_name)
431    {
432        const size_t old_size = indexes.size();
433        if (!m_name_indexes_computed)
434            InitNameIndexes();
435
436        const char *symbol_cstr = symbol_name.GetCString();
437        const UniqueCStringMap<uint32_t>::Entry *entry_ptr;
438
439        for (entry_ptr = m_name_to_index.FindFirstValueForName (symbol_cstr);
440             entry_ptr!= NULL;
441             entry_ptr = m_name_to_index.FindNextValueForName (symbol_cstr, entry_ptr))
442        {
443            indexes.push_back (entry_ptr->value);
444        }
445        return indexes.size() - old_size;
446    }
447    return 0;
448}
449
450uint32_t
451Symtab::AppendSymbolIndexesWithName (const ConstString& symbol_name, Debug symbol_debug_type, Visibility symbol_visibility, std::vector<uint32_t>& indexes)
452{
453    Mutex::Locker locker (m_mutex);
454
455    Timer scoped_timer (__PRETTY_FUNCTION__, "%s", __PRETTY_FUNCTION__);
456    if (symbol_name)
457    {
458        const size_t old_size = indexes.size();
459        if (!m_name_indexes_computed)
460            InitNameIndexes();
461
462        const char *symbol_cstr = symbol_name.GetCString();
463        const UniqueCStringMap<uint32_t>::Entry *entry_ptr;
464        for (entry_ptr = m_name_to_index.FindFirstValueForName (symbol_cstr);
465             entry_ptr!= NULL;
466             entry_ptr = m_name_to_index.FindNextValueForName (symbol_cstr, entry_ptr))
467        {
468            if (CheckSymbolAtIndex(entry_ptr->value, symbol_debug_type, symbol_visibility))
469                indexes.push_back (entry_ptr->value);
470        }
471        return indexes.size() - old_size;
472    }
473    return 0;
474}
475
476uint32_t
477Symtab::AppendSymbolIndexesWithNameAndType (const ConstString& symbol_name, SymbolType symbol_type, std::vector<uint32_t>& indexes)
478{
479    Mutex::Locker locker (m_mutex);
480
481    if (AppendSymbolIndexesWithName(symbol_name, indexes) > 0)
482    {
483        std::vector<uint32_t>::iterator pos = indexes.begin();
484        while (pos != indexes.end())
485        {
486            if (symbol_type == eSymbolTypeAny || m_symbols[*pos].GetType() == symbol_type)
487                ++pos;
488            else
489                indexes.erase(pos);
490        }
491    }
492    return indexes.size();
493}
494
495uint32_t
496Symtab::AppendSymbolIndexesWithNameAndType (const ConstString& symbol_name, SymbolType symbol_type, Debug symbol_debug_type, Visibility symbol_visibility, std::vector<uint32_t>& indexes)
497{
498    Mutex::Locker locker (m_mutex);
499
500    if (AppendSymbolIndexesWithName(symbol_name, symbol_debug_type, symbol_visibility, indexes) > 0)
501    {
502        std::vector<uint32_t>::iterator pos = indexes.begin();
503        while (pos != indexes.end())
504        {
505            if (symbol_type == eSymbolTypeAny || m_symbols[*pos].GetType() == symbol_type)
506                ++pos;
507            else
508                indexes.erase(pos);
509        }
510    }
511    return indexes.size();
512}
513
514
515uint32_t
516Symtab::AppendSymbolIndexesMatchingRegExAndType (const RegularExpression &regexp, SymbolType symbol_type, std::vector<uint32_t>& indexes)
517{
518    Mutex::Locker locker (m_mutex);
519
520    uint32_t prev_size = indexes.size();
521    uint32_t sym_end = m_symbols.size();
522
523    for (int i = 0; i < sym_end; i++)
524    {
525        if (symbol_type == eSymbolTypeAny || m_symbols[i].GetType() == symbol_type)
526        {
527            const char *name = m_symbols[i].GetMangled().GetName().AsCString();
528            if (name)
529            {
530                if (regexp.Execute (name))
531                    indexes.push_back(i);
532            }
533        }
534    }
535    return indexes.size() - prev_size;
536
537}
538
539uint32_t
540Symtab::AppendSymbolIndexesMatchingRegExAndType (const RegularExpression &regexp, SymbolType symbol_type, Debug symbol_debug_type, Visibility symbol_visibility, std::vector<uint32_t>& indexes)
541{
542    Mutex::Locker locker (m_mutex);
543
544    uint32_t prev_size = indexes.size();
545    uint32_t sym_end = m_symbols.size();
546
547    for (int i = 0; i < sym_end; i++)
548    {
549        if (symbol_type == eSymbolTypeAny || m_symbols[i].GetType() == symbol_type)
550        {
551            if (CheckSymbolAtIndex(i, symbol_debug_type, symbol_visibility) == false)
552                continue;
553
554            const char *name = m_symbols[i].GetMangled().GetName().AsCString();
555            if (name)
556            {
557                if (regexp.Execute (name))
558                    indexes.push_back(i);
559            }
560        }
561    }
562    return indexes.size() - prev_size;
563
564}
565
566Symbol *
567Symtab::FindSymbolWithType (SymbolType symbol_type, Debug symbol_debug_type, Visibility symbol_visibility, uint32_t& start_idx)
568{
569    Mutex::Locker locker (m_mutex);
570
571    const size_t count = m_symbols.size();
572    for (uint32_t idx = start_idx; idx < count; ++idx)
573    {
574        if (symbol_type == eSymbolTypeAny || m_symbols[idx].GetType() == symbol_type)
575        {
576            if (CheckSymbolAtIndex(idx, symbol_debug_type, symbol_visibility))
577            {
578                start_idx = idx;
579                return &m_symbols[idx];
580            }
581        }
582    }
583    return NULL;
584}
585
586size_t
587Symtab::FindAllSymbolsWithNameAndType (const ConstString &name, SymbolType symbol_type, std::vector<uint32_t>& symbol_indexes)
588{
589    Mutex::Locker locker (m_mutex);
590
591    Timer scoped_timer (__PRETTY_FUNCTION__, "%s", __PRETTY_FUNCTION__);
592    // Initialize all of the lookup by name indexes before converting NAME
593    // to a uniqued string NAME_STR below.
594    if (!m_name_indexes_computed)
595        InitNameIndexes();
596
597    if (name)
598    {
599        // The string table did have a string that matched, but we need
600        // to check the symbols and match the symbol_type if any was given.
601        AppendSymbolIndexesWithNameAndType (name, symbol_type, symbol_indexes);
602    }
603    return symbol_indexes.size();
604}
605
606size_t
607Symtab::FindAllSymbolsWithNameAndType (const ConstString &name, SymbolType symbol_type, Debug symbol_debug_type, Visibility symbol_visibility, std::vector<uint32_t>& symbol_indexes)
608{
609    Mutex::Locker locker (m_mutex);
610
611    Timer scoped_timer (__PRETTY_FUNCTION__, "%s", __PRETTY_FUNCTION__);
612    // Initialize all of the lookup by name indexes before converting NAME
613    // to a uniqued string NAME_STR below.
614    if (!m_name_indexes_computed)
615        InitNameIndexes();
616
617    if (name)
618    {
619        // The string table did have a string that matched, but we need
620        // to check the symbols and match the symbol_type if any was given.
621        AppendSymbolIndexesWithNameAndType (name, symbol_type, symbol_debug_type, symbol_visibility, symbol_indexes);
622    }
623    return symbol_indexes.size();
624}
625
626size_t
627Symtab::FindAllSymbolsMatchingRexExAndType (const RegularExpression &regex, SymbolType symbol_type, Debug symbol_debug_type, Visibility symbol_visibility, std::vector<uint32_t>& symbol_indexes)
628{
629    Mutex::Locker locker (m_mutex);
630
631    AppendSymbolIndexesMatchingRegExAndType(regex, symbol_type, symbol_debug_type, symbol_visibility, symbol_indexes);
632    return symbol_indexes.size();
633}
634
635Symbol *
636Symtab::FindFirstSymbolWithNameAndType (const ConstString &name, SymbolType symbol_type, Debug symbol_debug_type, Visibility symbol_visibility)
637{
638    Mutex::Locker locker (m_mutex);
639
640    Timer scoped_timer (__PRETTY_FUNCTION__, "%s", __PRETTY_FUNCTION__);
641    if (!m_name_indexes_computed)
642        InitNameIndexes();
643
644    if (name)
645    {
646        std::vector<uint32_t> matching_indexes;
647        // The string table did have a string that matched, but we need
648        // to check the symbols and match the symbol_type if any was given.
649        if (AppendSymbolIndexesWithNameAndType (name, symbol_type, symbol_debug_type, symbol_visibility, matching_indexes))
650        {
651            std::vector<uint32_t>::const_iterator pos, end = matching_indexes.end();
652            for (pos = matching_indexes.begin(); pos != end; ++pos)
653            {
654                Symbol *symbol = SymbolAtIndex(*pos);
655
656                if (symbol->Compare(name, symbol_type))
657                    return symbol;
658            }
659        }
660    }
661    return NULL;
662}
663
664typedef struct
665{
666    const Symtab *symtab;
667    const addr_t file_addr;
668    Symbol *match_symbol;
669    const uint32_t *match_index_ptr;
670    addr_t match_offset;
671} SymbolSearchInfo;
672
673static int
674SymbolWithFileAddress (SymbolSearchInfo *info, const uint32_t *index_ptr)
675{
676    const Symbol *curr_symbol = info->symtab->SymbolAtIndex (index_ptr[0]);
677    if (curr_symbol == NULL)
678        return -1;
679
680    const addr_t info_file_addr = info->file_addr;
681
682    // lldb::Symbol::GetAddressRangePtr() will only return a non NULL address
683    // range if the symbol has a section!
684    const AddressRange *curr_range = curr_symbol->GetAddressRangePtr();
685    if (curr_range)
686    {
687        const addr_t curr_file_addr = curr_range->GetBaseAddress().GetFileAddress();
688        if (info_file_addr < curr_file_addr)
689            return -1;
690        if (info_file_addr > curr_file_addr)
691            return +1;
692        info->match_symbol = const_cast<Symbol *>(curr_symbol);
693        info->match_index_ptr = index_ptr;
694        return 0;
695    }
696
697    return -1;
698}
699
700static int
701SymbolWithClosestFileAddress (SymbolSearchInfo *info, const uint32_t *index_ptr)
702{
703    const Symbol *symbol = info->symtab->SymbolAtIndex (index_ptr[0]);
704    if (symbol == NULL)
705        return -1;
706
707    const addr_t info_file_addr = info->file_addr;
708    const AddressRange *curr_range = symbol->GetAddressRangePtr();
709    if (curr_range)
710    {
711        const addr_t curr_file_addr = curr_range->GetBaseAddress().GetFileAddress();
712        if (info_file_addr < curr_file_addr)
713            return -1;
714
715        // Since we are finding the closest symbol that is greater than or equal
716        // to 'info->file_addr' we set the symbol here. This will get set
717        // multiple times, but after the search is done it will contain the best
718        // symbol match
719        info->match_symbol = const_cast<Symbol *>(symbol);
720        info->match_index_ptr = index_ptr;
721        info->match_offset = info_file_addr - curr_file_addr;
722
723        if (info_file_addr > curr_file_addr)
724            return +1;
725        return 0;
726    }
727    return -1;
728}
729
730static SymbolSearchInfo
731FindIndexPtrForSymbolContainingAddress(Symtab* symtab, addr_t file_addr, const uint32_t* indexes, uint32_t num_indexes)
732{
733    SymbolSearchInfo info = { symtab, file_addr, NULL, NULL, 0 };
734    bsearch(&info, indexes, num_indexes, sizeof(uint32_t), (comparison_function)SymbolWithClosestFileAddress);
735    return info;
736}
737
738
739void
740Symtab::InitAddressIndexes()
741{
742    // Protected function, no need to lock mutex...
743    if (!m_addr_indexes_computed && !m_symbols.empty())
744    {
745        m_addr_indexes_computed = true;
746#if 0
747        // The old was to add only code, trampoline or data symbols...
748        AppendSymbolIndexesWithType (eSymbolTypeCode, m_addr_indexes);
749        AppendSymbolIndexesWithType (eSymbolTypeTrampoline, m_addr_indexes);
750        AppendSymbolIndexesWithType (eSymbolTypeData, m_addr_indexes);
751#else
752        // The new way adds all symbols with valid addresses that are section
753        // offset.
754        const_iterator begin = m_symbols.begin();
755        const_iterator end = m_symbols.end();
756        for (const_iterator pos = m_symbols.begin(); pos != end; ++pos)
757        {
758            if (pos->GetAddressRangePtr())
759                m_addr_indexes.push_back (std::distance(begin, pos));
760        }
761#endif
762        SortSymbolIndexesByValue (m_addr_indexes, false);
763        m_addr_indexes.push_back (UINT32_MAX);   // Terminator for bsearch since we might need to look at the next symbol
764    }
765}
766
767size_t
768Symtab::CalculateSymbolSize (Symbol *symbol)
769{
770    Mutex::Locker locker (m_mutex);
771
772    if (m_symbols.empty())
773        return 0;
774
775    // Make sure this symbol is from this symbol table...
776    if (symbol < &m_symbols.front() || symbol > &m_symbols.back())
777        return 0;
778
779    // See if this symbol already has a byte size?
780    size_t byte_size = symbol->GetByteSize();
781
782    if (byte_size)
783    {
784        // It does, just return it
785        return byte_size;
786    }
787
788    // Else if this is an address based symbol, figure out the delta between
789    // it and the next address based symbol
790    if (symbol->GetAddressRangePtr())
791    {
792        if (!m_addr_indexes_computed)
793            InitAddressIndexes();
794        const size_t num_addr_indexes = m_addr_indexes.size();
795        SymbolSearchInfo info = FindIndexPtrForSymbolContainingAddress(this, symbol->GetAddressRangePtr()->GetBaseAddress().GetFileAddress(), &m_addr_indexes.front(), num_addr_indexes);
796        if (info.match_index_ptr != NULL)
797        {
798            const lldb::addr_t curr_file_addr = symbol->GetAddressRangePtr()->GetBaseAddress().GetFileAddress();
799            // We can figure out the address range of all symbols except the
800            // last one by taking the delta between the current symbol and
801            // the next symbol
802
803            for (uint32_t addr_index = info.match_index_ptr - &m_addr_indexes.front() + 1;
804                 addr_index < num_addr_indexes;
805                 ++addr_index)
806            {
807                Symbol *next_symbol = SymbolAtIndex(m_addr_indexes[addr_index]);
808                if (next_symbol == NULL)
809                    break;
810
811                assert (next_symbol->GetAddressRangePtr());
812                const lldb::addr_t next_file_addr = next_symbol->GetAddressRangePtr()->GetBaseAddress().GetFileAddress();
813                if (next_file_addr > curr_file_addr)
814                {
815                    byte_size = next_file_addr - curr_file_addr;
816                    symbol->GetAddressRangePtr()->SetByteSize(byte_size);
817                    symbol->SetSizeIsSynthesized(true);
818                    break;
819                }
820            }
821        }
822    }
823    return byte_size;
824}
825
826Symbol *
827Symtab::FindSymbolWithFileAddress (addr_t file_addr)
828{
829    Mutex::Locker locker (m_mutex);
830
831    if (!m_addr_indexes_computed)
832        InitAddressIndexes();
833
834    SymbolSearchInfo info = { this, file_addr, NULL, NULL, 0 };
835
836    uint32_t* match = (uint32_t*)bsearch(&info, &m_addr_indexes[0], m_addr_indexes.size(), sizeof(uint32_t), (comparison_function)SymbolWithFileAddress);
837    if (match)
838        return SymbolAtIndex (*match);
839    return NULL;
840}
841
842
843Symbol *
844Symtab::FindSymbolContainingFileAddress (addr_t file_addr, const uint32_t* indexes, uint32_t num_indexes)
845{
846    Mutex::Locker locker (m_mutex);
847
848    SymbolSearchInfo info = { this, file_addr, NULL, NULL, 0 };
849
850    bsearch(&info, indexes, num_indexes, sizeof(uint32_t), (comparison_function)SymbolWithClosestFileAddress);
851
852    if (info.match_symbol)
853    {
854        if (info.match_offset == 0)
855        {
856            // We found an exact match!
857            return info.match_symbol;
858        }
859
860        const size_t symbol_byte_size = CalculateSymbolSize(info.match_symbol);
861
862        if (symbol_byte_size == 0)
863        {
864            // We weren't able to find the size of the symbol so lets just go
865            // with that match we found in our search...
866            return info.match_symbol;
867        }
868
869        // We were able to figure out a symbol size so lets make sure our
870        // offset puts "file_addr" in the symbol's address range.
871        if (info.match_offset < symbol_byte_size)
872            return info.match_symbol;
873    }
874    return NULL;
875}
876
877Symbol *
878Symtab::FindSymbolContainingFileAddress (addr_t file_addr)
879{
880    Mutex::Locker locker (m_mutex);
881
882    if (!m_addr_indexes_computed)
883        InitAddressIndexes();
884
885    return FindSymbolContainingFileAddress (file_addr, &m_addr_indexes[0], m_addr_indexes.size());
886}
887
888