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
))
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 bool Block::GetStartAddress(Address
&addr
) {
318 if (m_ranges
.IsEmpty())
321 Function
*function
= CalculateSymbolContextFunction();
323 addr
= function
->GetAddressRange().GetBaseAddress();
324 addr
.Slide(m_ranges
.GetEntryRef(0).GetRangeBase());
330 void Block::FinalizeRanges() {
332 m_ranges
.CombineConsecutiveRanges();
335 void Block::AddRange(const Range
&range
) {
336 Block
*parent_block
= GetParent();
337 if (parent_block
&& !parent_block
->Contains(range
)) {
338 Log
*log
= GetLog(LLDBLog::Symbols
);
340 ModuleSP
module_sp(m_parent_scope
->CalculateSymbolContextModule());
341 Function
*function
= m_parent_scope
->CalculateSymbolContextFunction();
342 const addr_t function_file_addr
=
343 function
->GetAddressRange().GetBaseAddress().GetFileAddress();
344 const addr_t block_start_addr
= function_file_addr
+ range
.GetRangeBase();
345 const addr_t block_end_addr
= function_file_addr
+ range
.GetRangeEnd();
346 Type
*func_type
= function
->GetType();
348 const Declaration
&func_decl
= func_type
->GetDeclaration();
349 if (func_decl
.GetLine()) {
351 "warning: %s:%u block {0x%8.8" PRIx64
352 "} has range[%u] [0x%" PRIx64
" - 0x%" PRIx64
353 ") which is not contained in parent block {0x%8.8" PRIx64
354 "} in function {0x%8.8" PRIx64
"} from %s",
355 func_decl
.GetFile().GetPath().c_str(), func_decl
.GetLine(),
356 GetID(), (uint32_t)m_ranges
.GetSize(), block_start_addr
,
357 block_end_addr
, parent_block
->GetID(), function
->GetID(),
358 module_sp
->GetFileSpec().GetPath().c_str());
361 "warning: block {0x%8.8" PRIx64
"} has range[%u] [0x%" PRIx64
363 ") which is not contained in parent block {0x%8.8" PRIx64
364 "} in function {0x%8.8" PRIx64
"} from %s",
365 GetID(), (uint32_t)m_ranges
.GetSize(), block_start_addr
,
366 block_end_addr
, parent_block
->GetID(), function
->GetID(),
367 module_sp
->GetFileSpec().GetPath().c_str());
370 parent_block
->AddRange(range
);
372 m_ranges
.Append(range
);
375 // Return the current number of bytes that this object occupies in memory
376 size_t Block::MemorySize() const {
377 size_t mem_size
= sizeof(Block
) + m_ranges
.GetSize() * sizeof(Range
);
378 if (m_inlineInfoSP
.get())
379 mem_size
+= m_inlineInfoSP
->MemorySize();
380 if (m_variable_list_sp
.get())
381 mem_size
+= m_variable_list_sp
->MemorySize();
385 void Block::AddChild(const BlockSP
&child_block_sp
) {
386 if (child_block_sp
) {
387 child_block_sp
->SetParentScope(this);
388 m_children
.push_back(child_block_sp
);
392 void Block::SetInlinedFunctionInfo(const char *name
, const char *mangled
,
393 const Declaration
*decl_ptr
,
394 const Declaration
*call_decl_ptr
) {
395 m_inlineInfoSP
= std::make_shared
<InlineFunctionInfo
>(name
, mangled
, decl_ptr
,
399 VariableListSP
Block::GetBlockVariableList(bool can_create
) {
400 if (!m_parsed_block_variables
) {
401 if (m_variable_list_sp
.get() == nullptr && can_create
) {
402 m_parsed_block_variables
= true;
404 CalculateSymbolContext(&sc
);
405 assert(sc
.module_sp
);
406 sc
.module_sp
->GetSymbolFile()->ParseVariablesForContext(sc
);
409 return m_variable_list_sp
;
413 Block::AppendBlockVariables(bool can_create
, bool get_child_block_variables
,
414 bool stop_if_child_block_is_inlined_function
,
415 const std::function
<bool(Variable
*)> &filter
,
416 VariableList
*variable_list
) {
417 uint32_t num_variables_added
= 0;
418 VariableList
*block_var_list
= GetBlockVariableList(can_create
).get();
419 if (block_var_list
) {
420 for (const VariableSP
&var_sp
: *block_var_list
) {
421 if (filter(var_sp
.get())) {
422 num_variables_added
++;
423 variable_list
->AddVariable(var_sp
);
428 if (get_child_block_variables
) {
429 collection::const_iterator pos
, end
= m_children
.end();
430 for (pos
= m_children
.begin(); pos
!= end
; ++pos
) {
431 Block
*child_block
= pos
->get();
432 if (!stop_if_child_block_is_inlined_function
||
433 child_block
->GetInlinedFunctionInfo() == nullptr) {
434 num_variables_added
+= child_block
->AppendBlockVariables(
435 can_create
, get_child_block_variables
,
436 stop_if_child_block_is_inlined_function
, filter
, variable_list
);
440 return num_variables_added
;
443 uint32_t Block::AppendVariables(bool can_create
, bool get_parent_variables
,
444 bool stop_if_block_is_inlined_function
,
445 const std::function
<bool(Variable
*)> &filter
,
446 VariableList
*variable_list
) {
447 uint32_t num_variables_added
= 0;
448 VariableListSP
variable_list_sp(GetBlockVariableList(can_create
));
450 bool is_inlined_function
= GetInlinedFunctionInfo() != nullptr;
451 if (variable_list_sp
) {
452 for (size_t i
= 0; i
< variable_list_sp
->GetSize(); ++i
) {
453 VariableSP variable
= variable_list_sp
->GetVariableAtIndex(i
);
454 if (filter(variable
.get())) {
455 num_variables_added
++;
456 variable_list
->AddVariable(variable
);
461 if (get_parent_variables
) {
462 if (stop_if_block_is_inlined_function
&& is_inlined_function
)
463 return num_variables_added
;
465 Block
*parent_block
= GetParent();
467 num_variables_added
+= parent_block
->AppendVariables(
468 can_create
, get_parent_variables
, stop_if_block_is_inlined_function
,
469 filter
, variable_list
);
471 return num_variables_added
;
474 SymbolFile
*Block::GetSymbolFile() {
475 if (ModuleSP module_sp
= CalculateSymbolContextModule())
476 return module_sp
->GetSymbolFile();
480 CompilerDeclContext
Block::GetDeclContext() {
481 if (SymbolFile
*sym_file
= GetSymbolFile())
482 return sym_file
->GetDeclContextForUID(GetID());
483 return CompilerDeclContext();
486 void Block::SetBlockInfoHasBeenParsed(bool b
, bool set_children
) {
487 m_parsed_block_info
= b
;
489 m_parsed_child_blocks
= true;
490 collection::const_iterator pos
, end
= m_children
.end();
491 for (pos
= m_children
.begin(); pos
!= end
; ++pos
)
492 (*pos
)->SetBlockInfoHasBeenParsed(b
, true);
496 void Block::SetDidParseVariables(bool b
, bool set_children
) {
497 m_parsed_block_variables
= b
;
499 collection::const_iterator pos
, end
= m_children
.end();
500 for (pos
= m_children
.begin(); pos
!= end
; ++pos
)
501 (*pos
)->SetDidParseVariables(b
, true);
505 Block
*Block::GetSibling() const {
506 if (m_parent_scope
) {
507 Block
*parent_block
= GetParent();
509 return parent_block
->GetSiblingForChild(this);
513 // A parent of child blocks can be asked to find a sibling block given
514 // one of its child blocks
515 Block
*Block::GetSiblingForChild(const Block
*child_block
) const {
516 if (!m_children
.empty()) {
517 collection::const_iterator pos
, end
= m_children
.end();
518 for (pos
= m_children
.begin(); pos
!= end
; ++pos
) {
519 if (pos
->get() == child_block
) {