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 #include "lldb/Symbol/Function.h"
12 #include "lldb/Core/Module.h"
13 #include "lldb/Core/Section.h"
14 #include "lldb/Symbol/SymbolVendor.h"
15 #include "lldb/Symbol/VariableList.h"
16 
17 using namespace lldb;
18 using namespace lldb_private;
19 
20 Block::Block(lldb::user_id_t uid) :
21     UserID(uid),
22     m_parent_scope (NULL),
23     m_sibling (NULL),
24     m_children (),
25     m_ranges (),
26     m_inlineInfoSP (),
27     m_variable_list_sp (),
28     m_parsed_block_info (false),
29     m_parsed_block_variables (false),
30     m_parsed_child_blocks (false)
31 {
32 }
33 
34 Block::~Block ()
35 {
36 }
37 
38 void
39 Block::GetDescription(Stream *s, Function *function, lldb::DescriptionLevel level, Target *target) const
40 {
41     *s << "id = " << ((const UserID&)*this);
42 
43     size_t num_ranges = m_ranges.size();
44     if (num_ranges)
45     {
46 
47         addr_t base_addr = LLDB_INVALID_ADDRESS;
48         if (target)
49             base_addr = function->GetAddressRange().GetBaseAddress().GetLoadAddress(target);
50         if (base_addr == LLDB_INVALID_ADDRESS)
51             base_addr = function->GetAddressRange().GetBaseAddress().GetFileAddress();
52 
53         s->Printf(", range%s = ", num_ranges > 1 ? "s" : "");
54         std::vector<VMRange>::const_iterator pos, end = m_ranges.end();
55         for (pos = m_ranges.begin(); pos != end; ++pos)
56             pos->Dump(s, base_addr, 4);
57     }
58 
59     if (m_inlineInfoSP.get() != NULL)
60     {
61         bool show_fullpaths = (level == eDescriptionLevelVerbose);
62         m_inlineInfoSP->Dump(s, show_fullpaths);
63     }
64 }
65 
66 void
67 Block::Dump(Stream *s, addr_t base_addr, int32_t depth, bool show_context) const
68 {
69     if (depth < 0)
70     {
71         Block *parent = GetParent();
72         if (parent)
73         {
74             // We have a depth that is less than zero, print our parent blocks
75             // first
76             parent->Dump(s, base_addr, depth + 1, show_context);
77         }
78     }
79 
80     s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
81     s->Indent();
82     *s << "Block" << ((const UserID&)*this);
83     const Block* parent_block = GetParent();
84     if (parent_block)
85     {
86         s->Printf(", parent = {0x%8.8x}", parent_block->GetID());
87     }
88     if (m_inlineInfoSP.get() != NULL)
89     {
90         bool show_fullpaths = false;
91         m_inlineInfoSP->Dump(s, show_fullpaths);
92     }
93 
94     if (!m_ranges.empty())
95     {
96         *s << ", ranges =";
97         std::vector<VMRange>::const_iterator pos;
98         std::vector<VMRange>::const_iterator end = m_ranges.end();
99         for (pos = m_ranges.begin(); pos != end; ++pos)
100         {
101             if (parent_block != NULL && parent_block->Contains(*pos) == false)
102                 *s << '!';
103             else
104                 *s << ' ';
105             pos->Dump(s, base_addr);
106         }
107     }
108     s->EOL();
109 
110     if (depth > 0)
111     {
112         s->IndentMore();
113 
114         if (m_variable_list_sp.get())
115         {
116             m_variable_list_sp->Dump(s, show_context);
117         }
118 
119         for (Block *child_block = GetFirstChild(); child_block != NULL; child_block = child_block->GetSibling())
120         {
121             child_block->Dump(s, base_addr, depth - 1, show_context);
122         }
123 
124         s->IndentLess();
125     }
126 
127 }
128 
129 
130 Block *
131 Block::FindBlockByID (user_id_t block_id)
132 {
133     if (block_id == GetID())
134         return this;
135 
136     Block *matching_block = NULL;
137     for (Block *child_block = GetFirstChild(); child_block != NULL; child_block = child_block->GetSibling())
138     {
139         matching_block = child_block->FindBlockByID (block_id);
140         if (matching_block)
141             break;
142     }
143     return matching_block;
144 }
145 
146 void
147 Block::CalculateSymbolContext (SymbolContext* sc)
148 {
149     if (m_parent_scope)
150         m_parent_scope->CalculateSymbolContext(sc);
151     sc->block = this;
152 }
153 
154 void
155 Block::DumpStopContext
156 (
157     Stream *s,
158     const SymbolContext *sc_ptr,
159     const Declaration *child_inline_call_site,
160     bool show_fullpaths,
161     bool show_inline_blocks)
162 {
163     const InlineFunctionInfo* inline_info = NULL;
164     Block* inlined_block;
165     if (sc_ptr)
166         inlined_block = GetContainingInlinedBlock ();
167     else
168         inlined_block = GetInlinedParent();
169 
170     if (inlined_block)
171         inline_info = inlined_block->GetInlinedFunctionInfo();
172     const Declaration *inline_call_site = child_inline_call_site;
173     if (inline_info)
174     {
175         inline_call_site = &inline_info->GetCallSite();
176         if (sc_ptr)
177         {
178             // First frame in a frame with inlined functions
179             s->PutCString (" [inlined]");
180         }
181         if (show_inline_blocks && child_inline_call_site)
182             s->EOL();
183         else
184             s->PutChar(' ');
185 
186         if (sc_ptr == NULL)
187             s->Indent();
188 
189         s->PutCString(inline_info->GetName ().AsCString());
190 
191         if (child_inline_call_site && child_inline_call_site->IsValid())
192         {
193             s->PutCString(" at ");
194             child_inline_call_site->DumpStopContext (s, show_fullpaths);
195         }
196     }
197 
198     // The first call to this function from something that has a symbol
199     // context will pass in a valid sc_ptr. Subsequent calls to this function
200     // from this function for inline purposes will NULL out sc_ptr. So on the
201     // first time through we dump the line table entry (which is always at the
202     // deepest inline code block). And subsequent calls to this function we
203     // will use hte inline call site information to print line numbers.
204     if (sc_ptr)
205     {
206         // If we have any inlined functions, this will be the deepest most
207         // inlined location
208         if (sc_ptr->line_entry.IsValid())
209         {
210             s->PutCString(" at ");
211             sc_ptr->line_entry.DumpStopContext (s, show_fullpaths);
212         }
213     }
214 
215     if (show_inline_blocks)
216     {
217         if (inlined_block)
218         {
219             inlined_block->Block::DumpStopContext (s,
220                                                    NULL,
221                                                    inline_call_site,
222                                                    show_fullpaths,
223                                                    show_inline_blocks);
224         }
225         else if (child_inline_call_site)
226         {
227             SymbolContext sc;
228             CalculateSymbolContext(&sc);
229             if (sc.function)
230             {
231                 s->EOL();
232                 s->Indent (sc.function->GetMangled().GetName().AsCString());
233                 if (child_inline_call_site && child_inline_call_site->IsValid())
234                 {
235                     s->PutCString(" at ");
236                     child_inline_call_site->DumpStopContext (s, show_fullpaths);
237                 }
238             }
239         }
240     }
241 }
242 
243 
244 void
245 Block::DumpSymbolContext(Stream *s)
246 {
247     SymbolContext sc;
248     CalculateSymbolContext(&sc);
249     if (sc.function)
250         sc.function->DumpSymbolContext(s);
251     s->Printf(", Block{0x%8.8x}", GetID());
252 }
253 
254 void
255 Block::DumpAddressRanges (Stream *s, lldb::addr_t base_addr)
256 {
257     if (!m_ranges.empty())
258     {
259         std::vector<VMRange>::const_iterator pos, end = m_ranges.end();
260         for (pos = m_ranges.begin(); pos != end; ++pos)
261             pos->Dump (s, base_addr);
262     }
263 }
264 
265 bool
266 Block::Contains (addr_t range_offset) const
267 {
268     return VMRange::ContainsValue(m_ranges, range_offset);
269 }
270 
271 bool
272 Block::Contains (const Block *block) const
273 {
274     if (this == block)
275         return false; // This block doesn't contain itself...
276 
277     // Walk the parent chain for "block" and see if any if them match this block
278     const Block *block_parent;
279     for (block_parent = block->GetParent();
280          block_parent != NULL;
281          block_parent = block_parent->GetParent())
282     {
283         if (this == block_parent)
284             return true; // One of the parents of "block" is this object!
285     }
286     return false;
287 }
288 
289 bool
290 Block::Contains (const VMRange& range) const
291 {
292     return VMRange::ContainsRange(m_ranges, range);
293 }
294 
295 Block *
296 Block::GetParent () const
297 {
298     if (m_parent_scope)
299     {
300         SymbolContext sc;
301         m_parent_scope->CalculateSymbolContext(&sc);
302         if (sc.block)
303             return sc.block;
304     }
305     return NULL;
306 }
307 
308 Block *
309 Block::GetContainingInlinedBlock ()
310 {
311     if (GetInlinedFunctionInfo())
312         return this;
313     return GetInlinedParent ();
314 }
315 
316 Block *
317 Block::GetInlinedParent ()
318 {
319     Block *parent_block = GetParent ();
320     if (parent_block)
321     {
322         if (parent_block->GetInlinedFunctionInfo())
323             return parent_block;
324         else
325             return parent_block->GetInlinedParent();
326     }
327     return NULL;
328 }
329 
330 
331 bool
332 Block::GetRangeContainingOffset (const addr_t offset, VMRange &range)
333 {
334     uint32_t range_idx = VMRange::FindRangeIndexThatContainsValue (m_ranges, offset);
335     if (range_idx < m_ranges.size())
336     {
337         range = m_ranges[range_idx];
338         return true;
339     }
340     range.Clear();
341     return false;
342 }
343 
344 
345 bool
346 Block::GetRangeContainingAddress (const Address& addr, AddressRange &range)
347 {
348     SymbolContext sc;
349     CalculateSymbolContext(&sc);
350     if (sc.function)
351     {
352         const AddressRange &func_range = sc.function->GetAddressRange();
353         if (addr.GetSection() == func_range.GetBaseAddress().GetSection())
354         {
355             const addr_t addr_offset = addr.GetOffset();
356             const addr_t func_offset = func_range.GetBaseAddress().GetOffset();
357             if (addr_offset >= func_offset && addr_offset < func_offset + func_range.GetByteSize())
358             {
359                 addr_t offset = addr_offset - func_offset;
360 
361                 uint32_t range_idx = VMRange::FindRangeIndexThatContainsValue (m_ranges, offset);
362                 if (range_idx < m_ranges.size())
363                 {
364                     range.GetBaseAddress() = func_range.GetBaseAddress();
365                     range.GetBaseAddress().SetOffset(func_offset + m_ranges[range_idx].GetBaseAddress());
366                     range.SetByteSize(m_ranges[range_idx].GetByteSize());
367                     return true;
368                 }
369             }
370         }
371     }
372     range.Clear();
373     return false;
374 }
375 
376 bool
377 Block::GetRangeAtIndex (uint32_t range_idx, AddressRange &range)
378 {
379     if (range_idx < m_ranges.size())
380     {
381         SymbolContext sc;
382         CalculateSymbolContext(&sc);
383         if (sc.function)
384         {
385             range.GetBaseAddress() = sc.function->GetAddressRange().GetBaseAddress();
386             range.GetBaseAddress().Slide(m_ranges[range_idx].GetBaseAddress ());
387             range.SetByteSize (m_ranges[range_idx].GetByteSize());
388             return true;
389         }
390     }
391     return false;
392 }
393 
394 bool
395 Block::GetStartAddress (Address &addr)
396 {
397     if (m_ranges.empty())
398         return false;
399 
400     SymbolContext sc;
401     CalculateSymbolContext(&sc);
402     if (sc.function)
403     {
404         addr = sc.function->GetAddressRange().GetBaseAddress();
405         addr.Slide(m_ranges.front().GetBaseAddress ());
406         return true;
407     }
408     return false;
409 }
410 
411 void
412 Block::AddRange(addr_t start_offset, addr_t end_offset)
413 {
414     m_ranges.resize(m_ranges.size()+1);
415     m_ranges.back().Reset(start_offset, end_offset);
416 }
417 
418 // Return the current number of bytes that this object occupies in memory
419 size_t
420 Block::MemorySize() const
421 {
422     size_t mem_size = sizeof(Block) + m_ranges.size() * sizeof(VMRange);
423     if (m_inlineInfoSP.get())
424         mem_size += m_inlineInfoSP->MemorySize();
425     if (m_variable_list_sp.get())
426         mem_size += m_variable_list_sp->MemorySize();
427     return mem_size;
428 
429 }
430 
431 void
432 Block::AddChild(const BlockSP &child_block_sp)
433 {
434     if (child_block_sp)
435     {
436         Block *block_needs_sibling = NULL;
437 
438         if (!m_children.empty())
439             block_needs_sibling = m_children.back().get();
440 
441         child_block_sp->SetParentScope (this);
442         m_children.push_back (child_block_sp);
443 
444         if (block_needs_sibling)
445             block_needs_sibling->SetSibling (child_block_sp.get());
446     }
447 }
448 
449 void
450 Block::SetInlinedFunctionInfo(const char *name, const char *mangled, const Declaration *decl_ptr, const Declaration *call_decl_ptr)
451 {
452     m_inlineInfoSP.reset(new InlineFunctionInfo(name, mangled, decl_ptr, call_decl_ptr));
453 }
454 
455 
456 
457 VariableListSP
458 Block::GetVariableList (bool get_child_variables, bool can_create)
459 {
460     VariableListSP variable_list_sp;
461     if (m_parsed_block_variables == false)
462     {
463         if (m_variable_list_sp.get() == NULL && can_create)
464         {
465             m_parsed_block_variables = true;
466             SymbolContext sc;
467             CalculateSymbolContext(&sc);
468             assert(sc.module_sp);
469             sc.module_sp->GetSymbolVendor()->ParseVariablesForContext(sc);
470         }
471     }
472 
473     if (m_variable_list_sp.get())
474     {
475         variable_list_sp.reset(new VariableList());
476         if (variable_list_sp.get())
477             variable_list_sp->AddVariables(m_variable_list_sp.get());
478 
479         if (get_child_variables)
480         {
481             for (Block *child_block = GetFirstChild();
482                  child_block != NULL;
483                  child_block = child_block->GetSibling())
484             {
485                 if (child_block->GetInlinedFunctionInfo() == NULL)
486                 {
487                     VariableListSP child_block_variable_list(child_block->GetVariableList(get_child_variables, can_create));
488                     if (child_block_variable_list.get())
489                         variable_list_sp->AddVariables(child_block_variable_list.get());
490                 }
491 
492             }
493         }
494     }
495 
496     return variable_list_sp;
497 }
498 
499 uint32_t
500 Block::AppendVariables
501 (
502     bool can_create,
503     bool get_parent_variables,
504     bool stop_if_block_is_inlined_function,
505     VariableList *variable_list
506 )
507 {
508     uint32_t num_variables_added = 0;
509     VariableListSP variable_list_sp(GetVariableList(false, can_create));
510 
511     bool is_inlined_function = GetInlinedFunctionInfo() != NULL;
512     if (variable_list_sp.get())
513     {
514         num_variables_added = variable_list_sp->GetSize();
515         variable_list->AddVariables(variable_list_sp.get());
516     }
517 
518     if (get_parent_variables)
519     {
520         if (stop_if_block_is_inlined_function && is_inlined_function)
521             return num_variables_added;
522 
523         Block* parent_block = GetParent();
524         if (parent_block)
525             num_variables_added += parent_block->AppendVariables (can_create, get_parent_variables, stop_if_block_is_inlined_function, variable_list);
526     }
527     return num_variables_added;
528 }
529 
530 void
531 Block::SetBlockInfoHasBeenParsed (bool b, bool set_children)
532 {
533     m_parsed_block_info = b;
534     if (set_children)
535     {
536         m_parsed_child_blocks = true;
537         for (Block *child_block = GetFirstChild(); child_block != NULL; child_block = child_block->GetSibling())
538             child_block->SetBlockInfoHasBeenParsed (b, true);
539     }
540 }
541