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