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