@@ -2582,6 +2582,39 @@ lldb::addr_t SwiftLanguageRuntime::GetAsyncContext(RegisterContext *regctx) {
2582
2582
return LLDB_INVALID_ADDRESS;
2583
2583
}
2584
2584
2585
+ // / Creates an expression accessing *(fp - 8) or **(fp - 8) if
2586
+ // / `with_double_deref` is true. This is only valid for x86_64 or aarch64.
2587
+ llvm::ArrayRef<uint8_t >
2588
+ GetAsyncRegFromFramePointerDWARFExpr (llvm::Triple::ArchType triple,
2589
+ bool with_double_deref) {
2590
+ assert (triple == llvm::Triple::x86_64 || triple == llvm::Triple::aarch64);
2591
+
2592
+ // These expressions must have static storage, due to how UnwindPlan::Row
2593
+ // works.
2594
+ static const uint8_t g_cfa_dwarf_expression_x86_64[] = {
2595
+ llvm::dwarf::DW_OP_breg6, // DW_OP_breg6, register 6 == rbp
2596
+ 0x78 , // sleb128 -8 (ptrsize)
2597
+ llvm::dwarf::DW_OP_deref,
2598
+ llvm::dwarf::DW_OP_deref,
2599
+ };
2600
+ static const uint8_t g_cfa_dwarf_expression_arm64[] = {
2601
+ llvm::dwarf::DW_OP_breg29, // DW_OP_breg29, register 29 == fp
2602
+ 0x78 , // sleb128 -8 (ptrsize)
2603
+ llvm::dwarf::DW_OP_deref,
2604
+ llvm::dwarf::DW_OP_deref,
2605
+ };
2606
+
2607
+ const uint8_t *expr = triple == llvm::Triple::x86_64
2608
+ ? g_cfa_dwarf_expression_x86_64
2609
+ : g_cfa_dwarf_expression_arm64;
2610
+ auto size = triple == llvm::Triple::x86_64
2611
+ ? sizeof (g_cfa_dwarf_expression_x86_64)
2612
+ : sizeof (g_cfa_dwarf_expression_arm64);
2613
+ if (with_double_deref)
2614
+ return llvm::ArrayRef<uint8_t >(expr, size);
2615
+ return llvm::ArrayRef<uint8_t >(expr, size - 1 );
2616
+ }
2617
+
2585
2618
// Examine the register state and detect the transition from a real
2586
2619
// stack frame to an AsyncContext frame, or a frame in the middle of
2587
2620
// the AsyncContext chain, and return an UnwindPlan for these situations.
@@ -2671,64 +2704,28 @@ SwiftLanguageRuntime::GetRuntimeUnwindPlan(ProcessSP process_sp,
2671
2704
const int32_t ptr_size = 8 ;
2672
2705
row->SetOffset (0 );
2673
2706
2674
- // A DWARF Expression to set the CFA.
2675
- // pushes the frame pointer register - 8
2676
- // dereference
2677
-
2678
- // FIXME: Row::RegisterLocation::RestoreType doesn't have a
2679
- // deref(reg-value + offset) yet, shortcut around it with
2680
- // a dwarf expression for now.
2681
- // The CFA of an async frame is the address of it's associated AsyncContext.
2682
- // In an async frame currently on the stack, this address is stored right
2683
- // before the saved frame pointer on the stack.
2684
- static const uint8_t g_cfa_dwarf_expression_x86_64[] = {
2685
- llvm::dwarf::DW_OP_breg6, // DW_OP_breg6, register 6 == rbp
2686
- 0x78 , // sleb128 -8 (ptrsize)
2687
- llvm::dwarf::DW_OP_deref,
2688
- };
2689
- static const uint8_t g_cfa_dwarf_expression_arm64[] = {
2690
- llvm::dwarf::DW_OP_breg29, // DW_OP_breg29, register 29 == fp
2691
- 0x78 , // sleb128 -8 (ptrsize)
2692
- llvm::dwarf::DW_OP_deref,
2693
- };
2694
-
2695
- constexpr unsigned expr_size = sizeof (g_cfa_dwarf_expression_arm64);
2696
-
2697
- static_assert (sizeof (g_cfa_dwarf_expression_x86_64) ==
2698
- sizeof (g_cfa_dwarf_expression_arm64),
2699
- " Code relies on DWARF expressions being the same size" );
2700
-
2701
- const uint8_t *expr = nullptr ;
2702
- if (arch.GetMachine () == llvm::Triple::x86_64)
2703
- expr = g_cfa_dwarf_expression_x86_64;
2704
- else if (arch.GetMachine () == llvm::Triple::aarch64)
2705
- expr = g_cfa_dwarf_expression_arm64;
2706
- else
2707
- llvm_unreachable (" Unsupported architecture" );
2708
-
2709
2707
if (in_prologue) {
2710
2708
if (indirect_context)
2711
2709
row->GetCFAValue ().SetIsRegisterDereferenced (regnums->async_ctx_regnum );
2712
2710
else
2713
2711
row->GetCFAValue ().SetIsRegisterPlusOffset (regnums->async_ctx_regnum , 0 );
2714
2712
} else {
2715
- row->GetCFAValue ().SetIsDWARFExpression (expr, expr_size);
2713
+ // In indirect funclets, dereferencing (fp-8) once produces the CFA of the
2714
+ // frame above. Dereferencing twice will produce the current frame's CFA.
2715
+ bool with_double_deref = indirect_context;
2716
+ llvm::ArrayRef<uint8_t > expr = GetAsyncRegFromFramePointerDWARFExpr (
2717
+ arch.GetMachine (), with_double_deref);
2718
+ row->GetCFAValue ().SetIsDWARFExpression (expr.data (), expr.size ());
2716
2719
}
2717
2720
2718
2721
if (indirect_context) {
2719
2722
if (in_prologue) {
2720
2723
row->SetRegisterLocationToSame (regnums->async_ctx_regnum , false );
2721
2724
} else {
2722
- // In a "resume" coroutine, the passed context argument needs to be
2723
- // dereferenced once to get the context. This is reflected in the debug
2724
- // info so we need to account for it and report am async register value
2725
- // that needs to be dereferenced to get to the context.
2726
- // Note that the size passed for the DWARF expression is the size of the
2727
- // array minus one. This skips the last deref for this use.
2728
- assert (expr[expr_size - 1 ] == llvm::dwarf::DW_OP_deref &&
2729
- " Should skip a deref" );
2730
- row->SetRegisterLocationToIsDWARFExpression (regnums->async_ctx_regnum ,
2731
- expr, expr_size - 1 , false );
2725
+ llvm::ArrayRef<uint8_t > expr = GetAsyncRegFromFramePointerDWARFExpr (
2726
+ arch.GetMachine (), false /* with_double_deref*/ );
2727
+ row->SetRegisterLocationToIsDWARFExpression (
2728
+ regnums->async_ctx_regnum , expr.data (), expr.size (), false );
2732
2729
}
2733
2730
} else {
2734
2731
// In the first part of a split async function, the context is passed
0 commit comments