1 //===-- UnwindAssemblyInstEmulation.cpp --------------------------*- C++ 2 //-*-===// 3 // 4 // The LLVM Compiler Infrastructure 5 // 6 // This file is distributed under the University of Illinois Open Source 7 // License. See LICENSE.TXT for details. 8 // 9 //===----------------------------------------------------------------------===// 10 11 #include "UnwindAssemblyInstEmulation.h" 12 13 #include "lldb/Core/Address.h" 14 #include "lldb/Core/ArchSpec.h" 15 #include "lldb/Core/DataBufferHeap.h" 16 #include "lldb/Core/DataExtractor.h" 17 #include "lldb/Core/Disassembler.h" 18 #include "lldb/Core/Error.h" 19 #include "lldb/Core/FormatEntity.h" 20 #include "lldb/Core/Log.h" 21 #include "lldb/Core/PluginManager.h" 22 #include "lldb/Core/StreamString.h" 23 #include "lldb/Target/ExecutionContext.h" 24 #include "lldb/Target/Process.h" 25 #include "lldb/Target/Target.h" 26 #include "lldb/Target/Thread.h" 27 28 using namespace lldb; 29 using namespace lldb_private; 30 31 //----------------------------------------------------------------------------------------------- 32 // UnwindAssemblyInstEmulation method definitions 33 //----------------------------------------------------------------------------------------------- 34 35 bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly( 36 AddressRange &range, Thread &thread, UnwindPlan &unwind_plan) { 37 std::vector<uint8_t> function_text(range.GetByteSize()); 38 ProcessSP process_sp(thread.GetProcess()); 39 if (process_sp) { 40 Error error; 41 const bool prefer_file_cache = true; 42 if (process_sp->GetTarget().ReadMemory( 43 range.GetBaseAddress(), prefer_file_cache, function_text.data(), 44 range.GetByteSize(), error) != range.GetByteSize()) { 45 return false; 46 } 47 } 48 return GetNonCallSiteUnwindPlanFromAssembly( 49 range, function_text.data(), function_text.size(), unwind_plan); 50 } 51 52 bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly( 53 AddressRange &range, uint8_t *opcode_data, size_t opcode_size, 54 UnwindPlan &unwind_plan) { 55 if (opcode_data == nullptr || opcode_size == 0) 56 return false; 57 58 if (range.GetByteSize() > 0 && range.GetBaseAddress().IsValid() && 59 m_inst_emulator_ap.get()) { 60 61 // The instruction emulation subclass setup the unwind plan for the 62 // first instruction. 63 m_inst_emulator_ap->CreateFunctionEntryUnwind(unwind_plan); 64 65 // CreateFunctionEntryUnwind should have created the first row. If it 66 // doesn't, then we are done. 67 if (unwind_plan.GetRowCount() == 0) 68 return false; 69 70 const bool prefer_file_cache = true; 71 DisassemblerSP disasm_sp(Disassembler::DisassembleBytes( 72 m_arch, NULL, NULL, range.GetBaseAddress(), opcode_data, opcode_size, 73 99999, prefer_file_cache)); 74 75 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); 76 77 if (disasm_sp) { 78 79 m_range_ptr = ⦥ 80 m_unwind_plan_ptr = &unwind_plan; 81 82 const uint32_t addr_byte_size = m_arch.GetAddressByteSize(); 83 const bool show_address = true; 84 const bool show_bytes = true; 85 m_inst_emulator_ap->GetRegisterInfo(unwind_plan.GetRegisterKind(), 86 unwind_plan.GetInitialCFARegister(), 87 m_cfa_reg_info); 88 89 m_fp_is_cfa = false; 90 m_register_values.clear(); 91 m_pushed_regs.clear(); 92 93 // Initialize the CFA with a known value. In the 32 bit case 94 // it will be 0x80000000, and in the 64 bit case 0x8000000000000000. 95 // We use the address byte size to be safe for any future address sizes 96 m_initial_sp = (1ull << ((addr_byte_size * 8) - 1)); 97 RegisterValue cfa_reg_value; 98 cfa_reg_value.SetUInt(m_initial_sp, m_cfa_reg_info.byte_size); 99 SetRegisterValue(m_cfa_reg_info, cfa_reg_value); 100 101 const InstructionList &inst_list = disasm_sp->GetInstructionList(); 102 const size_t num_instructions = inst_list.GetSize(); 103 104 if (num_instructions > 0) { 105 Instruction *inst = inst_list.GetInstructionAtIndex(0).get(); 106 const lldb::addr_t base_addr = inst->GetAddress().GetFileAddress(); 107 108 // Map for storing the unwind plan row and the value of the registers at 109 // a given offset. 110 // When we see a forward branch we add a new entry to this map with the 111 // actual unwind plan 112 // row and register context for the target address of the branch as the 113 // current data have 114 // to be valid for the target address of the branch too if we are in the 115 // same function. 116 std::map<lldb::addr_t, std::pair<UnwindPlan::RowSP, RegisterValueMap>> 117 saved_unwind_states; 118 119 // Make a copy of the current instruction Row and save it in m_curr_row 120 // so we can add updates as we process the instructions. 121 UnwindPlan::RowSP last_row = unwind_plan.GetLastRow(); 122 UnwindPlan::Row *newrow = new UnwindPlan::Row; 123 if (last_row.get()) 124 *newrow = *last_row.get(); 125 m_curr_row.reset(newrow); 126 127 // Add the initial state to the save list with offset 0. 128 saved_unwind_states.insert({0, {last_row, m_register_values}}); 129 130 // cache the pc register number (in whatever register numbering this 131 // UnwindPlan uses) for 132 // quick reference during instruction parsing. 133 RegisterInfo pc_reg_info; 134 m_inst_emulator_ap->GetRegisterInfo( 135 eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc_reg_info); 136 137 // cache the return address register number (in whatever register 138 // numbering this UnwindPlan uses) for 139 // quick reference during instruction parsing. 140 RegisterInfo ra_reg_info; 141 m_inst_emulator_ap->GetRegisterInfo( 142 eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, ra_reg_info); 143 144 // The architecture dependent condition code of the last processed 145 // instruction. 146 EmulateInstruction::InstructionCondition last_condition = 147 EmulateInstruction::UnconditionalCondition; 148 lldb::addr_t condition_block_start_offset = 0; 149 150 for (size_t idx = 0; idx < num_instructions; ++idx) { 151 m_curr_row_modified = false; 152 m_forward_branch_offset = 0; 153 154 inst = inst_list.GetInstructionAtIndex(idx).get(); 155 if (inst) { 156 lldb::addr_t current_offset = 157 inst->GetAddress().GetFileAddress() - base_addr; 158 auto it = saved_unwind_states.upper_bound(current_offset); 159 assert(it != saved_unwind_states.begin() && 160 "Unwind row for the function entry missing"); 161 --it; // Move it to the row corresponding to the current offset 162 163 // If the offset of m_curr_row don't match with the offset we see in 164 // saved_unwind_states 165 // then we have to update m_curr_row and m_register_values based on 166 // the saved values. It 167 // is happenning after we processed an epilogue and a return to 168 // caller instruction. 169 if (it->second.first->GetOffset() != m_curr_row->GetOffset()) { 170 UnwindPlan::Row *newrow = new UnwindPlan::Row; 171 *newrow = *it->second.first; 172 m_curr_row.reset(newrow); 173 m_register_values = it->second.second; 174 } 175 176 m_inst_emulator_ap->SetInstruction(inst->GetOpcode(), 177 inst->GetAddress(), nullptr); 178 179 if (last_condition != 180 m_inst_emulator_ap->GetInstructionCondition()) { 181 if (m_inst_emulator_ap->GetInstructionCondition() != 182 EmulateInstruction::UnconditionalCondition && 183 saved_unwind_states.count(current_offset) == 0) { 184 // If we don't have a saved row for the current offset then save 185 // our 186 // current state because we will have to restore it after the 187 // conditional block. 188 auto new_row = 189 std::make_shared<UnwindPlan::Row>(*m_curr_row.get()); 190 saved_unwind_states.insert( 191 {current_offset, {new_row, m_register_values}}); 192 } 193 194 // If the last instruction was conditional with a different 195 // condition 196 // then the then current condition then restore the condition. 197 if (last_condition != 198 EmulateInstruction::UnconditionalCondition) { 199 const auto &saved_state = 200 saved_unwind_states.at(condition_block_start_offset); 201 m_curr_row = 202 std::make_shared<UnwindPlan::Row>(*saved_state.first); 203 m_curr_row->SetOffset(current_offset); 204 m_register_values = saved_state.second; 205 bool replace_existing = 206 true; // The last instruction might already 207 // created a row for this offset and 208 // we want to overwrite it. 209 unwind_plan.InsertRow( 210 std::make_shared<UnwindPlan::Row>(*m_curr_row), 211 replace_existing); 212 } 213 214 // We are starting a new conditional block at the catual offset 215 condition_block_start_offset = current_offset; 216 } 217 218 if (log && log->GetVerbose()) { 219 StreamString strm; 220 lldb_private::FormatEntity::Entry format; 221 FormatEntity::Parse("${frame.pc}: ", format); 222 inst->Dump(&strm, inst_list.GetMaxOpcocdeByteSize(), show_address, 223 show_bytes, NULL, NULL, NULL, &format, 0); 224 log->PutCString(strm.GetData()); 225 } 226 227 last_condition = m_inst_emulator_ap->GetInstructionCondition(); 228 229 m_inst_emulator_ap->EvaluateInstruction( 230 eEmulateInstructionOptionIgnoreConditions); 231 232 // If the current instruction is a branch forward then save the 233 // current CFI information 234 // for the offset where we are branching. 235 if (m_forward_branch_offset != 0 && 236 range.ContainsFileAddress(inst->GetAddress().GetFileAddress() + 237 m_forward_branch_offset)) { 238 auto newrow = 239 std::make_shared<UnwindPlan::Row>(*m_curr_row.get()); 240 newrow->SetOffset(current_offset + m_forward_branch_offset); 241 saved_unwind_states.insert( 242 {current_offset + m_forward_branch_offset, 243 {newrow, m_register_values}}); 244 unwind_plan.InsertRow(newrow); 245 } 246 247 // Were there any changes to the CFI while evaluating this 248 // instruction? 249 if (m_curr_row_modified) { 250 // Save the modified row if we don't already have a CFI row in the 251 // currennt address 252 if (saved_unwind_states.count( 253 current_offset + inst->GetOpcode().GetByteSize()) == 0) { 254 m_curr_row->SetOffset(current_offset + 255 inst->GetOpcode().GetByteSize()); 256 unwind_plan.InsertRow(m_curr_row); 257 saved_unwind_states.insert( 258 {current_offset + inst->GetOpcode().GetByteSize(), 259 {m_curr_row, m_register_values}}); 260 261 // Allocate a new Row for m_curr_row, copy the current state 262 // into it 263 UnwindPlan::Row *newrow = new UnwindPlan::Row; 264 *newrow = *m_curr_row.get(); 265 m_curr_row.reset(newrow); 266 } 267 } 268 } 269 } 270 } 271 } 272 273 if (log && log->GetVerbose()) { 274 StreamString strm; 275 lldb::addr_t base_addr = range.GetBaseAddress().GetFileAddress(); 276 strm.Printf("Resulting unwind rows for [0x%" PRIx64 " - 0x%" PRIx64 "):", 277 base_addr, base_addr + range.GetByteSize()); 278 unwind_plan.Dump(strm, nullptr, base_addr); 279 log->PutCString(strm.GetData()); 280 } 281 return unwind_plan.GetRowCount() > 0; 282 } 283 return false; 284 } 285 286 bool UnwindAssemblyInstEmulation::AugmentUnwindPlanFromCallSite( 287 AddressRange &func, Thread &thread, UnwindPlan &unwind_plan) { 288 return false; 289 } 290 291 bool UnwindAssemblyInstEmulation::GetFastUnwindPlan(AddressRange &func, 292 Thread &thread, 293 UnwindPlan &unwind_plan) { 294 return false; 295 } 296 297 bool UnwindAssemblyInstEmulation::FirstNonPrologueInsn( 298 AddressRange &func, const ExecutionContext &exe_ctx, 299 Address &first_non_prologue_insn) { 300 return false; 301 } 302 303 UnwindAssembly * 304 UnwindAssemblyInstEmulation::CreateInstance(const ArchSpec &arch) { 305 std::unique_ptr<EmulateInstruction> inst_emulator_ap( 306 EmulateInstruction::FindPlugin(arch, eInstructionTypePrologueEpilogue, 307 NULL)); 308 // Make sure that all prologue instructions are handled 309 if (inst_emulator_ap.get()) 310 return new UnwindAssemblyInstEmulation(arch, inst_emulator_ap.release()); 311 return NULL; 312 } 313 314 //------------------------------------------------------------------ 315 // PluginInterface protocol in UnwindAssemblyParser_x86 316 //------------------------------------------------------------------ 317 ConstString UnwindAssemblyInstEmulation::GetPluginName() { 318 return GetPluginNameStatic(); 319 } 320 321 uint32_t UnwindAssemblyInstEmulation::GetPluginVersion() { return 1; } 322 323 void UnwindAssemblyInstEmulation::Initialize() { 324 PluginManager::RegisterPlugin(GetPluginNameStatic(), 325 GetPluginDescriptionStatic(), CreateInstance); 326 } 327 328 void UnwindAssemblyInstEmulation::Terminate() { 329 PluginManager::UnregisterPlugin(CreateInstance); 330 } 331 332 ConstString UnwindAssemblyInstEmulation::GetPluginNameStatic() { 333 static ConstString g_name("inst-emulation"); 334 return g_name; 335 } 336 337 const char *UnwindAssemblyInstEmulation::GetPluginDescriptionStatic() { 338 return "Instruction emulation based unwind information."; 339 } 340 341 uint64_t UnwindAssemblyInstEmulation::MakeRegisterKindValuePair( 342 const RegisterInfo ®_info) { 343 lldb::RegisterKind reg_kind; 344 uint32_t reg_num; 345 if (EmulateInstruction::GetBestRegisterKindAndNumber(®_info, reg_kind, 346 reg_num)) 347 return (uint64_t)reg_kind << 24 | reg_num; 348 return 0ull; 349 } 350 351 void UnwindAssemblyInstEmulation::SetRegisterValue( 352 const RegisterInfo ®_info, const RegisterValue ®_value) { 353 m_register_values[MakeRegisterKindValuePair(reg_info)] = reg_value; 354 } 355 356 bool UnwindAssemblyInstEmulation::GetRegisterValue(const RegisterInfo ®_info, 357 RegisterValue ®_value) { 358 const uint64_t reg_id = MakeRegisterKindValuePair(reg_info); 359 RegisterValueMap::const_iterator pos = m_register_values.find(reg_id); 360 if (pos != m_register_values.end()) { 361 reg_value = pos->second; 362 return true; // We had a real value that comes from an opcode that wrote 363 // to it... 364 } 365 // We are making up a value that is recognizable... 366 reg_value.SetUInt(reg_id, reg_info.byte_size); 367 return false; 368 } 369 370 size_t UnwindAssemblyInstEmulation::ReadMemory( 371 EmulateInstruction *instruction, void *baton, 372 const EmulateInstruction::Context &context, lldb::addr_t addr, void *dst, 373 size_t dst_len) { 374 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); 375 376 if (log && log->GetVerbose()) { 377 StreamString strm; 378 strm.Printf( 379 "UnwindAssemblyInstEmulation::ReadMemory (addr = 0x%16.16" PRIx64 380 ", dst = %p, dst_len = %" PRIu64 ", context = ", 381 addr, dst, (uint64_t)dst_len); 382 context.Dump(strm, instruction); 383 log->PutCString(strm.GetData()); 384 } 385 memset(dst, 0, dst_len); 386 return dst_len; 387 } 388 389 size_t UnwindAssemblyInstEmulation::WriteMemory( 390 EmulateInstruction *instruction, void *baton, 391 const EmulateInstruction::Context &context, lldb::addr_t addr, 392 const void *dst, size_t dst_len) { 393 if (baton && dst && dst_len) 394 return ((UnwindAssemblyInstEmulation *)baton) 395 ->WriteMemory(instruction, context, addr, dst, dst_len); 396 return 0; 397 } 398 399 size_t UnwindAssemblyInstEmulation::WriteMemory( 400 EmulateInstruction *instruction, const EmulateInstruction::Context &context, 401 lldb::addr_t addr, const void *dst, size_t dst_len) { 402 DataExtractor data(dst, dst_len, 403 instruction->GetArchitecture().GetByteOrder(), 404 instruction->GetArchitecture().GetAddressByteSize()); 405 406 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); 407 408 if (log && log->GetVerbose()) { 409 StreamString strm; 410 411 strm.PutCString("UnwindAssemblyInstEmulation::WriteMemory ("); 412 data.Dump(&strm, 0, eFormatBytes, 1, dst_len, UINT32_MAX, addr, 0, 0); 413 strm.PutCString(", context = "); 414 context.Dump(strm, instruction); 415 log->PutCString(strm.GetData()); 416 } 417 418 const bool cant_replace = false; 419 420 switch (context.type) { 421 default: 422 case EmulateInstruction::eContextInvalid: 423 case EmulateInstruction::eContextReadOpcode: 424 case EmulateInstruction::eContextImmediate: 425 case EmulateInstruction::eContextAdjustBaseRegister: 426 case EmulateInstruction::eContextRegisterPlusOffset: 427 case EmulateInstruction::eContextAdjustPC: 428 case EmulateInstruction::eContextRegisterStore: 429 case EmulateInstruction::eContextRegisterLoad: 430 case EmulateInstruction::eContextRelativeBranchImmediate: 431 case EmulateInstruction::eContextAbsoluteBranchRegister: 432 case EmulateInstruction::eContextSupervisorCall: 433 case EmulateInstruction::eContextTableBranchReadMemory: 434 case EmulateInstruction::eContextWriteRegisterRandomBits: 435 case EmulateInstruction::eContextWriteMemoryRandomBits: 436 case EmulateInstruction::eContextArithmetic: 437 case EmulateInstruction::eContextAdvancePC: 438 case EmulateInstruction::eContextReturnFromException: 439 case EmulateInstruction::eContextPopRegisterOffStack: 440 case EmulateInstruction::eContextAdjustStackPointer: 441 break; 442 443 case EmulateInstruction::eContextPushRegisterOnStack: { 444 uint32_t reg_num = LLDB_INVALID_REGNUM; 445 uint32_t generic_regnum = LLDB_INVALID_REGNUM; 446 if (context.info_type == 447 EmulateInstruction::eInfoTypeRegisterToRegisterPlusOffset) { 448 const uint32_t unwind_reg_kind = m_unwind_plan_ptr->GetRegisterKind(); 449 reg_num = context.info.RegisterToRegisterPlusOffset.data_reg 450 .kinds[unwind_reg_kind]; 451 generic_regnum = context.info.RegisterToRegisterPlusOffset.data_reg 452 .kinds[eRegisterKindGeneric]; 453 } else 454 assert(!"unhandled case, add code to handle this!"); 455 456 if (reg_num != LLDB_INVALID_REGNUM && 457 generic_regnum != LLDB_REGNUM_GENERIC_SP) { 458 if (m_pushed_regs.find(reg_num) == m_pushed_regs.end()) { 459 m_pushed_regs[reg_num] = addr; 460 const int32_t offset = addr - m_initial_sp; 461 m_curr_row->SetRegisterLocationToAtCFAPlusOffset(reg_num, offset, 462 cant_replace); 463 m_curr_row_modified = true; 464 } 465 } 466 } break; 467 } 468 469 return dst_len; 470 } 471 472 bool UnwindAssemblyInstEmulation::ReadRegister(EmulateInstruction *instruction, 473 void *baton, 474 const RegisterInfo *reg_info, 475 RegisterValue ®_value) { 476 477 if (baton && reg_info) 478 return ((UnwindAssemblyInstEmulation *)baton) 479 ->ReadRegister(instruction, reg_info, reg_value); 480 return false; 481 } 482 bool UnwindAssemblyInstEmulation::ReadRegister(EmulateInstruction *instruction, 483 const RegisterInfo *reg_info, 484 RegisterValue ®_value) { 485 bool synthetic = GetRegisterValue(*reg_info, reg_value); 486 487 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); 488 489 if (log && log->GetVerbose()) { 490 491 StreamString strm; 492 strm.Printf("UnwindAssemblyInstEmulation::ReadRegister (name = \"%s\") => " 493 "synthetic_value = %i, value = ", 494 reg_info->name, synthetic); 495 reg_value.Dump(&strm, reg_info, false, false, eFormatDefault); 496 log->PutCString(strm.GetData()); 497 } 498 return true; 499 } 500 501 bool UnwindAssemblyInstEmulation::WriteRegister( 502 EmulateInstruction *instruction, void *baton, 503 const EmulateInstruction::Context &context, const RegisterInfo *reg_info, 504 const RegisterValue ®_value) { 505 if (baton && reg_info) 506 return ((UnwindAssemblyInstEmulation *)baton) 507 ->WriteRegister(instruction, context, reg_info, reg_value); 508 return false; 509 } 510 bool UnwindAssemblyInstEmulation::WriteRegister( 511 EmulateInstruction *instruction, const EmulateInstruction::Context &context, 512 const RegisterInfo *reg_info, const RegisterValue ®_value) { 513 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); 514 515 if (log && log->GetVerbose()) { 516 517 StreamString strm; 518 strm.Printf( 519 "UnwindAssemblyInstEmulation::WriteRegister (name = \"%s\", value = ", 520 reg_info->name); 521 reg_value.Dump(&strm, reg_info, false, false, eFormatDefault); 522 strm.PutCString(", context = "); 523 context.Dump(strm, instruction); 524 log->PutCString(strm.GetData()); 525 } 526 527 SetRegisterValue(*reg_info, reg_value); 528 529 switch (context.type) { 530 case EmulateInstruction::eContextInvalid: 531 case EmulateInstruction::eContextReadOpcode: 532 case EmulateInstruction::eContextImmediate: 533 case EmulateInstruction::eContextAdjustBaseRegister: 534 case EmulateInstruction::eContextRegisterPlusOffset: 535 case EmulateInstruction::eContextAdjustPC: 536 case EmulateInstruction::eContextRegisterStore: 537 case EmulateInstruction::eContextSupervisorCall: 538 case EmulateInstruction::eContextTableBranchReadMemory: 539 case EmulateInstruction::eContextWriteRegisterRandomBits: 540 case EmulateInstruction::eContextWriteMemoryRandomBits: 541 case EmulateInstruction::eContextAdvancePC: 542 case EmulateInstruction::eContextReturnFromException: 543 case EmulateInstruction::eContextPushRegisterOnStack: 544 case EmulateInstruction::eContextRegisterLoad: 545 // { 546 // const uint32_t reg_num = 547 // reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()]; 548 // if (reg_num != LLDB_INVALID_REGNUM) 549 // { 550 // const bool can_replace_only_if_unspecified = true; 551 // 552 // m_curr_row.SetRegisterLocationToUndefined (reg_num, 553 // can_replace_only_if_unspecified, 554 // can_replace_only_if_unspecified); 555 // m_curr_row_modified = true; 556 // } 557 // } 558 break; 559 560 case EmulateInstruction::eContextArithmetic: { 561 // If we adjusted the current frame pointer by a constant then adjust the 562 // CFA offset 563 // with the same amount. 564 lldb::RegisterKind kind = m_unwind_plan_ptr->GetRegisterKind(); 565 if (m_fp_is_cfa && reg_info->kinds[kind] == m_cfa_reg_info.kinds[kind] && 566 context.info_type == EmulateInstruction::eInfoTypeRegisterPlusOffset && 567 context.info.RegisterPlusOffset.reg.kinds[kind] == 568 m_cfa_reg_info.kinds[kind]) { 569 const int64_t offset = context.info.RegisterPlusOffset.signed_offset; 570 m_curr_row->GetCFAValue().IncOffset(-1 * offset); 571 m_curr_row_modified = true; 572 } 573 } break; 574 575 case EmulateInstruction::eContextAbsoluteBranchRegister: 576 case EmulateInstruction::eContextRelativeBranchImmediate: { 577 if (context.info_type == EmulateInstruction::eInfoTypeISAAndImmediate && 578 context.info.ISAAndImmediate.unsigned_data32 > 0) { 579 m_forward_branch_offset = 580 context.info.ISAAndImmediateSigned.signed_data32; 581 } else if (context.info_type == 582 EmulateInstruction::eInfoTypeISAAndImmediateSigned && 583 context.info.ISAAndImmediateSigned.signed_data32 > 0) { 584 m_forward_branch_offset = context.info.ISAAndImmediate.unsigned_data32; 585 } else if (context.info_type == EmulateInstruction::eInfoTypeImmediate && 586 context.info.unsigned_immediate > 0) { 587 m_forward_branch_offset = context.info.unsigned_immediate; 588 } else if (context.info_type == 589 EmulateInstruction::eInfoTypeImmediateSigned && 590 context.info.signed_immediate > 0) { 591 m_forward_branch_offset = context.info.signed_immediate; 592 } 593 } break; 594 595 case EmulateInstruction::eContextPopRegisterOffStack: { 596 const uint32_t reg_num = 597 reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()]; 598 const uint32_t generic_regnum = reg_info->kinds[eRegisterKindGeneric]; 599 if (reg_num != LLDB_INVALID_REGNUM && 600 generic_regnum != LLDB_REGNUM_GENERIC_SP) { 601 switch (context.info_type) { 602 case EmulateInstruction::eInfoTypeAddress: 603 if (m_pushed_regs.find(reg_num) != m_pushed_regs.end() && 604 context.info.address == m_pushed_regs[reg_num]) { 605 m_curr_row->SetRegisterLocationToSame(reg_num, 606 false /*must_replace*/); 607 m_curr_row_modified = true; 608 } 609 break; 610 case EmulateInstruction::eInfoTypeISA: 611 assert( 612 (generic_regnum == LLDB_REGNUM_GENERIC_PC || 613 generic_regnum == LLDB_REGNUM_GENERIC_FLAGS) && 614 "eInfoTypeISA used for poping a register other the the PC/FLAGS"); 615 if (generic_regnum != LLDB_REGNUM_GENERIC_FLAGS) { 616 m_curr_row->SetRegisterLocationToSame(reg_num, 617 false /*must_replace*/); 618 m_curr_row_modified = true; 619 } 620 break; 621 default: 622 assert(false && "unhandled case, add code to handle this!"); 623 break; 624 } 625 } 626 } break; 627 628 case EmulateInstruction::eContextSetFramePointer: 629 if (!m_fp_is_cfa) { 630 m_fp_is_cfa = true; 631 m_cfa_reg_info = *reg_info; 632 const uint32_t cfa_reg_num = 633 reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()]; 634 assert(cfa_reg_num != LLDB_INVALID_REGNUM); 635 m_curr_row->GetCFAValue().SetIsRegisterPlusOffset( 636 cfa_reg_num, m_initial_sp - reg_value.GetAsUInt64()); 637 m_curr_row_modified = true; 638 } 639 break; 640 641 case EmulateInstruction::eContextRestoreStackPointer: 642 if (m_fp_is_cfa) { 643 m_fp_is_cfa = false; 644 m_cfa_reg_info = *reg_info; 645 const uint32_t cfa_reg_num = 646 reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()]; 647 assert(cfa_reg_num != LLDB_INVALID_REGNUM); 648 m_curr_row->GetCFAValue().SetIsRegisterPlusOffset( 649 cfa_reg_num, m_initial_sp - reg_value.GetAsUInt64()); 650 m_curr_row_modified = true; 651 } 652 break; 653 654 case EmulateInstruction::eContextAdjustStackPointer: 655 // If we have created a frame using the frame pointer, don't follow 656 // subsequent adjustments to the stack pointer. 657 if (!m_fp_is_cfa) { 658 m_curr_row->GetCFAValue().SetIsRegisterPlusOffset( 659 m_curr_row->GetCFAValue().GetRegisterNumber(), 660 m_initial_sp - reg_value.GetAsUInt64()); 661 m_curr_row_modified = true; 662 } 663 break; 664 } 665 return true; 666 } 667