Coverage Report

Created: 2023-09-30 09:22

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- LibStdcpp.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 "LibStdcpp.h"
10
#include "LibCxx.h"
11
12
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
13
#include "lldb/Core/ValueObject.h"
14
#include "lldb/Core/ValueObjectConstResult.h"
15
#include "lldb/DataFormatters/StringPrinter.h"
16
#include "lldb/DataFormatters/VectorIterator.h"
17
#include "lldb/Target/Target.h"
18
#include "lldb/Utility/DataBufferHeap.h"
19
#include "lldb/Utility/Endian.h"
20
#include "lldb/Utility/Status.h"
21
#include "lldb/Utility/Stream.h"
22
#include <optional>
23
24
using namespace lldb;
25
using namespace lldb_private;
26
using namespace lldb_private::formatters;
27
28
namespace {
29
30
class LibstdcppMapIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
31
  /*
32
   (std::_Rb_tree_iterator<std::pair<const int, std::basic_string<char,
33
   std::char_traits<char>, std::allocator<char> > > >) ibeg = {
34
   (_Base_ptr) _M_node = 0x0000000100103910 {
35
   (std::_Rb_tree_color) _M_color = _S_black
36
   (std::_Rb_tree_node_base::_Base_ptr) _M_parent = 0x00000001001038c0
37
   (std::_Rb_tree_node_base::_Base_ptr) _M_left = 0x0000000000000000
38
   (std::_Rb_tree_node_base::_Base_ptr) _M_right = 0x0000000000000000
39
   }
40
   }
41
   */
42
43
public:
44
  explicit LibstdcppMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
45
46
  size_t CalculateNumChildren() override;
47
48
  lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
49
50
  bool Update() override;
51
52
  bool MightHaveChildren() override;
53
54
  size_t GetIndexOfChildWithName(ConstString name) override;
55
56
private:
57
  ExecutionContextRef m_exe_ctx_ref;
58
  lldb::addr_t m_pair_address = 0;
59
  CompilerType m_pair_type;
60
  lldb::ValueObjectSP m_pair_sp;
61
};
62
63
class LibStdcppSharedPtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
64
public:
65
  explicit LibStdcppSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
66
67
  size_t CalculateNumChildren() override;
68
69
  lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
70
71
  bool Update() override;
72
73
  bool MightHaveChildren() override;
74
75
  size_t GetIndexOfChildWithName(ConstString name) override;
76
private:
77
78
  // The lifetime of a ValueObject and all its derivative ValueObjects
79
  // (children, clones, etc.) is managed by a ClusterManager. These
80
  // objects are only destroyed when every shared pointer to any of them
81
  // is destroyed, so we must not store a shared pointer to any ValueObject
82
  // derived from our backend ValueObject (since we're in the same cluster).
83
  ValueObject* m_ptr_obj = nullptr; // Underlying pointer (held, not owned)
84
  ValueObject* m_obj_obj = nullptr; // Underlying object (held, not owned)
85
};
86
87
} // end of anonymous namespace
88
89
LibstdcppMapIteratorSyntheticFrontEnd::LibstdcppMapIteratorSyntheticFrontEnd(
90
    lldb::ValueObjectSP valobj_sp)
91
0
    : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_pair_type(),
92
0
      m_pair_sp() {
93
0
  if (valobj_sp)
94
0
    Update();
95
0
}
96
97
0
bool LibstdcppMapIteratorSyntheticFrontEnd::Update() {
98
0
  ValueObjectSP valobj_sp = m_backend.GetSP();
99
0
  if (!valobj_sp)
100
0
    return false;
101
102
0
  TargetSP target_sp(valobj_sp->GetTargetSP());
103
104
0
  if (!target_sp)
105
0
    return false;
106
107
0
  bool is_64bit = (target_sp->GetArchitecture().GetAddressByteSize() == 8);
108
109
0
  if (!valobj_sp)
110
0
    return false;
111
0
  m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
112
113
0
  ValueObjectSP _M_node_sp(valobj_sp->GetChildMemberWithName("_M_node"));
114
0
  if (!_M_node_sp)
115
0
    return false;
116
117
0
  m_pair_address = _M_node_sp->GetValueAsUnsigned(0);
118
0
  if (m_pair_address == 0)
119
0
    return false;
120
121
0
  m_pair_address += (is_64bit ? 32 : 16);
122
123
0
  CompilerType my_type(valobj_sp->GetCompilerType());
124
0
  if (my_type.GetNumTemplateArguments() >= 1) {
125
0
    CompilerType pair_type = my_type.GetTypeTemplateArgument(0);
126
0
    if (!pair_type)
127
0
      return false;
128
0
    m_pair_type = pair_type;
129
0
  } else
130
0
    return false;
131
132
0
  return true;
133
0
}
134
135
0
size_t LibstdcppMapIteratorSyntheticFrontEnd::CalculateNumChildren() {
136
0
  return 2;
137
0
}
138
139
lldb::ValueObjectSP
140
0
LibstdcppMapIteratorSyntheticFrontEnd::GetChildAtIndex(size_t idx) {
141
0
  if (m_pair_address != 0 && m_pair_type) {
142
0
    if (!m_pair_sp)
143
0
      m_pair_sp = CreateValueObjectFromAddress("pair", m_pair_address,
144
0
                                               m_exe_ctx_ref, m_pair_type);
145
0
    if (m_pair_sp)
146
0
      return m_pair_sp->GetChildAtIndex(idx);
147
0
  }
148
0
  return lldb::ValueObjectSP();
149
0
}
150
151
0
bool LibstdcppMapIteratorSyntheticFrontEnd::MightHaveChildren() { return true; }
152
153
size_t LibstdcppMapIteratorSyntheticFrontEnd::GetIndexOfChildWithName(
154
0
    ConstString name) {
155
0
  if (name == "first")
156
0
    return 0;
157
0
  if (name == "second")
158
0
    return 1;
159
0
  return UINT32_MAX;
160
0
}
161
162
SyntheticChildrenFrontEnd *
163
lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEndCreator(
164
0
    CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
165
0
  return (valobj_sp ? new LibstdcppMapIteratorSyntheticFrontEnd(valobj_sp)
166
0
                    : nullptr);
167
0
}
168
169
/*
170
 (lldb) fr var ibeg --ptr-depth 1
171
 (__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >)
172
 ibeg = {
173
 _M_current = 0x00000001001037a0 {
174
 *_M_current = 1
175
 }
176
 }
177
 */
178
179
SyntheticChildrenFrontEnd *
180
lldb_private::formatters::LibStdcppVectorIteratorSyntheticFrontEndCreator(
181
0
    CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
182
0
  return (valobj_sp ? new VectorIteratorSyntheticFrontEnd(
183
0
                          valobj_sp, {ConstString("_M_current")})
184
0
                    : nullptr);
185
0
}
186
187
lldb_private::formatters::VectorIteratorSyntheticFrontEnd::
188
    VectorIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp,
189
                                    llvm::ArrayRef<ConstString> item_names)
190
14
    : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(),
191
14
      m_item_names(item_names), m_item_sp() {
192
14
  if (valobj_sp)
193
14
    Update();
194
14
}
195
196
26
bool VectorIteratorSyntheticFrontEnd::Update() {
197
26
  m_item_sp.reset();
198
199
26
  ValueObjectSP valobj_sp = m_backend.GetSP();
200
26
  if (!valobj_sp)
201
0
    return false;
202
203
26
  if (!valobj_sp)
204
0
    return false;
205
206
26
  ValueObjectSP item_ptr =
207
26
      formatters::GetChildMemberWithName(*valobj_sp, m_item_names);
208
26
  if (!item_ptr)
209
0
    return false;
210
26
  if (item_ptr->GetValueAsUnsigned(0) == 0)
211
0
    return false;
212
26
  Status err;
213
26
  m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
214
26
  m_item_sp = CreateValueObjectFromAddress(
215
26
      "item", item_ptr->GetValueAsUnsigned(0), m_exe_ctx_ref,
216
26
      item_ptr->GetCompilerType().GetPointeeType());
217
26
  if (err.Fail())
218
0
    m_item_sp.reset();
219
26
  return false;
220
26
}
221
222
12
size_t VectorIteratorSyntheticFrontEnd::CalculateNumChildren() { return 1; }
223
224
lldb::ValueObjectSP
225
12
VectorIteratorSyntheticFrontEnd::GetChildAtIndex(size_t idx) {
226
12
  if (idx == 0)
227
12
    return m_item_sp;
228
0
  return lldb::ValueObjectSP();
229
12
}
230
231
6
bool VectorIteratorSyntheticFrontEnd::MightHaveChildren() { return true; }
232
233
size_t VectorIteratorSyntheticFrontEnd::GetIndexOfChildWithName(
234
0
    ConstString name) {
235
0
  if (name == "item")
236
0
    return 0;
237
0
  return UINT32_MAX;
238
0
}
239
240
bool lldb_private::formatters::LibStdcppStringSummaryProvider(
241
0
    ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
242
0
  const bool scalar_is_load_addr = true;
243
0
  AddressType addr_type;
244
0
  lldb::addr_t addr_of_string = LLDB_INVALID_ADDRESS;
245
0
  if (valobj.IsPointerOrReferenceType()) {
246
0
    Status error;
247
0
    ValueObjectSP pointee_sp = valobj.Dereference(error);
248
0
    if (pointee_sp && error.Success())
249
0
      addr_of_string = pointee_sp->GetAddressOf(scalar_is_load_addr, &addr_type);
250
0
  } else
251
0
    addr_of_string =
252
0
        valobj.GetAddressOf(scalar_is_load_addr, &addr_type);
253
0
  if (addr_of_string != LLDB_INVALID_ADDRESS) {
254
0
    switch (addr_type) {
255
0
    case eAddressTypeLoad: {
256
0
      ProcessSP process_sp(valobj.GetProcessSP());
257
0
      if (!process_sp)
258
0
        return false;
259
260
0
      StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
261
0
      Status error;
262
0
      lldb::addr_t addr_of_data =
263
0
          process_sp->ReadPointerFromMemory(addr_of_string, error);
264
0
      if (error.Fail() || addr_of_data == 0 ||
265
0
          addr_of_data == LLDB_INVALID_ADDRESS)
266
0
        return false;
267
0
      options.SetLocation(addr_of_data);
268
0
      options.SetTargetSP(valobj.GetTargetSP());
269
0
      options.SetStream(&stream);
270
0
      options.SetNeedsZeroTermination(false);
271
0
      options.SetBinaryZeroIsTerminator(true);
272
0
      lldb::addr_t size_of_data = process_sp->ReadPointerFromMemory(
273
0
          addr_of_string + process_sp->GetAddressByteSize(), error);
274
0
      if (error.Fail())
275
0
        return false;
276
0
      options.SetSourceSize(size_of_data);
277
0
      options.SetHasSourceSize(true);
278
279
0
      if (!StringPrinter::ReadStringAndDumpToStream<
280
0
              StringPrinter::StringElementType::UTF8>(options)) {
281
0
        stream.Printf("Summary Unavailable");
282
0
        return true;
283
0
      } else
284
0
        return true;
285
0
    } break;
286
0
    case eAddressTypeHost:
287
0
      break;
288
0
    case eAddressTypeInvalid:
289
0
    case eAddressTypeFile:
290
0
      break;
291
0
    }
292
0
  }
293
0
  return false;
294
0
}
295
296
bool lldb_private::formatters::LibStdcppWStringSummaryProvider(
297
0
    ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
298
0
  const bool scalar_is_load_addr = true;
299
0
  AddressType addr_type;
300
0
  lldb::addr_t addr_of_string =
301
0
      valobj.GetAddressOf(scalar_is_load_addr, &addr_type);
302
0
  if (addr_of_string != LLDB_INVALID_ADDRESS) {
303
0
    switch (addr_type) {
304
0
    case eAddressTypeLoad: {
305
0
      ProcessSP process_sp(valobj.GetProcessSP());
306
0
      if (!process_sp)
307
0
        return false;
308
309
0
      CompilerType wchar_compiler_type =
310
0
          valobj.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeWChar);
311
312
0
      if (!wchar_compiler_type)
313
0
        return false;
314
315
      // Safe to pass nullptr for exe_scope here.
316
0
      std::optional<uint64_t> size = wchar_compiler_type.GetBitSize(nullptr);
317
0
      if (!size)
318
0
        return false;
319
0
      const uint32_t wchar_size = *size;
320
321
0
      StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
322
0
      Status error;
323
0
      lldb::addr_t addr_of_data =
324
0
          process_sp->ReadPointerFromMemory(addr_of_string, error);
325
0
      if (error.Fail() || addr_of_data == 0 ||
326
0
          addr_of_data == LLDB_INVALID_ADDRESS)
327
0
        return false;
328
0
      options.SetLocation(addr_of_data);
329
0
      options.SetTargetSP(valobj.GetTargetSP());
330
0
      options.SetStream(&stream);
331
0
      options.SetNeedsZeroTermination(false);
332
0
      options.SetBinaryZeroIsTerminator(false);
333
0
      lldb::addr_t size_of_data = process_sp->ReadPointerFromMemory(
334
0
          addr_of_string + process_sp->GetAddressByteSize(), error);
335
0
      if (error.Fail())
336
0
        return false;
337
0
      options.SetSourceSize(size_of_data);
338
0
      options.SetHasSourceSize(true);
339
0
      options.SetPrefixToken("L");
340
341
0
      switch (wchar_size) {
342
0
      case 8:
343
0
        return StringPrinter::ReadStringAndDumpToStream<
344
0
            StringPrinter::StringElementType::UTF8>(options);
345
0
      case 16:
346
0
        return StringPrinter::ReadStringAndDumpToStream<
347
0
            StringPrinter::StringElementType::UTF16>(options);
348
0
      case 32:
349
0
        return StringPrinter::ReadStringAndDumpToStream<
350
0
            StringPrinter::StringElementType::UTF32>(options);
351
0
      default:
352
0
        stream.Printf("size for wchar_t is not valid");
353
0
        return true;
354
0
      }
355
0
      return true;
356
0
    } break;
357
0
    case eAddressTypeHost:
358
0
      break;
359
0
    case eAddressTypeInvalid:
360
0
    case eAddressTypeFile:
361
0
      break;
362
0
    }
363
0
  }
364
0
  return false;
365
0
}
366
367
LibStdcppSharedPtrSyntheticFrontEnd::LibStdcppSharedPtrSyntheticFrontEnd(
368
    lldb::ValueObjectSP valobj_sp)
369
0
    : SyntheticChildrenFrontEnd(*valobj_sp) {
370
0
  if (valobj_sp)
371
0
    Update();
372
0
}
373
374
0
size_t LibStdcppSharedPtrSyntheticFrontEnd::CalculateNumChildren() { return 1; }
375
376
lldb::ValueObjectSP
377
0
LibStdcppSharedPtrSyntheticFrontEnd::GetChildAtIndex(size_t idx) {
378
0
  if (idx == 0)
379
0
    return m_ptr_obj->GetSP();
380
0
  if (idx == 1) {
381
0
    if (m_ptr_obj && !m_obj_obj) {
382
0
      Status error;
383
0
      ValueObjectSP obj_obj = m_ptr_obj->Dereference(error);
384
0
      if (error.Success())
385
0
        m_obj_obj = obj_obj->Clone(ConstString("object")).get();
386
0
    }
387
0
    if (m_obj_obj)
388
0
      return m_obj_obj->GetSP();
389
0
  }
390
0
  return lldb::ValueObjectSP();
391
0
}
392
393
0
bool LibStdcppSharedPtrSyntheticFrontEnd::Update() {
394
0
  auto backend = m_backend.GetSP();
395
0
  if (!backend)
396
0
    return false;
397
398
0
  auto valobj_sp = backend->GetNonSyntheticValue();
399
0
  if (!valobj_sp)
400
0
    return false;
401
402
0
  auto ptr_obj_sp = valobj_sp->GetChildMemberWithName("_M_ptr");
403
0
  if (!ptr_obj_sp)
404
0
    return false;
405
406
0
  m_ptr_obj = ptr_obj_sp->Clone(ConstString("pointer")).get();
407
0
  m_obj_obj = nullptr;
408
409
0
  return false;
410
0
}
411
412
0
bool LibStdcppSharedPtrSyntheticFrontEnd::MightHaveChildren() { return true; }
413
414
size_t LibStdcppSharedPtrSyntheticFrontEnd::GetIndexOfChildWithName(
415
0
    ConstString name) {
416
0
  if (name == "pointer")
417
0
    return 0;
418
0
  if (name == "object" || name == "$$dereference$$")
419
0
    return 1;
420
0
  return UINT32_MAX;
421
0
}
422
423
SyntheticChildrenFrontEnd *
424
lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator(
425
0
    CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
426
0
  return (valobj_sp ? new LibStdcppSharedPtrSyntheticFrontEnd(valobj_sp)
427
0
                    : nullptr);
428
0
}
429
430
bool lldb_private::formatters::LibStdcppSmartPointerSummaryProvider(
431
0
    ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
432
0
  ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
433
0
  if (!valobj_sp)
434
0
    return false;
435
436
0
  ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("_M_ptr"));
437
0
  if (!ptr_sp)
438
0
    return false;
439
440
0
  ValueObjectSP usecount_sp(
441
0
      valobj_sp->GetChildAtNamePath({"_M_refcount", "_M_pi", "_M_use_count"}));
442
0
  if (!usecount_sp)
443
0
    return false;
444
445
0
  if (ptr_sp->GetValueAsUnsigned(0) == 0 ||
446
0
      usecount_sp->GetValueAsUnsigned(0) == 0) {
447
0
    stream.Printf("nullptr");
448
0
    return true;
449
0
  }
450
451
0
  Status error;
452
0
  ValueObjectSP pointee_sp = ptr_sp->Dereference(error);
453
0
  if (pointee_sp && error.Success()) {
454
0
    if (pointee_sp->DumpPrintableRepresentation(
455
0
            stream, ValueObject::eValueObjectRepresentationStyleSummary,
456
0
            lldb::eFormatInvalid,
457
0
            ValueObject::PrintableRepresentationSpecialCases::eDisable,
458
0
            false)) {
459
0
      return true;
460
0
    }
461
0
  }
462
463
0
  stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0));
464
0
  return true;
465
0
}