1 | //===-- Block.cpp ---------------------------------------------------------===// |
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/LLDBLog.h" |
17 | #include "lldb/Utility/Log.h" |
18 | |
19 | #include <memory> |
20 | |
21 | using namespace lldb; |
22 | using namespace lldb_private; |
23 | |
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) {} |
28 | |
29 | Block::~Block() = default; |
30 | |
31 | void Block::GetDescription(Stream *s, Function *function, |
32 | lldb::DescriptionLevel level, Target *target) const { |
33 | *s << "id = " << ((const UserID &)*this); |
34 | |
35 | size_t num_ranges = m_ranges.GetSize(); |
36 | if (num_ranges > 0) { |
37 | |
38 | addr_t base_addr = LLDB_INVALID_ADDRESS; |
39 | if (target) |
40 | base_addr = |
41 | function->GetAddressRange().GetBaseAddress().GetLoadAddress(target); |
42 | if (base_addr == LLDB_INVALID_ADDRESS) |
43 | base_addr = function->GetAddressRange().GetBaseAddress().GetFileAddress(); |
44 | |
45 | s->Printf(format: ", 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&: s->AsRawOstream(), lo_addr: base_addr + range.GetRangeBase(), |
49 | hi_addr: base_addr + range.GetRangeEnd(), addr_size: 4); |
50 | } |
51 | } |
52 | |
53 | if (m_inlineInfoSP.get() != nullptr) { |
54 | bool show_fullpaths = (level == eDescriptionLevelVerbose); |
55 | m_inlineInfoSP->Dump(s, show_fullpaths); |
56 | } |
57 | } |
58 | |
59 | void Block::Dump(Stream *s, addr_t base_addr, int32_t depth, |
60 | bool show_context) const { |
61 | if (depth < 0) { |
62 | Block *parent = GetParent(); |
63 | if (parent) { |
64 | // We have a depth that is less than zero, print our parent blocks first |
65 | parent->Dump(s, base_addr, depth: depth + 1, show_context); |
66 | } |
67 | } |
68 | |
69 | s->Printf(format: "%p: " , static_cast<const void *>(this)); |
70 | s->Indent(); |
71 | *s << "Block" << static_cast<const UserID &>(*this); |
72 | const Block *parent_block = GetParent(); |
73 | if (parent_block) { |
74 | s->Printf(format: ", parent = {0x%8.8" PRIx64 "}" , parent_block->GetID()); |
75 | } |
76 | if (m_inlineInfoSP.get() != nullptr) { |
77 | bool show_fullpaths = false; |
78 | m_inlineInfoSP->Dump(s, show_fullpaths); |
79 | } |
80 | |
81 | if (!m_ranges.IsEmpty()) { |
82 | *s << ", ranges =" ; |
83 | |
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)) |
88 | *s << '!'; |
89 | else |
90 | *s << ' '; |
91 | DumpAddressRange(s&: s->AsRawOstream(), lo_addr: base_addr + range.GetRangeBase(), |
92 | hi_addr: base_addr + range.GetRangeEnd(), addr_size: 4); |
93 | } |
94 | } |
95 | s->EOL(); |
96 | |
97 | if (depth > 0) { |
98 | s->IndentMore(); |
99 | |
100 | if (m_variable_list_sp.get()) { |
101 | m_variable_list_sp->Dump(s, show_context); |
102 | } |
103 | |
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: depth - 1, show_context); |
107 | |
108 | s->IndentLess(); |
109 | } |
110 | } |
111 | |
112 | Block *Block::FindBlockByID(user_id_t block_id) { |
113 | if (block_id == GetID()) |
114 | return this; |
115 | |
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); |
120 | if (matching_block) |
121 | break; |
122 | } |
123 | return matching_block; |
124 | } |
125 | |
126 | Block *Block::FindInnermostBlockByOffset(const lldb::addr_t offset) { |
127 | if (!Contains(range_offset: offset)) |
128 | return nullptr; |
129 | for (const BlockSP &block_sp : m_children) { |
130 | if (Block *block = block_sp->FindInnermostBlockByOffset(offset)) |
131 | return block; |
132 | } |
133 | return this; |
134 | } |
135 | |
136 | void Block::CalculateSymbolContext(SymbolContext *sc) { |
137 | if (m_parent_scope) |
138 | m_parent_scope->CalculateSymbolContext(sc); |
139 | sc->block = this; |
140 | } |
141 | |
142 | lldb::ModuleSP Block::CalculateSymbolContextModule() { |
143 | if (m_parent_scope) |
144 | return m_parent_scope->CalculateSymbolContextModule(); |
145 | return lldb::ModuleSP(); |
146 | } |
147 | |
148 | CompileUnit *Block::CalculateSymbolContextCompileUnit() { |
149 | if (m_parent_scope) |
150 | return m_parent_scope->CalculateSymbolContextCompileUnit(); |
151 | return nullptr; |
152 | } |
153 | |
154 | Function *Block::CalculateSymbolContextFunction() { |
155 | if (m_parent_scope) |
156 | return m_parent_scope->CalculateSymbolContextFunction(); |
157 | return nullptr; |
158 | } |
159 | |
160 | Block *Block::CalculateSymbolContextBlock() { return this; } |
161 | |
162 | void Block::DumpSymbolContext(Stream *s) { |
163 | Function *function = CalculateSymbolContextFunction(); |
164 | if (function) |
165 | function->DumpSymbolContext(s); |
166 | s->Printf(format: ", Block{0x%8.8" PRIx64 "}" , GetID()); |
167 | } |
168 | |
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&: s->AsRawOstream(), lo_addr: base_addr + range.GetRangeBase(), |
175 | hi_addr: base_addr + range.GetRangeEnd(), addr_size: 4); |
176 | } |
177 | } |
178 | } |
179 | |
180 | bool Block::Contains(addr_t range_offset) const { |
181 | return m_ranges.FindEntryThatContains(addr: range_offset) != nullptr; |
182 | } |
183 | |
184 | bool Block::Contains(const Block *block) const { |
185 | if (this == block) |
186 | return false; // This block doesn't contain itself... |
187 | |
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! |
194 | } |
195 | return false; |
196 | } |
197 | |
198 | bool Block::Contains(const Range &range) const { |
199 | return m_ranges.FindEntryThatContains(range) != nullptr; |
200 | } |
201 | |
202 | Block *Block::GetParent() const { |
203 | if (m_parent_scope) |
204 | return m_parent_scope->CalculateSymbolContextBlock(); |
205 | return nullptr; |
206 | } |
207 | |
208 | Block *Block::GetContainingInlinedBlock() { |
209 | if (GetInlinedFunctionInfo()) |
210 | return this; |
211 | return GetInlinedParent(); |
212 | } |
213 | |
214 | Block *Block::GetInlinedParent() { |
215 | Block *parent_block = GetParent(); |
216 | if (parent_block) { |
217 | if (parent_block->GetInlinedFunctionInfo()) |
218 | return parent_block; |
219 | else |
220 | return parent_block->GetInlinedParent(); |
221 | } |
222 | return nullptr; |
223 | } |
224 | |
225 | Block *Block::GetContainingInlinedBlockWithCallSite( |
226 | const Declaration &find_call_site) { |
227 | Block *inlined_block = GetContainingInlinedBlock(); |
228 | |
229 | while (inlined_block) { |
230 | const auto *function_info = inlined_block->GetInlinedFunctionInfo(); |
231 | |
232 | if (function_info && |
233 | function_info->GetCallSite().FileAndLineEqual(declaration: find_call_site)) |
234 | return inlined_block; |
235 | inlined_block = inlined_block->GetInlinedParent(); |
236 | } |
237 | return nullptr; |
238 | } |
239 | |
240 | bool Block::GetRangeContainingOffset(const addr_t offset, Range &range) { |
241 | const Range *range_ptr = m_ranges.FindEntryThatContains(addr: offset); |
242 | if (range_ptr) { |
243 | range = *range_ptr; |
244 | return true; |
245 | } |
246 | range.Clear(); |
247 | return false; |
248 | } |
249 | |
250 | bool Block::GetRangeContainingAddress(const Address &addr, |
251 | AddressRange &range) { |
252 | Function *function = CalculateSymbolContextFunction(); |
253 | if (function) { |
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; |
261 | |
262 | const Range *range_ptr = m_ranges.FindEntryThatContains(addr: offset); |
263 | |
264 | if (range_ptr) { |
265 | range.GetBaseAddress() = func_range.GetBaseAddress(); |
266 | range.GetBaseAddress().SetOffset(func_offset + |
267 | range_ptr->GetRangeBase()); |
268 | range.SetByteSize(range_ptr->GetByteSize()); |
269 | return true; |
270 | } |
271 | } |
272 | } |
273 | } |
274 | range.Clear(); |
275 | return false; |
276 | } |
277 | |
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: &target); |
282 | AddressRange containing_range; |
283 | return GetRangeContainingAddress(addr: load_address, range&: containing_range); |
284 | } |
285 | |
286 | uint32_t Block::GetRangeIndexContainingAddress(const Address &addr) { |
287 | Function *function = CalculateSymbolContextFunction(); |
288 | if (function) { |
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(addr: offset); |
297 | } |
298 | } |
299 | } |
300 | return UINT32_MAX; |
301 | } |
302 | |
303 | bool Block::GetRangeAtIndex(uint32_t range_idx, AddressRange &range) { |
304 | if (range_idx < m_ranges.GetSize()) { |
305 | Function *function = CalculateSymbolContextFunction(); |
306 | if (function) { |
307 | const Range &vm_range = m_ranges.GetEntryRef(i: range_idx); |
308 | range.GetBaseAddress() = function->GetAddressRange().GetBaseAddress(); |
309 | range.GetBaseAddress().Slide(offset: vm_range.GetRangeBase()); |
310 | range.SetByteSize(vm_range.GetByteSize()); |
311 | return true; |
312 | } |
313 | } |
314 | return false; |
315 | } |
316 | |
317 | bool Block::GetStartAddress(Address &addr) { |
318 | if (m_ranges.IsEmpty()) |
319 | return false; |
320 | |
321 | Function *function = CalculateSymbolContextFunction(); |
322 | if (function) { |
323 | addr = function->GetAddressRange().GetBaseAddress(); |
324 | addr.Slide(offset: m_ranges.GetEntryRef(i: 0).GetRangeBase()); |
325 | return true; |
326 | } |
327 | return false; |
328 | } |
329 | |
330 | void Block::FinalizeRanges() { |
331 | m_ranges.Sort(); |
332 | m_ranges.CombineConsecutiveRanges(); |
333 | } |
334 | |
335 | void Block::AddRange(const Range &range) { |
336 | Block *parent_block = GetParent(); |
337 | if (parent_block && !parent_block->Contains(range)) { |
338 | Log *log = GetLog(mask: LLDBLog::Symbols); |
339 | if (log) { |
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(); |
347 | |
348 | const Declaration &func_decl = func_type->GetDeclaration(); |
349 | if (func_decl.GetLine()) { |
350 | LLDB_LOGF(log, |
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()); |
359 | } else { |
360 | LLDB_LOGF(log, |
361 | "warning: block {0x%8.8" PRIx64 "} has range[%u] [0x%" PRIx64 |
362 | " - 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()); |
368 | } |
369 | } |
370 | parent_block->AddRange(range); |
371 | } |
372 | m_ranges.Append(entry: range); |
373 | } |
374 | |
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(); |
382 | return mem_size; |
383 | } |
384 | |
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(x: child_block_sp); |
389 | } |
390 | } |
391 | |
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>(args&: name, args&: mangled, args&: decl_ptr, |
396 | args&: call_decl_ptr); |
397 | } |
398 | |
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; |
403 | SymbolContext sc; |
404 | CalculateSymbolContext(sc: &sc); |
405 | assert(sc.module_sp); |
406 | sc.module_sp->GetSymbolFile()->ParseVariablesForContext(sc); |
407 | } |
408 | } |
409 | return m_variable_list_sp; |
410 | } |
411 | |
412 | uint32_t |
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); |
424 | } |
425 | } |
426 | } |
427 | |
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); |
437 | } |
438 | } |
439 | } |
440 | return num_variables_added; |
441 | } |
442 | |
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)); |
449 | |
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(idx: i); |
454 | if (filter(variable.get())) { |
455 | num_variables_added++; |
456 | variable_list->AddVariable(var_sp: variable); |
457 | } |
458 | } |
459 | } |
460 | |
461 | if (get_parent_variables) { |
462 | if (stop_if_block_is_inlined_function && is_inlined_function) |
463 | return num_variables_added; |
464 | |
465 | Block *parent_block = GetParent(); |
466 | if (parent_block) |
467 | num_variables_added += parent_block->AppendVariables( |
468 | can_create, get_parent_variables, stop_if_block_is_inlined_function, |
469 | filter, variable_list); |
470 | } |
471 | return num_variables_added; |
472 | } |
473 | |
474 | SymbolFile *Block::GetSymbolFile() { |
475 | if (ModuleSP module_sp = CalculateSymbolContextModule()) |
476 | return module_sp->GetSymbolFile(); |
477 | return nullptr; |
478 | } |
479 | |
480 | CompilerDeclContext Block::GetDeclContext() { |
481 | if (SymbolFile *sym_file = GetSymbolFile()) |
482 | return sym_file->GetDeclContextForUID(uid: GetID()); |
483 | return CompilerDeclContext(); |
484 | } |
485 | |
486 | void Block::SetBlockInfoHasBeenParsed(bool b, bool set_children) { |
487 | m_parsed_block_info = b; |
488 | if (set_children) { |
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, set_children: true); |
493 | } |
494 | } |
495 | |
496 | void Block::SetDidParseVariables(bool b, bool set_children) { |
497 | m_parsed_block_variables = b; |
498 | if (set_children) { |
499 | collection::const_iterator pos, end = m_children.end(); |
500 | for (pos = m_children.begin(); pos != end; ++pos) |
501 | (*pos)->SetDidParseVariables(b, set_children: true); |
502 | } |
503 | } |
504 | |
505 | Block *Block::GetSibling() const { |
506 | if (m_parent_scope) { |
507 | Block *parent_block = GetParent(); |
508 | if (parent_block) |
509 | return parent_block->GetSiblingForChild(child_block: this); |
510 | } |
511 | return nullptr; |
512 | } |
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) { |
520 | if (++pos != end) |
521 | return pos->get(); |
522 | break; |
523 | } |
524 | } |
525 | } |
526 | return nullptr; |
527 | } |
528 | |