1 //===-- Block.cpp ---------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "lldb/Symbol/Block.h"
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/LLDBLog.h"
17 #include "lldb/Utility/Log.h"
22 using namespace lldb_private
;
24 Block::Block(lldb::user_id_t uid
)
25 : UserID(uid
), m_parent_scope(nullptr), m_children(), m_ranges(),
26 m_inlineInfoSP(), m_variable_list_sp(), m_parsed_block_info(false),
27 m_parsed_block_variables(false), m_parsed_child_blocks(false) {}
29 Block::~Block() = default;
31 void Block::GetDescription(Stream
*s
, Function
*function
,
32 lldb::DescriptionLevel level
, Target
*target
) const {
33 *s
<< "id = " << ((const UserID
&)*this);
35 size_t num_ranges
= m_ranges
.GetSize();
38 addr_t base_addr
= LLDB_INVALID_ADDRESS
;
41 function
->GetAddressRange().GetBaseAddress().GetLoadAddress(target
);
42 if (base_addr
== LLDB_INVALID_ADDRESS
)
43 base_addr
= function
->GetAddressRange().GetBaseAddress().GetFileAddress();
45 s
->Printf(", range%s = ", num_ranges
> 1 ? "s" : "");
46 for (size_t i
= 0; i
< num_ranges
; ++i
) {
47 const Range
&range
= m_ranges
.GetEntryRef(i
);
48 DumpAddressRange(s
->AsRawOstream(), base_addr
+ range
.GetRangeBase(),
49 base_addr
+ range
.GetRangeEnd(), 4);
53 if (m_inlineInfoSP
.get() != nullptr) {
54 bool show_fullpaths
= (level
== eDescriptionLevelVerbose
);
55 m_inlineInfoSP
->Dump(s
, show_fullpaths
);
59 void Block::Dump(Stream
*s
, addr_t base_addr
, int32_t depth
,
60 bool show_context
) const {
62 Block
*parent
= GetParent();
64 // We have a depth that is less than zero, print our parent blocks first
65 parent
->Dump(s
, base_addr
, depth
+ 1, show_context
);
69 s
->Printf("%p: ", static_cast<const void *>(this));
71 *s
<< "Block" << static_cast<const UserID
&>(*this);
72 const Block
*parent_block
= GetParent();
74 s
->Printf(", parent = {0x%8.8" PRIx64
"}", parent_block
->GetID());
76 if (m_inlineInfoSP
.get() != nullptr) {
77 bool show_fullpaths
= false;
78 m_inlineInfoSP
->Dump(s
, show_fullpaths
);
81 if (!m_ranges
.IsEmpty()) {
84 size_t num_ranges
= m_ranges
.GetSize();
85 for (size_t i
= 0; i
< num_ranges
; ++i
) {
86 const Range
&range
= m_ranges
.GetEntryRef(i
);
87 if (parent_block
!= nullptr && !parent_block
->Contains(range
))
91 DumpAddressRange(s
->AsRawOstream(), base_addr
+ range
.GetRangeBase(),
92 base_addr
+ range
.GetRangeEnd(), 4);
100 if (m_variable_list_sp
.get()) {
101 m_variable_list_sp
->Dump(s
, show_context
);
104 collection::const_iterator pos
, end
= m_children
.end();
105 for (pos
= m_children
.begin(); pos
!= end
; ++pos
)
106 (*pos
)->Dump(s
, base_addr
, depth
- 1, show_context
);
112 Block
*Block::FindBlockByID(user_id_t block_id
) {
113 if (block_id
== GetID())
116 Block
*matching_block
= nullptr;
117 collection::const_iterator pos
, end
= m_children
.end();
118 for (pos
= m_children
.begin(); pos
!= end
; ++pos
) {
119 matching_block
= (*pos
)->FindBlockByID(block_id
);
123 return matching_block
;
126 Block
*Block::FindInnermostBlockByOffset(const lldb::addr_t offset
) {
127 if (!Contains(offset
))
129 for (const BlockSP
&block_sp
: m_children
) {
130 if (Block
*block
= block_sp
->FindInnermostBlockByOffset(offset
))
136 void Block::CalculateSymbolContext(SymbolContext
*sc
) {
138 m_parent_scope
->CalculateSymbolContext(sc
);
142 lldb::ModuleSP
Block::CalculateSymbolContextModule() {
144 return m_parent_scope
->CalculateSymbolContextModule();
145 return lldb::ModuleSP();
148 CompileUnit
*Block::CalculateSymbolContextCompileUnit() {
150 return m_parent_scope
->CalculateSymbolContextCompileUnit();
154 Function
*Block::CalculateSymbolContextFunction() {
156 return m_parent_scope
->CalculateSymbolContextFunction();
160 Block
*Block::CalculateSymbolContextBlock() { return this; }
162 void Block::DumpSymbolContext(Stream
*s
) {
163 Function
*function
= CalculateSymbolContextFunction();
165 function
->DumpSymbolContext(s
);
166 s
->Printf(", Block{0x%8.8" PRIx64
"}", GetID());
169 void Block::DumpAddressRanges(Stream
*s
, lldb::addr_t base_addr
) {
170 if (!m_ranges
.IsEmpty()) {
171 size_t num_ranges
= m_ranges
.GetSize();
172 for (size_t i
= 0; i
< num_ranges
; ++i
) {
173 const Range
&range
= m_ranges
.GetEntryRef(i
);
174 DumpAddressRange(s
->AsRawOstream(), base_addr
+ range
.GetRangeBase(),
175 base_addr
+ range
.GetRangeEnd(), 4);
180 bool Block::Contains(addr_t range_offset
) const {
181 return m_ranges
.FindEntryThatContains(range_offset
) != nullptr;
184 bool Block::Contains(const Block
*block
) const {
186 return false; // This block doesn't contain itself...
188 // Walk the parent chain for "block" and see if any if them match this block
189 const Block
*block_parent
;
190 for (block_parent
= block
->GetParent(); block_parent
!= nullptr;
191 block_parent
= block_parent
->GetParent()) {
192 if (this == block_parent
)
193 return true; // One of the parents of "block" is this object!
198 bool Block::Contains(const Range
&range
) const {
199 return m_ranges
.FindEntryThatContains(range
) != nullptr;
202 Block
*Block::GetParent() const {
204 return m_parent_scope
->CalculateSymbolContextBlock();
208 Block
*Block::GetContainingInlinedBlock() {
209 if (GetInlinedFunctionInfo())
211 return GetInlinedParent();
214 Block
*Block::GetInlinedParent() {
215 Block
*parent_block
= GetParent();
217 if (parent_block
->GetInlinedFunctionInfo())
220 return parent_block
->GetInlinedParent();
225 Block
*Block::GetContainingInlinedBlockWithCallSite(
226 const Declaration
&find_call_site
) {
227 Block
*inlined_block
= GetContainingInlinedBlock();
229 while (inlined_block
) {
230 const auto *function_info
= inlined_block
->GetInlinedFunctionInfo();
233 function_info
->GetCallSite().FileAndLineEqual(find_call_site
, true))
234 return inlined_block
;
235 inlined_block
= inlined_block
->GetInlinedParent();
240 bool Block::GetRangeContainingOffset(const addr_t offset
, Range
&range
) {
241 const Range
*range_ptr
= m_ranges
.FindEntryThatContains(offset
);
250 bool Block::GetRangeContainingAddress(const Address
&addr
,
251 AddressRange
&range
) {
252 Function
*function
= CalculateSymbolContextFunction();
254 const AddressRange
&func_range
= function
->GetAddressRange();
255 if (addr
.GetSection() == func_range
.GetBaseAddress().GetSection()) {
256 const addr_t addr_offset
= addr
.GetOffset();
257 const addr_t func_offset
= func_range
.GetBaseAddress().GetOffset();
258 if (addr_offset
>= func_offset
&&
259 addr_offset
< func_offset
+ func_range
.GetByteSize()) {
260 addr_t offset
= addr_offset
- func_offset
;
262 const Range
*range_ptr
= m_ranges
.FindEntryThatContains(offset
);
265 range
.GetBaseAddress() = func_range
.GetBaseAddress();
266 range
.GetBaseAddress().SetOffset(func_offset
+
267 range_ptr
->GetRangeBase());
268 range
.SetByteSize(range_ptr
->GetByteSize());
278 bool Block::GetRangeContainingLoadAddress(lldb::addr_t load_addr
,
279 Target
&target
, AddressRange
&range
) {
280 Address load_address
;
281 load_address
.SetLoadAddress(load_addr
, &target
);
282 AddressRange containing_range
;
283 return GetRangeContainingAddress(load_address
, containing_range
);
286 uint32_t Block::GetRangeIndexContainingAddress(const Address
&addr
) {
287 Function
*function
= CalculateSymbolContextFunction();
289 const AddressRange
&func_range
= function
->GetAddressRange();
290 if (addr
.GetSection() == func_range
.GetBaseAddress().GetSection()) {
291 const addr_t addr_offset
= addr
.GetOffset();
292 const addr_t func_offset
= func_range
.GetBaseAddress().GetOffset();
293 if (addr_offset
>= func_offset
&&
294 addr_offset
< func_offset
+ func_range
.GetByteSize()) {
295 addr_t offset
= addr_offset
- func_offset
;
296 return m_ranges
.FindEntryIndexThatContains(offset
);
303 bool Block::GetRangeAtIndex(uint32_t range_idx
, AddressRange
&range
) {
304 if (range_idx
< m_ranges
.GetSize()) {
305 Function
*function
= CalculateSymbolContextFunction();
307 const Range
&vm_range
= m_ranges
.GetEntryRef(range_idx
);
308 range
.GetBaseAddress() = function
->GetAddressRange().GetBaseAddress();
309 range
.GetBaseAddress().Slide(vm_range
.GetRangeBase());
310 range
.SetByteSize(vm_range
.GetByteSize());
317 AddressRanges
Block::GetRanges() {
318 AddressRanges ranges
;
319 Function
*function
= CalculateSymbolContextFunction();
322 for (size_t i
= 0, e
= m_ranges
.GetSize(); i
< e
; ++i
) {
323 ranges
.emplace_back();
324 auto &range
= ranges
.back();
325 const Range
&vm_range
= m_ranges
.GetEntryRef(i
);
326 range
.GetBaseAddress() = function
->GetAddressRange().GetBaseAddress();
327 range
.GetBaseAddress().Slide(vm_range
.GetRangeBase());
328 range
.SetByteSize(vm_range
.GetByteSize());
333 bool Block::GetStartAddress(Address
&addr
) {
334 if (m_ranges
.IsEmpty())
337 Function
*function
= CalculateSymbolContextFunction();
339 addr
= function
->GetAddressRange().GetBaseAddress();
340 addr
.Slide(m_ranges
.GetEntryRef(0).GetRangeBase());
346 void Block::FinalizeRanges() {
348 m_ranges
.CombineConsecutiveRanges();
351 void Block::AddRange(const Range
&range
) {
352 Block
*parent_block
= GetParent();
353 if (parent_block
&& !parent_block
->Contains(range
)) {
354 Log
*log
= GetLog(LLDBLog::Symbols
);
356 ModuleSP
module_sp(m_parent_scope
->CalculateSymbolContextModule());
357 Function
*function
= m_parent_scope
->CalculateSymbolContextFunction();
358 const addr_t function_file_addr
=
359 function
->GetAddressRange().GetBaseAddress().GetFileAddress();
360 const addr_t block_start_addr
= function_file_addr
+ range
.GetRangeBase();
361 const addr_t block_end_addr
= function_file_addr
+ range
.GetRangeEnd();
362 Type
*func_type
= function
->GetType();
364 const Declaration
&func_decl
= func_type
->GetDeclaration();
365 if (func_decl
.GetLine()) {
367 "warning: %s:%u block {0x%8.8" PRIx64
368 "} has range[%u] [0x%" PRIx64
" - 0x%" PRIx64
369 ") which is not contained in parent block {0x%8.8" PRIx64
370 "} in function {0x%8.8" PRIx64
"} from %s",
371 func_decl
.GetFile().GetPath().c_str(), func_decl
.GetLine(),
372 GetID(), (uint32_t)m_ranges
.GetSize(), block_start_addr
,
373 block_end_addr
, parent_block
->GetID(), function
->GetID(),
374 module_sp
->GetFileSpec().GetPath().c_str());
377 "warning: block {0x%8.8" PRIx64
"} has range[%u] [0x%" PRIx64
379 ") which is not contained in parent block {0x%8.8" PRIx64
380 "} in function {0x%8.8" PRIx64
"} from %s",
381 GetID(), (uint32_t)m_ranges
.GetSize(), block_start_addr
,
382 block_end_addr
, parent_block
->GetID(), function
->GetID(),
383 module_sp
->GetFileSpec().GetPath().c_str());
386 parent_block
->AddRange(range
);
388 m_ranges
.Append(range
);
391 // Return the current number of bytes that this object occupies in memory
392 size_t Block::MemorySize() const {
393 size_t mem_size
= sizeof(Block
) + m_ranges
.GetSize() * sizeof(Range
);
394 if (m_inlineInfoSP
.get())
395 mem_size
+= m_inlineInfoSP
->MemorySize();
396 if (m_variable_list_sp
.get())
397 mem_size
+= m_variable_list_sp
->MemorySize();
401 void Block::AddChild(const BlockSP
&child_block_sp
) {
402 if (child_block_sp
) {
403 child_block_sp
->SetParentScope(this);
404 m_children
.push_back(child_block_sp
);
408 void Block::SetInlinedFunctionInfo(const char *name
, const char *mangled
,
409 const Declaration
*decl_ptr
,
410 const Declaration
*call_decl_ptr
) {
411 m_inlineInfoSP
= std::make_shared
<InlineFunctionInfo
>(name
, mangled
, decl_ptr
,
415 VariableListSP
Block::GetBlockVariableList(bool can_create
) {
416 if (!m_parsed_block_variables
) {
417 if (m_variable_list_sp
.get() == nullptr && can_create
) {
418 m_parsed_block_variables
= true;
420 CalculateSymbolContext(&sc
);
421 assert(sc
.module_sp
);
422 sc
.module_sp
->GetSymbolFile()->ParseVariablesForContext(sc
);
425 return m_variable_list_sp
;
429 Block::AppendBlockVariables(bool can_create
, bool get_child_block_variables
,
430 bool stop_if_child_block_is_inlined_function
,
431 const std::function
<bool(Variable
*)> &filter
,
432 VariableList
*variable_list
) {
433 uint32_t num_variables_added
= 0;
434 VariableList
*block_var_list
= GetBlockVariableList(can_create
).get();
435 if (block_var_list
) {
436 for (const VariableSP
&var_sp
: *block_var_list
) {
437 if (filter(var_sp
.get())) {
438 num_variables_added
++;
439 variable_list
->AddVariable(var_sp
);
444 if (get_child_block_variables
) {
445 collection::const_iterator pos
, end
= m_children
.end();
446 for (pos
= m_children
.begin(); pos
!= end
; ++pos
) {
447 Block
*child_block
= pos
->get();
448 if (!stop_if_child_block_is_inlined_function
||
449 child_block
->GetInlinedFunctionInfo() == nullptr) {
450 num_variables_added
+= child_block
->AppendBlockVariables(
451 can_create
, get_child_block_variables
,
452 stop_if_child_block_is_inlined_function
, filter
, variable_list
);
456 return num_variables_added
;
459 uint32_t Block::AppendVariables(bool can_create
, bool get_parent_variables
,
460 bool stop_if_block_is_inlined_function
,
461 const std::function
<bool(Variable
*)> &filter
,
462 VariableList
*variable_list
) {
463 uint32_t num_variables_added
= 0;
464 VariableListSP
variable_list_sp(GetBlockVariableList(can_create
));
466 bool is_inlined_function
= GetInlinedFunctionInfo() != nullptr;
467 if (variable_list_sp
) {
468 for (size_t i
= 0; i
< variable_list_sp
->GetSize(); ++i
) {
469 VariableSP variable
= variable_list_sp
->GetVariableAtIndex(i
);
470 if (filter(variable
.get())) {
471 num_variables_added
++;
472 variable_list
->AddVariable(variable
);
477 if (get_parent_variables
) {
478 if (stop_if_block_is_inlined_function
&& is_inlined_function
)
479 return num_variables_added
;
481 Block
*parent_block
= GetParent();
483 num_variables_added
+= parent_block
->AppendVariables(
484 can_create
, get_parent_variables
, stop_if_block_is_inlined_function
,
485 filter
, variable_list
);
487 return num_variables_added
;
490 SymbolFile
*Block::GetSymbolFile() {
491 if (ModuleSP module_sp
= CalculateSymbolContextModule())
492 return module_sp
->GetSymbolFile();
496 CompilerDeclContext
Block::GetDeclContext() {
497 if (SymbolFile
*sym_file
= GetSymbolFile())
498 return sym_file
->GetDeclContextForUID(GetID());
499 return CompilerDeclContext();
502 void Block::SetBlockInfoHasBeenParsed(bool b
, bool set_children
) {
503 m_parsed_block_info
= b
;
505 m_parsed_child_blocks
= true;
506 collection::const_iterator pos
, end
= m_children
.end();
507 for (pos
= m_children
.begin(); pos
!= end
; ++pos
)
508 (*pos
)->SetBlockInfoHasBeenParsed(b
, true);
512 void Block::SetDidParseVariables(bool b
, bool set_children
) {
513 m_parsed_block_variables
= b
;
515 collection::const_iterator pos
, end
= m_children
.end();
516 for (pos
= m_children
.begin(); pos
!= end
; ++pos
)
517 (*pos
)->SetDidParseVariables(b
, true);
521 Block
*Block::GetSibling() const {
522 if (m_parent_scope
) {
523 Block
*parent_block
= GetParent();
525 return parent_block
->GetSiblingForChild(this);
529 // A parent of child blocks can be asked to find a sibling block given
530 // one of its child blocks
531 Block
*Block::GetSiblingForChild(const Block
*child_block
) const {
532 if (!m_children
.empty()) {
533 collection::const_iterator pos
, end
= m_children
.end();
534 for (pos
= m_children
.begin(); pos
!= end
; ++pos
) {
535 if (pos
->get() == child_block
) {