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