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/Log.h"
21 using namespace lldb_private
;
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) {}
28 Block::~Block() = default;
30 void Block::GetDescription(Stream
*s
, Function
*function
,
31 lldb::DescriptionLevel level
, Target
*target
) const {
32 *s
<< "id = " << ((const UserID
&)*this);
34 size_t num_ranges
= m_ranges
.GetSize();
37 addr_t base_addr
= LLDB_INVALID_ADDRESS
;
40 function
->GetAddressRange().GetBaseAddress().GetLoadAddress(target
);
41 if (base_addr
== LLDB_INVALID_ADDRESS
)
42 base_addr
= function
->GetAddressRange().GetBaseAddress().GetFileAddress();
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);
52 if (m_inlineInfoSP
.get() != nullptr) {
53 bool show_fullpaths
= (level
== eDescriptionLevelVerbose
);
54 m_inlineInfoSP
->Dump(s
, show_fullpaths
);
58 void Block::Dump(Stream
*s
, addr_t base_addr
, int32_t depth
,
59 bool show_context
) const {
61 Block
*parent
= GetParent();
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
);
68 s
->Printf("%p: ", static_cast<const void *>(this));
70 *s
<< "Block" << static_cast<const UserID
&>(*this);
71 const Block
*parent_block
= GetParent();
73 s
->Printf(", parent = {0x%8.8" PRIx64
"}", parent_block
->GetID());
75 if (m_inlineInfoSP
.get() != nullptr) {
76 bool show_fullpaths
= false;
77 m_inlineInfoSP
->Dump(s
, show_fullpaths
);
80 if (!m_ranges
.IsEmpty()) {
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
))
90 DumpAddressRange(s
->AsRawOstream(), base_addr
+ range
.GetRangeBase(),
91 base_addr
+ range
.GetRangeEnd(), 4);
99 if (m_variable_list_sp
.get()) {
100 m_variable_list_sp
->Dump(s
, show_context
);
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
);
111 Block
*Block::FindBlockByID(user_id_t block_id
) {
112 if (block_id
== GetID())
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
);
122 return matching_block
;
125 Block
*Block::FindInnermostBlockByOffset(const lldb::addr_t offset
) {
126 if (!Contains(offset
))
128 for (const BlockSP
&block_sp
: m_children
) {
129 if (Block
*block
= block_sp
->FindInnermostBlockByOffset(offset
))
135 void Block::CalculateSymbolContext(SymbolContext
*sc
) {
137 m_parent_scope
->CalculateSymbolContext(sc
);
141 lldb::ModuleSP
Block::CalculateSymbolContextModule() {
143 return m_parent_scope
->CalculateSymbolContextModule();
144 return lldb::ModuleSP();
147 CompileUnit
*Block::CalculateSymbolContextCompileUnit() {
149 return m_parent_scope
->CalculateSymbolContextCompileUnit();
153 Function
*Block::CalculateSymbolContextFunction() {
155 return m_parent_scope
->CalculateSymbolContextFunction();
159 Block
*Block::CalculateSymbolContextBlock() { return this; }
161 void Block::DumpSymbolContext(Stream
*s
) {
162 Function
*function
= CalculateSymbolContextFunction();
164 function
->DumpSymbolContext(s
);
165 s
->Printf(", Block{0x%8.8" PRIx64
"}", GetID());
168 void Block::DumpAddressRanges(Stream
*s
, lldb::addr_t base_addr
) {
169 if (!m_ranges
.IsEmpty()) {
170 size_t num_ranges
= m_ranges
.GetSize();
171 for (size_t i
= 0; i
< num_ranges
; ++i
) {
172 const Range
&range
= m_ranges
.GetEntryRef(i
);
173 DumpAddressRange(s
->AsRawOstream(), base_addr
+ range
.GetRangeBase(),
174 base_addr
+ range
.GetRangeEnd(), 4);
179 bool Block::Contains(addr_t range_offset
) const {
180 return m_ranges
.FindEntryThatContains(range_offset
) != nullptr;
183 bool Block::Contains(const Block
*block
) const {
185 return false; // This block doesn't contain itself...
187 // Walk the parent chain for "block" and see if any if them match this block
188 const Block
*block_parent
;
189 for (block_parent
= block
->GetParent(); block_parent
!= nullptr;
190 block_parent
= block_parent
->GetParent()) {
191 if (this == block_parent
)
192 return true; // One of the parents of "block" is this object!
197 bool Block::Contains(const Range
&range
) const {
198 return m_ranges
.FindEntryThatContains(range
) != nullptr;
201 Block
*Block::GetParent() const {
203 return m_parent_scope
->CalculateSymbolContextBlock();
207 Block
*Block::GetContainingInlinedBlock() {
208 if (GetInlinedFunctionInfo())
210 return GetInlinedParent();
213 Block
*Block::GetInlinedParent() {
214 Block
*parent_block
= GetParent();
216 if (parent_block
->GetInlinedFunctionInfo())
219 return parent_block
->GetInlinedParent();
224 Block
*Block::GetContainingInlinedBlockWithCallSite(
225 const Declaration
&find_call_site
) {
226 Block
*inlined_block
= GetContainingInlinedBlock();
228 while (inlined_block
) {
229 const auto *function_info
= inlined_block
->GetInlinedFunctionInfo();
232 function_info
->GetCallSite().FileAndLineEqual(find_call_site
))
233 return inlined_block
;
234 inlined_block
= inlined_block
->GetInlinedParent();
239 bool Block::GetRangeContainingOffset(const addr_t offset
, Range
&range
) {
240 const Range
*range_ptr
= m_ranges
.FindEntryThatContains(offset
);
249 bool Block::GetRangeContainingAddress(const Address
&addr
,
250 AddressRange
&range
) {
251 Function
*function
= CalculateSymbolContextFunction();
253 const AddressRange
&func_range
= function
->GetAddressRange();
254 if (addr
.GetSection() == func_range
.GetBaseAddress().GetSection()) {
255 const addr_t addr_offset
= addr
.GetOffset();
256 const addr_t func_offset
= func_range
.GetBaseAddress().GetOffset();
257 if (addr_offset
>= func_offset
&&
258 addr_offset
< func_offset
+ func_range
.GetByteSize()) {
259 addr_t offset
= addr_offset
- func_offset
;
261 const Range
*range_ptr
= m_ranges
.FindEntryThatContains(offset
);
264 range
.GetBaseAddress() = func_range
.GetBaseAddress();
265 range
.GetBaseAddress().SetOffset(func_offset
+
266 range_ptr
->GetRangeBase());
267 range
.SetByteSize(range_ptr
->GetByteSize());
277 bool Block::GetRangeContainingLoadAddress(lldb::addr_t load_addr
,
278 Target
&target
, AddressRange
&range
) {
279 Address load_address
;
280 load_address
.SetLoadAddress(load_addr
, &target
);
281 AddressRange containing_range
;
282 return GetRangeContainingAddress(load_address
, containing_range
);
285 uint32_t Block::GetRangeIndexContainingAddress(const Address
&addr
) {
286 Function
*function
= CalculateSymbolContextFunction();
288 const AddressRange
&func_range
= function
->GetAddressRange();
289 if (addr
.GetSection() == func_range
.GetBaseAddress().GetSection()) {
290 const addr_t addr_offset
= addr
.GetOffset();
291 const addr_t func_offset
= func_range
.GetBaseAddress().GetOffset();
292 if (addr_offset
>= func_offset
&&
293 addr_offset
< func_offset
+ func_range
.GetByteSize()) {
294 addr_t offset
= addr_offset
- func_offset
;
295 return m_ranges
.FindEntryIndexThatContains(offset
);
302 bool Block::GetRangeAtIndex(uint32_t range_idx
, AddressRange
&range
) {
303 if (range_idx
< m_ranges
.GetSize()) {
304 Function
*function
= CalculateSymbolContextFunction();
306 const Range
&vm_range
= m_ranges
.GetEntryRef(range_idx
);
307 range
.GetBaseAddress() = function
->GetAddressRange().GetBaseAddress();
308 range
.GetBaseAddress().Slide(vm_range
.GetRangeBase());
309 range
.SetByteSize(vm_range
.GetByteSize());
316 bool Block::GetStartAddress(Address
&addr
) {
317 if (m_ranges
.IsEmpty())
320 Function
*function
= CalculateSymbolContextFunction();
322 addr
= function
->GetAddressRange().GetBaseAddress();
323 addr
.Slide(m_ranges
.GetEntryRef(0).GetRangeBase());
329 void Block::FinalizeRanges() {
331 m_ranges
.CombineConsecutiveRanges();
334 void Block::AddRange(const Range
&range
) {
335 Block
*parent_block
= GetParent();
336 if (parent_block
&& !parent_block
->Contains(range
)) {
337 Log
*log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS
));
339 ModuleSP
module_sp(m_parent_scope
->CalculateSymbolContextModule());
340 Function
*function
= m_parent_scope
->CalculateSymbolContextFunction();
341 const addr_t function_file_addr
=
342 function
->GetAddressRange().GetBaseAddress().GetFileAddress();
343 const addr_t block_start_addr
= function_file_addr
+ range
.GetRangeBase();
344 const addr_t block_end_addr
= function_file_addr
+ range
.GetRangeEnd();
345 Type
*func_type
= function
->GetType();
347 const Declaration
&func_decl
= func_type
->GetDeclaration();
348 if (func_decl
.GetLine()) {
350 "warning: %s:%u block {0x%8.8" PRIx64
351 "} has range[%u] [0x%" PRIx64
" - 0x%" PRIx64
352 ") which is not contained in parent block {0x%8.8" PRIx64
353 "} in function {0x%8.8" PRIx64
"} from %s",
354 func_decl
.GetFile().GetPath().c_str(), func_decl
.GetLine(),
355 GetID(), (uint32_t)m_ranges
.GetSize(), block_start_addr
,
356 block_end_addr
, parent_block
->GetID(), function
->GetID(),
357 module_sp
->GetFileSpec().GetPath().c_str());
360 "warning: block {0x%8.8" PRIx64
"} has range[%u] [0x%" PRIx64
362 ") which is not contained in parent block {0x%8.8" PRIx64
363 "} in function {0x%8.8" PRIx64
"} from %s",
364 GetID(), (uint32_t)m_ranges
.GetSize(), block_start_addr
,
365 block_end_addr
, parent_block
->GetID(), function
->GetID(),
366 module_sp
->GetFileSpec().GetPath().c_str());
369 parent_block
->AddRange(range
);
371 m_ranges
.Append(range
);
374 // Return the current number of bytes that this object occupies in memory
375 size_t Block::MemorySize() const {
376 size_t mem_size
= sizeof(Block
) + m_ranges
.GetSize() * sizeof(Range
);
377 if (m_inlineInfoSP
.get())
378 mem_size
+= m_inlineInfoSP
->MemorySize();
379 if (m_variable_list_sp
.get())
380 mem_size
+= m_variable_list_sp
->MemorySize();
384 void Block::AddChild(const BlockSP
&child_block_sp
) {
385 if (child_block_sp
) {
386 child_block_sp
->SetParentScope(this);
387 m_children
.push_back(child_block_sp
);
391 void Block::SetInlinedFunctionInfo(const char *name
, const char *mangled
,
392 const Declaration
*decl_ptr
,
393 const Declaration
*call_decl_ptr
) {
394 m_inlineInfoSP
= std::make_shared
<InlineFunctionInfo
>(name
, mangled
, decl_ptr
,
398 VariableListSP
Block::GetBlockVariableList(bool can_create
) {
399 if (!m_parsed_block_variables
) {
400 if (m_variable_list_sp
.get() == nullptr && can_create
) {
401 m_parsed_block_variables
= true;
403 CalculateSymbolContext(&sc
);
404 assert(sc
.module_sp
);
405 sc
.module_sp
->GetSymbolFile()->ParseVariablesForContext(sc
);
408 return m_variable_list_sp
;
412 Block::AppendBlockVariables(bool can_create
, bool get_child_block_variables
,
413 bool stop_if_child_block_is_inlined_function
,
414 const std::function
<bool(Variable
*)> &filter
,
415 VariableList
*variable_list
) {
416 uint32_t num_variables_added
= 0;
417 VariableList
*block_var_list
= GetBlockVariableList(can_create
).get();
418 if (block_var_list
) {
419 for (const VariableSP
&var_sp
: *block_var_list
) {
420 if (filter(var_sp
.get())) {
421 num_variables_added
++;
422 variable_list
->AddVariable(var_sp
);
427 if (get_child_block_variables
) {
428 collection::const_iterator pos
, end
= m_children
.end();
429 for (pos
= m_children
.begin(); pos
!= end
; ++pos
) {
430 Block
*child_block
= pos
->get();
431 if (!stop_if_child_block_is_inlined_function
||
432 child_block
->GetInlinedFunctionInfo() == nullptr) {
433 num_variables_added
+= child_block
->AppendBlockVariables(
434 can_create
, get_child_block_variables
,
435 stop_if_child_block_is_inlined_function
, filter
, variable_list
);
439 return num_variables_added
;
442 uint32_t Block::AppendVariables(bool can_create
, bool get_parent_variables
,
443 bool stop_if_block_is_inlined_function
,
444 const std::function
<bool(Variable
*)> &filter
,
445 VariableList
*variable_list
) {
446 uint32_t num_variables_added
= 0;
447 VariableListSP
variable_list_sp(GetBlockVariableList(can_create
));
449 bool is_inlined_function
= GetInlinedFunctionInfo() != nullptr;
450 if (variable_list_sp
) {
451 for (size_t i
= 0; i
< variable_list_sp
->GetSize(); ++i
) {
452 VariableSP variable
= variable_list_sp
->GetVariableAtIndex(i
);
453 if (filter(variable
.get())) {
454 num_variables_added
++;
455 variable_list
->AddVariable(variable
);
460 if (get_parent_variables
) {
461 if (stop_if_block_is_inlined_function
&& is_inlined_function
)
462 return num_variables_added
;
464 Block
*parent_block
= GetParent();
466 num_variables_added
+= parent_block
->AppendVariables(
467 can_create
, get_parent_variables
, stop_if_block_is_inlined_function
,
468 filter
, variable_list
);
470 return num_variables_added
;
473 SymbolFile
*Block::GetSymbolFile() {
474 if (ModuleSP module_sp
= CalculateSymbolContextModule())
475 return module_sp
->GetSymbolFile();
479 CompilerDeclContext
Block::GetDeclContext() {
480 if (SymbolFile
*sym_file
= GetSymbolFile())
481 return sym_file
->GetDeclContextForUID(GetID());
482 return CompilerDeclContext();
485 void Block::SetBlockInfoHasBeenParsed(bool b
, bool set_children
) {
486 m_parsed_block_info
= b
;
488 m_parsed_child_blocks
= true;
489 collection::const_iterator pos
, end
= m_children
.end();
490 for (pos
= m_children
.begin(); pos
!= end
; ++pos
)
491 (*pos
)->SetBlockInfoHasBeenParsed(b
, true);
495 void Block::SetDidParseVariables(bool b
, bool set_children
) {
496 m_parsed_block_variables
= b
;
498 collection::const_iterator pos
, end
= m_children
.end();
499 for (pos
= m_children
.begin(); pos
!= end
; ++pos
)
500 (*pos
)->SetDidParseVariables(b
, true);
504 Block
*Block::GetSibling() const {
505 if (m_parent_scope
) {
506 Block
*parent_block
= GetParent();
508 return parent_block
->GetSiblingForChild(this);
512 // A parent of child blocks can be asked to find a sibling block given
513 // one of its child blocks
514 Block
*Block::GetSiblingForChild(const Block
*child_block
) const {
515 if (!m_children
.empty()) {
516 collection::const_iterator pos
, end
= m_children
.end();
517 for (pos
= m_children
.begin(); pos
!= end
; ++pos
) {
518 if (pos
->get() == child_block
) {