18
18
#include " lldb/Utility/Status.h"
19
19
#include " lldb/Utility/Stream.h"
20
20
#include " lldb/lldb-forward.h"
21
+ #include < cstdint>
22
+ #include < locale>
23
+ #include < optional>
21
24
22
25
using namespace lldb ;
23
26
using namespace lldb_private ;
24
27
using namespace lldb_private ::formatters;
25
28
29
+ // The flattened layout of the std::__tree_iterator::__ptr_ looks
30
+ // as follows:
31
+ //
32
+ // The following shows the contiguous block of memory:
33
+ //
34
+ // +-----------------------------+ class __tree_end_node
35
+ // __ptr_ | pointer __left_; |
36
+ // +-----------------------------+ class __tree_node_base
37
+ // | pointer __right_; |
38
+ // | __parent_pointer __parent_; |
39
+ // | bool __is_black_; |
40
+ // +-----------------------------+ class __tree_node
41
+ // | __node_value_type __value_; | <<< our key/value pair
42
+ // +-----------------------------+
43
+ //
44
+ // where __ptr_ has type __iter_pointer.
45
+
26
46
class MapEntry {
27
47
public:
28
48
MapEntry () = default ;
@@ -181,10 +201,6 @@ class LibcxxStdMapSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
181
201
size_t GetIndexOfChildWithName (ConstString name) override ;
182
202
183
203
private:
184
- bool GetDataType ();
185
-
186
- void GetValueOffset (const lldb::ValueObjectSP &node);
187
-
188
204
// / Returns the ValueObject for the __tree_node type that
189
205
// / holds the key/value pair of the node at index \ref idx.
190
206
// /
@@ -203,8 +219,7 @@ class LibcxxStdMapSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
203
219
204
220
ValueObject *m_tree = nullptr ;
205
221
ValueObject *m_root_node = nullptr ;
206
- CompilerType m_element_type;
207
- uint32_t m_skip_size = UINT32_MAX;
222
+ CompilerType m_node_ptr_type;
208
223
size_t m_count = UINT32_MAX;
209
224
std::map<size_t , MapIterator> m_iterators;
210
225
};
@@ -213,7 +228,7 @@ class LibcxxStdMapSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
213
228
214
229
lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
215
230
LibcxxStdMapSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp)
216
- : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type(), m_iterators() {
231
+ : SyntheticChildrenFrontEnd(*valobj_sp) {
217
232
if (valobj_sp)
218
233
Update ();
219
234
}
@@ -239,146 +254,52 @@ llvm::Expected<uint32_t> lldb_private::formatters::
239
254
return m_count;
240
255
}
241
256
242
- bool lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetDataType () {
243
- if (m_element_type.IsValid ())
244
- return true ;
245
- m_element_type.Clear ();
246
- ValueObjectSP deref;
247
- Status error;
248
- deref = m_root_node->Dereference (error);
249
- if (!deref || error.Fail ())
250
- return false ;
251
- deref = deref->GetChildMemberWithName (" __value_" );
252
- if (deref) {
253
- m_element_type = deref->GetCompilerType ();
254
- return true ;
255
- }
256
- deref = m_backend.GetChildAtNamePath ({" __tree_" , " __pair3_" });
257
- if (!deref)
258
- return false ;
259
- m_element_type = deref->GetCompilerType ()
260
- .GetTypeTemplateArgument (1 )
261
- .GetTypeTemplateArgument (1 );
262
- if (m_element_type) {
263
- std::string name;
264
- uint64_t bit_offset_ptr;
265
- uint32_t bitfield_bit_size_ptr;
266
- bool is_bitfield_ptr;
267
- m_element_type = m_element_type.GetFieldAtIndex (
268
- 0 , name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr);
269
- m_element_type = m_element_type.GetTypedefedType ();
270
- return m_element_type.IsValid ();
271
- } else {
272
- m_element_type = m_backend.GetCompilerType ().GetTypeTemplateArgument (0 );
273
- return m_element_type.IsValid ();
274
- }
275
- }
276
-
277
- void lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetValueOffset (
278
- const lldb::ValueObjectSP &node) {
279
- if (m_skip_size != UINT32_MAX)
280
- return ;
281
- if (!node)
282
- return ;
283
- CompilerType node_type (node->GetCompilerType ());
284
- uint64_t bit_offset;
285
- if (node_type.GetIndexOfFieldWithName (" __value_" , nullptr , &bit_offset) !=
286
- UINT32_MAX) {
287
- // Old layout (pre 089a7cc5dea)
288
- m_skip_size = bit_offset / 8u ;
289
- } else {
290
- auto ast_ctx = node_type.GetTypeSystem ().dyn_cast_or_null <TypeSystemClang>();
291
- if (!ast_ctx)
292
- return ;
293
- CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier (
294
- llvm::StringRef (),
295
- {{" ptr0" , ast_ctx->GetBasicType (lldb::eBasicTypeVoid).GetPointerType ()},
296
- {" ptr1" , ast_ctx->GetBasicType (lldb::eBasicTypeVoid).GetPointerType ()},
297
- {" ptr2" , ast_ctx->GetBasicType (lldb::eBasicTypeVoid).GetPointerType ()},
298
- {" cw" , ast_ctx->GetBasicType (lldb::eBasicTypeBool)},
299
- {" payload" , (m_element_type.GetCompleteType (), m_element_type)}});
300
- std::string child_name;
301
- uint32_t child_byte_size;
302
- int32_t child_byte_offset = 0 ;
303
- uint32_t child_bitfield_bit_size;
304
- uint32_t child_bitfield_bit_offset;
305
- bool child_is_base_class;
306
- bool child_is_deref_of_parent;
307
- uint64_t language_flags;
308
- auto child_type =
309
- llvm::expectedToStdOptional (tree_node_type.GetChildCompilerTypeAtIndex (
310
- nullptr , 4 , true , true , true , child_name, child_byte_size,
311
- child_byte_offset, child_bitfield_bit_size,
312
- child_bitfield_bit_offset, child_is_base_class,
313
- child_is_deref_of_parent, nullptr , language_flags));
314
- if (child_type && child_type->IsValid ())
315
- m_skip_size = (uint32_t )child_byte_offset;
316
- }
317
- }
318
-
319
257
ValueObjectSP
320
258
lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetKeyValuePair (
321
259
size_t idx, size_t max_depth) {
322
260
MapIterator iterator (m_root_node, max_depth);
323
261
324
- const bool need_to_skip = (idx > 0 );
325
- size_t actual_advance = idx;
326
- if (need_to_skip) {
262
+ size_t advance_by = idx;
263
+ if (idx > 0 ) {
327
264
// If we have already created the iterator for the previous
328
265
// index, we can start from there and advance by 1.
329
266
auto cached_iterator = m_iterators.find (idx - 1 );
330
267
if (cached_iterator != m_iterators.end ()) {
331
268
iterator = cached_iterator->second ;
332
- actual_advance = 1 ;
269
+ advance_by = 1 ;
333
270
}
334
271
}
335
272
336
- ValueObjectSP iterated_sp (iterator.advance (actual_advance ));
273
+ ValueObjectSP iterated_sp (iterator.advance (advance_by ));
337
274
if (!iterated_sp)
338
275
// this tree is garbage - stop
339
276
return nullptr ;
340
277
341
- if (!GetDataType ())
278
+ if (!m_node_ptr_type. IsValid ())
342
279
return nullptr ;
343
280
344
- if (!need_to_skip) {
345
- Status error;
346
- iterated_sp = iterated_sp->Dereference (error);
347
- if (!iterated_sp || error.Fail ())
348
- return nullptr ;
349
-
350
- GetValueOffset (iterated_sp);
351
- auto child_sp = iterated_sp->GetChildMemberWithName (" __value_" );
352
- if (child_sp) {
353
- // Old layout (pre 089a7cc5dea)
354
- iterated_sp = child_sp;
355
- } else {
356
- iterated_sp = iterated_sp->GetSyntheticChildAtOffset (
357
- m_skip_size, m_element_type, true );
358
- }
281
+ // iterated_sp is a __iter_pointer at this point.
282
+ // We can cast it to a __node_pointer (which is what libc++ does).
283
+ auto value_type_sp = iterated_sp->Cast (m_node_ptr_type);
284
+ if (!value_type_sp)
285
+ return nullptr ;
359
286
360
- if (!iterated_sp)
361
- return nullptr ;
362
- } else {
363
- // because of the way our debug info is made, we need to read item 0
364
- // first so that we can cache information used to generate other elements
365
- if (m_skip_size == UINT32_MAX)
366
- GetChildAtIndex (0 );
367
-
368
- if (m_skip_size == UINT32_MAX)
369
- return nullptr ;
370
-
371
- iterated_sp = iterated_sp->GetSyntheticChildAtOffset (m_skip_size,
372
- m_element_type, true );
373
- if (!iterated_sp)
374
- return nullptr ;
375
- }
287
+ // After dereferencing the __node_pointer, we will have a handle to
288
+ // a std::__1::__tree_node<void *>, which has the __value_ member
289
+ // we are looking for.
290
+ Status s;
291
+ value_type_sp = value_type_sp->Dereference (s);
292
+ if (!value_type_sp || s.Fail ())
293
+ return nullptr ;
294
+
295
+ // Finally, get the key/value pair.
296
+ value_type_sp = value_type_sp->GetChildMemberWithName (" __value_" );
297
+ if (!value_type_sp)
298
+ return nullptr ;
376
299
377
300
m_iterators[idx] = iterator;
378
- assert (iterated_sp != nullptr &&
379
- " Cached MapIterator for invalid ValueObject" );
380
301
381
- return iterated_sp ;
302
+ return value_type_sp ;
382
303
}
383
304
384
305
lldb::ValueObjectSP
@@ -438,6 +359,9 @@ lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::Update() {
438
359
if (!m_tree)
439
360
return lldb::ChildCacheState::eRefetch;
440
361
m_root_node = m_tree->GetChildMemberWithName (" __begin_node_" ).get ();
362
+ m_node_ptr_type =
363
+ m_tree->GetCompilerType ().GetDirectNestedTypeWithName (" __node_pointer" );
364
+
441
365
return lldb::ChildCacheState::eRefetch;
442
366
}
443
367
0 commit comments