@@ -2480,14 +2480,21 @@ static llvm::Expected<addr_t> ReadPtrFromAddr(Process &process, addr_t addr,
2480
2480
// / simplified version of the methods in RegisterContextUnwind, since plumbing
2481
2481
// / access to those here would be challenging.
2482
2482
static llvm::Expected<addr_t > GetCFA (Process &process, RegisterContext ®ctx,
2483
- RegisterKind regkind,
2484
- UnwindPlan::Row::FAValue cfa_loc) {
2483
+ addr_t pc_offset,
2484
+ UnwindPlan &unwind_plan) {
2485
+ auto *row = unwind_plan.GetRowForFunctionOffset (pc_offset);
2486
+ if (!row)
2487
+ return llvm::createStringError (
2488
+ " SwiftLanguageRuntime: Invalid Unwind Row when computing CFA" );
2489
+
2490
+ UnwindPlan::Row::FAValue cfa_loc = row->GetCFAValue ();
2491
+
2485
2492
using ValueType = UnwindPlan::Row::FAValue::ValueType;
2486
2493
switch (cfa_loc.GetValueType ()) {
2487
2494
case ValueType::isRegisterPlusOffset: {
2488
2495
unsigned regnum = cfa_loc.GetRegisterNumber ();
2489
- if (llvm::Expected<addr_t > regvalue =
2490
- ReadRegisterAsAddress ( regctx, regkind , regnum))
2496
+ if (llvm::Expected<addr_t > regvalue = ReadRegisterAsAddress (
2497
+ regctx, unwind_plan. GetRegisterKind () , regnum))
2491
2498
return *regvalue + cfa_loc.GetOffset ();
2492
2499
else
2493
2500
return regvalue;
@@ -2519,13 +2526,8 @@ static UnwindPlanSP GetUnwindPlanForAsyncRegister(FuncUnwinders &unwinders,
2519
2526
return unwinders.GetUnwindPlanAtNonCallSite (target, thread);
2520
2527
}
2521
2528
2522
- // / Attempts to use UnwindPlans that inspect assembly to recover the entry value
2523
- // / of the async context register. This is a simplified version of the methods
2524
- // / in RegisterContextUnwind, since plumbing access to those here would be
2525
- // / challenging.
2526
- static llvm::Expected<addr_t > ReadAsyncContextRegisterFromUnwind (
2527
- SymbolContext &sc, Process &process, Address pc, Address func_start_addr,
2528
- RegisterContext ®ctx, AsyncUnwindRegisterNumbers regnums) {
2529
+ static llvm::Expected<UnwindPlanSP>
2530
+ GetAsmUnwindPlan (Address pc, SymbolContext &sc, Thread &thread) {
2529
2531
FuncUnwindersSP unwinders =
2530
2532
pc.GetModule ()->GetUnwindTable ().GetFuncUnwindersContainingAddress (pc,
2531
2533
sc);
@@ -2534,77 +2536,136 @@ static llvm::Expected<addr_t> ReadAsyncContextRegisterFromUnwind(
2534
2536
" function unwinder at address 0x%8.8" PRIx64,
2535
2537
pc.GetFileAddress ());
2536
2538
2537
- Target &target = process.GetTarget ();
2538
- UnwindPlanSP unwind_plan =
2539
- GetUnwindPlanForAsyncRegister (*unwinders, target, regctx.GetThread ());
2539
+ UnwindPlanSP unwind_plan = GetUnwindPlanForAsyncRegister (
2540
+ *unwinders, thread.GetProcess ()->GetTarget (), thread);
2540
2541
if (!unwind_plan)
2541
2542
return llvm::createStringError (
2542
2543
" SwiftLanguageRuntime: Failed to find non call site unwind plan at "
2543
2544
" address 0x%8.8" PRIx64,
2544
2545
pc.GetFileAddress ());
2546
+ return unwind_plan;
2547
+ }
2545
2548
2546
- const RegisterKind unwind_regkind = unwind_plan->GetRegisterKind ();
2547
- auto *row = unwind_plan->GetRowForFunctionOffset (
2548
- pc.GetFileAddress () - func_start_addr.GetFileAddress ());
2549
-
2550
- // To request info about a register from the unwind plan, the register must
2551
- // be in the same domain as the unwind plan's registers.
2552
- uint32_t async_reg_unwind_regdomain;
2549
+ static llvm::Expected<uint32_t > GetFpRegisterNumber (UnwindPlan &unwind_plan,
2550
+ RegisterContext ®ctx) {
2551
+ uint32_t fp_unwind_regdomain;
2553
2552
if (!regctx.ConvertBetweenRegisterKinds (
2554
- regnums. GetRegisterKind (), regnums. async_ctx_regnum , unwind_regkind ,
2555
- async_reg_unwind_regdomain )) {
2553
+ lldb::eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP ,
2554
+ unwind_plan. GetRegisterKind (), fp_unwind_regdomain )) {
2556
2555
// This should never happen.
2557
2556
// If asserts are disabled, return an error to avoid creating an invalid
2558
2557
// unwind plan.
2559
- auto error_msg = " SwiftLanguageRuntime: Failed to convert register domains" ;
2558
+ const auto *error_msg =
2559
+ " SwiftLanguageRuntime: Failed to convert register domains" ;
2560
2560
llvm_unreachable (error_msg);
2561
2561
return llvm::createStringError (error_msg);
2562
2562
}
2563
+ return fp_unwind_regdomain;
2564
+ }
2563
2565
2564
- // If the plan doesn't have information about the async register, we can use
2565
- // its current value, as this is a callee saved register.
2566
- UnwindPlan::Row::AbstractRegisterLocation regloc;
2567
- if (!row->GetRegisterInfo (async_reg_unwind_regdomain, regloc))
2568
- return ReadRegisterAsAddress (regctx, regnums.GetRegisterKind (),
2569
- regnums.async_ctx_regnum );
2566
+ struct FrameSetupInfo {
2567
+ addr_t frame_setup_func_offset;
2568
+ int fp_cfa_offset;
2569
+ };
2570
2570
2571
- // Handle the few abstract locations we are likely to encounter.
2572
- using RestoreType = UnwindPlan::Row::AbstractRegisterLocation::RestoreType;
2573
- RestoreType loctype = regloc.GetLocationType ();
2574
- switch (loctype) {
2575
- case RestoreType::same:
2571
+ // / Detect the point in the function where the prologue created a frame,
2572
+ // / returning:
2573
+ // / 1. The offset of the first instruction after that point. For a frameless
2574
+ // / function, this offset is large positive number, so that PC can still be
2575
+ // / compared against it.
2576
+ // / 2. The CFA offset at which FP is stored, meaningless in the frameless case.
2577
+ static llvm::Expected<FrameSetupInfo>
2578
+ GetFrameSetupInfo (UnwindPlan &unwind_plan, RegisterContext ®ctx) {
2579
+ using AbstractRegisterLocation = UnwindPlan::Row::AbstractRegisterLocation;
2580
+
2581
+ llvm::Expected<uint32_t > fp_unwind_regdomain =
2582
+ GetFpRegisterNumber (unwind_plan, regctx);
2583
+ if (!fp_unwind_regdomain)
2584
+ return fp_unwind_regdomain.takeError ();
2585
+
2586
+ // Look at the first few (4) rows of the plan and store FP's location.
2587
+ const int upper_bound = std::min (4 , unwind_plan.GetRowCount ());
2588
+ llvm::SmallVector<AbstractRegisterLocation, 4 > fp_locs;
2589
+ for (int row_idx = 0 ; row_idx < upper_bound; row_idx++) {
2590
+ auto *row = unwind_plan.GetRowAtIndex (row_idx);
2591
+ AbstractRegisterLocation regloc;
2592
+ if (!row->GetRegisterInfo (*fp_unwind_regdomain, regloc))
2593
+ regloc.SetSame ();
2594
+ fp_locs.push_back (regloc);
2595
+ }
2596
+
2597
+ // Find first location where FP is stored *at* some CFA offset.
2598
+ auto *it = llvm::find_if (
2599
+ fp_locs, [](auto fp_loc) { return fp_loc.IsAtCFAPlusOffset (); });
2600
+
2601
+ // This is a frameless function, use large positive offset so that a PC can
2602
+ // still be compared against it.
2603
+ if (it == fp_locs.end ())
2604
+ return FrameSetupInfo{std::numeric_limits<addr_t >::max (), 0 };
2605
+
2606
+ // This is an async function with a frame. The prologue roughly follows this
2607
+ // sequence of instructions:
2608
+ // adjust sp
2609
+ // save lr @ CFA-8
2610
+ // save fp @ CFA-16 << `it` points to this row.
2611
+ // save async_reg @ CFA-24 << subsequent row.
2612
+ // Use subsequent row, if available.
2613
+ // Pointer auth may introduce more instructions, but they don't affect the
2614
+ // unwinder rows / store to the stack.
2615
+ int row_idx = fp_locs.end () - it;
2616
+ int next_row_idx = row_idx + 1 ;
2617
+
2618
+ // If subsequent row is invalid, approximate through current row.
2619
+ if (next_row_idx == unwind_plan.GetRowCount () ||
2620
+ next_row_idx == upper_bound ||
2621
+ !fp_locs[next_row_idx].IsAtCFAPlusOffset ()) {
2622
+ LLDB_LOG (GetLog (LLDBLog::Unwind), " SwiftLanguageRuntime:: UnwindPlan did "
2623
+ " not contain a valid row after FP setup" );
2624
+ auto *row = unwind_plan.GetRowAtIndex (row_idx);
2625
+ return FrameSetupInfo{row->GetOffset (), fp_locs[row_idx].GetOffset ()};
2626
+ }
2627
+
2628
+ auto *subsequent_row = unwind_plan.GetRowAtIndex (next_row_idx);
2629
+ return FrameSetupInfo{subsequent_row->GetOffset (),
2630
+ fp_locs[next_row_idx].GetOffset ()};
2631
+ }
2632
+
2633
+ // / Reads the async register from its ABI-guaranteed stack-slot, or directly
2634
+ // / from the register depending on where pc is relative to the start of the
2635
+ // / function.
2636
+ static llvm::Expected<addr_t > ReadAsyncContextRegisterFromUnwind (
2637
+ SymbolContext &sc, Process &process, Address pc, Address func_start_addr,
2638
+ RegisterContext ®ctx, AsyncUnwindRegisterNumbers regnums) {
2639
+ llvm::Expected<UnwindPlanSP> unwind_plan =
2640
+ GetAsmUnwindPlan (pc, sc, regctx.GetThread ());
2641
+ if (!unwind_plan)
2642
+ return unwind_plan.takeError ();
2643
+ llvm::Expected<FrameSetupInfo> frame_setup =
2644
+ GetFrameSetupInfo (**unwind_plan, regctx);
2645
+ if (!frame_setup)
2646
+ return frame_setup.takeError ();
2647
+
2648
+ // Is PC before the frame formation? If so, use async register directly.
2649
+ // This handles frameless functions, as frame_setup_func_offset is INT_MAX.
2650
+ addr_t pc_offset = pc.GetFileAddress () - func_start_addr.GetFileAddress ();
2651
+ if (pc_offset < frame_setup->frame_setup_func_offset )
2576
2652
return ReadRegisterAsAddress (regctx, regnums.GetRegisterKind (),
2577
2653
regnums.async_ctx_regnum );
2578
- case RestoreType::inOtherRegister: {
2579
- unsigned regnum = regloc.GetRegisterNumber ();
2580
- return ReadRegisterAsAddress (regctx, unwind_regkind, regnum);
2581
- }
2582
- case RestoreType::atCFAPlusOffset: {
2583
- llvm::Expected<addr_t > cfa =
2584
- GetCFA (process, regctx, unwind_regkind, row->GetCFAValue ());
2585
- if (!cfa)
2586
- return cfa.takeError ();
2587
- return ReadPtrFromAddr (process, *cfa, regloc.GetOffset ());
2588
- }
2589
- case RestoreType::isCFAPlusOffset: {
2590
- if (llvm::Expected<addr_t > cfa =
2591
- GetCFA (process, regctx, unwind_regkind, row->GetCFAValue ()))
2592
- return *cfa + regloc.GetOffset ();
2593
- else
2594
- return cfa;
2595
- }
2596
- case RestoreType::isConstant:
2597
- return regloc.GetConstant ();
2598
- case RestoreType::unspecified:
2599
- case RestoreType::undefined:
2600
- case RestoreType::atAFAPlusOffset:
2601
- case RestoreType::isAFAPlusOffset:
2602
- case RestoreType::isDWARFExpression:
2603
- case RestoreType::atDWARFExpression:
2604
- break ;
2605
- }
2606
- return llvm::createStringError (
2607
- " SwiftLanguageRuntime: Unsupported register location type = %d" , loctype);
2654
+
2655
+ // A frame was formed, and FP was saved at a CFA offset. Compute CFA and read
2656
+ // the location beneath where FP was saved.
2657
+ llvm::Expected<addr_t > cfa =
2658
+ GetCFA (process, regctx, pc_offset, **unwind_plan);
2659
+ if (!cfa)
2660
+ return cfa.takeError ();
2661
+
2662
+ addr_t async_reg_addr = process.FixDataAddress (
2663
+ *cfa + frame_setup->fp_cfa_offset - process.GetAddressByteSize ());
2664
+ Status error;
2665
+ addr_t async_reg = process.ReadPointerFromMemory (async_reg_addr, error);
2666
+ if (error.Fail ())
2667
+ return error.ToError ();
2668
+ return async_reg;
2608
2669
}
2609
2670
2610
2671
// / Returns true if the async register should be dereferenced once to obtain the
0 commit comments