1 //===-- SBBlock.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/API/SBBlock.h"
10 #include "lldb/API/SBAddress.h"
11 #include "lldb/API/SBFileSpec.h"
12 #include "lldb/API/SBFrame.h"
13 #include "lldb/API/SBStream.h"
14 #include "lldb/API/SBValue.h"
15 #include "lldb/Core/AddressRange.h"
16 #include "lldb/Core/ValueObjectVariable.h"
17 #include "lldb/Symbol/Block.h"
18 #include "lldb/Symbol/Function.h"
19 #include "lldb/Symbol/SymbolContext.h"
20 #include "lldb/Symbol/VariableList.h"
21 #include "lldb/Target/StackFrame.h"
22 #include "lldb/Target/Target.h"
23 #include "lldb/Utility/Instrumentation.h"
24 
25 using namespace lldb;
26 using namespace lldb_private;
27 
28 SBBlock::SBBlock() { LLDB_INSTRUMENT_VA(this); }
29 
30 SBBlock::SBBlock(lldb_private::Block *lldb_object_ptr)
31     : m_opaque_ptr(lldb_object_ptr) {}
32 
33 SBBlock::SBBlock(const SBBlock &rhs) : m_opaque_ptr(rhs.m_opaque_ptr) {
34   LLDB_INSTRUMENT_VA(this, rhs);
35 }
36 
37 const SBBlock &SBBlock::operator=(const SBBlock &rhs) {
38   LLDB_INSTRUMENT_VA(this, rhs);
39 
40   m_opaque_ptr = rhs.m_opaque_ptr;
41   return *this;
42 }
43 
44 SBBlock::~SBBlock() { m_opaque_ptr = nullptr; }
45 
46 bool SBBlock::IsValid() const {
47   LLDB_INSTRUMENT_VA(this);
48   return this->operator bool();
49 }
50 SBBlock::operator bool() const {
51   LLDB_INSTRUMENT_VA(this);
52 
53   return m_opaque_ptr != nullptr;
54 }
55 
56 bool SBBlock::IsInlined() const {
57   LLDB_INSTRUMENT_VA(this);
58 
59   if (m_opaque_ptr)
60     return m_opaque_ptr->GetInlinedFunctionInfo() != nullptr;
61   return false;
62 }
63 
64 const char *SBBlock::GetInlinedName() const {
65   LLDB_INSTRUMENT_VA(this);
66 
67   if (m_opaque_ptr) {
68     const InlineFunctionInfo *inlined_info =
69         m_opaque_ptr->GetInlinedFunctionInfo();
70     if (inlined_info) {
71       return inlined_info->GetName().AsCString(nullptr);
72     }
73   }
74   return nullptr;
75 }
76 
77 SBFileSpec SBBlock::GetInlinedCallSiteFile() const {
78   LLDB_INSTRUMENT_VA(this);
79 
80   SBFileSpec sb_file;
81   if (m_opaque_ptr) {
82     const InlineFunctionInfo *inlined_info =
83         m_opaque_ptr->GetInlinedFunctionInfo();
84     if (inlined_info)
85       sb_file.SetFileSpec(inlined_info->GetCallSite().GetFile());
86   }
87   return sb_file;
88 }
89 
90 uint32_t SBBlock::GetInlinedCallSiteLine() const {
91   LLDB_INSTRUMENT_VA(this);
92 
93   if (m_opaque_ptr) {
94     const InlineFunctionInfo *inlined_info =
95         m_opaque_ptr->GetInlinedFunctionInfo();
96     if (inlined_info)
97       return inlined_info->GetCallSite().GetLine();
98   }
99   return 0;
100 }
101 
102 uint32_t SBBlock::GetInlinedCallSiteColumn() const {
103   LLDB_INSTRUMENT_VA(this);
104 
105   if (m_opaque_ptr) {
106     const InlineFunctionInfo *inlined_info =
107         m_opaque_ptr->GetInlinedFunctionInfo();
108     if (inlined_info)
109       return inlined_info->GetCallSite().GetColumn();
110   }
111   return 0;
112 }
113 
114 void SBBlock::AppendVariables(bool can_create, bool get_parent_variables,
115                               lldb_private::VariableList *var_list) {
116   if (IsValid()) {
117     bool show_inline = true;
118     m_opaque_ptr->AppendVariables(can_create, get_parent_variables, show_inline,
119                                   [](Variable *) { return true; }, var_list);
120   }
121 }
122 
123 SBBlock SBBlock::GetParent() {
124   LLDB_INSTRUMENT_VA(this);
125 
126   SBBlock sb_block;
127   if (m_opaque_ptr)
128     sb_block.m_opaque_ptr = m_opaque_ptr->GetParent();
129   return sb_block;
130 }
131 
132 lldb::SBBlock SBBlock::GetContainingInlinedBlock() {
133   LLDB_INSTRUMENT_VA(this);
134 
135   SBBlock sb_block;
136   if (m_opaque_ptr)
137     sb_block.m_opaque_ptr = m_opaque_ptr->GetContainingInlinedBlock();
138   return sb_block;
139 }
140 
141 SBBlock SBBlock::GetSibling() {
142   LLDB_INSTRUMENT_VA(this);
143 
144   SBBlock sb_block;
145   if (m_opaque_ptr)
146     sb_block.m_opaque_ptr = m_opaque_ptr->GetSibling();
147   return sb_block;
148 }
149 
150 SBBlock SBBlock::GetFirstChild() {
151   LLDB_INSTRUMENT_VA(this);
152 
153   SBBlock sb_block;
154   if (m_opaque_ptr)
155     sb_block.m_opaque_ptr = m_opaque_ptr->GetFirstChild();
156   return sb_block;
157 }
158 
159 lldb_private::Block *SBBlock::GetPtr() { return m_opaque_ptr; }
160 
161 void SBBlock::SetPtr(lldb_private::Block *block) { m_opaque_ptr = block; }
162 
163 bool SBBlock::GetDescription(SBStream &description) {
164   LLDB_INSTRUMENT_VA(this, description);
165 
166   Stream &strm = description.ref();
167 
168   if (m_opaque_ptr) {
169     lldb::user_id_t id = m_opaque_ptr->GetID();
170     strm.Printf("Block: {id: %" PRIu64 "} ", id);
171     if (IsInlined()) {
172       strm.Printf(" (inlined, '%s') ", GetInlinedName());
173     }
174     lldb_private::SymbolContext sc;
175     m_opaque_ptr->CalculateSymbolContext(&sc);
176     if (sc.function) {
177       m_opaque_ptr->DumpAddressRanges(
178           &strm,
179           sc.function->GetAddressRange().GetBaseAddress().GetFileAddress());
180     }
181   } else
182     strm.PutCString("No value");
183 
184   return true;
185 }
186 
187 uint32_t SBBlock::GetNumRanges() {
188   LLDB_INSTRUMENT_VA(this);
189 
190   if (m_opaque_ptr)
191     return m_opaque_ptr->GetNumRanges();
192   return 0;
193 }
194 
195 lldb::SBAddress SBBlock::GetRangeStartAddress(uint32_t idx) {
196   LLDB_INSTRUMENT_VA(this, idx);
197 
198   lldb::SBAddress sb_addr;
199   if (m_opaque_ptr) {
200     AddressRange range;
201     if (m_opaque_ptr->GetRangeAtIndex(idx, range)) {
202       sb_addr.ref() = range.GetBaseAddress();
203     }
204   }
205   return sb_addr;
206 }
207 
208 lldb::SBAddress SBBlock::GetRangeEndAddress(uint32_t idx) {
209   LLDB_INSTRUMENT_VA(this, idx);
210 
211   lldb::SBAddress sb_addr;
212   if (m_opaque_ptr) {
213     AddressRange range;
214     if (m_opaque_ptr->GetRangeAtIndex(idx, range)) {
215       sb_addr.ref() = range.GetBaseAddress();
216       sb_addr.ref().Slide(range.GetByteSize());
217     }
218   }
219   return sb_addr;
220 }
221 
222 uint32_t SBBlock::GetRangeIndexForBlockAddress(lldb::SBAddress block_addr) {
223   LLDB_INSTRUMENT_VA(this, block_addr);
224 
225   if (m_opaque_ptr && block_addr.IsValid()) {
226     return m_opaque_ptr->GetRangeIndexContainingAddress(block_addr.ref());
227   }
228 
229   return UINT32_MAX;
230 }
231 
232 lldb::SBValueList SBBlock::GetVariables(lldb::SBFrame &frame, bool arguments,
233                                         bool locals, bool statics,
234                                         lldb::DynamicValueType use_dynamic) {
235   LLDB_INSTRUMENT_VA(this, frame, arguments, locals, statics, use_dynamic);
236 
237   Block *block = GetPtr();
238   SBValueList value_list;
239   if (block) {
240     StackFrameSP frame_sp(frame.GetFrameSP());
241     VariableListSP variable_list_sp(block->GetBlockVariableList(true));
242 
243     if (variable_list_sp) {
244       const size_t num_variables = variable_list_sp->GetSize();
245       if (num_variables) {
246         for (size_t i = 0; i < num_variables; ++i) {
247           VariableSP variable_sp(variable_list_sp->GetVariableAtIndex(i));
248           if (variable_sp) {
249             bool add_variable = false;
250             switch (variable_sp->GetScope()) {
251             case eValueTypeVariableGlobal:
252             case eValueTypeVariableStatic:
253             case eValueTypeVariableThreadLocal:
254               add_variable = statics;
255               break;
256 
257             case eValueTypeVariableArgument:
258               add_variable = arguments;
259               break;
260 
261             case eValueTypeVariableLocal:
262               add_variable = locals;
263               break;
264 
265             default:
266               break;
267             }
268             if (add_variable) {
269               if (frame_sp) {
270                 lldb::ValueObjectSP valobj_sp(
271                     frame_sp->GetValueObjectForFrameVariable(variable_sp,
272                                                              eNoDynamicValues));
273                 SBValue value_sb;
274                 value_sb.SetSP(valobj_sp, use_dynamic);
275                 value_list.Append(value_sb);
276               }
277             }
278           }
279         }
280       }
281     }
282   }
283   return value_list;
284 }
285 
286 lldb::SBValueList SBBlock::GetVariables(lldb::SBTarget &target, bool arguments,
287                                         bool locals, bool statics) {
288   LLDB_INSTRUMENT_VA(this, target, arguments, locals, statics);
289 
290   Block *block = GetPtr();
291 
292   SBValueList value_list;
293   if (block) {
294     TargetSP target_sp(target.GetSP());
295 
296     VariableListSP variable_list_sp(block->GetBlockVariableList(true));
297 
298     if (variable_list_sp) {
299       const size_t num_variables = variable_list_sp->GetSize();
300       if (num_variables) {
301         for (size_t i = 0; i < num_variables; ++i) {
302           VariableSP variable_sp(variable_list_sp->GetVariableAtIndex(i));
303           if (variable_sp) {
304             bool add_variable = false;
305             switch (variable_sp->GetScope()) {
306             case eValueTypeVariableGlobal:
307             case eValueTypeVariableStatic:
308             case eValueTypeVariableThreadLocal:
309               add_variable = statics;
310               break;
311 
312             case eValueTypeVariableArgument:
313               add_variable = arguments;
314               break;
315 
316             case eValueTypeVariableLocal:
317               add_variable = locals;
318               break;
319 
320             default:
321               break;
322             }
323             if (add_variable) {
324               if (target_sp)
325                 value_list.Append(
326                     ValueObjectVariable::Create(target_sp.get(), variable_sp));
327             }
328           }
329         }
330       }
331     }
332   }
333   return value_list;
334 }
335