DWARF 堆栈展开详细实现原理分析

2025-12-29  本文已影响0人  马小藤

DWARF 堆栈展开详细实现原理分析

概述

本文档详细解释 Android libunwindstack 中 DWARF CFI (Call Frame Information) 堆栈展开的实现原理,重点分析 DwarfSection::Step()GetCfaLocationInfo()Eval() 方法的实现机制。

DWARF CFI 基础知识

什么是 DWARF CFI?

DWARF CFI (Call Frame Information) 是一种描述函数调用帧布局的标准格式,用于在运行时恢复上一帧的寄存器状态。它包含在 ELF 文件的 .eh_frame.debug_frame 段中。

核心概念

  1. CFA (Canonical Frame Address) - 规范帧地址

    • 指上一帧的栈指针(SP)值
    • 是恢复其他寄存器的基准地址
  2. FDE (Frame Description Entry) - 帧描述条目

    • 描述一个函数范围内的堆栈布局
    • 包含该函数的起始地址、结束地址和展开规则
  3. CIE (Common Information Entry) - 公共信息条目

    • 多个 FDE 共享的公共信息
    • 包含架构相关的默认规则
  4. Location Rules - 位置规则

    • 描述如何计算每个寄存器的值
    • 可以是:寄存器值、内存地址、表达式等

完整调用链

Unwinder::Unwind()
  └─ elf->Step(rel_pc, regs, process_memory, finished, is_signal_frame)
      └─ interface_->Step(pc, regs, process_memory, finished, is_signal_frame)
          └─ eh_frame->Step(pc, regs, process_memory, finished, is_signal_frame)
              ├─ GetFdeFromPc(pc)                    // 查找 FDE
              ├─ GetCfaLocationInfo(pc, fde, ...)     // 获取 CFA 位置信息
              └─ Eval(cie, process_memory, loc_regs, regs, finished)  // 执行寄存器恢复

第一步:DwarfSection::Step() 方法详解

方法签名

bool DwarfSection::Step(uint64_t pc, Regs* regs, Memory* process_memory, 
                        bool* finished, bool* is_signal_frame)

实现流程

bool DwarfSection::Step(uint64_t pc, Regs* regs, Memory* process_memory, 
                        bool* finished, bool* is_signal_frame) {
  // 1. 查找缓存中的位置信息
  auto it = loc_regs_.upper_bound(pc);
  
  // 2. 如果缓存未命中,需要重新解析
  if (it == loc_regs_.end() || pc < it->second.pc_start) {
    last_error_.code = DWARF_ERROR_NONE;
    
    // 3. 根据 PC 查找对应的 FDE
    const DwarfFde* fde = GetFdeFromPc(pc);
    if (fde == nullptr || fde->cie == nullptr) {
      last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
      return false;
    }
    
    // 4. 获取该 PC 位置的所有寄存器位置信息
    DwarfLocations loc_regs;
    if (!GetCfaLocationInfo(pc, fde, &loc_regs, regs->Arch())) {
      return false;
    }
    
    loc_regs.cie = fde->cie;
    
    // 5. 将解析结果存入缓存(以 pc_end 为键)
    it = loc_regs_.emplace(loc_regs.pc_end, std::move(loc_regs)).first;
  }
  
  // 6. 检查是否为信号帧
  *is_signal_frame = it->second.cie->is_signal_frame;
  
  // 7. 执行寄存器恢复
  return Eval(it->second.cie, process_memory, it->second, regs, finished);
}

关键步骤解析

步骤 1-2:缓存查找

auto it = loc_regs_.upper_bound(pc);
if (it == loc_regs_.end() || pc < it->second.pc_start) {
    // 缓存未命中,需要重新解析
}

作用

为什么使用 pc_end 作为键?

步骤 3:查找 FDE

const DwarfFde* fde = GetFdeFromPc(pc);

GetFdeFromPc() 的实现原理

const DwarfFde* DwarfSection::GetFdeFromPc(uint64_t pc) {
  // 1. 在 FDE 列表中二分查找
  // FDE 列表按函数起始地址排序
  for (const auto& fde : fdes_) {
    if (pc >= fde->pc_start && pc < fde->pc_end) {
      return fde.get();
    }
  }
  return nullptr;
}

FDE 结构

struct DwarfFde {
  uint64_t pc_start;        // 函数起始地址
  uint64_t pc_end;          // 函数结束地址
  DwarfCie* cie;            // 关联的 CIE
  std::vector<uint8_t> instructions;  // CFI 指令序列
};

作用:找到包含当前 PC 的函数对应的 FDE。

步骤 4:获取 CFA 位置信息

DwarfLocations loc_regs;
if (!GetCfaLocationInfo(pc, fde, &loc_regs, regs->Arch())) {
  return false;
}

这是最复杂的步骤,下面详细解释。

第二步:GetCfaLocationInfo() 方法详解

方法签名

bool DwarfSection::GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde,
                                       DwarfLocations* loc_regs, ArchEnum arch)

核心原理

GetCfaLocationInfo() 的作用是解析 DWARF CFI 指令,计算出在当前 PC 位置时,如何恢复上一帧的所有寄存器

DWARF CFI 指令系统

DWARF CFI 使用基于栈的状态机来编码展开规则:

  1. 初始状态:从 CIE 中获取初始规则
  2. 执行指令:按顺序执行 FDE 中的指令,直到覆盖当前 PC
  3. 最终状态:得到当前 PC 位置的所有寄存器恢复规则

主要 CFI 指令

指令 作用 示例
DW_CFA_def_cfa 定义 CFA 的位置 DW_CFA_def_cfa reg, offset
DW_CFA_def_cfa_register 修改 CFA 的基寄存器 DW_CFA_def_cfa_register reg
DW_CFA_def_cfa_offset 修改 CFA 的偏移量 DW_CFA_def_cfa_offset offset
DW_CFA_offset 定义寄存器保存在 CFA+offset DW_CFA_offset reg, offset
DW_CFA_register 定义寄存器等于另一个寄存器 DW_CFA_register reg1, reg2
DW_CFA_expression 使用表达式计算寄存器位置 DW_CFA_expression reg, expr
DW_CFA_advance_loc 前进到下一个地址范围 DW_CFA_advance_loc delta
DW_CFA_restore 恢复寄存器的默认规则 DW_CFA_restore reg

GetCfaLocationInfo() 实现流程(简化)

bool DwarfSection::GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde,
                                       DwarfLocations* loc_regs, ArchEnum arch) {
  // 1. 初始化:从 CIE 复制初始规则
  DwarfLocations cie_loc_regs;
  if (!GetCieLocationInfo(fde->cie, &cie_loc_regs, arch)) {
    return false;
  }
  
  // 2. 设置初始状态
  *loc_regs = cie_loc_regs;
  loc_regs->pc_start = fde->pc_start;
  uint64_t cur_pc = fde->pc_start;
  
  // 3. 解析 FDE 中的 CFI 指令
  Memory* memory = process_memory_;
  const uint8_t* cur_instructions = fde->instructions.data();
  const uint8_t* end_instructions = cur_instructions + fde->instructions.size();
  
  while (cur_instructions < end_instructions) {
    uint8_t cfi_value = *cur_instructions++;
    
    // 解析指令操作码
    uint8_t opcode = cfi_value & 0x3f;
    uint8_t operand = (cfi_value >> 6) & 0x3;
    
    switch (opcode) {
      case DW_CFA_advance_loc: {
        // 前进到新的地址范围
        uint64_t delta = ReadULEB128(&cur_instructions);
        cur_pc += delta;
        
        // 如果已经超过目标 PC,停止解析
        if (cur_pc > pc) {
          loc_regs->pc_end = cur_pc;
          return true;
        }
        break;
      }
      
      case DW_CFA_def_cfa: {
        // 定义 CFA: CFA = reg + offset
        uint64_t reg = ReadULEB128(&cur_instructions);
        uint64_t offset = ReadULEB128(&cur_instructions);
        
        DwarfLocation loc;
        loc.type = DWARF_LOCATION_REGISTER;
        loc.values[0] = reg;      // 基寄存器
        loc.values[1] = offset;   // 偏移量
        (*loc_regs)[CFA_REG] = loc;
        break;
      }
      
      case DW_CFA_def_cfa_register: {
        // 修改 CFA 的基寄存器
        uint64_t reg = ReadULEB128(&cur_instructions);
        auto it = loc_regs->find(CFA_REG);
        if (it != loc_regs->end()) {
          it->second.values[0] = reg;  // 只修改寄存器,保持偏移不变
        }
        break;
      }
      
      case DW_CFA_def_cfa_offset: {
        // 修改 CFA 的偏移量
        uint64_t offset = ReadULEB128(&cur_instructions);
        auto it = loc_regs->find(CFA_REG);
        if (it != loc_regs->end()) {
          it->second.values[1] = offset;  // 只修改偏移,保持寄存器不变
        }
        break;
      }
      
      case DW_CFA_offset: {
        // 定义寄存器保存在 CFA + offset
        uint64_t reg = ReadULEB128(&cur_instructions);
        uint64_t offset = ReadULEB128(&cur_instructions);
        
        DwarfLocation loc;
        loc.type = DWARF_LOCATION_OFFSET;
        loc.values[0] = offset;
        (*loc_regs)[reg] = loc;
        break;
      }
      
      case DW_CFA_register: {
        // 定义寄存器等于另一个寄存器
        uint64_t reg1 = ReadULEB128(&cur_instructions);
        uint64_t reg2 = ReadULEB128(&cur_instructions);
        
        DwarfLocation loc;
        loc.type = DWARF_LOCATION_REGISTER;
        loc.values[0] = reg2;
        (*loc_regs)[reg1] = loc;
        break;
      }
      
      case DW_CFA_expression: {
        // 使用表达式计算寄存器位置
        uint64_t reg = ReadULEB128(&cur_instructions);
        uint64_t expr_length = ReadULEB128(&cur_instructions);
        
        DwarfLocation loc;
        loc.type = DWARF_LOCATION_VAL_EXPRESSION;
        loc.values[0] = expr_length;
        // 保存表达式字节码
        loc.expression = std::vector<uint8_t>(cur_instructions, 
                                              cur_instructions + expr_length);
        (*loc_regs)[reg] = loc;
        cur_instructions += expr_length;
        break;
      }
      
      case DW_CFA_restore: {
        // 恢复寄存器的默认规则(从 CIE 中)
        uint64_t reg = ReadULEB128(&cur_instructions);
        auto cie_it = cie_loc_regs.find(reg);
        if (cie_it != cie_loc_regs.end()) {
          (*loc_regs)[reg] = cie_it->second;
        } else {
          loc_regs->erase(reg);
        }
        break;
      }
      
      // ... 其他指令 ...
    }
  }
  
  // 4. 设置有效范围
  loc_regs->pc_end = fde->pc_end;
  return true;
}

DwarfLocations 数据结构

struct DwarfLocation {
  uint8_t type;                    // 位置类型
  std::vector<uint64_t> values;     // 参数值
  std::vector<uint8_t> expression;  // 表达式字节码(如果类型是 EXPRESSION)
};

typedef std::map<uint32_t, DwarfLocation> DwarfLocations;
// 键:寄存器编号
// 值:如何恢复该寄存器的规则

位置类型(DwarfLocation::type)

类型 含义 如何计算
DWARF_LOCATION_REGISTER 寄存器值 reg[values[0]] + values[1]
DWARF_LOCATION_OFFSET 内存偏移 CFA + values[0]
DWARF_LOCATION_VAL_OFFSET 值偏移 CFA + values[0](作为值,不是地址)
DWARF_LOCATION_VAL_EXPRESSION 表达式值 执行表达式字节码
DWARF_LOCATION_EXPRESSION 表达式地址 执行表达式字节码得到地址,然后读取
DWARF_LOCATION_UNDEFINED 未定义 寄存器值未知
DWARF_LOCATION_SAME_VALUE 相同值 寄存器值不变(等于当前帧的值)

示例:解析过程

假设有以下函数:

void function_a() {
    // PC = 0x1000
    int local_var;
    function_b();  // PC = 0x1010
    // PC = 0x1014
}

对应的 DWARF CFI 指令可能是:

CIE:
  DW_CFA_def_cfa: SP, 0          // CFA = SP + 0
  DW_CFA_offset: LR, -8          // LR 保存在 CFA - 8

FDE for function_a (0x1000-0x1020):
  DW_CFA_advance_loc: 16         // 前进到 0x1010
  DW_CFA_def_cfa_offset: 16      // CFA = SP + 16(分配了栈空间)
  DW_CFA_offset: R0, -16         // R0 保存在 CFA - 16
  DW_CFA_advance_loc: 4         // 前进到 0x1014
  DW_CFA_def_cfa_offset: 0      // CFA = SP + 0(恢复栈)

pc = 0x1010(调用 function_b 时)时,解析过程:

  1. 初始状态(从 CIE):

    • CFA = SP + 0
    • LR = [CFA - 8]
  2. 执行 DW_CFA_advance_loc: 16

    • cur_pc = 0x1000 + 16 = 0x1010,匹配目标 PC
  3. 执行 DW_CFA_def_cfa_offset: 16

    • CFA = SP + 16
  4. 执行 DW_CFA_offset: R0, -16

    • R0 = [CFA - 16]
  5. 最终结果

    • CFA = SP + 16
    • LR = [CFA - 8] = [SP + 16 - 8] = [SP + 8]
    • R0 = [CFA - 16] = [SP + 16 - 16] = [SP]

第三步:Eval() 方法详解

方法签名

template <typename AddressType>
bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, 
                                         Memory* regular_memory,
                                         const DwarfLocations& loc_regs, 
                                         Regs* regs,
                                         bool* finished)

核心原理

Eval() 方法的作用是根据解析出的位置规则,实际执行寄存器恢复,将当前帧的寄存器更新为上一帧的寄存器值。

实现流程详解

template <typename AddressType>
bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, 
                                         Memory* regular_memory,
                                         const DwarfLocations& loc_regs, 
                                         Regs* regs,
                                         bool* finished) {
  // 1. 类型转换
  RegsImpl<AddressType>* cur_regs = 
      reinterpret_cast<RegsImpl<AddressType>*>(regs);
  
  // 2. 验证返回地址寄存器
  if (cie->return_address_register >= cur_regs->total_regs()) {
    last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
    return false;
  }
  
  // 3. 查找 CFA 的位置规则
  auto cfa_entry = loc_regs.find(CFA_REG);
  if (cfa_entry == loc_regs.end()) {
    last_error_.code = DWARF_ERROR_CFA_NOT_DEFINED;
    return false;
  }
  
  // 4. 清除 DEX PC(Java 层相关)
  cur_regs->set_dex_pc(0);
  
  // 5. 重置伪寄存器
  regs->ResetPseudoRegisters();
  
  // 6. 准备评估信息
  EvalInfo<AddressType> eval_info{
    .loc_regs = &loc_regs,
    .cie = cie,
    .regular_memory = regular_memory,
    .regs_info = RegsInfo<AddressType>(cur_regs)
  };
  
  // 7. 计算 CFA 值
  const DwarfLocation* cfa_loc = &cfa_entry->second;
  AddressType cfa_value;
  
  switch (cfa_loc->type) {
    case DWARF_LOCATION_REGISTER: {
      // CFA = reg[values[0]] + values[1]
      if (cfa_loc->values[0] >= cur_regs->total_regs()) {
        last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
        return false;
      }
      cfa_value = (*cur_regs)[cfa_loc->values[0]];  // 读取基寄存器
      cfa_value += cfa_loc->values[1];              // 加上偏移
      break;
    }
    
    case DWARF_LOCATION_VAL_EXPRESSION: {
      // CFA = 执行表达式的结果
      if (!EvalExpression(*cfa_loc, regular_memory, &cfa_value, 
                         &eval_info.regs_info, nullptr)) {
        return false;
      }
      break;
    }
    
    default:
      last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
      return false;
  }
  
  eval_info.cfa = cfa_value;
  
  // 8. 恢复所有寄存器
  for (const auto& entry : loc_regs) {
    uint32_t reg = entry.first;
    
    // 跳过 CFA 寄存器(已经处理)
    if (reg == CFA_REG) continue;
    
    AddressType* reg_ptr;
    
    if (reg >= cur_regs->total_regs()) {
      // 伪寄存器处理
      if (entry.second.type != DWARF_LOCATION_PSEUDO_REGISTER) {
        continue;  // 跳过未知寄存器
      }
      if (!eval_info.regs_info.regs->SetPseudoRegister(reg, 
                                                        entry.second.values[0])) {
        last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
        return false;
      }
    } else {
      // 普通寄存器:获取保存位置并恢复
      reg_ptr = eval_info.regs_info.Save(reg);
      if (!EvalRegister(&entry.second, reg, reg_ptr, &eval_info)) {
        return false;
      }
    }
  }
  
  // 9. 恢复返回地址(PC)
  if (eval_info.return_address_undefined) {
    cur_regs->set_pc(0);  // 返回地址未定义,到达栈底
  } else {
    // 从返回地址寄存器读取 PC
    cur_regs->set_pc((*cur_regs)[cie->return_address_register]);
  }
  
  // 10. 检查是否到达栈底
  *finished = (cur_regs->pc() == 0 && !cie->is_signal_frame) ? true : false;
  
  // 11. 更新栈指针为 CFA
  cur_regs->set_sp(eval_info.cfa);
  
  return true;
}

关键步骤详解

步骤 7:计算 CFA 值

CFA 是恢复其他寄存器的基准,必须先计算出来。

情况 1:CFA = 寄存器 + 偏移

case DWARF_LOCATION_REGISTER:
    cfa_value = (*cur_regs)[cfa_loc->values[0]];  // 读取基寄存器(通常是 SP)
    cfa_value += cfa_loc->values[1];              // 加上偏移
    break;

示例

情况 2:CFA = 表达式结果

case DWARF_LOCATION_VAL_EXPRESSION:
    EvalExpression(*cfa_loc, regular_memory, &cfa_value, 
                   &eval_info.regs_info, nullptr);
    break;

表达式是 DWARF 字节码,需要解释执行。

步骤 8:恢复所有寄存器

对每个寄存器,根据其位置规则恢复值:

for (const auto& entry : loc_regs) {
    uint32_t reg = entry.first;
    const DwarfLocation& loc = entry.second;
    
    AddressType* reg_ptr = eval_info.regs_info.Save(reg);
    EvalRegister(&loc, reg, reg_ptr, &eval_info);
}

EvalRegister() 的实现

template <typename AddressType>
bool DwarfSectionImpl<AddressType>::EvalRegister(
    const DwarfLocation* loc, uint32_t reg, AddressType* reg_ptr,
    EvalInfo<AddressType>* eval_info) {
  
  switch (loc->type) {
    case DWARF_LOCATION_OFFSET: {
      // 寄存器保存在 CFA + offset
      AddressType addr = eval_info->cfa + loc->values[0];
      if (!eval_info->regular_memory->Read(addr, reg_ptr, sizeof(AddressType))) {
        return false;
      }
      break;
    }
    
    case DWARF_LOCATION_REGISTER: {
      // 寄存器等于另一个寄存器
      if (loc->values[0] >= eval_info->regs_info.regs->total_regs()) {
        return false;
      }
      *reg_ptr = (*eval_info->regs_info.regs)[loc->values[0]];
      if (loc->values.size() > 1) {
        *reg_ptr += loc->values[1];  // 加上偏移
      }
      break;
    }
    
    case DWARF_LOCATION_VAL_OFFSET: {
      // 寄存器值 = CFA + offset(直接作为值,不是地址)
      *reg_ptr = eval_info->cfa + loc->values[0];
      break;
    }
    
    case DWARF_LOCATION_EXPRESSION: {
      // 寄存器保存在表达式计算的地址
      AddressType addr;
      if (!EvalExpression(*loc, eval_info->regular_memory, &addr,
                         &eval_info->regs_info, nullptr)) {
        return false;
      }
      if (!eval_info->regular_memory->Read(addr, reg_ptr, sizeof(AddressType))) {
        return false;
      }
      break;
    }
    
    case DWARF_LOCATION_VAL_EXPRESSION: {
      // 寄存器值 = 表达式的结果
      if (!EvalExpression(*loc, eval_info->regular_memory, reg_ptr,
                         &eval_info->regs_info, nullptr)) {
        return false;
      }
      break;
    }
    
    case DWARF_LOCATION_SAME_VALUE: {
      // 寄存器值不变(保持当前帧的值)
      // 不需要修改 reg_ptr
      break;
    }
    
    case DWARF_LOCATION_UNDEFINED: {
      // 寄存器值未定义,设置为 0 或保持原值
      *reg_ptr = 0;
      break;
    }
    
    default:
      return false;
  }
  
  return true;
}

寄存器恢复示例

假设当前帧的状态:

CFI 规则:

执行过程

  1. 计算 CFA

    cfa = SP + 16 = 0x7fff0000 + 16 = 0x7fff0010
    
  2. 恢复 LR

    lr_addr = CFA - 8 = 0x7fff0010 - 8 = 0x7fff0008
    LR = memory[lr_addr]  // 从内存读取
    
  3. 恢复 R0

    r0_addr = CFA - 16 = 0x7fff0010 - 16 = 0x7fff0000
    R0 = memory[r0_addr]  // 从内存读取
    
  4. 更新寄存器

    new_SP = CFA = 0x7fff0010  // 上一帧的 SP
    new_PC = LR = memory[0x7fff0008]  // 返回地址
    

步骤 9:恢复返回地址(PC)

if (eval_info.return_address_undefined) {
    cur_regs->set_pc(0);  // 到达栈底
} else {
    // 从返回地址寄存器读取 PC
    cur_regs->set_pc((*cur_regs)[cie->return_address_register]);
}

返回地址寄存器

示例(ARM64)

步骤 10-11:更新 SP 和检查结束

*finished = (cur_regs->pc() == 0 && !cie->is_signal_frame) ? true : false;
cur_regs->set_sp(eval_info.cfa);

完整示例:一次完整的展开过程

场景

假设有以下调用链:

main() -> function_a() -> function_b() [当前在这里]

当前状态(function_b 中):

步骤 1:查找 FDE

fde = GetFdeFromPc(0x40002000);
// 找到 function_b 的 FDE (0x40001ff0 - 0x40002050)

步骤 2:解析 CFI 规则

GetCfaLocationInfo(0x40002000, fde, &loc_regs, ARCH_ARM64);

解析结果:

CFA = SP + 16
LR = [CFA - 8]
R19 = [CFA - 16]
R20 = [CFA - 24]

步骤 3:执行寄存器恢复

Eval(cie, process_memory, loc_regs, regs, &finished);

执行过程:

  1. 计算 CFA

    cfa = SP + 16 = 0x7fff0000 + 16 = 0x7fff0010
    
  2. 恢复 LR

    lr_addr = 0x7fff0010 - 8 = 0x7fff0008
    LR = memory[0x7fff0008]  // 假设读取到 0x40001014
    
  3. 恢复 R19, R20

    R19 = memory[0x7fff0010 - 16] = memory[0x7fff0000]
    R20 = memory[0x7fff0010 - 24] = memory[0x7fffffe8]
    
  4. 更新寄存器

    new_PC = LR = 0x40001014  // 返回到 function_a
    new_SP = CFA = 0x7fff0010  // 上一帧的 SP
    

结果

展开后的状态(function_a 中):

关键数据结构

DwarfLocation

struct DwarfLocation {
  uint8_t type;                    // 位置类型
  std::vector<uint64_t> values;    // 参数值
  std::vector<uint8_t> expression; // 表达式字节码(可选)
};

DwarfLocations

typedef std::map<uint32_t, DwarfLocation> DwarfLocations;
// 键:寄存器编号(CFA_REG 是特殊值)
// 值:如何恢复该寄存器

DwarfFde

struct DwarfFde {
  uint64_t pc_start;              // 函数起始地址
  uint64_t pc_end;                // 函数结束地址
  DwarfCie* cie;                  // 关联的 CIE
  std::vector<uint8_t> instructions; // CFI 指令序列
};

DwarfCie

struct DwarfCie {
  uint8_t version;                // CIE 版本
  std::string augmentation;       // 增强字符串
  uint64_t code_alignment_factor; // 代码对齐因子
  int64_t data_alignment_factor;  // 数据对齐因子
  uint64_t return_address_register; // 返回地址寄存器编号
  std::vector<uint8_t> instructions; // 初始 CFI 指令
  bool is_signal_frame;           // 是否为信号帧
};

总结

DWARF 堆栈展开的核心原理:

  1. 查找 FDE:根据 PC 找到对应的函数描述
  2. 解析 CFI 指令:执行指令序列,得到当前 PC 位置的展开规则
  3. 计算 CFA:确定上一帧的栈指针位置
  4. 恢复寄存器:根据规则从内存或寄存器中恢复所有寄存器
  5. 更新 PC/SP:将 PC 设置为返回地址,SP 设置为 CFA

整个过程依赖于:

这使得 Unwinder 能够在不修改目标进程的情况下,完整地展开其调用栈。

参考资料

上一篇 下一篇

猜你喜欢

热点阅读