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