1//===-- Block.cpp -----------------------------------------------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "lldb/Symbol/Block.h"
11
12#include "lldb/lldb-private-log.h"
13
14#include "lldb/Core/Log.h"
15#include "lldb/Core/Module.h"
16#include "lldb/Core/Section.h"
17#include "lldb/Symbol/Function.h"
18#include "lldb/Symbol/SymbolFile.h"
19#include "lldb/Symbol/SymbolVendor.h"
20#include "lldb/Symbol/VariableList.h"
21
22using namespace lldb;
23using namespace lldb_private;
24
25Block::Block(lldb::user_id_t uid) :
26    UserID(uid),
27    m_parent_scope (NULL),
28    m_children (),
29    m_ranges (),
30    m_inlineInfoSP (),
31    m_variable_list_sp (),
32    m_parsed_block_info (false),
33    m_parsed_block_variables (false),
34    m_parsed_child_blocks (false)
35{
36}
37
38Block::~Block ()
39{
40}
41
42void
43Block::GetDescription(Stream *s, Function *function, lldb::DescriptionLevel level, Target *target) const
44{
45    *s << "id = " << ((const UserID&)*this);
46
47    size_t num_ranges = m_ranges.GetSize();
48    if (num_ranges > 0)
49    {
50
51        addr_t base_addr = LLDB_INVALID_ADDRESS;
52        if (target)
53            base_addr = function->GetAddressRange().GetBaseAddress().GetLoadAddress(target);
54        if (base_addr == LLDB_INVALID_ADDRESS)
55            base_addr = function->GetAddressRange().GetBaseAddress().GetFileAddress();
56
57        s->Printf(", range%s = ", num_ranges > 1 ? "s" : "");
58        for (size_t i=0; i<num_ranges; ++i)
59        {
60            const Range &range = m_ranges.GetEntryRef(i);
61            s->AddressRange(base_addr + range.GetRangeBase(), base_addr + range.GetRangeEnd(), 4);
62        }
63    }
64
65    if (m_inlineInfoSP.get() != NULL)
66    {
67        bool show_fullpaths = (level == eDescriptionLevelVerbose);
68        m_inlineInfoSP->Dump(s, show_fullpaths);
69    }
70}
71
72void
73Block::Dump(Stream *s, addr_t base_addr, int32_t depth, bool show_context) const
74{
75    if (depth < 0)
76    {
77        Block *parent = GetParent();
78        if (parent)
79        {
80            // We have a depth that is less than zero, print our parent blocks
81            // first
82            parent->Dump(s, base_addr, depth + 1, show_context);
83        }
84    }
85
86    s->Printf("%p: ", this);
87    s->Indent();
88    *s << "Block" << ((const UserID&)*this);
89    const Block* parent_block = GetParent();
90    if (parent_block)
91    {
92        s->Printf(", parent = {0x%8.8" PRIx64 "}", parent_block->GetID());
93    }
94    if (m_inlineInfoSP.get() != NULL)
95    {
96        bool show_fullpaths = false;
97        m_inlineInfoSP->Dump(s, show_fullpaths);
98    }
99
100    if (!m_ranges.IsEmpty())
101    {
102        *s << ", ranges =";
103
104        size_t num_ranges = m_ranges.GetSize();
105        for (size_t i=0; i<num_ranges; ++i)
106        {
107            const Range &range = m_ranges.GetEntryRef(i);
108            if (parent_block != NULL && parent_block->Contains(range) == false)
109                *s << '!';
110            else
111                *s << ' ';
112            s->AddressRange(base_addr + range.GetRangeBase(), base_addr + range.GetRangeEnd(), 4);
113        }
114    }
115    s->EOL();
116
117    if (depth > 0)
118    {
119        s->IndentMore();
120
121        if (m_variable_list_sp.get())
122        {
123            m_variable_list_sp->Dump(s, show_context);
124        }
125
126        collection::const_iterator pos, end = m_children.end();
127        for (pos = m_children.begin(); pos != end; ++pos)
128            (*pos)->Dump(s, base_addr, depth - 1, show_context);
129
130        s->IndentLess();
131    }
132
133}
134
135
136Block *
137Block::FindBlockByID (user_id_t block_id)
138{
139    if (block_id == GetID())
140        return this;
141
142    Block *matching_block = NULL;
143    collection::const_iterator pos, end = m_children.end();
144    for (pos = m_children.begin(); pos != end; ++pos)
145    {
146        matching_block = (*pos)->FindBlockByID (block_id);
147        if (matching_block)
148            break;
149    }
150    return matching_block;
151}
152
153void
154Block::CalculateSymbolContext (SymbolContext* sc)
155{
156    if (m_parent_scope)
157        m_parent_scope->CalculateSymbolContext(sc);
158    sc->block = this;
159}
160
161lldb::ModuleSP
162Block::CalculateSymbolContextModule ()
163{
164    if (m_parent_scope)
165        return m_parent_scope->CalculateSymbolContextModule ();
166    return lldb::ModuleSP();
167}
168
169CompileUnit *
170Block::CalculateSymbolContextCompileUnit ()
171{
172    if (m_parent_scope)
173        return m_parent_scope->CalculateSymbolContextCompileUnit ();
174    return NULL;
175}
176
177Function *
178Block::CalculateSymbolContextFunction ()
179{
180    if (m_parent_scope)
181        return m_parent_scope->CalculateSymbolContextFunction ();
182    return NULL;
183}
184
185Block *
186Block::CalculateSymbolContextBlock ()
187{
188    return this;
189}
190
191void
192Block::DumpSymbolContext(Stream *s)
193{
194    Function *function = CalculateSymbolContextFunction();
195    if (function)
196        function->DumpSymbolContext(s);
197    s->Printf(", Block{0x%8.8" PRIx64 "}", GetID());
198}
199
200void
201Block::DumpAddressRanges (Stream *s, lldb::addr_t base_addr)
202{
203    if (!m_ranges.IsEmpty())
204    {
205        size_t num_ranges = m_ranges.GetSize();
206        for (size_t i=0; i<num_ranges; ++i)
207        {
208            const Range &range = m_ranges.GetEntryRef(i);
209            s->AddressRange(base_addr + range.GetRangeBase(), base_addr + range.GetRangeEnd(), 4);
210        }
211    }
212}
213
214bool
215Block::Contains (addr_t range_offset) const
216{
217    return m_ranges.FindEntryThatContains(range_offset) != NULL;
218}
219
220bool
221Block::Contains (const Block *block) const
222{
223    if (this == block)
224        return false; // This block doesn't contain itself...
225
226    // Walk the parent chain for "block" and see if any if them match this block
227    const Block *block_parent;
228    for (block_parent = block->GetParent();
229         block_parent != NULL;
230         block_parent = block_parent->GetParent())
231    {
232        if (this == block_parent)
233            return true; // One of the parents of "block" is this object!
234    }
235    return false;
236}
237
238bool
239Block::Contains (const Range& range) const
240{
241    return m_ranges.FindEntryThatContains (range) != NULL;
242}
243
244Block *
245Block::GetParent () const
246{
247    if (m_parent_scope)
248        return m_parent_scope->CalculateSymbolContextBlock();
249    return NULL;
250}
251
252Block *
253Block::GetContainingInlinedBlock ()
254{
255    if (GetInlinedFunctionInfo())
256        return this;
257    return GetInlinedParent ();
258}
259
260Block *
261Block::GetInlinedParent ()
262{
263    Block *parent_block = GetParent ();
264    if (parent_block)
265    {
266        if (parent_block->GetInlinedFunctionInfo())
267            return parent_block;
268        else
269            return parent_block->GetInlinedParent();
270    }
271    return NULL;
272}
273
274
275bool
276Block::GetRangeContainingOffset (const addr_t offset, Range &range)
277{
278    const Range *range_ptr = m_ranges.FindEntryThatContains (offset);
279    if (range_ptr)
280    {
281        range = *range_ptr;
282        return true;
283    }
284    range.Clear();
285    return false;
286}
287
288
289bool
290Block::GetRangeContainingAddress (const Address& addr, AddressRange &range)
291{
292    Function *function = CalculateSymbolContextFunction();
293    if (function)
294    {
295        const AddressRange &func_range = function->GetAddressRange();
296        if (addr.GetSection() == func_range.GetBaseAddress().GetSection())
297        {
298            const addr_t addr_offset = addr.GetOffset();
299            const addr_t func_offset = func_range.GetBaseAddress().GetOffset();
300            if (addr_offset >= func_offset && addr_offset < func_offset + func_range.GetByteSize())
301            {
302                addr_t offset = addr_offset - func_offset;
303
304                const Range *range_ptr = m_ranges.FindEntryThatContains (offset);
305
306                if (range_ptr)
307                {
308                    range.GetBaseAddress() = func_range.GetBaseAddress();
309                    range.GetBaseAddress().SetOffset(func_offset + range_ptr->GetRangeBase());
310                    range.SetByteSize(range_ptr->GetByteSize());
311                    return true;
312                }
313            }
314        }
315    }
316    range.Clear();
317    return false;
318}
319
320bool
321Block::GetRangeContainingLoadAddress (lldb::addr_t load_addr, Target &target, AddressRange &range)
322{
323    Address load_address;
324    load_address.SetLoadAddress(load_addr, &target);
325    AddressRange containing_range;
326    return GetRangeContainingAddress(load_address, containing_range);
327}
328
329
330uint32_t
331Block::GetRangeIndexContainingAddress (const Address& addr)
332{
333    Function *function = CalculateSymbolContextFunction();
334    if (function)
335    {
336        const AddressRange &func_range = function->GetAddressRange();
337        if (addr.GetSection() == func_range.GetBaseAddress().GetSection())
338        {
339            const addr_t addr_offset = addr.GetOffset();
340            const addr_t func_offset = func_range.GetBaseAddress().GetOffset();
341            if (addr_offset >= func_offset && addr_offset < func_offset + func_range.GetByteSize())
342            {
343                addr_t offset = addr_offset - func_offset;
344                return m_ranges.FindEntryIndexThatContains (offset);
345            }
346        }
347    }
348    return UINT32_MAX;
349}
350
351bool
352Block::GetRangeAtIndex (uint32_t range_idx, AddressRange &range)
353{
354    if (range_idx < m_ranges.GetSize())
355    {
356        Function *function = CalculateSymbolContextFunction();
357        if (function)
358        {
359            const Range &vm_range = m_ranges.GetEntryRef(range_idx);
360            range.GetBaseAddress() = function->GetAddressRange().GetBaseAddress();
361            range.GetBaseAddress().Slide(vm_range.GetRangeBase ());
362            range.SetByteSize (vm_range.GetByteSize());
363            return true;
364        }
365    }
366    return false;
367}
368
369bool
370Block::GetStartAddress (Address &addr)
371{
372    if (m_ranges.IsEmpty())
373        return false;
374
375    Function *function = CalculateSymbolContextFunction();
376    if (function)
377    {
378        addr = function->GetAddressRange().GetBaseAddress();
379        addr.Slide(m_ranges.GetEntryRef(0).GetRangeBase ());
380        return true;
381    }
382    return false;
383}
384
385void
386Block::FinalizeRanges ()
387{
388    m_ranges.Sort();
389    m_ranges.CombineConsecutiveRanges ();
390}
391
392void
393Block::AddRange (const Range& range)
394{
395    Block *parent_block = GetParent ();
396    if (parent_block && !parent_block->Contains(range))
397    {
398        Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYMBOLS));
399        if (log)
400        {
401            ModuleSP module_sp (m_parent_scope->CalculateSymbolContextModule());
402            Function *function = m_parent_scope->CalculateSymbolContextFunction();
403            const addr_t function_file_addr = function->GetAddressRange().GetBaseAddress().GetFileAddress();
404            const addr_t block_start_addr = function_file_addr + range.GetRangeBase ();
405            const addr_t block_end_addr = function_file_addr + range.GetRangeEnd ();
406            Type *func_type = function->GetType();
407
408            const Declaration &func_decl = func_type->GetDeclaration();
409            if (func_decl.GetLine())
410            {
411                log->Printf ("warning: %s:%u block {0x%8.8" PRIx64 "} has range[%u] [0x%" PRIx64 " - 0x%" PRIx64 ") which is not contained in parent block {0x%8.8" PRIx64 "} in function {0x%8.8" PRIx64 "} from %s",
412                             func_decl.GetFile().GetPath().c_str(),
413                             func_decl.GetLine(),
414                             GetID(),
415                             (uint32_t)m_ranges.GetSize(),
416                             block_start_addr,
417                             block_end_addr,
418                             parent_block->GetID(),
419                             function->GetID(),
420                             module_sp->GetFileSpec().GetPath().c_str());
421            }
422            else
423            {
424                log->Printf ("warning: block {0x%8.8" PRIx64 "} has range[%u] [0x%" PRIx64 " - 0x%" PRIx64 ") which is not contained in parent block {0x%8.8" PRIx64 "} in function {0x%8.8" PRIx64 "} from %s",
425                             GetID(),
426                             (uint32_t)m_ranges.GetSize(),
427                             block_start_addr,
428                             block_end_addr,
429                             parent_block->GetID(),
430                             function->GetID(),
431                             module_sp->GetFileSpec().GetPath().c_str());
432            }
433        }
434        parent_block->AddRange (range);
435    }
436    m_ranges.Append(range);
437}
438
439// Return the current number of bytes that this object occupies in memory
440size_t
441Block::MemorySize() const
442{
443    size_t mem_size = sizeof(Block) + m_ranges.GetSize() * sizeof(Range);
444    if (m_inlineInfoSP.get())
445        mem_size += m_inlineInfoSP->MemorySize();
446    if (m_variable_list_sp.get())
447        mem_size += m_variable_list_sp->MemorySize();
448    return mem_size;
449
450}
451
452void
453Block::AddChild(const BlockSP &child_block_sp)
454{
455    if (child_block_sp)
456    {
457        child_block_sp->SetParentScope (this);
458        m_children.push_back (child_block_sp);
459    }
460}
461
462void
463Block::SetInlinedFunctionInfo(const char *name, const char *mangled, const Declaration *decl_ptr, const Declaration *call_decl_ptr)
464{
465    m_inlineInfoSP.reset(new InlineFunctionInfo(name, mangled, decl_ptr, call_decl_ptr));
466}
467
468
469
470VariableListSP
471Block::GetBlockVariableList (bool can_create)
472{
473    if (m_parsed_block_variables == false)
474    {
475        if (m_variable_list_sp.get() == NULL && can_create)
476        {
477            m_parsed_block_variables = true;
478            SymbolContext sc;
479            CalculateSymbolContext(&sc);
480            assert(sc.module_sp);
481            sc.module_sp->GetSymbolVendor()->ParseVariablesForContext(sc);
482        }
483    }
484    return m_variable_list_sp;
485}
486
487uint32_t
488Block::AppendBlockVariables (bool can_create,
489                             bool get_child_block_variables,
490                             bool stop_if_child_block_is_inlined_function,
491                             VariableList *variable_list)
492{
493    uint32_t num_variables_added = 0;
494    VariableList *block_var_list = GetBlockVariableList (can_create).get();
495    if (block_var_list)
496    {
497        num_variables_added += block_var_list->GetSize();
498        variable_list->AddVariables (block_var_list);
499    }
500
501    if (get_child_block_variables)
502    {
503        collection::const_iterator pos, end = m_children.end();
504        for (pos = m_children.begin(); pos != end; ++pos)
505        {
506            Block *child_block = pos->get();
507            if (stop_if_child_block_is_inlined_function == false ||
508                child_block->GetInlinedFunctionInfo() == NULL)
509            {
510                num_variables_added += child_block->AppendBlockVariables (can_create,
511                                                                          get_child_block_variables,
512                                                                          stop_if_child_block_is_inlined_function,
513                                                                          variable_list);
514            }
515        }
516    }
517    return num_variables_added;
518}
519
520uint32_t
521Block::AppendVariables
522(
523    bool can_create,
524    bool get_parent_variables,
525    bool stop_if_block_is_inlined_function,
526    VariableList *variable_list
527)
528{
529    uint32_t num_variables_added = 0;
530    VariableListSP variable_list_sp(GetBlockVariableList(can_create));
531
532    bool is_inlined_function = GetInlinedFunctionInfo() != NULL;
533    if (variable_list_sp.get())
534    {
535        num_variables_added = variable_list_sp->GetSize();
536        variable_list->AddVariables(variable_list_sp.get());
537    }
538
539    if (get_parent_variables)
540    {
541        if (stop_if_block_is_inlined_function && is_inlined_function)
542            return num_variables_added;
543
544        Block* parent_block = GetParent();
545        if (parent_block)
546            num_variables_added += parent_block->AppendVariables (can_create, get_parent_variables, stop_if_block_is_inlined_function, variable_list);
547    }
548    return num_variables_added;
549}
550
551clang::DeclContext *
552Block::GetClangDeclContext()
553{
554    SymbolContext sc;
555
556    CalculateSymbolContext (&sc);
557
558    if (!sc.module_sp)
559        return NULL;
560
561    SymbolVendor *sym_vendor = sc.module_sp->GetSymbolVendor();
562
563    if (!sym_vendor)
564        return NULL;
565
566    SymbolFile *sym_file = sym_vendor->GetSymbolFile();
567
568    if (!sym_file)
569        return NULL;
570
571    return sym_file->GetClangDeclContextForTypeUID (sc, m_uid);
572}
573
574void
575Block::SetBlockInfoHasBeenParsed (bool b, bool set_children)
576{
577    m_parsed_block_info = b;
578    if (set_children)
579    {
580        m_parsed_child_blocks = true;
581        collection::const_iterator pos, end = m_children.end();
582        for (pos = m_children.begin(); pos != end; ++pos)
583            (*pos)->SetBlockInfoHasBeenParsed (b, true);
584    }
585}
586
587void
588Block::SetDidParseVariables (bool b, bool set_children)
589{
590    m_parsed_block_variables = b;
591    if (set_children)
592    {
593        collection::const_iterator pos, end = m_children.end();
594        for (pos = m_children.begin(); pos != end; ++pos)
595            (*pos)->SetDidParseVariables (b, true);
596    }
597}
598
599
600Block *
601Block::GetSibling() const
602{
603    if (m_parent_scope)
604    {
605        Block *parent_block = GetParent();
606        if (parent_block)
607            return parent_block->GetSiblingForChild (this);
608    }
609    return NULL;
610}
611// A parent of child blocks can be asked to find a sibling block given
612// one of its child blocks
613Block *
614Block::GetSiblingForChild (const Block *child_block) const
615{
616    if (!m_children.empty())
617    {
618        collection::const_iterator pos, end = m_children.end();
619        for (pos = m_children.begin(); pos != end; ++pos)
620        {
621            if (pos->get() == child_block)
622            {
623                if (++pos != end)
624                    return pos->get();
625                break;
626            }
627        }
628    }
629    return NULL;
630}
631
632