|
27 | 27 |
|
28 | 28 | #include "Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h"
|
29 | 29 | #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
|
| 30 | +#include "lldb/lldb-enumerations.h" |
30 | 31 | #include <tuple>
|
31 | 32 |
|
32 | 33 | using namespace lldb;
|
@@ -283,6 +284,22 @@ bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::Update() {
|
283 | 284 | llvm::dyn_cast_or_null<TypeSystemClang>(pair_type.GetTypeSystem());
|
284 | 285 | if (!ast_ctx)
|
285 | 286 | return false;
|
| 287 | + |
| 288 | + // Mimick layout of std::__tree_iterator::__ptr_ and read it in |
| 289 | + // from process memory. |
| 290 | + // |
| 291 | + // The following shows the contiguous block of memory: |
| 292 | + // |
| 293 | + // +-----------------------------+ class __tree_end_node |
| 294 | + // __ptr_ | pointer __left_; | |
| 295 | + // +-----------------------------+ class __tree_node_base |
| 296 | + // | pointer __right_; | |
| 297 | + // | __parent_pointer __parent_; | |
| 298 | + // | bool __is_black_; | |
| 299 | + // +-----------------------------+ class __tree_node |
| 300 | + // | __node_value_type __value_; | <<< our key/value pair |
| 301 | + // +-----------------------------+ |
| 302 | + // |
286 | 303 | CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier(
|
287 | 304 | ConstString(),
|
288 | 305 | {{"ptr0",
|
@@ -359,6 +376,156 @@ lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator(
|
359 | 376 | : nullptr);
|
360 | 377 | }
|
361 | 378 |
|
| 379 | +lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEnd:: |
| 380 | + LibCxxUnorderedMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) |
| 381 | + : SyntheticChildrenFrontEnd(*valobj_sp) { |
| 382 | + if (valobj_sp) |
| 383 | + Update(); |
| 384 | +} |
| 385 | + |
| 386 | +bool lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEnd:: |
| 387 | + Update() { |
| 388 | + m_pair_sp.reset(); |
| 389 | + m_iter_ptr = nullptr; |
| 390 | + |
| 391 | + ValueObjectSP valobj_sp = m_backend.GetSP(); |
| 392 | + if (!valobj_sp) |
| 393 | + return false; |
| 394 | + |
| 395 | + TargetSP target_sp(valobj_sp->GetTargetSP()); |
| 396 | + |
| 397 | + if (!target_sp) |
| 398 | + return false; |
| 399 | + |
| 400 | + if (!valobj_sp) |
| 401 | + return false; |
| 402 | + |
| 403 | + auto exprPathOptions = ValueObject::GetValueForExpressionPathOptions() |
| 404 | + .DontCheckDotVsArrowSyntax() |
| 405 | + .SetSyntheticChildrenTraversal( |
| 406 | + ValueObject::GetValueForExpressionPathOptions:: |
| 407 | + SyntheticChildrenTraversal::None); |
| 408 | + |
| 409 | + // This must be a ValueObject* because it is a child of the ValueObject we |
| 410 | + // are producing children for it if were a ValueObjectSP, we would end up |
| 411 | + // with a loop (iterator -> synthetic -> child -> parent == iterator) and |
| 412 | + // that would in turn leak memory by never allowing the ValueObjects to die |
| 413 | + // and free their memory. |
| 414 | + m_iter_ptr = |
| 415 | + valobj_sp |
| 416 | + ->GetValueForExpressionPath(".__i_.__node_", nullptr, nullptr, |
| 417 | + exprPathOptions, nullptr) |
| 418 | + .get(); |
| 419 | + |
| 420 | + if (m_iter_ptr) { |
| 421 | + auto iter_child( |
| 422 | + valobj_sp->GetChildMemberWithName(ConstString("__i_"), true)); |
| 423 | + if (!iter_child) { |
| 424 | + m_iter_ptr = nullptr; |
| 425 | + return false; |
| 426 | + } |
| 427 | + |
| 428 | + CompilerType node_type(iter_child->GetCompilerType() |
| 429 | + .GetTypeTemplateArgument(0) |
| 430 | + .GetPointeeType()); |
| 431 | + |
| 432 | + CompilerType pair_type(node_type.GetTypeTemplateArgument(0)); |
| 433 | + |
| 434 | + std::string name; |
| 435 | + uint64_t bit_offset_ptr; |
| 436 | + uint32_t bitfield_bit_size_ptr; |
| 437 | + bool is_bitfield_ptr; |
| 438 | + |
| 439 | + pair_type = pair_type.GetFieldAtIndex( |
| 440 | + 0, name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr); |
| 441 | + if (!pair_type) { |
| 442 | + m_iter_ptr = nullptr; |
| 443 | + return false; |
| 444 | + } |
| 445 | + |
| 446 | + uint64_t addr = m_iter_ptr->GetValueAsUnsigned(LLDB_INVALID_ADDRESS); |
| 447 | + m_iter_ptr = nullptr; |
| 448 | + |
| 449 | + if (addr == 0 || addr == LLDB_INVALID_ADDRESS) |
| 450 | + return false; |
| 451 | + |
| 452 | + TypeSystemClang *ast_ctx = |
| 453 | + llvm::dyn_cast_or_null<TypeSystemClang>(pair_type.GetTypeSystem()); |
| 454 | + if (!ast_ctx) |
| 455 | + return false; |
| 456 | + |
| 457 | + // Mimick layout of std::__hash_iterator::__node_ and read it in |
| 458 | + // from process memory. |
| 459 | + // |
| 460 | + // The following shows the contiguous block of memory: |
| 461 | + // |
| 462 | + // +-----------------------------+ class __hash_node_base |
| 463 | + // __node_ | __next_pointer __next_; | |
| 464 | + // +-----------------------------+ class __hash_node |
| 465 | + // | size_t __hash_; | |
| 466 | + // | __node_value_type __value_; | <<< our key/value pair |
| 467 | + // +-----------------------------+ |
| 468 | + // |
| 469 | + CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier( |
| 470 | + ConstString(), |
| 471 | + {{"__next_", |
| 472 | + ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, |
| 473 | + {"__hash_", ast_ctx->GetBasicType(lldb::eBasicTypeUnsignedLongLong)}, |
| 474 | + {"__value_", pair_type}}); |
| 475 | + llvm::Optional<uint64_t> size = tree_node_type.GetByteSize(nullptr); |
| 476 | + if (!size) |
| 477 | + return false; |
| 478 | + WritableDataBufferSP buffer_sp(new DataBufferHeap(*size, 0)); |
| 479 | + ProcessSP process_sp(target_sp->GetProcessSP()); |
| 480 | + Status error; |
| 481 | + process_sp->ReadMemory(addr, buffer_sp->GetBytes(), |
| 482 | + buffer_sp->GetByteSize(), error); |
| 483 | + if (error.Fail()) |
| 484 | + return false; |
| 485 | + DataExtractor extractor(buffer_sp, process_sp->GetByteOrder(), |
| 486 | + process_sp->GetAddressByteSize()); |
| 487 | + auto pair_sp = CreateValueObjectFromData( |
| 488 | + "pair", extractor, valobj_sp->GetExecutionContextRef(), tree_node_type); |
| 489 | + if (pair_sp) |
| 490 | + m_pair_sp = pair_sp->GetChildAtIndex(2, true); |
| 491 | + } |
| 492 | + |
| 493 | + return false; |
| 494 | +} |
| 495 | + |
| 496 | +size_t lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEnd:: |
| 497 | + CalculateNumChildren() { |
| 498 | + return 2; |
| 499 | +} |
| 500 | + |
| 501 | +lldb::ValueObjectSP lldb_private::formatters:: |
| 502 | + LibCxxUnorderedMapIteratorSyntheticFrontEnd::GetChildAtIndex(size_t idx) { |
| 503 | + if (m_pair_sp) |
| 504 | + return m_pair_sp->GetChildAtIndex(idx, true); |
| 505 | + return lldb::ValueObjectSP(); |
| 506 | +} |
| 507 | + |
| 508 | +bool lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEnd:: |
| 509 | + MightHaveChildren() { |
| 510 | + return true; |
| 511 | +} |
| 512 | + |
| 513 | +size_t lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEnd:: |
| 514 | + GetIndexOfChildWithName(ConstString name) { |
| 515 | + if (name == "first") |
| 516 | + return 0; |
| 517 | + if (name == "second") |
| 518 | + return 1; |
| 519 | + return UINT32_MAX; |
| 520 | +} |
| 521 | + |
| 522 | +SyntheticChildrenFrontEnd * |
| 523 | +lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEndCreator( |
| 524 | + CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { |
| 525 | + return (valobj_sp ? new LibCxxUnorderedMapIteratorSyntheticFrontEnd(valobj_sp) |
| 526 | + : nullptr); |
| 527 | +} |
| 528 | + |
362 | 529 | /*
|
363 | 530 | (lldb) fr var ibeg --raw --ptr-depth 1 -T
|
364 | 531 | (std::__1::__wrap_iter<int *>) ibeg = {
|
|
0 commit comments