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